📄 baseresource.cpp
字号:
/*
* Openmysee
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include "stdafx.h"
#include ".\baseresource.h"
#include "Communicator.h"
#include "BufferMgr.h"
namespace NPLayer1 {
BaseResource::BaseResource(Communicator* c) :
comm(c), bInited(FALSE), spIPList(NULL), spIPListSize(0),
blockIDArray(NULL), blockMapArray(NULL), blockMapSize(0),
blocks4Play(1), bufferMgr(NULL)
{
}
BaseResource::~BaseResource(void) {
// 此处不能调用纯虚函数
}
void BaseResource::UninitEx() {
delete [] blockMapArray;
delete [] blockIDArray;
delete [] spIPList;
blockMapArray = blockIDArray = NULL;
spIPList = NULL;
}
// 复制全部区间列表
void BaseResource::GetAllIntervals(BlockInterval* targetArray, UINT8& size) {
allIntervals.CopyIntervalArray(targetArray, size);
};
// 发送给TS/NP的区间列表
void BaseResource::GetDiffIntervals(BlockInterval* targetArray, UINT8& size, bool forTS, bool getInc) {
if(forTS) {
if(getInc)
csIncIntervals.CopyIntervalArray(targetArray, size);
else
csDecIntervals.CopyIntervalArray(targetArray, size);
}
else {
if(getInc)
p2pIncIntervals.CopyIntervalArray(targetArray, size);
else
p2pDecIntervals.CopyIntervalArray(targetArray, size);
}
};
// 清空发送给TS/NP的增量区间列表
void BaseResource::ClearDiffIntervals(bool forTS) {
if(forTS) {
csIncIntervals.Clear();
csDecIntervals.Clear();
}
else {
p2pIncIntervals.Clear();
p2pDecIntervals.Clear();
}
};
P2P_RETURN_TYPE BaseResource::GetBlock(UINT blockID, UINT& blockSize, LPVOID data) {
blockSize = 0;
if(!bInited)
return PRT_NOT_INIT;
if(!data)
return PRT_WRONG_ARG;
if(blockID == UINT_MAX)
return PRT_BLOCK_NOTFOUND;
CriticalSection::Owner lock(dataLocker);
// 查找此块在虚拟缓冲区中的编号
UINT blockIndex = FindBlockIndex(blockID);
// 如果找到了,相应的根据此编号得知此块的大小
// 然后根据虚拟缓冲区与实际缓冲区的对应表,查找它在实际缓冲区的位置,并读取数据
if(blockIndex != UINT_MAX) {
// 此块的大小,如果是最后一块,则大小不是BLOCK_SIZE
blockSize = BLOCK_SIZE;
P2P_RETURN_TYPE ret = bufferMgr->GetIndexData(blockMapArray[blockIndex], 0, data, blockSize);
if(ret < PRT_OK)
return ret;
return PRT_OK;
}
return PRT_BLOCK_NOTFOUND;
}
P2P_RETURN_TYPE BaseResource::PutBlock(UINT blockID, UINT blockSize, PBYTE data) {
if(!data || !bInited)
return PRT_WRONG_ARG;
CriticalSection::Owner lock(dataLocker);
assert(blockID != UINT_MAX);
// 已经有此块,呵呵
if(allIntervals.FindBlock(blockID)) {
comm->logFile.StatusOut("Duplicate Block!");
return PRT_OK;
}
// 检查虚拟缓冲区里是否还有空位置,如果没有就执行强制替换
UINT32 emptyIndex = bufferMgr->GetEmptyIndex(rand(&comm->ctx));
assert(emptyIndex != UINT_MAX);
comm->logFile.StatusOut("empty space in buffermgr %d.", emptyIndex);
// 查找一个可用的位置(空的,或者可以替换的)
UINT replacedBlockID = UINT_MAX;
UINT replacableIndex = GetReplacableBlock(blockID, replacedBlockID);
if(replacableIndex == UINT_MAX) {
bufferMgr->EraseIndex(emptyIndex);
//assert(0);
return PRT_BUFFER_FULL;
}
// 找到可以替换的块, 先删除掉
comm->logFile.StatusOut("%d replaced %d.", blockID, replacedBlockID);
DelBlock(replacedBlockID);
// 将数据存储到实际的缓冲区
P2P_RETURN_TYPE ret = bufferMgr->PutIndexData(emptyIndex, data, blockSize);
if(ret < PRT_OK) {
comm->logFile.StatusErr("Save data", GetLastError());
// 如果存储失败,当然要释放空间
bufferMgr->EraseIndex(emptyIndex);
assert(0);
return ret;
}
// 数据成功保存, 更新虚拟缓冲区管理数组
blockIDArray[replacableIndex] = blockID;
// 设置实际缓冲区的位置
blockMapArray[replacableIndex] = emptyIndex;
// 在区间列表中添加此块
allIntervals.AddInterval(blockID, 1);
csIncIntervals.AddInterval(blockID, 1);
p2pIncIntervals.AddInterval(blockID, 1);
// 区间发生变化
comm->p2pMgr.m_bBlockIntervalHasChanged = true;
return PRT_OK;
}
void BaseResource::DelBlock(UINT blockID) {
CriticalSection::Owner lock(dataLocker);
if(blockID == UINT_MAX)
return;
// 查找此块在虚拟缓冲区中的编号
UINT blockIndex = FindBlockIndex(blockID);
if(blockIndex != UINT_MAX) {
comm->logFile.StatusOut("Delete Block %d", blockID);
// 在实际缓冲区中删除此块
bufferMgr->EraseIndex(blockMapArray[blockIndex]);
// 在区间列表中删除要替换的块
allIntervals.DelInterval(blockIDArray[blockIndex], 1);
csDecIntervals.AddInterval(blockIDArray[blockIndex], 1);
p2pDecIntervals.AddInterval(blockIDArray[blockIndex], 1);
// 在虚拟缓冲区中删除此块
blockMapArray[blockIndex] = UINT_MAX;
blockIDArray[blockIndex] = UINT_MAX;
}
}
// 在虚拟缓冲区寻找空块或者可以替换的块,返回其在虚拟缓冲区的位置
UINT BaseResource::GetReplacableBlock(const UINT newBlockID, UINT& replacedBlockID) {
replacedBlockID = UINT_MAX;
// 1. 查找一个未使用的位置,如果找到了,就直接使用
UINT replacableIndex = FindBlockIndex(UINT_MAX);
comm->logFile.StatusOut("find empty space in virtual buffer %d", replacableIndex);
if(replacableIndex != UINT_MAX) {
replacedBlockID = blockIDArray[replacableIndex];
return replacableIndex;
}
// 2. 没找到未使用的, 先后尝试替换minBlockID和maxBlockID
UINT minBlockID = GetMinBlockID();
if(GetPlayingBlock(false) > minBlockID) {
// 由于现在只有直播,而直播必定是顺序播放的,那么min只要存在,就可以替换
replacedBlockID = minBlockID;
}
else {
// 因为是半闭半开区间,所以maxBlockID要减去1才是最后一块的ID
UINT maxBlockID = GetMaxBlockID();
maxBlockID--;
if(maxBlockID > newBlockID && maxBlockID > GetPlayingBlock(true))
replacedBlockID = maxBlockID;
}
// 3. 如果找到了可以替换的min/max,查找其在虚拟缓冲区中的位置
if(replacedBlockID != UINT_MAX) {
replacableIndex = FindBlockIndex(replacedBlockID);
if(replacableIndex == UINT_MAX) {
// 如果没找到对应的index,说明区间列表出现问题!!!!
// 只能重新生成区间列表了
comm->logFile.StatusOut("no max block, rebuild interval array.");
assert(0);
allIntervals.Clear();
for(UINT i = 0; i < blockMapSize; ++i)
allIntervals.AddInterval(blockIDArray[i], 1);
// 下次再重试吧
replacedBlockID = UINT_MAX;
return UINT_MAX;
}
}
return replacableIndex;
}
// 针对某个NP的区间列表,获取可以下载的区间列表
void BaseResource::GetDownloadableArray(const IntervalArray& anotherNP, IntervalArray& result) {
result.Clear();
// 从当前播放的块到可以暂停下载的块是允许下载的最大区间
IntervalArray downloadable;
// 允许下载区间大小不能超过虚拟缓冲区的大小
downloadable.AddInterval(GetPlayingBlock(), DEFAULT_SPACE/BLOCK_SIZE);
// 允许下载的区间和现有块的区间之差就是本机需要下载但是却没有的块
downloadable.DeleteArray(allIntervals);
// 本机需要的块和对方拥有的块做&运算,结果就是对方拥有而本机需要的块
downloadable.AndOperator(anotherNP, result);
}
P2P_RETURN_TYPE BaseResource::ParseSPList(string strSPList) {
// 不能为空
if(strSPList.empty())
return PRT_WRONG_ARG;
// 临时中转的列表
list<NormalAddress> spList;
istrstream is(strSPList.data());
string line;
string ip;
string port;
NormalAddress tmpAddr;
while(getline(is,line, '/')) {
if(!line.length())
continue;
int index = line.find(':');
if(index == -1)
continue;
ip = line.substr(0, index);
port = line.substr(index+1, line.length()-index-1);
tmpAddr.sin_addr.s_addr = TE_GetIP(ip.data(), TRUE);
if(tmpAddr.sin_addr.s_addr == INADDR_NONE)
continue;
tmpAddr.sin_port = htons(static_cast<USHORT>(atoi(port.data())));
spList.push_back(tmpAddr);
}
spIPListSize = min(0xff, spList.size());
// 必须至少包含一个SP的地址
if(spIPListSize == 0)
return PRT_WRONG_ARG;
spIPList = new NormalAddress[spList.size()];
if(!spIPList)
return PRT_ALLOC;
// 复制到实际使用的列表
copy(spList.begin(), spList.end(), spIPList);
return PRT_OK;
}
// 查找一个未使用的块ID,并返回此块在虚拟缓冲区中的Index
UINT BaseResource::FindBlockIndex(UINT blockID) {
// 首先在区间表中查询,速度非常快!
// 如果BlockID等于UINT_MAX说明是要寻找空位,则交给后面的find进行查找
if(blockID != UINT_MAX && !allIntervals.FindBlock(blockID)) {
#ifdef _DEBUG
UINT* index = find(blockIDArray, blockIDArray+blockMapSize, blockID);
assert(index == blockIDArray+blockMapSize);
#endif
return UINT_MAX;
}
// 如果确认存在,再查询此块的Index
UINT* index = find(blockIDArray, blockIDArray+blockMapSize, blockID);
if(index == blockIDArray+blockMapSize)
return UINT_MAX;
return index-blockIDArray;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -