mirror of
https://github.com/RetroShare/RetroShare.git
synced 2024-12-21 21:55:15 -05:00
- Implemented chunk-based file transfer from partial sources. This in particular means:
- exchange of chunk availability maps from different peers - correct handling of what is available to which source before asking the data - correct display of chunks in the progress bars - generalised the use of compressed chunk maps - removed the size parameters from the hash search functions - In addition: - suppressed a number of per-value transfers of std::string - improved the FileTransferInfo Widget, to show some additional info Still to be done: - chunk map exchange for non anonymous traffic (easy) - improve accuracy of completion for uploads (for now it's a integer number of chunks) - check compilation on windows git-svn-id: http://svn.code.sf.net/p/retroshare/code/trunk@1993 b45a01b8-16f6-495d-af2f-9b41ad6348cc
This commit is contained in:
parent
add5d45eeb
commit
cfaaec31c7
@ -1,8 +1,11 @@
|
||||
#include <math.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <rsiface/rspeers.h>
|
||||
#include "ftchunkmap.h"
|
||||
|
||||
static const uint32_t SOURCE_CHUNK_MAP_UPDATE_PERIOD = 60 ; //! TTL for chunkmap info
|
||||
|
||||
std::ostream& operator<<(std::ostream& o,const ftChunk& c)
|
||||
{
|
||||
return o << "\tChunk [" << c.offset << "] size: " << c.size << " ChunkId: " << c.id << " Age: " << time(NULL) - c.ts ;
|
||||
@ -28,26 +31,6 @@ void Chunk::getSlice(uint32_t size_hint,ftChunk& chunk)
|
||||
_offset += chunk.size ;
|
||||
}
|
||||
|
||||
//uint32_t Chunk::dataReceived(const ftChunk::ChunkId cid)
|
||||
//{
|
||||
//#ifdef DEBUG_FTCHUNK
|
||||
// std::cerr << "*** Chunk::dataReceived: slice " << cid << " finished" << std::endl ;
|
||||
//#endif
|
||||
// std::map<ftChunk::ChunkId,uint32_t>::iterator it( _slices_to_download.find(cid) ) ;
|
||||
//
|
||||
// if(it == _slices_to_download.end())
|
||||
// {
|
||||
// std::cerr << "!!! Chunk::dataReceived: could not find chunk " << cid << ": probably a fatal error" << std::endl ;
|
||||
// return 0 ;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// uint32_t n = it->second ;
|
||||
// _slices_to_download.erase(it) ;
|
||||
// return n ;
|
||||
// }
|
||||
//}
|
||||
|
||||
ChunkMap::ChunkMap(uint64_t s)
|
||||
:_file_size(s),_chunk_size(1024*1024) // 1MB chunks
|
||||
{
|
||||
@ -67,34 +50,46 @@ ChunkMap::ChunkMap(uint64_t s)
|
||||
#endif
|
||||
}
|
||||
|
||||
ChunkMap::ChunkMap(uint64_t file_size,
|
||||
const std::vector<uint32_t>& map,
|
||||
uint32_t chunk_size,
|
||||
uint32_t chunk_number,
|
||||
FileChunksInfo::ChunkStrategy strategy)
|
||||
|
||||
:_file_size(file_size),_chunk_size(chunk_size),_strategy(strategy)
|
||||
void ChunkMap::setAvailabilityMap(const CompressedChunkMap& map)
|
||||
{
|
||||
#ifdef DEBUG_FTCHUNK
|
||||
std::cerr << "ChunkMap:: loading availability map of size " << map.size() << ", chunk_size=" << chunk_size << ", chunknumber = " << chunk_number << std::endl ;
|
||||
#endif
|
||||
|
||||
_map.clear() ;
|
||||
_map.resize(chunk_number) ;
|
||||
_total_downloaded = 0 ;
|
||||
|
||||
for(uint32_t i=0;i<_map.size();++i)
|
||||
{
|
||||
uint32_t j = i & 31 ; // i%32
|
||||
uint32_t k = i >> 5 ; // i/32
|
||||
|
||||
_map[i] = ( (map[k] & (1<<j)) > 0)?(FileChunksInfo::CHUNK_DONE) : (FileChunksInfo::CHUNK_OUTSTANDING) ;
|
||||
|
||||
if(_map[i] == FileChunksInfo::CHUNK_DONE)
|
||||
if(map[i] > 0)
|
||||
{
|
||||
_map[i] = FileChunksInfo::CHUNK_DONE ;
|
||||
_total_downloaded += _chunk_size ;
|
||||
}
|
||||
}
|
||||
else
|
||||
_map[i] = FileChunksInfo::CHUNK_OUTSTANDING ;
|
||||
}
|
||||
|
||||
//ChunkMap::ChunkMap(uint64_t file_size,
|
||||
// const std::vector<uint32_t>& map,
|
||||
// uint32_t chunk_size,
|
||||
// uint32_t chunk_number,
|
||||
// FileChunksInfo::ChunkStrategy strategy)
|
||||
//
|
||||
// :_file_size(file_size),_chunk_size(chunk_size),_strategy(strategy)
|
||||
//{
|
||||
//#ifdef DEBUG_FTCHUNK
|
||||
// std::cerr << "ChunkMap:: loading availability map of size " << map.size() << ", chunk_size=" << chunk_size << ", chunknumber = " << chunk_number << std::endl ;
|
||||
//#endif
|
||||
//
|
||||
// _map.clear() ;
|
||||
// _map.resize(chunk_number) ;
|
||||
// _total_downloaded = 0 ;
|
||||
//
|
||||
// for(uint32_t i=0;i<_map.size();++i)
|
||||
// {
|
||||
// uint32_t j = i & 31 ; // i%32
|
||||
// uint32_t k = i >> 5 ; // i/32
|
||||
//
|
||||
// _map[i] = ( (map[k] & (1<<j)) > 0)?(FileChunksInfo::CHUNK_DONE) : (FileChunksInfo::CHUNK_OUTSTANDING) ;
|
||||
//
|
||||
// if(_map[i] == FileChunksInfo::CHUNK_DONE)
|
||||
// _total_downloaded += _chunk_size ;
|
||||
// }
|
||||
//}
|
||||
|
||||
|
||||
void ChunkMap::dataReceived(const ftChunk::ChunkId& cid)
|
||||
{
|
||||
@ -151,7 +146,7 @@ void ChunkMap::dataReceived(const ftChunk::ChunkId& cid)
|
||||
// - chunks pushed when new chunks are needed
|
||||
// - chunks removed when completely downloaded
|
||||
//
|
||||
bool ChunkMap::getDataChunk(const std::string& peer_id,uint32_t size_hint,ftChunk& chunk)
|
||||
bool ChunkMap::getDataChunk(const std::string& peer_id,uint32_t size_hint,ftChunk& chunk,bool& source_chunk_map_needed)
|
||||
{
|
||||
#ifdef DEBUG_FTCHUNK
|
||||
std::cerr << "*** ChunkMap::getDataChunk: size_hint = " << size_hint << std::endl ;
|
||||
@ -168,10 +163,10 @@ bool ChunkMap::getDataChunk(const std::string& peer_id,uint32_t size_hint,ftChun
|
||||
|
||||
switch(_strategy)
|
||||
{
|
||||
case FileChunksInfo::CHUNK_STRATEGY_STREAMING: c = getAvailableChunk(0,peer_id) ; // very bold!!
|
||||
case FileChunksInfo::CHUNK_STRATEGY_STREAMING: c = getAvailableChunk(0,peer_id,source_chunk_map_needed) ; // very bold!!
|
||||
break ;
|
||||
|
||||
case FileChunksInfo::CHUNK_STRATEGY_RANDOM: c = getAvailableChunk(rand()%_map.size(),peer_id) ;
|
||||
case FileChunksInfo::CHUNK_STRATEGY_RANDOM: c = getAvailableChunk(rand()%_map.size(),peer_id,source_chunk_map_needed) ;
|
||||
break ;
|
||||
default:
|
||||
#ifdef DEBUG_FTCHUNK
|
||||
@ -212,23 +207,51 @@ bool ChunkMap::getDataChunk(const std::string& peer_id,uint32_t size_hint,ftChun
|
||||
return true ;
|
||||
}
|
||||
|
||||
void ChunkMap::setPeerAvailabilityMap(const std::string& peer_id,uint32_t chunk_size,uint32_t nb_chunks,const std::vector<uint32_t>& compressed_peer_map)
|
||||
bool ChunkMap::isChunkAvailable(uint64_t offset, uint32_t chunk_size) const
|
||||
{
|
||||
uint32_t chunk_number_start = offset/(uint64_t)_chunk_size ;
|
||||
uint32_t chunk_number_end = (offset+(uint64_t)chunk_size)/(uint64_t)_chunk_size ;
|
||||
|
||||
if((offset+(uint64_t)chunk_size) % (uint64_t)_chunk_size == 0)
|
||||
--chunk_number_end ;
|
||||
|
||||
// It's possible that chunk_number_start==chunk_number_end+1, but for this we need to have
|
||||
// chunk_size=0, and offset%_chunk_size=0, so the response "true" is still valid.
|
||||
//
|
||||
for(uint32_t i=chunk_number_start;i!=chunk_number_end;++i)
|
||||
if(_map[i] != FileChunksInfo::CHUNK_DONE)
|
||||
return false ;
|
||||
|
||||
return true ;
|
||||
}
|
||||
|
||||
void ChunkMap::setPeerAvailabilityMap(const std::string& peer_id,const CompressedChunkMap& cmap)
|
||||
{
|
||||
#ifdef DEBUG_FTCHUNK
|
||||
std::cout << "ChunkMap::Receiving new availability map for peer " << peer_id << std::endl ;
|
||||
#endif
|
||||
// Check that the parameters are the same. Otherwise we should convert the info into the local format.
|
||||
// If all RS instances have the same policy for deciding the sizes of chunks, this should not happen.
|
||||
|
||||
if(chunk_size != _chunk_size || nb_chunks != _map.size())
|
||||
if(cmap._map.size() != _map.size()/32+(_map.size()%32 != 0))
|
||||
{
|
||||
std::cerr << "ChunkMap::setPeerAvailabilityMap: chunk size / number of chunks is not correct. Dropping the info." << std::endl ;
|
||||
std::cerr << "ChunkMap::setPeerAvailabilityMap: chunk size / number of chunks is not correct. Dropping the info. cmap.size()=" << cmap._map.size() << ", _map/32+0/1 = " << _map.size()/32+(_map.size()%32 != 0) << std::endl ;
|
||||
return ;
|
||||
}
|
||||
|
||||
// sets the map.
|
||||
//
|
||||
_peers_chunks_availability[peer_id] = compressed_peer_map ;
|
||||
SourceChunksInfo& mi(_peers_chunks_availability[peer_id]) ;
|
||||
mi.cmap = cmap ;
|
||||
mi.TS = time(NULL) ;
|
||||
mi.is_full = true ;
|
||||
|
||||
// Checks wether the map is full of not.
|
||||
//
|
||||
for(uint i=0;i<_map.size();++i)
|
||||
if(!cmap[i])
|
||||
{
|
||||
mi.is_full = false ;
|
||||
break ;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_FTCHUNK
|
||||
std::cerr << "ChunkMap::setPeerAvailabilityMap: Setting chunk availability info for peer " << peer_id << std::endl ;
|
||||
@ -243,32 +266,54 @@ uint32_t ChunkMap::sizeOfChunk(uint32_t cid) const
|
||||
return _chunk_size ;
|
||||
}
|
||||
|
||||
uint32_t ChunkMap::getAvailableChunk(uint32_t start_location,const std::string& peer_id)
|
||||
uint32_t ChunkMap::getAvailableChunk(uint32_t start_location,const std::string& peer_id,bool& map_is_too_old)
|
||||
{
|
||||
// Very bold algorithm: checks for 1st availabe chunk for this peer starting
|
||||
// from the given start location.
|
||||
std::map<std::string,std::vector<uint32_t> >::const_iterator it(_peers_chunks_availability.find(peer_id)) ;
|
||||
std::map<std::string,SourceChunksInfo>::iterator it(_peers_chunks_availability.find(peer_id)) ;
|
||||
|
||||
// Do we have records for this file source ?
|
||||
//
|
||||
if(it == _peers_chunks_availability.end())
|
||||
{
|
||||
#ifdef DEBUG_FTCHUNK
|
||||
std::cout << "No chunk map for peer " << peer_id << ": supposing full data." << std::endl ;
|
||||
#endif
|
||||
std::vector<uint32_t>& pchunks(_peers_chunks_availability[peer_id]) ;
|
||||
SourceChunksInfo& pchunks(_peers_chunks_availability[peer_id]) ;
|
||||
|
||||
pchunks.resize( (_map.size() >> 5)+!!(_map.size() & 0x11111),~(uint32_t)0 ) ;
|
||||
// Ok, we don't have the info, so two cases:
|
||||
// - we are the actual source, so we can safely init the map to a full map
|
||||
// - we are not the source, so we init it with an empty map, and set the time stamp to 0.
|
||||
//
|
||||
if(peer_id == rsPeers->getOwnId())
|
||||
{
|
||||
pchunks.cmap._map.resize( CompressedChunkMap::getCompressedSize(_map.size()),~(uint32_t)0 ) ;
|
||||
pchunks.TS = 0 ;
|
||||
pchunks.is_full = true ;
|
||||
}
|
||||
else
|
||||
{
|
||||
pchunks.cmap._map.resize( CompressedChunkMap::getCompressedSize(_map.size()),0 ) ;
|
||||
pchunks.TS = 0 ;
|
||||
pchunks.is_full = false ;
|
||||
}
|
||||
|
||||
it = _peers_chunks_availability.find(peer_id) ;
|
||||
}
|
||||
const std::vector<uint32_t>& peer_chunks(it->second) ;
|
||||
SourceChunksInfo& peer_chunks(it->second) ;
|
||||
|
||||
// If the info is too old, we ask for a new one. When the map is full, we ask 10 times less, as it's probably not
|
||||
// useful to get a new map that will also be full, but because we need to be careful not to mislead information,
|
||||
// we still keep asking.
|
||||
//
|
||||
time_t now = time(NULL) ;
|
||||
map_is_too_old = (int)now - (int)peer_chunks.TS > (int)SOURCE_CHUNK_MAP_UPDATE_PERIOD*(1+9*peer_chunks.is_full) ;
|
||||
|
||||
// We will re-ask but not now seconds.
|
||||
peer_chunks.TS = now ;
|
||||
|
||||
for(unsigned int i=0;i<_map.size();++i)
|
||||
{
|
||||
uint32_t j = (start_location+i)%(int)_map.size() ; // index of the chunk
|
||||
|
||||
if(_map[j] == FileChunksInfo::CHUNK_OUTSTANDING && COMPRESSED_MAP_READ(peer_chunks,j))
|
||||
if(_map[j] == FileChunksInfo::CHUNK_OUTSTANDING && peer_chunks.cmap[j])
|
||||
{
|
||||
#ifdef DEBUG_FTCHUNK
|
||||
std::cerr << "ChunkMap::getAvailableChunk: returning chunk " << j << " for peer " << peer_id << std::endl;
|
||||
@ -296,35 +341,30 @@ void ChunkMap::getChunksInfo(FileChunksInfo& info) const
|
||||
|
||||
info.compressed_peer_availability_maps.clear() ;
|
||||
|
||||
for(std::map<std::string,std::vector<uint32_t> >::const_iterator it(_peers_chunks_availability.begin());it!= _peers_chunks_availability.end();++it)
|
||||
info.compressed_peer_availability_maps.push_back(std::pair<std::string,std::vector<uint32_t> >(it->first,it->second)) ;
|
||||
for(std::map<std::string,SourceChunksInfo>::const_iterator it(_peers_chunks_availability.begin());it!=_peers_chunks_availability.end();++it)
|
||||
info.compressed_peer_availability_maps[it->first] = it->second.cmap ;
|
||||
}
|
||||
|
||||
void ChunkMap::buildAvailabilityMap(std::vector<uint32_t>& map,uint32_t& chunk_size,uint32_t& chunk_number,FileChunksInfo::ChunkStrategy& strategy) const
|
||||
void ChunkMap::getAvailabilityMap(CompressedChunkMap& compressed_map) const
|
||||
{
|
||||
chunk_size = _chunk_size ;
|
||||
chunk_number = _map.size() ;
|
||||
strategy = _strategy ;
|
||||
compressed_map = CompressedChunkMap(_map) ;
|
||||
|
||||
map.clear() ;
|
||||
map.reserve((chunk_number >> 5)+1) ;
|
||||
|
||||
uint32_t r=0 ;
|
||||
for(uint32_t i=0;i<_map.size();++i)
|
||||
{
|
||||
uint32_t j = i & 31 ;
|
||||
r |= (_map[i]==FileChunksInfo::CHUNK_DONE)?(1<<j):0 ;
|
||||
|
||||
if(j==31 || i==_map.size()-1)
|
||||
{
|
||||
map.push_back(r);
|
||||
r=0 ;
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG_FTCHUNK
|
||||
std::cerr << "ChunkMap:: built availability map of size " << map.size() << ", chunk_size=" << chunk_size << ", chunknumber = " << chunk_number << ", strategy=" << _strategy << std::endl ;
|
||||
std::cerr << "ChunkMap:: retrieved availability map of size " << _map.size() << ", chunk_size=" << _chunk_size << std::endl ;
|
||||
#endif
|
||||
}
|
||||
|
||||
void ChunkMap::buildPlainMap(uint64_t size, CompressedChunkMap& map)
|
||||
{
|
||||
uint32_t chunk_size(1024*1024) ; // 1MB chunks
|
||||
uint64_t n = size/(uint64_t)chunk_size ;
|
||||
|
||||
if(size % (uint64_t)chunk_size != 0)
|
||||
++n ;
|
||||
|
||||
map = CompressedChunkMap(n,~uint32_t(0)) ;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -73,80 +73,96 @@ class ChunkDownloadInfo
|
||||
uint32_t _remains ;
|
||||
};
|
||||
|
||||
class SourceChunksInfo
|
||||
{
|
||||
public:
|
||||
CompressedChunkMap cmap ; //! map of what the peer has/doens't have
|
||||
time_t TS ; //! last update time for this info
|
||||
bool is_full ; //! is the map full ? In such a case, re-asking for it is unnecessary.
|
||||
};
|
||||
|
||||
class ChunkMap
|
||||
{
|
||||
public:
|
||||
typedef uint32_t ChunkNumber ;
|
||||
|
||||
// Constructor. Decides what will be the size of chunks and how many there will be.
|
||||
/// Constructor. Decides what will be the size of chunks and how many there will be.
|
||||
|
||||
ChunkMap(uint64_t file_size) ;
|
||||
|
||||
// constructor from saved map info
|
||||
/// constructor from saved map info
|
||||
ChunkMap(uint64_t file_size,const std::vector<uint32_t>& map,uint32_t chunk_size,uint32_t chunk_number,FileChunksInfo::ChunkStrategy s) ;
|
||||
|
||||
// destructor
|
||||
/// destructor
|
||||
virtual ~ChunkMap() {}
|
||||
|
||||
// Returns an slice of data to be asked to the peer within a chunk.
|
||||
// If a chunk is already been downloaded by this peer, take a slice at
|
||||
// the beginning of this chunk, or at least where it starts.
|
||||
// If not, randomly/streamly select a new chunk depending on the strategy.
|
||||
// adds an entry in the chunk_ids map, and sets up 1 interval for it.
|
||||
// the chunk should be available from the designated peer.
|
||||
/// Returns an slice of data to be asked to the peer within a chunk.
|
||||
/// If a chunk is already been downloaded by this peer, take a slice at
|
||||
/// the beginning of this chunk, or at least where it starts.
|
||||
/// If not, randomly/streamly select a new chunk depending on the strategy.
|
||||
/// adds an entry in the chunk_ids map, and sets up 1 interval for it.
|
||||
/// the chunk should be available from the designated peer.
|
||||
|
||||
virtual bool getDataChunk(const std::string& peer_id,uint32_t size_hint,ftChunk& chunk) ;
|
||||
virtual bool getDataChunk(const std::string& peer_id,uint32_t size_hint,ftChunk& chunk,bool& source_chunk_map_needed) ;
|
||||
|
||||
// Notify received a slice of data. This needs to
|
||||
// - carve in the map of chunks what is received, what is not.
|
||||
// - tell which chunks are finished. For this, each interval must know what chunk number it has been attributed
|
||||
// when the interval is split in the middle, the number of intervals for the chunk is increased. If the interval is
|
||||
// completely covered by the data, the interval number is decreased.
|
||||
/// Notify received a slice of data. This needs to
|
||||
/// - carve in the map of chunks what is received, what is not.
|
||||
/// - tell which chunks are finished. For this, each interval must know what chunk number it has been attributed
|
||||
/// when the interval is split in the middle, the number of intervals for the chunk is increased. If the interval is
|
||||
/// completely covered by the data, the interval number is decreased.
|
||||
|
||||
virtual void dataReceived(const ftChunk::ChunkId& c_id) ;
|
||||
|
||||
// Decides how chunks are selected.
|
||||
// STREAMING: the 1st chunk is always returned
|
||||
// RANDOM: the beginning of a random interval is selected first. If two few intervals
|
||||
// exist, the largest one is randomly split into two.
|
||||
/// Decides how chunks are selected.
|
||||
/// STREAMING: the 1st chunk is always returned
|
||||
/// RANDOM: the beginning of a random interval is selected first. If two few intervals
|
||||
/// exist, the largest one is randomly split into two.
|
||||
|
||||
void setStrategy(FileChunksInfo::ChunkStrategy s) { _strategy = s ; }
|
||||
FileChunksInfo::ChunkStrategy getStrategy() const { return _strategy ; }
|
||||
|
||||
// Properly fills an vector of fixed size chunks with availability or download state.
|
||||
// chunks is given with the proper number of chunks and we have to adapt to it. This can be used
|
||||
// to display square chunks in the gui or display a blue bar of availability by collapsing info from all peers.
|
||||
/// Properly fills an vector of fixed size chunks with availability or download state.
|
||||
/// chunks is given with the proper number of chunks and we have to adapt to it. This can be used
|
||||
/// to display square chunks in the gui or display a blue bar of availability by collapsing info from all peers.
|
||||
/// The set method is not virtual because it has no reason to exist in the parent ftFileProvider
|
||||
|
||||
void buildAvailabilityMap(std::vector<uint32_t>& map,uint32_t& chunk_size,uint32_t& chunk_number,FileChunksInfo::ChunkStrategy& s) const ;
|
||||
void loadAvailabilityMap(const std::vector<uint32_t>& map,uint32_t chunk_size,uint32_t chunk_number,FileChunksInfo::ChunkStrategy s) ;
|
||||
virtual void getAvailabilityMap(CompressedChunkMap& cmap) const ;
|
||||
void setAvailabilityMap(const CompressedChunkMap& cmap) ;
|
||||
|
||||
// Updates the peer's availablility map
|
||||
/// This function fills in a plain map for a file of the given size. This
|
||||
/// is used to ensure that the chunk size will be consistent with the rest
|
||||
/// of the code.
|
||||
//
|
||||
void setPeerAvailabilityMap(const std::string& peer_id,uint32_t chunk_size,uint32_t nb_chunks,const std::vector<uint32_t>& peer_map) ;
|
||||
static void buildPlainMap(uint64_t size,CompressedChunkMap& map) ;
|
||||
|
||||
// Returns the total size of downloaded data in the file.
|
||||
/// This function is used by the parent ftFileProvider to know whether the chunk can be sent or not.
|
||||
bool isChunkAvailable(uint64_t offset, uint32_t chunk_size) const ;
|
||||
|
||||
/// Updates the peer's availablility map
|
||||
//
|
||||
void setPeerAvailabilityMap(const std::string& peer_id,const CompressedChunkMap& peer_map) ;
|
||||
|
||||
/// Returns the total size of downloaded data in the file.
|
||||
uint64_t getTotalReceived() const { return _total_downloaded ; }
|
||||
|
||||
void getChunksInfo(FileChunksInfo& info) const ;
|
||||
protected:
|
||||
// handles what size the last chunk has.
|
||||
/// handles what size the last chunk has.
|
||||
uint32_t sizeOfChunk(uint32_t chunk_number) const ;
|
||||
|
||||
// Returns the first chunk available starting from start_location for this peer_id.
|
||||
/// Returns the first chunk available starting from start_location for this peer_id.
|
||||
//
|
||||
uint32_t getAvailableChunk(uint32_t start_location,const std::string& peer_id) ;
|
||||
uint32_t getAvailableChunk(uint32_t start_location,const std::string& peer_id,bool& chunk_map_too_old) ;
|
||||
|
||||
private:
|
||||
uint64_t _file_size ; // total size of the file in bytes.
|
||||
uint32_t _chunk_size ; // Size of chunks. Common to all chunks.
|
||||
FileChunksInfo::ChunkStrategy _strategy ; // how do we allocate new chunks
|
||||
std::map<std::string,Chunk> _active_chunks_feed ; // vector of chunks being downloaded. Exactly one chunk per peer id.
|
||||
std::map<ChunkNumber,ChunkDownloadInfo> _slices_to_download ; // list of (slice id,slice size)
|
||||
|
||||
std::vector<FileChunksInfo::ChunkState> _map ; // vector of chunk state over the whole file
|
||||
|
||||
std::map<std::string,std::vector<uint32_t> > _peers_chunks_availability ; // what does each source peer have, stored in compressed format.
|
||||
|
||||
uint64_t _total_downloaded ;
|
||||
uint64_t _file_size ; //! total size of the file in bytes.
|
||||
uint32_t _chunk_size ; //! Size of chunks. Common to all chunks.
|
||||
FileChunksInfo::ChunkStrategy _strategy ; //! how do we allocate new chunks
|
||||
std::map<std::string,Chunk> _active_chunks_feed ; //! vector of chunks being downloaded. Exactly 1 chunk per peer.
|
||||
std::map<ChunkNumber,ChunkDownloadInfo> _slices_to_download ; //! list of (slice id,slice size)
|
||||
std::vector<FileChunksInfo::ChunkState> _map ; //! vector of chunk state over the whole file
|
||||
std::map<std::string,SourceChunksInfo> _peers_chunks_availability ; //! what does each source peer have
|
||||
uint64_t _total_downloaded ; //! completion for the file
|
||||
};
|
||||
|
||||
|
||||
|
@ -80,8 +80,12 @@ ftFileControl::ftFileControl(std::string fname,
|
||||
}
|
||||
|
||||
ftController::ftController(CacheStrapper *cs, ftDataMultiplex *dm, std::string configDir)
|
||||
:CacheTransfer(cs), p3Config(CONFIG_TYPE_FT_CONTROL), mDataplex(dm), mFtActive(false),
|
||||
mTurtle(NULL), mShareDownloadDir(true),last_save_time(0)
|
||||
:CacheTransfer(cs), p3Config(CONFIG_TYPE_FT_CONTROL),
|
||||
last_save_time(0),
|
||||
mDataplex(dm),
|
||||
mTurtle(NULL),
|
||||
mFtActive(false),
|
||||
mShareDownloadDir(true)
|
||||
{
|
||||
/* TODO */
|
||||
}
|
||||
@ -96,7 +100,7 @@ void ftController::setFtSearchNExtra(ftSearch *search, ftExtraList *list)
|
||||
mExtraList = list;
|
||||
}
|
||||
|
||||
bool ftController::getFileChunksDetails(const std::string& hash,FileChunksInfo& info)
|
||||
bool ftController::getFileDownloadChunksDetails(const std::string& hash,FileChunksInfo& info)
|
||||
{
|
||||
RsStackMutex stack(ctrlMutex); /******* LOCKED ********/
|
||||
|
||||
@ -185,7 +189,7 @@ void ftController::run()
|
||||
}
|
||||
|
||||
time_t now = time(NULL) ;
|
||||
if(now - last_save_time > SAVE_TRANSFERS_DELAY)
|
||||
if((int)now - (int)last_save_time > (int)SAVE_TRANSFERS_DELAY)
|
||||
{
|
||||
IndicateConfigChanged() ;
|
||||
last_save_time = now ;
|
||||
@ -593,7 +597,10 @@ bool ftController::handleAPendingRequest()
|
||||
std::cerr << "ftController::loadList(): Error: could not find hash " << rsft->file.hash << " in mDownloads list !" << std::endl ;
|
||||
}
|
||||
else
|
||||
(fit->second).mCreator->loadAvailabilityMap(rsft->chunk_map,rsft->chunk_size,rsft->chunk_number,rsft->chunk_strategy) ;
|
||||
{
|
||||
(fit->second).mCreator->setAvailabilityMap(rsft->compressed_chunk_map) ;
|
||||
(fit->second).mCreator->setChunkStrategy((FileChunksInfo::ChunkStrategy)(rsft->chunk_strategy)) ;
|
||||
}
|
||||
|
||||
delete rsft ;
|
||||
mPendingChunkMaps.erase(it) ;
|
||||
@ -733,10 +740,7 @@ bool ftController::FileRequest(std::string fname, std::string hash,
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mSearch->search(hash, size,
|
||||
RS_FILE_HINTS_LOCAL |
|
||||
RS_FILE_HINTS_EXTRA |
|
||||
RS_FILE_HINTS_SPEC_ONLY, info))
|
||||
if (mSearch->search(hash, RS_FILE_HINTS_LOCAL | RS_FILE_HINTS_EXTRA | RS_FILE_HINTS_SPEC_ONLY, info))
|
||||
{
|
||||
/* have it already */
|
||||
/* add in as completed transfer */
|
||||
@ -750,10 +754,7 @@ bool ftController::FileRequest(std::string fname, std::string hash,
|
||||
}
|
||||
|
||||
/* do a source search - for any extra sources */
|
||||
if (mSearch->search(hash, size,
|
||||
RS_FILE_HINTS_REMOTE |
|
||||
// RS_FILE_HINTS_TURTLE |
|
||||
RS_FILE_HINTS_SPEC_ONLY, info))
|
||||
if (mSearch->search(hash, RS_FILE_HINTS_REMOTE | RS_FILE_HINTS_SPEC_ONLY, info))
|
||||
{
|
||||
/* do something with results */
|
||||
#ifdef CONTROL_DEBUG
|
||||
@ -817,8 +818,7 @@ bool ftController::FileRequest(std::string fname, std::string hash,
|
||||
ftTransferModule *tm = new ftTransferModule(fc, mDataplex,this);
|
||||
|
||||
/* add into maps */
|
||||
ftFileControl ftfc(fname, savepath, destination,
|
||||
size, hash, flags, fc, tm, callbackCode);
|
||||
ftFileControl ftfc(fname, savepath, destination, size, hash, flags, fc, tm, callbackCode);
|
||||
ftfc.mCreateTime = time(NULL);
|
||||
|
||||
#ifdef CONTROL_DEBUG
|
||||
@ -1469,7 +1469,23 @@ std::list<RsItem *> ftController::saveList(bool &cleanup)
|
||||
//rft->flags = fit->second.mFlags;
|
||||
|
||||
fit->second.mTransfer->getFileSources(rft->allPeerIds.ids);
|
||||
fit->second.mCreator->storeAvailabilityMap(rft->chunk_map,rft->chunk_size,rft->chunk_number,rft->chunk_strategy) ;
|
||||
|
||||
// Remove turtle peers from sources, as they are not supposed to survive a reboot of RS, since they are dynamic sources.
|
||||
// Otherwize, such sources are unknown from the turtle router, at restart, and never get removed.
|
||||
//
|
||||
for(std::list<std::string>::iterator sit(rft->allPeerIds.ids.begin());sit!=rft->allPeerIds.ids.end();)
|
||||
if(mTurtle->isTurtlePeer(*sit))
|
||||
{
|
||||
std::list<std::string>::iterator sittmp(sit) ;
|
||||
++sittmp ;
|
||||
rft->allPeerIds.ids.erase(sit) ;
|
||||
sit = sittmp ;
|
||||
}
|
||||
else
|
||||
++sit ;
|
||||
|
||||
fit->second.mCreator->getAvailabilityMap(rft->compressed_chunk_map) ;
|
||||
rft->chunk_strategy = fit->second.mCreator->getChunkStrategy() ;
|
||||
|
||||
saveData.push_back(rft);
|
||||
}
|
||||
@ -1528,7 +1544,10 @@ bool ftController::loadList(std::list<RsItem *> load)
|
||||
continue ; // i.e. don't delete the item!
|
||||
}
|
||||
else
|
||||
(fit->second).mCreator->loadAvailabilityMap(rsft->chunk_map,rsft->chunk_size,rsft->chunk_number,rsft->chunk_strategy) ;
|
||||
{
|
||||
(fit->second).mCreator->setAvailabilityMap(rsft->compressed_chunk_map) ;
|
||||
(fit->second).mCreator->setChunkStrategy((FileChunksInfo::ChunkStrategy)(rsft->chunk_strategy)) ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -138,7 +138,7 @@ bool FileCancel(std::string hash);
|
||||
bool FileControl(std::string hash, uint32_t flags);
|
||||
bool FileClearCompleted();
|
||||
bool FlagFileComplete(std::string hash);
|
||||
bool getFileChunksDetails(const std::string& hash,FileChunksInfo& info);
|
||||
bool getFileDownloadChunksDetails(const std::string& hash,FileChunksInfo& info);
|
||||
|
||||
/* get Details of File Transfers */
|
||||
bool FileDownloads(std::list<std::string> &hashs);
|
||||
|
@ -40,19 +40,23 @@
|
||||
|
||||
/*************** SEND INTERFACE *******************/
|
||||
|
||||
class CompressedChunkMap ;
|
||||
|
||||
class ftDataSend
|
||||
{
|
||||
public:
|
||||
virtual ~ftDataSend() { return; }
|
||||
virtual ~ftDataSend() { return; }
|
||||
|
||||
/* Client Send */
|
||||
virtual bool sendDataRequest(std::string peerId, std::string hash,
|
||||
uint64_t size, uint64_t offset, uint32_t chunksize) = 0;
|
||||
/* Client Send */
|
||||
virtual bool sendDataRequest(const std::string& peerId, const std::string& hash, uint64_t size, uint64_t offset, uint32_t chunksize) = 0;
|
||||
|
||||
/* Server Send */
|
||||
virtual bool sendData(std::string peerId, std::string hash, uint64_t size,
|
||||
uint64_t offset, uint32_t chunksize, void *data) = 0;
|
||||
/* Server Send */
|
||||
virtual bool sendData(const std::string& peerId, const std::string& hash, uint64_t size, uint64_t offset, uint32_t chunksize, void *data) = 0;
|
||||
|
||||
/// Send a request for a chunk map
|
||||
virtual bool sendChunkMapRequest(const std::string& peer_id,const std::string& hash) = 0;
|
||||
/// Send a chunk map
|
||||
virtual bool sendChunkMap(const std::string& peer_id,const std::string& hash,const CompressedChunkMap& cmap) = 0;
|
||||
};
|
||||
|
||||
|
||||
@ -62,18 +66,19 @@ virtual bool sendData(std::string peerId, std::string hash, uint64_t size,
|
||||
class ftDataRecv
|
||||
{
|
||||
public:
|
||||
virtual ~ftDataRecv() { return; }
|
||||
|
||||
virtual ~ftDataRecv() { return; }
|
||||
/* Client Recv */
|
||||
virtual bool recvData(const std::string& peerId, const std::string& hash, uint64_t size, uint64_t offset, uint32_t chunksize, void *data) = 0;
|
||||
|
||||
/* Client Recv */
|
||||
virtual bool recvData(std::string peerId, std::string hash, uint64_t size,
|
||||
uint64_t offset, uint32_t chunksize, void *data) = 0;
|
||||
|
||||
/* Server Recv */
|
||||
virtual bool recvDataRequest(std::string peerId, std::string hash,
|
||||
uint64_t size, uint64_t offset, uint32_t chunksize) = 0;
|
||||
/* Server Recv */
|
||||
virtual bool recvDataRequest(const std::string& peerId, const std::string& hash, uint64_t size, uint64_t offset, uint32_t chunksize) = 0;
|
||||
|
||||
/// Send a request for a chunk map
|
||||
virtual bool recvChunkMapRequest(const std::string& peer_id,const std::string& hash,bool is_client) = 0;
|
||||
|
||||
/// Send a chunk map
|
||||
virtual bool recvChunkMap(const std::string& peer_id,const std::string& hash,const CompressedChunkMap& cmap,bool is_client) = 0;
|
||||
};
|
||||
|
||||
/******* Pair of Send/Recv (Only need to handle Send side) ******/
|
||||
|
@ -50,8 +50,10 @@ ftClient::ftClient(ftTransferModule *module, ftFileCreator *creator)
|
||||
return;
|
||||
}
|
||||
|
||||
const uint32_t FT_DATA = 0x0001;
|
||||
const uint32_t FT_DATA_REQ = 0x0002;
|
||||
const uint32_t FT_DATA = 0x0001; // data cuhnk to be stored
|
||||
const uint32_t FT_DATA_REQ = 0x0002; // data request to be treated
|
||||
const uint32_t FT_CLIENT_CHUNK_MAP_REQ = 0x0003; // chunk map request to be treated by client
|
||||
const uint32_t FT_SERVER_CHUNK_MAP_REQ = 0x0004; // chunk map reuqest to be treated by server
|
||||
|
||||
ftRequest::ftRequest(uint32_t type, std::string peerId, std::string hash, uint64_t size, uint64_t offset, uint32_t chunk, void *data)
|
||||
:mType(type), mPeerId(peerId), mHash(hash), mSize(size),
|
||||
@ -179,8 +181,7 @@ bool ftDataMultiplex::FileDetails(std::string hash, uint32_t hintsflag, FileI
|
||||
/*************** SEND INTERFACE (calls ftDataSend) *******************/
|
||||
|
||||
/* Client Send */
|
||||
bool ftDataMultiplex::sendDataRequest(std::string peerId,
|
||||
std::string hash, uint64_t size, uint64_t offset, uint32_t chunksize)
|
||||
bool ftDataMultiplex::sendDataRequest(const std::string& peerId, const std::string& hash, uint64_t size, uint64_t offset, uint32_t chunksize)
|
||||
{
|
||||
#ifdef MPLEX_DEBUG
|
||||
std::cerr << "ftDataMultiplex::sendDataRequest() Client Send";
|
||||
@ -190,9 +191,7 @@ bool ftDataMultiplex::sendDataRequest(std::string peerId,
|
||||
}
|
||||
|
||||
/* Server Send */
|
||||
bool ftDataMultiplex::sendData(std::string peerId,
|
||||
std::string hash, uint64_t size,
|
||||
uint64_t offset, uint32_t chunksize, void *data)
|
||||
bool ftDataMultiplex::sendData(const std::string& peerId, const std::string& hash, uint64_t size, uint64_t offset, uint32_t chunksize, void *data)
|
||||
{
|
||||
#ifdef MPLEX_DEBUG
|
||||
std::cerr << "ftDataMultiplex::sendData() Server Send";
|
||||
@ -205,9 +204,7 @@ bool ftDataMultiplex::sendData(std::string peerId,
|
||||
/*************** RECV INTERFACE (provides ftDataRecv) ****************/
|
||||
|
||||
/* Client Recv */
|
||||
bool ftDataMultiplex::recvData(std::string peerId,
|
||||
std::string hash, uint64_t size,
|
||||
uint64_t offset, uint32_t chunksize, void *data)
|
||||
bool ftDataMultiplex::recvData(const std::string& peerId, const std::string& hash, uint64_t size, uint64_t offset, uint32_t chunksize, void *data)
|
||||
{
|
||||
#ifdef MPLEX_DEBUG
|
||||
std::cerr << "ftDataMultiplex::recvData() Client Recv";
|
||||
@ -215,17 +212,14 @@ bool ftDataMultiplex::recvData(std::string peerId,
|
||||
#endif
|
||||
/* Store in Queue */
|
||||
RsStackMutex stack(dataMtx); /******* LOCK MUTEX ******/
|
||||
mRequestQueue.push_back(
|
||||
ftRequest(FT_DATA,peerId,hash,size,offset,chunksize,data));
|
||||
mRequestQueue.push_back(ftRequest(FT_DATA,peerId,hash,size,offset,chunksize,data));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/* Server Recv */
|
||||
bool ftDataMultiplex::recvDataRequest(std::string peerId,
|
||||
std::string hash, uint64_t size,
|
||||
uint64_t offset, uint32_t chunksize)
|
||||
bool ftDataMultiplex::recvDataRequest(const std::string& peerId, const std::string& hash, uint64_t size, uint64_t offset, uint32_t chunksize)
|
||||
{
|
||||
#ifdef MPLEX_DEBUG
|
||||
std::cerr << "ftDataMultiplex::recvDataRequest() Server Recv";
|
||||
@ -239,6 +233,24 @@ bool ftDataMultiplex::recvDataRequest(std::string peerId,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ftDataMultiplex::recvChunkMapRequest(const std::string& peerId, const std::string& hash,bool is_client)
|
||||
{
|
||||
#ifdef MPLEX_DEBUG
|
||||
std::cerr << "ftDataMultiplex::recvChunkMapRequest() Server Recv";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
/* Store in Queue */
|
||||
RsStackMutex stack(dataMtx); /******* LOCK MUTEX ******/
|
||||
|
||||
if(is_client)
|
||||
mRequestQueue.push_back(ftRequest(FT_CLIENT_CHUNK_MAP_REQ,peerId,hash,0,0,0,NULL));
|
||||
else
|
||||
mRequestQueue.push_back(ftRequest(FT_SERVER_CHUNK_MAP_REQ,peerId,hash,0,0,0,NULL));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*********** BACKGROUND THREAD OPERATIONS ***********/
|
||||
bool ftDataMultiplex::workQueued()
|
||||
@ -282,30 +294,44 @@ bool ftDataMultiplex::doWork()
|
||||
|
||||
switch(req.mType)
|
||||
{
|
||||
case FT_DATA:
|
||||
case FT_DATA:
|
||||
#ifdef MPLEX_DEBUG
|
||||
std::cerr << "ftDataMultiplex::doWork() Handling FT_DATA";
|
||||
std::cerr << std::endl;
|
||||
std::cerr << "ftDataMultiplex::doWork() Handling FT_DATA";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
handleRecvData(req.mPeerId, req.mHash, req.mSize,
|
||||
req.mOffset, req.mChunk, req.mData);
|
||||
break;
|
||||
handleRecvData(req.mPeerId, req.mHash, req.mSize, req.mOffset, req.mChunk, req.mData);
|
||||
break;
|
||||
|
||||
case FT_DATA_REQ:
|
||||
case FT_DATA_REQ:
|
||||
#ifdef MPLEX_DEBUG
|
||||
std::cerr << "ftDataMultiplex::doWork() Handling FT_DATA_REQ";
|
||||
std::cerr << std::endl;
|
||||
std::cerr << "ftDataMultiplex::doWork() Handling FT_DATA_REQ";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
handleRecvDataRequest(req.mPeerId, req.mHash,
|
||||
req.mSize, req.mOffset, req.mChunk);
|
||||
break;
|
||||
handleRecvDataRequest(req.mPeerId, req.mHash, req.mSize, req.mOffset, req.mChunk);
|
||||
break;
|
||||
|
||||
default:
|
||||
case FT_CLIENT_CHUNK_MAP_REQ:
|
||||
#ifdef MPLEX_DEBUG
|
||||
std::cerr << "ftDataMultiplex::doWork() Ignoring UNKNOWN";
|
||||
std::cerr << std::endl;
|
||||
std::cerr << "ftDataMultiplex::doWork() Handling FT_CLIENT_CHUNK_MAP_REQ";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
break;
|
||||
handleRecvClientChunkMapRequest(req.mPeerId,req.mHash) ;
|
||||
break ;
|
||||
|
||||
case FT_SERVER_CHUNK_MAP_REQ:
|
||||
#ifdef MPLEX_DEBUG
|
||||
std::cerr << "ftDataMultiplex::doWork() Handling FT_CLIENT_CHUNK_MAP_REQ";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
handleRecvServerChunkMapRequest(req.mPeerId,req.mHash) ;
|
||||
break ;
|
||||
|
||||
default:
|
||||
#ifdef MPLEX_DEBUG
|
||||
std::cerr << "ftDataMultiplex::doWork() Ignoring UNKNOWN";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -330,40 +356,137 @@ bool ftDataMultiplex::doWork()
|
||||
std::cerr << "ftDataMultiplex::doWork() Handling Search Request";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
handleSearchRequest(req.mPeerId, req.mHash, req.mSize,
|
||||
req.mOffset, req.mChunk);
|
||||
if(handleSearchRequest(req.mPeerId, req.mHash))
|
||||
handleRecvDataRequest(req.mPeerId, req.mHash, req.mSize, req.mOffset, req.mChunk) ;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ftDataMultiplex::recvFileMap(const std::string& peerId, const std::string& hash, uint32_t chunk_size, uint32_t nb_chunks, const std::vector<uint32_t>& compressed_map)
|
||||
// A chunk map has arrived. It can be two different situations:
|
||||
// - an uploader has sent his chunk map, so we need to store it in the corresponding ftFileProvider
|
||||
// - a source for a download has sent his chunk map, so we need to send it to the corresponding ftFileCreator.
|
||||
//
|
||||
bool ftDataMultiplex::recvChunkMap(const std::string& peerId, const std::string& hash,const CompressedChunkMap& compressed_map,bool client)
|
||||
{
|
||||
RsStackMutex stack(dataMtx); /******* LOCK MUTEX ******/
|
||||
std::map<std::string, ftClient>::iterator it;
|
||||
|
||||
if (mClients.end() == (it = mClients.find(hash)))
|
||||
if(client) // is the chunk map for a client, or for a server ?
|
||||
{
|
||||
std::map<std::string, ftClient>::iterator it = mClients.find(hash);
|
||||
|
||||
if(it == mClients.end())
|
||||
{
|
||||
#ifdef MPLEX_DEBUG
|
||||
std::cerr << "ftDataMultiplex::handleRecvMap() ERROR: No matching Client!";
|
||||
std::cerr << "ftDataMultiplex::recvChunkMap() ERROR: No matching Client for hash " << hash << " !";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
/* error */
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef MPLEX_DEBUG
|
||||
std::cerr << "ftDataMultiplex::recvChunkMap() Passing map of file " << hash << ", to FT Module";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
/* error */
|
||||
return false;
|
||||
|
||||
(it->second).mCreator->setSourceMap(peerId, compressed_map);
|
||||
return true ;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::map<std::string, ftFileProvider *>::iterator it = mServers.find(hash) ;
|
||||
|
||||
if(it == mServers.end())
|
||||
{
|
||||
#ifdef MPLEX_DEBUG
|
||||
std::cerr << "ftDataMultiplex::handleRecvChunkMap() ERROR: No matching file Provider for hash " << hash ;
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
it->second->setClientMap(peerId, compressed_map);
|
||||
return true ;
|
||||
}
|
||||
|
||||
#ifdef MPLEX_DEBUG
|
||||
std::cerr << "ftDataMultiplex::handleRecvMap() Passing map to FT Module";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
(it->second).mCreator->setSourceMap(peerId, chunk_size, nb_chunks,compressed_map);
|
||||
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ftDataMultiplex::handleRecvData(std::string peerId,
|
||||
std::string hash, uint64_t size,
|
||||
bool ftDataMultiplex::handleRecvClientChunkMapRequest(const std::string& peerId, const std::string& hash)
|
||||
{
|
||||
CompressedChunkMap cmap ;
|
||||
|
||||
{
|
||||
RsStackMutex stack(dataMtx); /******* LOCK MUTEX ******/
|
||||
|
||||
std::map<std::string, ftClient>::iterator it = mClients.find(hash);
|
||||
|
||||
if(it == mClients.end())
|
||||
{
|
||||
// If we can't find the client, it's not a problem. Chunk maps from
|
||||
// clients are not essential, as they are only used for display.
|
||||
#ifdef MPLEX_DEBUG
|
||||
std::cerr << "ftDataMultiplex::handleRecvServerChunkMapRequest() ERROR: No matching Client for hash " << hash ;
|
||||
std::cerr << ". Performing local search." << std::endl;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef MPLEX_DEBUG
|
||||
std::cerr << "ftDataMultiplex::handleRecvServerChunkMapRequest() Sending map of file " << hash << ", to peer " << peerId << std::endl;
|
||||
#endif
|
||||
|
||||
(it->second).mCreator->getAvailabilityMap(cmap);
|
||||
}
|
||||
|
||||
mDataSend->sendChunkMap(peerId,hash,cmap);
|
||||
|
||||
return true ;
|
||||
}
|
||||
|
||||
bool ftDataMultiplex::handleRecvServerChunkMapRequest(const std::string& peerId, const std::string& hash)
|
||||
{
|
||||
CompressedChunkMap cmap ;
|
||||
std::map<std::string, ftFileProvider *>::iterator it ;
|
||||
bool found = true ;
|
||||
|
||||
{
|
||||
RsStackMutex stack(dataMtx); /******* LOCK MUTEX ******/
|
||||
|
||||
it = mServers.find(hash) ;
|
||||
|
||||
if(it == mServers.end())
|
||||
found = false ;
|
||||
}
|
||||
|
||||
if(!found)
|
||||
{
|
||||
#ifdef MPLEX_DEBUG
|
||||
std::cerr << "ftDataMultiplex::handleRecvChunkMapReq() ERROR: No matching file Provider for hash " << hash ;
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
if(!handleSearchRequest(peerId,hash))
|
||||
return false ;
|
||||
|
||||
#ifdef MPLEX_DEBUG
|
||||
std::cerr << "ftDataMultiplex::handleRecvChunkMapReq() A new file Provider has been made up for hash " << hash ;
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
{
|
||||
RsStackMutex stack(dataMtx); /******* LOCK MUTEX ******/
|
||||
|
||||
it = mServers.find(hash) ;
|
||||
it->second->getAvailabilityMap(cmap);
|
||||
}
|
||||
|
||||
mDataSend->sendChunkMap(peerId,hash,cmap);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ftDataMultiplex::handleRecvData(const std::string& peerId,
|
||||
const std::string& hash, uint64_t size,
|
||||
uint64_t offset, uint32_t chunksize, void *data)
|
||||
{
|
||||
RsStackMutex stack(dataMtx); /******* LOCK MUTEX ******/
|
||||
@ -390,9 +513,7 @@ bool ftDataMultiplex::handleRecvData(std::string peerId,
|
||||
|
||||
|
||||
/* called by ftTransferModule */
|
||||
bool ftDataMultiplex::handleRecvDataRequest(std::string peerId,
|
||||
std::string hash, uint64_t size,
|
||||
uint64_t offset, uint32_t chunksize)
|
||||
bool ftDataMultiplex::handleRecvDataRequest(const std::string& peerId, const std::string& hash, uint64_t size, uint64_t offset, uint32_t chunksize)
|
||||
{
|
||||
/**** Find Files *****/
|
||||
|
||||
@ -412,8 +533,7 @@ bool ftDataMultiplex::handleRecvDataRequest(std::string peerId,
|
||||
std::cerr << "ftDataMultiplex::handleRecvData() Matched to a Client.";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
locked_handleServerRequest((cit->second).mCreator,
|
||||
peerId, hash, size, offset, chunksize);
|
||||
locked_handleServerRequest((cit->second).mCreator, peerId, hash, size, offset, chunksize);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -424,8 +544,7 @@ bool ftDataMultiplex::handleRecvDataRequest(std::string peerId,
|
||||
std::cerr << "ftDataMultiplex::handleRecvData() Matched to a Provider.";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
locked_handleServerRequest(sit->second,
|
||||
peerId, hash, size, offset, chunksize);
|
||||
locked_handleServerRequest(sit->second, peerId, hash, size, offset, chunksize);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -435,9 +554,7 @@ bool ftDataMultiplex::handleRecvDataRequest(std::string peerId,
|
||||
#endif
|
||||
|
||||
/* Add to Search Queue */
|
||||
mSearchQueue.push_back(
|
||||
ftRequest(FT_DATA_REQ, peerId, hash,
|
||||
size, offset, chunksize, NULL));
|
||||
mSearchQueue.push_back( ftRequest(FT_DATA_REQ, peerId, hash, size, offset, chunksize, NULL));
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -481,6 +598,33 @@ bool ftDataMultiplex::locked_handleServerRequest(ftFileProvider *provider,
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ftDataMultiplex::getClientChunkMap(const std::string& upload_hash,const std::string& peerId,CompressedChunkMap& cmap)
|
||||
{
|
||||
bool too_old ;
|
||||
{
|
||||
RsStackMutex stack(dataMtx); /******* LOCK MUTEX ******/
|
||||
|
||||
std::map<std::string,ftFileProvider *>::iterator sit = mServers.find(upload_hash);
|
||||
|
||||
if(mServers.end() == sit)
|
||||
return false ;
|
||||
|
||||
sit->second->getClientMap(peerId,cmap,too_old) ;
|
||||
}
|
||||
|
||||
// If the map is too old then we should ask an other map to the peer.
|
||||
//
|
||||
if(too_old)
|
||||
sendChunkMapRequest(peerId,upload_hash);
|
||||
|
||||
return true ;
|
||||
}
|
||||
|
||||
bool ftDataMultiplex::sendChunkMapRequest(const std::string& peer_id,const std::string& hash)
|
||||
{
|
||||
return mDataSend->sendChunkMapRequest(peer_id,hash);
|
||||
}
|
||||
|
||||
void ftDataMultiplex::deleteServers(const std::list<std::string>& serv)
|
||||
{
|
||||
RsStackMutex stack(dataMtx); /******* LOCK MUTEX ******/
|
||||
@ -491,42 +635,42 @@ void ftDataMultiplex::deleteServers(const std::list<std::string>& serv)
|
||||
|
||||
if(mServers.end() != sit)
|
||||
{
|
||||
delete sit->second;
|
||||
// Only delete servers that are not also file creators!
|
||||
//
|
||||
if(dynamic_cast<ftFileCreator*>(sit->second) == NULL)
|
||||
delete sit->second;
|
||||
|
||||
mServers.erase(sit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ftDataMultiplex::handleSearchRequest(std::string peerId,
|
||||
std::string hash, uint64_t size,
|
||||
uint64_t offset, uint32_t chunksize)
|
||||
bool ftDataMultiplex::handleSearchRequest(const std::string& peerId, const std::string& hash)
|
||||
{
|
||||
|
||||
|
||||
#ifdef MPLEX_DEBUG
|
||||
std::cerr << "ftDataMultiplex::handleSearchRequest(";
|
||||
std::cerr << peerId << ", " << hash << ", " << size << "...)";
|
||||
std::cerr << peerId << ", " << hash << "...)";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
{
|
||||
RsStackMutex stack(dataMtx); /******* LOCK MUTEX ******/
|
||||
|
||||
/* Check for bad requests */
|
||||
std::map<std::string, time_t>::iterator bit;
|
||||
if (mUnknownHashs.end() != (bit = mUnknownHashs.find(hash)))
|
||||
{
|
||||
|
||||
#ifdef MPLEX_DEBUG
|
||||
std::cerr << "ftDataMultiplex::handleSearchRequest(";
|
||||
std::cerr << " Found Ignore Hash ... done";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
/* We've previously rejected this one, so ignore */
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// {
|
||||
// RsStackMutex stack(dataMtx); /******* LOCK MUTEX ******/
|
||||
//
|
||||
// /* Check for bad requests */
|
||||
// std::map<std::string, time_t>::iterator bit;
|
||||
// if (mUnknownHashs.end() != (bit = mUnknownHashs.find(hash)))
|
||||
// {
|
||||
//
|
||||
//#ifdef MPLEX_DEBUG
|
||||
// std::cerr << "ftDataMultiplex::handleSearchRequest(";
|
||||
// std::cerr << " Found Ignore Hash ... done";
|
||||
// std::cerr << std::endl;
|
||||
//#endif
|
||||
//
|
||||
// /* We've previously rejected this one, so ignore */
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
/*
|
||||
@ -535,14 +679,10 @@ bool ftDataMultiplex::handleSearchRequest(std::string peerId,
|
||||
* (anywhere but remote really)
|
||||
*/
|
||||
|
||||
|
||||
FileInfo info;
|
||||
uint32_t hintflags = (RS_FILE_HINTS_CACHE |
|
||||
RS_FILE_HINTS_EXTRA |
|
||||
RS_FILE_HINTS_LOCAL |
|
||||
RS_FILE_HINTS_SPEC_ONLY);
|
||||
uint32_t hintflags = (RS_FILE_HINTS_CACHE | RS_FILE_HINTS_EXTRA | RS_FILE_HINTS_LOCAL | RS_FILE_HINTS_SPEC_ONLY);
|
||||
|
||||
if (mSearch->search(hash, size, hintflags, info))
|
||||
if (mSearch->search(hash, hintflags, info))
|
||||
{
|
||||
|
||||
#ifdef MPLEX_DEBUG
|
||||
@ -551,28 +691,35 @@ bool ftDataMultiplex::handleSearchRequest(std::string peerId,
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
|
||||
/* setup a new provider */
|
||||
RsStackMutex stack(dataMtx); /******* LOCK MUTEX ******/
|
||||
|
||||
ftFileProvider *provider =
|
||||
new ftFileProvider(info.path, size, hash);
|
||||
ftFileProvider *provider = new ftFileProvider(info.path, info.size, hash);
|
||||
|
||||
mServers[hash] = provider;
|
||||
|
||||
/* handle request finally */
|
||||
locked_handleServerRequest(provider,
|
||||
peerId, hash, size, offset, chunksize);
|
||||
|
||||
|
||||
/* now we should should check if any further requests for the same
|
||||
* file exists ... (can happen with caches!)
|
||||
*
|
||||
* but easier to check pre-search....
|
||||
*/
|
||||
|
||||
return true;
|
||||
}
|
||||
// Now check wether the required file is actually being downloaded. In such a case,
|
||||
// setup the file provider to be the file creator itself. Warning: this server should not
|
||||
// be deleted when not used anymore. We need to restrict this to client peers that are
|
||||
// not ourself, since the file transfer also handles the local cache traffic (this
|
||||
// is something to be changed soon!!)
|
||||
//
|
||||
|
||||
if(peerId != mOwnId)
|
||||
{
|
||||
RsStackMutex stack(dataMtx); /******* LOCK MUTEX ******/
|
||||
|
||||
std::map<std::string,ftClient>::const_iterator it(mClients.find(hash)) ;
|
||||
|
||||
if(it != mClients.end())
|
||||
{
|
||||
mServers[hash] = it->second.mCreator ;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -102,23 +102,31 @@ class ftDataMultiplex: public ftDataRecv, public RsQueueThread
|
||||
/*************** SEND INTERFACE (calls ftDataSend) *******************/
|
||||
|
||||
/* Client Send */
|
||||
bool sendDataRequest(std::string peerId, std::string hash, uint64_t size,
|
||||
uint64_t offset, uint32_t chunksize);
|
||||
bool sendDataRequest(const std::string& peerId, const std::string& hash, uint64_t size, uint64_t offset, uint32_t chunksize);
|
||||
|
||||
/* Server Send */
|
||||
bool sendData(std::string peerId, std::string hash, uint64_t size,
|
||||
uint64_t offset, uint32_t chunksize, void *data);
|
||||
bool sendData(const std::string& peerId, const std::string& hash, uint64_t size, uint64_t offset, uint32_t chunksize, void *data);
|
||||
|
||||
/* Server/client Send */
|
||||
bool sendChunkMapRequest(const std::string& peerId, const std::string& hash) ;
|
||||
|
||||
/*************** RECV INTERFACE (provides ftDataRecv) ****************/
|
||||
|
||||
/* Client Recv */
|
||||
virtual bool recvData(std::string peerId, std::string hash, uint64_t size, uint64_t offset, uint32_t chunksize, void *data);
|
||||
virtual bool recvFileMap(const std::string& peerId, const std::string& hash, uint32_t chunk_size, uint32_t nb_chunks, const std::vector<uint32_t>& compressed_map) ;
|
||||
virtual bool recvData(const std::string& peerId, const std::string& hash, uint64_t size, uint64_t offset, uint32_t chunksize, void *data);
|
||||
|
||||
/// Receive a request for a chunk map
|
||||
virtual bool recvChunkMapRequest(const std::string& peer_id,const std::string& hash,bool is_client) ;
|
||||
/// Receive a chunk map
|
||||
virtual bool recvChunkMap(const std::string& peer_id,const std::string& hash,const CompressedChunkMap& cmap,bool is_client) ;
|
||||
|
||||
/* Server Recv */
|
||||
virtual bool recvDataRequest(std::string peerId, std::string hash, uint64_t size, uint64_t offset, uint32_t chunksize);
|
||||
virtual bool recvDataRequest(const std::string& peerId, const std::string& hash, uint64_t size, uint64_t offset, uint32_t chunksize);
|
||||
|
||||
// Returns the chunk map from the file uploading client. Also initiates a chunk map request if this
|
||||
// map is too old. This supposes that the caller will ask again in a few seconds.
|
||||
//
|
||||
bool getClientChunkMap(const std::string& upload_hash,const std::string& peer_id,CompressedChunkMap& map) ;
|
||||
|
||||
protected:
|
||||
|
||||
@ -129,9 +137,11 @@ class ftDataMultiplex: public ftDataRecv, public RsQueueThread
|
||||
private:
|
||||
|
||||
/* Handling Job Queues */
|
||||
bool handleRecvData(std::string peerId, std::string hash, uint64_t size, uint64_t offset, uint32_t chunksize, void *data);
|
||||
bool handleRecvDataRequest(std::string peerId, std::string hash, uint64_t size, uint64_t offset, uint32_t chunksize);
|
||||
bool handleSearchRequest(std::string peerId, std::string hash, uint64_t size, uint64_t offset, uint32_t chunksize);
|
||||
bool handleRecvData(const std::string& peerId, const std::string& hash, uint64_t size, uint64_t offset, uint32_t chunksize, void *data);
|
||||
bool handleRecvDataRequest(const std::string& peerId, const std::string& hash, uint64_t size, uint64_t offset, uint32_t chunksize);
|
||||
bool handleSearchRequest(const std::string& peerId, const std::string& hash);
|
||||
bool handleRecvClientChunkMapRequest(const std::string& peerId, const std::string& hash) ;
|
||||
bool handleRecvServerChunkMapRequest(const std::string& peerId, const std::string& hash) ;
|
||||
|
||||
/* We end up doing the actual server job here */
|
||||
bool locked_handleServerRequest(ftFileProvider *provider, std::string peerId, std::string hash, uint64_t size, uint64_t offset, uint32_t chunksize);
|
||||
@ -143,7 +153,7 @@ class ftDataMultiplex: public ftDataRecv, public RsQueueThread
|
||||
|
||||
std::list<ftRequest> mRequestQueue;
|
||||
std::list<ftRequest> mSearchQueue;
|
||||
std::map<std::string, time_t> mUnknownHashs;
|
||||
// std::map<std::string, time_t> mUnknownHashs;
|
||||
|
||||
ftDataSend *mDataSend;
|
||||
ftSearch *mSearch;
|
||||
|
@ -37,7 +37,7 @@ ftFiStore::ftFiStore(CacheStrapper *cs, CacheTransfer *cft, NotifyBase *cb_in,
|
||||
return;
|
||||
}
|
||||
|
||||
bool ftFiStore::search(std::string hash, uint64_t size, uint32_t hintflags, FileInfo &info) const
|
||||
bool ftFiStore::search(std::string hash, uint32_t hintflags, FileInfo &info) const
|
||||
{
|
||||
/* could use hintflags to specify which bits of fileinfo to use additionally.
|
||||
eg. hintflags & FT_SEARCH_PEER_ID, then only return matching peers + hash.
|
||||
@ -47,7 +47,7 @@ bool ftFiStore::search(std::string hash, uint64_t size, uint32_t hintflags, File
|
||||
*/
|
||||
|
||||
#ifdef DB_DEBUG
|
||||
std::cerr << "ftFiStore::search(" << hash << "," << size << "," << hintflags;
|
||||
std::cerr << "ftFiStore::search(" << hash << "," << hintflags;
|
||||
std::cerr << ")";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
@ -68,8 +68,8 @@ bool ftFiStore::search(std::string hash, uint64_t size, uint32_t hintflags, File
|
||||
#endif
|
||||
bool fullmatch = true;
|
||||
|
||||
if (it->size != size)
|
||||
fullmatch = false;
|
||||
// if (it->size != size)
|
||||
// fullmatch = false;
|
||||
|
||||
|
||||
#if 0
|
||||
@ -125,13 +125,13 @@ ftFiMonitor::ftFiMonitor(CacheStrapper *cs,NotifyBase *cb_in, std::string cached
|
||||
return;
|
||||
}
|
||||
|
||||
bool ftFiMonitor::search(std::string hash, uint64_t size, uint32_t hintflags, FileInfo &info) const
|
||||
bool ftFiMonitor::search(std::string hash, uint32_t hintflags, FileInfo &info) const
|
||||
{
|
||||
uint64_t fsize;
|
||||
std::string path;
|
||||
|
||||
#ifdef DB_DEBUG
|
||||
std::cerr << "ftFiMonitor::search(" << hash << "," << size << "," << hintflags;
|
||||
std::cerr << "ftFiMonitor::search(" << hash << "," << hintflags;
|
||||
std::cerr << ")";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
@ -269,10 +269,10 @@ ftCacheStrapper::ftCacheStrapper(p3AuthMgr *am, p3ConnectMgr *cm)
|
||||
}
|
||||
|
||||
/* overloaded search function */
|
||||
bool ftCacheStrapper::search(std::string hash, uint64_t size, uint32_t hintflags, FileInfo &info) const
|
||||
bool ftCacheStrapper::search(std::string hash, uint32_t hintflags, FileInfo &info) const
|
||||
{
|
||||
#ifdef DB_DEBUG
|
||||
std::cerr << "ftCacheStrapper::search(" << hash << "," << size << "," << hintflags;
|
||||
std::cerr << "ftCacheStrapper::search(" << hash << "," << hintflags;
|
||||
std::cerr << ")";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
@ -48,7 +48,7 @@ class ftFiStore: public FileIndexStore, public ftSearch
|
||||
RsPeerId ownid, std::string cachedir);
|
||||
|
||||
/* overloaded search function */
|
||||
virtual bool search(std::string hash, uint64_t size, uint32_t hintflags, FileInfo &info) const;
|
||||
virtual bool search(std::string hash, uint32_t hintflags, FileInfo &info) const;
|
||||
};
|
||||
|
||||
class ftFiMonitor: public FileIndexMonitor, public ftSearch, public p3Config
|
||||
@ -57,7 +57,7 @@ class ftFiMonitor: public FileIndexMonitor, public ftSearch, public p3Config
|
||||
ftFiMonitor(CacheStrapper *cs,NotifyBase *cb_in, std::string cachedir, std::string pid);
|
||||
|
||||
/* overloaded search function */
|
||||
virtual bool search(std::string hash, uint64_t size, uint32_t hintflags, FileInfo &info) const;
|
||||
virtual bool search(std::string hash, uint32_t hintflags, FileInfo &info) const;
|
||||
|
||||
/* overloaded set dirs enables config indication */
|
||||
virtual void setSharedDirectories(std::list<SharedDirInfo> dirList);
|
||||
@ -81,7 +81,7 @@ class ftCacheStrapper: public CacheStrapper, public ftSearch
|
||||
ftCacheStrapper(p3AuthMgr *am, p3ConnectMgr *cm);
|
||||
|
||||
/* overloaded search function */
|
||||
virtual bool search(std::string hash, uint64_t size, uint32_t hintflags, FileInfo &info) const;
|
||||
virtual bool search(std::string hash, uint32_t hintflags, FileInfo &info) const;
|
||||
|
||||
};
|
||||
|
||||
|
@ -318,14 +318,14 @@ bool ftExtraList::hashExtraFileDone(std::string path, FileInfo &info)
|
||||
}
|
||||
hash = it->second;
|
||||
}
|
||||
return search(hash, 0, 0, info);
|
||||
return search(hash, 0, info);
|
||||
}
|
||||
|
||||
/***
|
||||
* Search Function - used by File Transfer
|
||||
*
|
||||
**/
|
||||
bool ftExtraList::search(std::string hash, uint64_t size, uint32_t hintflags, FileInfo &info) const
|
||||
bool ftExtraList::search(std::string hash, uint32_t hintflags, FileInfo &info) const
|
||||
{
|
||||
|
||||
#ifdef DEBUG_ELIST
|
||||
|
@ -138,7 +138,7 @@ bool hashExtraFileDone(std::string path, FileInfo &info);
|
||||
* implementation of ftSearch.
|
||||
*
|
||||
**/
|
||||
virtual bool search(std::string hash, uint64_t size, uint32_t hintflags, FileInfo &info) const;
|
||||
virtual bool search(std::string hash, uint32_t hintflags, FileInfo &info) const;
|
||||
|
||||
/***
|
||||
* Thread Main Loop
|
||||
|
@ -38,16 +38,19 @@ ftFileCreator::ftFileCreator(std::string path, uint64_t size, std::string hash,
|
||||
|
||||
bool ftFileCreator::getFileData(uint64_t offset, uint32_t &chunk_size, void *data)
|
||||
{
|
||||
// Only send the data if we actually have it.
|
||||
//
|
||||
bool have_it = false ;
|
||||
{
|
||||
RsStackMutex stack(ftcMutex); /********** STACK LOCKED MTX ******/
|
||||
if (offset + chunk_size > mStart)
|
||||
{
|
||||
/* don't have the data */
|
||||
return false;
|
||||
}
|
||||
|
||||
have_it = chunkMap.isChunkAvailable(offset, chunk_size) ;
|
||||
}
|
||||
|
||||
return ftFileProvider::getFileData(offset, chunk_size, data);
|
||||
if(have_it)
|
||||
return ftFileProvider::getFileData(offset, chunk_size, data);
|
||||
else
|
||||
return false ;
|
||||
}
|
||||
|
||||
uint64_t ftFileCreator::getRecvd()
|
||||
@ -225,7 +228,6 @@ int ftFileCreator::locked_notifyReceived(uint64_t offset, uint32_t chunk_size)
|
||||
/* find the chunk */
|
||||
std::map<uint64_t, ftChunk>::iterator it = mChunks.find(offset);
|
||||
|
||||
// bool isFirst = false;
|
||||
if (it == mChunks.end())
|
||||
{
|
||||
#ifdef FILE_DEBUG
|
||||
@ -238,11 +240,6 @@ int ftFileCreator::locked_notifyReceived(uint64_t offset, uint32_t chunk_size)
|
||||
return 0; /* ignoring */
|
||||
}
|
||||
|
||||
// if (it == mChunks.begin())
|
||||
// {
|
||||
// isFirst = true;
|
||||
// }
|
||||
|
||||
ftChunk chunk = it->second;
|
||||
mChunks.erase(it);
|
||||
|
||||
@ -256,25 +253,18 @@ int ftFileCreator::locked_notifyReceived(uint64_t offset, uint32_t chunk_size)
|
||||
else // notify the chunkmap that the slice is finished
|
||||
chunkMap.dataReceived(chunk.id) ;
|
||||
|
||||
// /* update how much has been completed */
|
||||
// if (isFirst)
|
||||
// {
|
||||
// mStart = offset + chunk_size;
|
||||
// }
|
||||
|
||||
// update chunk map
|
||||
|
||||
// if (mChunks.size() == 0)
|
||||
// {
|
||||
// mStart = mEnd;
|
||||
// }
|
||||
|
||||
/* otherwise there is another earlier block to go
|
||||
*/
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
FileChunksInfo::ChunkStrategy ftFileCreator::getChunkStrategy()
|
||||
{
|
||||
RsStackMutex stack(ftcMutex); /********** STACK LOCKED MTX ******/
|
||||
|
||||
return chunkMap.getStrategy() ;
|
||||
}
|
||||
void ftFileCreator::setChunkStrategy(FileChunksInfo::ChunkStrategy s)
|
||||
{
|
||||
RsStackMutex stack(ftcMutex); /********** STACK LOCKED MTX ******/
|
||||
@ -289,7 +279,7 @@ void ftFileCreator::setChunkStrategy(FileChunksInfo::ChunkStrategy s)
|
||||
* But can return size = 0, if we are still waiting for the data.
|
||||
*/
|
||||
|
||||
bool ftFileCreator::getMissingChunk(const std::string& peer_id,uint32_t size_hint,uint64_t &offset, uint32_t& size)
|
||||
bool ftFileCreator::getMissingChunk(const std::string& peer_id,uint32_t size_hint,uint64_t &offset, uint32_t& size,bool& source_chunk_map_needed)
|
||||
{
|
||||
RsStackMutex stack(ftcMutex); /********** STACK LOCKED MTX ******/
|
||||
#ifdef FILE_DEBUG
|
||||
@ -298,17 +288,7 @@ bool ftFileCreator::getMissingChunk(const std::string& peer_id,uint32_t size_hin
|
||||
std::cerr << std::endl;
|
||||
locked_printChunkMap();
|
||||
#endif
|
||||
|
||||
/* check start point */
|
||||
|
||||
// if(mStart == mSize)
|
||||
// {
|
||||
//#ifdef FILE_DEBUG
|
||||
// std::cerr << "ffc::getMissingChunk() File Done";
|
||||
// std::cerr << std::endl;
|
||||
//#endif
|
||||
// return false;
|
||||
// }
|
||||
source_chunk_map_needed = false ;
|
||||
|
||||
/* check for freed chunks */
|
||||
time_t ts = time(NULL);
|
||||
@ -338,30 +318,17 @@ bool ftFileCreator::getMissingChunk(const std::string& peer_id,uint32_t size_hin
|
||||
|
||||
ftChunk chunk ;
|
||||
|
||||
if(!chunkMap.getDataChunk(peer_id,size_hint,chunk))
|
||||
if(!chunkMap.getDataChunk(peer_id,size_hint,chunk,source_chunk_map_needed))
|
||||
return false ;
|
||||
|
||||
// if (mSize - mEnd < chunk)
|
||||
// chunk = mSize - mEnd;
|
||||
//
|
||||
// offset = mEnd;
|
||||
// mEnd += chunk;
|
||||
|
||||
// if (chunk > 0)
|
||||
// {
|
||||
#ifdef FILE_DEBUG
|
||||
std::cerr << "ffc::getMissingChunk() Retrieved new chunk: " << chunk << std::endl ;
|
||||
// std::cerr << std::endl;
|
||||
// std::cerr << " mStart: " << mStart << " mEnd: " << mEnd;
|
||||
// std::cerr << "mSize: " << mSize;
|
||||
// std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
mChunks[chunk.offset] = chunk ;
|
||||
|
||||
offset = chunk.offset ;
|
||||
size = chunk.size ;
|
||||
// }
|
||||
|
||||
return true; /* cos more data to get */
|
||||
}
|
||||
@ -382,7 +349,6 @@ bool ftFileCreator::locked_printChunkMap()
|
||||
#endif
|
||||
|
||||
/* check start point */
|
||||
// std::cerr << "Size: " << mSize << " Start: " << mStart << " End: " << mEnd;
|
||||
std::cerr << "\tOutstanding Chunks:";
|
||||
std::cerr << std::endl;
|
||||
|
||||
@ -394,23 +360,21 @@ bool ftFileCreator::locked_printChunkMap()
|
||||
return true;
|
||||
}
|
||||
|
||||
void ftFileCreator::loadAvailabilityMap(const std::vector<uint32_t>& map,uint32_t chunk_size,uint32_t chunk_number,uint32_t strategy)
|
||||
void ftFileCreator::setAvailabilityMap(const CompressedChunkMap& cmap)
|
||||
{
|
||||
RsStackMutex stack(ftcMutex); /********** STACK LOCKED MTX ******/
|
||||
|
||||
chunkMap = ChunkMap(mSize,map,chunk_size,chunk_number,FileChunksInfo::ChunkStrategy(strategy)) ;
|
||||
chunkMap.setAvailabilityMap(cmap) ;
|
||||
}
|
||||
|
||||
void ftFileCreator::storeAvailabilityMap(std::vector<uint32_t>& map,uint32_t& chunk_size,uint32_t& chunk_number,uint32_t& strategy)
|
||||
void ftFileCreator::getAvailabilityMap(CompressedChunkMap& map)
|
||||
{
|
||||
RsStackMutex stack(ftcMutex); /********** STACK LOCKED MTX ******/
|
||||
|
||||
FileChunksInfo::ChunkStrategy strat ;
|
||||
chunkMap.buildAvailabilityMap(map,chunk_size,chunk_number,strat) ;
|
||||
strategy = (uint32_t)strat ;
|
||||
chunkMap.getAvailabilityMap(map) ;
|
||||
}
|
||||
|
||||
void ftFileCreator::setSourceMap(const std::string& peer_id,uint32_t chunk_size,uint32_t nb_chunks,const std::vector<uint32_t>& compressed_map)
|
||||
void ftFileCreator::setSourceMap(const std::string& peer_id,const CompressedChunkMap& compressed_map)
|
||||
{
|
||||
RsStackMutex stack(ftcMutex); /********** STACK LOCKED MTX ******/
|
||||
|
||||
@ -421,7 +385,7 @@ void ftFileCreator::setSourceMap(const std::string& peer_id,uint32_t chunk_size,
|
||||
// - then asking the chunkmap which chunks are being downloaded, but actually shouldn't
|
||||
// - cancelling them in the ftFileCreator, so that they can be re-asked later to another peer.
|
||||
//
|
||||
chunkMap.setPeerAvailabilityMap(peer_id,chunk_size,nb_chunks,compressed_map) ;
|
||||
chunkMap.setPeerAvailabilityMap(peer_id,compressed_map) ;
|
||||
}
|
||||
|
||||
|
||||
|
@ -50,16 +50,20 @@ class ftFileCreator: public ftFileProvider
|
||||
uint64_t getRecvd();
|
||||
|
||||
void getChunkMap(FileChunksInfo& info) ;
|
||||
|
||||
void setChunkStrategy(FileChunksInfo::ChunkStrategy s) ;
|
||||
FileChunksInfo::ChunkStrategy getChunkStrategy() ;
|
||||
|
||||
/*
|
||||
* creation functions for FileCreator
|
||||
*/
|
||||
|
||||
// Gets a new variable-sized chunk of size "size_hint" from the given peer id. The returned size, "size" is
|
||||
// at most equal to size_hint.
|
||||
// at most equal to size_hint. chunk_map_needed is set if
|
||||
// - no chunkmap info is available. In such a case, the chunk info is irrelevant and false is returned.
|
||||
// - the chunk info is too old. In tis case, true is returned, and the chunks info can be used.
|
||||
//
|
||||
bool getMissingChunk(const std::string& peer_id,uint32_t size_hint,uint64_t& offset, uint32_t& size);
|
||||
bool getMissingChunk(const std::string& peer_id,uint32_t size_hint,uint64_t& offset, uint32_t& size,bool& is_chunk_map_too_old);
|
||||
|
||||
// actually store data in the file, and update chunks info
|
||||
//
|
||||
@ -71,12 +75,12 @@ class ftFileCreator: public ftFileProvider
|
||||
// - getting info about current chunks for the GUI
|
||||
// - sending availability info to the peers for which we also are a source
|
||||
//
|
||||
void loadAvailabilityMap(const std::vector<uint32_t>& map,uint32_t chunk_size,uint32_t chunk_number,uint32_t chunk_strategy) ;
|
||||
void storeAvailabilityMap(std::vector<uint32_t>& map,uint32_t& chunk_size,uint32_t& chunk_number,uint32_t& chunk_strategy) ;
|
||||
virtual void getAvailabilityMap(CompressedChunkMap& cmap) ;
|
||||
void setAvailabilityMap(const CompressedChunkMap& cmap) ;
|
||||
|
||||
// This is called when receiving the availability map from a source peer, for the file being handled.
|
||||
//
|
||||
void setSourceMap(const std::string& peer_id,uint32_t chunk_size,uint32_t nb_chunks,const std::vector<uint32_t>& map) ;
|
||||
void setSourceMap(const std::string& peer_id,const CompressedChunkMap& map) ;
|
||||
|
||||
protected:
|
||||
|
||||
|
@ -1,9 +1,12 @@
|
||||
#include "ftfileprovider.h"
|
||||
#include "ftchunkmap.h"
|
||||
|
||||
#include "util/rsdir.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static const time_t UPLOAD_CHUNK_MAPS_TIME = 30 ; // time to ask for a new chunkmap from uploaders in seconds.
|
||||
|
||||
ftFileProvider::ftFileProvider(std::string path, uint64_t size, std::string
|
||||
hash) : mSize(size), hash(hash), file_name(path), fd(NULL),transfer_rate(0),total_size(0)
|
||||
{
|
||||
@ -73,6 +76,13 @@ bool ftFileProvider::FileDetails(FileInfo &info)
|
||||
return true;
|
||||
}
|
||||
|
||||
void ftFileProvider::getAvailabilityMap(CompressedChunkMap& cmap)
|
||||
{
|
||||
// We are here because the file we deal with is complete. So we return a plain map.
|
||||
//
|
||||
ChunkMap::buildPlainMap(mSize,cmap) ;
|
||||
}
|
||||
|
||||
|
||||
bool ftFileProvider::getFileData(uint64_t offset, uint32_t &chunk_size, void *data)
|
||||
{
|
||||
@ -168,6 +178,39 @@ bool ftFileProvider::getFileData(uint64_t offset, uint32_t &chunk_size, void *da
|
||||
return 1;
|
||||
}
|
||||
|
||||
void ftFileProvider::setClientMap(const std::string& peer_id,const CompressedChunkMap& cmap)
|
||||
{
|
||||
RsStackMutex stack(ftcMutex); /********** STACK LOCKED MTX ******/
|
||||
|
||||
std::pair<CompressedChunkMap,time_t>& map_info(clients_chunk_maps[peer_id]) ;
|
||||
|
||||
map_info.first = cmap ;
|
||||
map_info.second = time(NULL) ;
|
||||
}
|
||||
|
||||
void ftFileProvider::getClientMap(const std::string& peer_id,CompressedChunkMap& cmap,bool& map_is_too_old)
|
||||
{
|
||||
RsStackMutex stack(ftcMutex); /********** STACK LOCKED MTX ******/
|
||||
|
||||
std::map<std::string,std::pair<CompressedChunkMap,time_t> >::iterator it(clients_chunk_maps.find(peer_id)) ;
|
||||
|
||||
if(it == clients_chunk_maps.end())
|
||||
{
|
||||
clients_chunk_maps[peer_id] = std::pair<CompressedChunkMap,time_t>(CompressedChunkMap(),0) ;
|
||||
it = clients_chunk_maps.find(peer_id) ;
|
||||
}
|
||||
|
||||
if(time(NULL) - it->second.second > UPLOAD_CHUNK_MAPS_TIME)
|
||||
{
|
||||
map_is_too_old = true ;
|
||||
it->second.second = time(NULL) ; // to avoid re-asking before the TTL
|
||||
}
|
||||
else
|
||||
map_is_too_old = false ;
|
||||
|
||||
cmap = it->second.first ;
|
||||
}
|
||||
|
||||
int ftFileProvider::initializeFileAttrs()
|
||||
{
|
||||
std::cerr << "ftFileProvider::initializeFileAttrs() Filename: ";
|
||||
|
@ -37,45 +37,57 @@
|
||||
|
||||
class ftFileProvider
|
||||
{
|
||||
public:
|
||||
ftFileProvider(std::string path, uint64_t size, std::string hash);
|
||||
virtual ~ftFileProvider();
|
||||
public:
|
||||
ftFileProvider(std::string path, uint64_t size, std::string hash);
|
||||
virtual ~ftFileProvider();
|
||||
|
||||
virtual bool getFileData(uint64_t offset, uint32_t &chunk_size, void *data);
|
||||
virtual bool FileDetails(FileInfo &info);
|
||||
std::string getHash();
|
||||
uint64_t getFileSize();
|
||||
bool fileOk();
|
||||
virtual bool getFileData(uint64_t offset, uint32_t &chunk_size, void *data);
|
||||
virtual bool FileDetails(FileInfo &info);
|
||||
std::string getHash();
|
||||
uint64_t getFileSize();
|
||||
bool fileOk();
|
||||
|
||||
void setPeerId(const std::string& id) ;
|
||||
void setPeerId(const std::string& id) ;
|
||||
|
||||
// Provides a client for the map of chunks actually present in the file. If the provider is also
|
||||
// a file creator, because the file is actually being downloaded, then the map may be partially complete.
|
||||
// Otherwize, a plain map is returned.
|
||||
//
|
||||
virtual void getAvailabilityMap(CompressedChunkMap& cmap) ;
|
||||
|
||||
protected:
|
||||
virtual int initializeFileAttrs(); /* does for both */
|
||||
// a ftFileProvider feeds a distant peer. To display what the peers already has, we need to store/read this info.
|
||||
void getClientMap(const std::string& peer_id,CompressedChunkMap& cmap,bool& map_is_too_old) ;
|
||||
void setClientMap(const std::string& peer_id,const CompressedChunkMap& cmap) ;
|
||||
|
||||
uint64_t mSize;
|
||||
std::string hash;
|
||||
std::string file_name;
|
||||
FILE *fd;
|
||||
protected:
|
||||
virtual int initializeFileAttrs(); /* does for both */
|
||||
|
||||
/*
|
||||
* Structure to gather statistics FIXME: lastRequestor - figure out a
|
||||
* way to get last requestor (peerID)
|
||||
*/
|
||||
std::string lastRequestor;
|
||||
uint64_t req_loc;
|
||||
uint32_t req_size;
|
||||
time_t lastTS; // used for checking if it's alive
|
||||
time_t lastTS_t; // used for estimating transfer rate.
|
||||
uint64_t mSize;
|
||||
std::string hash;
|
||||
std::string file_name;
|
||||
FILE *fd;
|
||||
|
||||
// these two are used for speed estimation
|
||||
float transfer_rate ;
|
||||
uint32_t total_size ;
|
||||
/*
|
||||
* Structure to gather statistics FIXME: lastRequestor - figure out a
|
||||
* way to get last requestor (peerID)
|
||||
*/
|
||||
std::string lastRequestor;
|
||||
uint64_t req_loc;
|
||||
uint32_t req_size;
|
||||
time_t lastTS; // used for checking if it's alive
|
||||
time_t lastTS_t; // used for estimating transfer rate.
|
||||
|
||||
/*
|
||||
* Mutex Required for stuff below
|
||||
*/
|
||||
RsMutex ftcMutex;
|
||||
// these two are used for speed estimation
|
||||
float transfer_rate ;
|
||||
uint32_t total_size ;
|
||||
|
||||
// Info about what the downloading peer already has
|
||||
std::map<std::string,std::pair<CompressedChunkMap,time_t> > clients_chunk_maps ;
|
||||
|
||||
/*
|
||||
* Mutex Required for stuff below
|
||||
*/
|
||||
RsMutex ftcMutex;
|
||||
};
|
||||
|
||||
|
||||
|
@ -75,12 +75,12 @@ bool ftFileSearch::addSearchMode(ftSearch *search, uint32_t hintflags)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ftFileSearch::search(std::string hash, uint64_t size, uint32_t hintflags, FileInfo &info) const
|
||||
bool ftFileSearch::search(std::string hash, uint32_t hintflags, FileInfo &info) const
|
||||
{
|
||||
uint32_t hints, i;
|
||||
|
||||
#ifdef DEBUG_SEARCH
|
||||
std::cerr << "ftFileSearch::search(" << hash << ", " << size;
|
||||
std::cerr << "ftFileSearch::search(" << hash ;
|
||||
std::cerr << ", " << hintflags << ");";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
@ -99,7 +99,7 @@ bool ftFileSearch::search(std::string hash, uint64_t size, uint32_t hintflags, F
|
||||
std::cerr << i;
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
if (search->search(hash, size, hintflags, info))
|
||||
if (search->search(hash, hintflags, info))
|
||||
{
|
||||
#ifdef DEBUG_SEARCH
|
||||
std::cerr << "ftFileSearch::search() SLOT: ";
|
||||
@ -155,7 +155,7 @@ bool ftFileSearch::search(std::string hash, uint64_t size, uint32_t hintflags, F
|
||||
std::cerr << "ftFileSearch::search() SLOT: " << i;
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
if (search->search(hash, size, hintflags, info))
|
||||
if (search->search(hash, hintflags, info))
|
||||
{
|
||||
#ifdef DEBUG_SEARCH
|
||||
std::cerr << "ftFileSearch::search() SLOT: ";
|
||||
@ -180,10 +180,10 @@ bool ftFileSearch::search(std::string hash, uint64_t size, uint32_t hintflags, F
|
||||
}
|
||||
|
||||
|
||||
bool ftSearchDummy::search(std::string hash, uint64_t size, uint32_t hintflags, FileInfo &info) const
|
||||
bool ftSearchDummy::search(std::string hash, uint32_t hintflags, FileInfo &info) const
|
||||
{
|
||||
#ifdef DEBUG_SEARCH
|
||||
std::cerr << "ftSearchDummy::search(" << hash << ", " << size;
|
||||
std::cerr << "ftSearchDummy::search(" << hash ;
|
||||
std::cerr << ", " << hintflags << ");";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
@ -45,7 +45,7 @@ class ftFileSearch: public ftSearch
|
||||
ftFileSearch();
|
||||
|
||||
bool addSearchMode(ftSearch *search, uint32_t hintflags);
|
||||
virtual bool search(std::string hash, uint64_t size, uint32_t hintflags, FileInfo &info) const;
|
||||
virtual bool search(std::string hash, uint32_t hintflags, FileInfo &info) const;
|
||||
|
||||
private:
|
||||
|
||||
|
@ -43,7 +43,7 @@ class ftSearch
|
||||
|
||||
ftSearch() { return; }
|
||||
virtual ~ftSearch() { return; }
|
||||
virtual bool search(std::string hash, uint64_t size, uint32_t hintflags, FileInfo &info) const = 0;
|
||||
virtual bool search(std::string hash, uint32_t hintflags, FileInfo &info) const = 0;
|
||||
|
||||
};
|
||||
|
||||
@ -54,7 +54,7 @@ class ftSearchDummy: public ftSearch
|
||||
|
||||
ftSearchDummy() { return; }
|
||||
virtual ~ftSearchDummy() { return; }
|
||||
virtual bool search(std::string hash, uint64_t size, uint32_t hintflags, FileInfo &info) const;
|
||||
virtual bool search(std::string hash, uint32_t hintflags, FileInfo &info) const;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -310,21 +310,9 @@ void ftServer::getDwlDetails(std::list<DwlDetails> & details)
|
||||
mFtDwlQueue->getDwlDetails(details);
|
||||
}
|
||||
|
||||
bool ftServer::FileChunksDetails(const std::string& hash,FileChunksInfo& info)
|
||||
bool ftServer::FileDownloadChunksDetails(const std::string& hash,FileChunksInfo& info)
|
||||
{
|
||||
return mFtController->getFileChunksDetails(hash,info);
|
||||
//
|
||||
// // for know put some dummy info. It's for display sake only.
|
||||
// info.chunk_size = 1024*1024 ;
|
||||
// info.file_size = 250*info.chunk_size - 123 ; // last chunk is not complete.
|
||||
// info.chunks.resize(250,FileChunksInfo::CHUNK_DONE) ;
|
||||
// int n = rand()%150 + 50 ;
|
||||
// for(int i=0;i<10;++i)
|
||||
// info.chunks[n+i] = FileChunksInfo::CHUNK_ACTIVE ;
|
||||
// for(int i=n+10;i<250;++i)
|
||||
// info.chunks[i] = FileChunksInfo::CHUNK_OUTSTANDING ;
|
||||
//
|
||||
// return true ;
|
||||
return mFtController->getFileDownloadChunksDetails(hash,info);
|
||||
}
|
||||
|
||||
/* Directory Handling */
|
||||
@ -360,6 +348,11 @@ bool ftServer::FileDownloads(std::list<std::string> &hashs)
|
||||
//return mFtDataplex->FileDownloads(hashs);
|
||||
}
|
||||
|
||||
bool ftServer::FileUploadChunksDetails(const std::string& hash,const std::string& peer_id,CompressedChunkMap& cmap)
|
||||
{
|
||||
return mFtDataplex->getClientChunkMap(hash,peer_id,cmap);
|
||||
}
|
||||
|
||||
bool ftServer::FileUploads(std::list<std::string> &hashs)
|
||||
{
|
||||
return mFtDataplex->FileUploads(hashs);
|
||||
@ -376,7 +369,7 @@ bool ftServer::FileDetails(std::string hash, uint32_t hintflags, FileInfo &info)
|
||||
return true ;
|
||||
|
||||
if(hintflags & ~(RS_FILE_HINTS_UPLOAD | RS_FILE_HINTS_DOWNLOAD))
|
||||
if(mFtSearch->search(hash, 0, hintflags, info))
|
||||
if(mFtSearch->search(hash, hintflags, info))
|
||||
return true ;
|
||||
|
||||
return false;
|
||||
@ -652,8 +645,7 @@ bool ftServer::loadConfigMap(std::map<std::string, std::string> &configMap)
|
||||
/***************************************************************/
|
||||
|
||||
/* Client Send */
|
||||
bool ftServer::sendDataRequest(std::string peerId, std::string hash,
|
||||
uint64_t size, uint64_t offset, uint32_t chunksize)
|
||||
bool ftServer::sendDataRequest(const std::string& peerId, const std::string& hash, uint64_t size, uint64_t offset, uint32_t chunksize)
|
||||
{
|
||||
if(mTurtleRouter->isTurtlePeer(peerId))
|
||||
mTurtleRouter->sendDataRequest(peerId,hash,size,offset,chunksize) ;
|
||||
@ -680,12 +672,33 @@ bool ftServer::sendDataRequest(std::string peerId, std::string hash,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ftServer::sendChunkMapRequest(const std::string& peerId,const std::string& hash)
|
||||
{
|
||||
if(mTurtleRouter->isTurtlePeer(peerId))
|
||||
mTurtleRouter->sendChunkMapRequest(peerId,hash) ;
|
||||
|
||||
// We only send chunkmap requests to turtle peers. This will be a problem at display time for
|
||||
// direct friends, so I'll see later whether I code it or not.
|
||||
return true ;
|
||||
}
|
||||
|
||||
bool ftServer::sendChunkMap(const std::string& peerId,const std::string& hash,const CompressedChunkMap& map)
|
||||
{
|
||||
if(mTurtleRouter->isTurtlePeer(peerId))
|
||||
mTurtleRouter->sendChunkMap(peerId,hash,map) ;
|
||||
|
||||
// We only send chunkmap requests to turtle peers. This will be a problem at display time for
|
||||
// direct friends, so I'll see later whether I code it or not.
|
||||
return true ;
|
||||
}
|
||||
|
||||
|
||||
//const uint32_t MAX_FT_CHUNK = 32 * 1024; /* 32K */
|
||||
//const uint32_t MAX_FT_CHUNK = 16 * 1024; /* 16K */
|
||||
const uint32_t MAX_FT_CHUNK = 8 * 1024; /* 16K */
|
||||
|
||||
/* Server Send */
|
||||
bool ftServer::sendData(std::string peerId, std::string hash, uint64_t size, uint64_t baseoffset, uint32_t chunksize, void *data)
|
||||
bool ftServer::sendData(const std::string& peerId, const std::string& hash, uint64_t size, uint64_t baseoffset, uint32_t chunksize, void *data)
|
||||
{
|
||||
/* create a packet */
|
||||
/* push to networking part */
|
||||
|
@ -138,7 +138,9 @@ virtual void getDwlDetails(std::list<DwlDetails> & details);
|
||||
virtual bool FileDownloads(std::list<std::string> &hashs);
|
||||
virtual bool FileUploads(std::list<std::string> &hashs);
|
||||
virtual bool FileDetails(std::string hash, uint32_t hintflags, FileInfo &info);
|
||||
virtual bool FileChunksDetails(const std::string& hash,FileChunksInfo& info) ;
|
||||
virtual bool FileDownloadChunksDetails(const std::string& hash,FileChunksInfo& info) ;
|
||||
virtual bool FileUploadChunksDetails(const std::string& hash,const std::string& peer_id,CompressedChunkMap& map) ;
|
||||
|
||||
|
||||
/***
|
||||
* Extra List Access
|
||||
@ -196,11 +198,11 @@ virtual bool unshareDownloadDirectory();
|
||||
/*************** Data Transfer Interface ***********************/
|
||||
/***************************************************************/
|
||||
public:
|
||||
virtual bool sendData(std::string peerId, std::string hash, uint64_t size,
|
||||
uint64_t offset, uint32_t chunksize, void *data);
|
||||
virtual bool sendDataRequest(std::string peerId,
|
||||
std::string hash, uint64_t size,
|
||||
uint64_t offset, uint32_t chunksize);
|
||||
virtual bool sendData(const std::string& peerId, const std::string& hash, uint64_t size, uint64_t offset, uint32_t chunksize, void *data);
|
||||
virtual bool sendDataRequest(const std::string& peerId, const std::string& hash, uint64_t size, uint64_t offset, uint32_t chunksize);
|
||||
virtual bool sendChunkMapRequest(const std::string& peer_id,const std::string& hash) ;
|
||||
virtual bool sendChunkMap(const std::string& peer_id,const std::string& hash,const CompressedChunkMap& cmap) ;
|
||||
|
||||
|
||||
/*************** Internal Transfer Fns *************************/
|
||||
virtual int tick();
|
||||
|
@ -327,7 +327,11 @@ bool ftTransferModule::getChunk(const std::string& peer_id,uint32_t size_hint,ui
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
bool val = mFileCreator->getMissingChunk(peer_id,size_hint,offset, chunk_size);
|
||||
bool source_peer_map_needed ;
|
||||
bool val = mFileCreator->getMissingChunk(peer_id,size_hint,offset, chunk_size,source_peer_map_needed);
|
||||
|
||||
if(source_peer_map_needed)
|
||||
mMultiplexor->sendChunkMapRequest(peer_id, mHash) ;
|
||||
|
||||
#ifdef FT_DEBUG
|
||||
if (val)
|
||||
@ -338,12 +342,14 @@ bool ftTransferModule::getChunk(const std::string& peer_id,uint32_t size_hint,ui
|
||||
std::cerr << " size: " << mSize;
|
||||
std::cerr << " offset: " << offset;
|
||||
std::cerr << " chunk_size: " << chunk_size;
|
||||
std::cerr << " peer map needed = " << source_peer_map_needed << std::endl ;
|
||||
std::cerr << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "ftTransferModule::getChunk()";
|
||||
std::cerr << " Answer: No Chunk Available";
|
||||
std::cerr << " peer map needed = " << source_peer_map_needed << std::endl ;
|
||||
std::cerr << std::endl;
|
||||
}
|
||||
#endif
|
||||
|
@ -129,7 +129,12 @@ virtual void getDwlDetails(std::list<DwlDetails> & details) = 0;
|
||||
virtual bool FileDownloads(std::list<std::string> &hashs) = 0;
|
||||
virtual bool FileUploads(std::list<std::string> &hashs) = 0;
|
||||
virtual bool FileDetails(std::string hash, uint32_t hintflags, FileInfo &info) = 0;
|
||||
virtual bool FileChunksDetails(const std::string& hash,FileChunksInfo& info) = 0 ;
|
||||
|
||||
/// Gives chunk details about the downloaded file with given hash.
|
||||
virtual bool FileDownloadChunksDetails(const std::string& hash,FileChunksInfo& info) = 0 ;
|
||||
|
||||
/// details about the upload with given hash
|
||||
virtual bool FileUploadChunksDetails(const std::string& hash,const std::string& peer_id,CompressedChunkMap& map) = 0 ;
|
||||
|
||||
/***
|
||||
* Extra List Access
|
||||
|
@ -28,6 +28,7 @@
|
||||
|
||||
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
@ -250,7 +251,10 @@ enum DwlPriority { Low = 0, Normal, High, Auto };
|
||||
|
||||
// Macro to read a bits array for compressed chunk maps
|
||||
//
|
||||
#define COMPRESSED_MAP_READ(A,j) (A[j >> 5] & (1 << (j & 0x11111)))
|
||||
//#define COMPRESSED_MAP_READ(A,j) (A[j >> 5] & (1 << (j & 0x11111)))
|
||||
//#define COMPRESSED_MAP_WRITE(A,j,x) (A[j >> 5] |= (1 << (j & 0x11111)))
|
||||
|
||||
class CompressedChunkMap ;
|
||||
|
||||
class FileChunksInfo
|
||||
{
|
||||
@ -265,12 +269,48 @@ class FileChunksInfo
|
||||
std::vector<ChunkState> chunks ;
|
||||
|
||||
// For each source peer, gives the compressed bit map of have/don't have sate
|
||||
std::vector<std::pair<std::string, std::vector<uint32_t> > > compressed_peer_availability_maps ;
|
||||
std::map<std::string, CompressedChunkMap> compressed_peer_availability_maps ;
|
||||
|
||||
// For each chunk (by chunk number), gives the completion of the chunk.
|
||||
//
|
||||
std::vector<std::pair<uint32_t,uint32_t> > active_chunks ;
|
||||
};
|
||||
|
||||
class CompressedChunkMap
|
||||
{
|
||||
public:
|
||||
CompressedChunkMap() {}
|
||||
|
||||
CompressedChunkMap(const std::vector<FileChunksInfo::ChunkState>& uncompressed_data)
|
||||
{
|
||||
_map.resize( getCompressedSize(uncompressed_data.size()),0 ) ;
|
||||
|
||||
for(uint32_t i=0;i<uncompressed_data.size();++i)
|
||||
if(uncompressed_data[i]==FileChunksInfo::CHUNK_DONE)
|
||||
set(i) ;
|
||||
}
|
||||
|
||||
CompressedChunkMap(uint32_t nb_chunks,uint32_t value)
|
||||
{
|
||||
_map.resize(getCompressedSize(nb_chunks),value) ;
|
||||
}
|
||||
|
||||
static uint32_t getCompressedSize(uint32_t size) { return (size>>5) + !!(size&31) ; }
|
||||
|
||||
uint32_t filledChunks(uint32_t nbchks)
|
||||
{
|
||||
uint32_t res = 0 ;
|
||||
for(uint32_t i=0;i<std::min(nbchks,_map.size()*32);++i)
|
||||
res += operator[](i) ;
|
||||
return res ;
|
||||
}
|
||||
inline bool operator[](uint32_t i) const { return (_map[i >> 5] & (1 << (i & 31))) > 0 ; }
|
||||
|
||||
inline void set(uint32_t j) { _map[j >> 5] |= (1 << (j & 31)) ; }
|
||||
inline void reset(uint32_t j) { _map[j >> 5] &= ~(1 << (j & 31)) ; }
|
||||
|
||||
/// compressed map, one bit per chunk
|
||||
std::vector<uint32_t> _map ;
|
||||
};
|
||||
|
||||
/* class which encapsulates download details */
|
||||
|
@ -196,11 +196,9 @@ uint32_t RsFileConfigSerialiser::sizeTransfer(RsFileTransfer *item)
|
||||
s += 4; /* trate */
|
||||
s += 4; /* lrate */
|
||||
s += 4; /* ltransfer */
|
||||
s += 4; // chunk_size
|
||||
s += 4; // chunk_number
|
||||
s += 4; // chunk_strategy
|
||||
s += 4; // chunk map size
|
||||
s += 4*item->chunk_map.size(); // chunk_map
|
||||
s += 4*item->compressed_chunk_map._map.size(); // compressed_chunk_map
|
||||
|
||||
return s;
|
||||
}
|
||||
@ -243,13 +241,11 @@ bool RsFileConfigSerialiser::serialiseTransfer(RsFileTransfer *item, void *d
|
||||
ok &= setRawUInt32(data, tlvsize, &offset, item->lrate);
|
||||
ok &= setRawUInt32(data, tlvsize, &offset, item->ltransfer);
|
||||
|
||||
ok &= setRawUInt32(data, tlvsize, &offset, item->chunk_size);
|
||||
ok &= setRawUInt32(data, tlvsize, &offset, item->chunk_number);
|
||||
ok &= setRawUInt32(data, tlvsize, &offset, item->chunk_strategy);
|
||||
ok &= setRawUInt32(data, tlvsize, &offset, item->chunk_map.size());
|
||||
ok &= setRawUInt32(data, tlvsize, &offset, item->compressed_chunk_map._map.size());
|
||||
|
||||
for(uint32_t i=0;i<item->chunk_map.size();++i)
|
||||
ok &= setRawUInt32(data, tlvsize, &offset, item->chunk_map[i]);
|
||||
for(uint32_t i=0;i<item->compressed_chunk_map._map.size();++i)
|
||||
ok &= setRawUInt32(data, tlvsize, &offset, item->compressed_chunk_map._map[i]);
|
||||
|
||||
if (offset != tlvsize)
|
||||
{
|
||||
@ -310,15 +306,13 @@ RsFileTransfer *RsFileConfigSerialiser::deserialiseTransfer(void *data, uint32_t
|
||||
ok &= getRawUInt32(data, rssize, &offset, &(item->lrate));
|
||||
ok &= getRawUInt32(data, rssize, &offset, &(item->ltransfer));
|
||||
|
||||
ok &= getRawUInt32(data, rssize, &offset, &(item->chunk_size));
|
||||
ok &= getRawUInt32(data, rssize, &offset, &(item->chunk_number));
|
||||
ok &= getRawUInt32(data, rssize, &offset, &(item->chunk_strategy));
|
||||
uint32_t map_size = 0 ;
|
||||
ok &= getRawUInt32(data, rssize, &offset, &map_size);
|
||||
|
||||
item->chunk_map.resize(map_size) ;
|
||||
item->compressed_chunk_map._map.resize(map_size) ;
|
||||
for(uint32_t i=0;i<map_size;++i)
|
||||
ok &= getRawUInt32(data, rssize, &offset, &(item->chunk_map[i]));
|
||||
ok &= getRawUInt32(data, rssize, &offset, &(item->compressed_chunk_map._map[i]));
|
||||
|
||||
if (offset != rssize)
|
||||
{
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include <rsiface/rstypes.h>
|
||||
#include "serialiser/rsserial.h"
|
||||
#include "serialiser/rstlvbase.h"
|
||||
#include "serialiser/rstlvtypes.h"
|
||||
@ -204,10 +205,8 @@ class RsFileTransfer: public RsItem
|
||||
uint32_t ltransfer;
|
||||
|
||||
// chunk information
|
||||
uint32_t chunk_size ; // common size of chunks
|
||||
uint32_t chunk_number ; // total number of chunks (this is not redondant, cause chunks are compressed)
|
||||
uint32_t chunk_strategy ; // strategy flags for chunks
|
||||
std::vector<uint32_t> chunk_map ; // chunk availability (bitwise)
|
||||
CompressedChunkMap compressed_chunk_map ; // chunk availability (bitwise)
|
||||
};
|
||||
|
||||
/**************************************************************************/
|
||||
|
@ -782,25 +782,24 @@ void p3turtle::routeGenericTunnelItem(RsTurtleGenericTunnelItem *item)
|
||||
// The packet was not forwarded, so it is for us. Let's treat it.
|
||||
// This is done off-mutex, to avoid various deadlocks
|
||||
//
|
||||
if(direction == RsTurtleGenericTunnelItem::DIRECTION_SERVER)
|
||||
switch(item->PacketSubType())
|
||||
{
|
||||
case RS_TURTLE_SUBTYPE_FILE_REQUEST: handleRecvFileRequest(dynamic_cast<RsTurtleFileRequestItem *>(item)) ;
|
||||
break ;
|
||||
default:
|
||||
std::cerr << "Unknown server packet type received: id=" << (void*)(item->PacketSubType()) << std::endl ;
|
||||
exit(-1) ;
|
||||
}
|
||||
|
||||
if(direction == RsTurtleGenericTunnelItem::DIRECTION_CLIENT)
|
||||
switch(item->PacketSubType())
|
||||
{
|
||||
case RS_TURTLE_SUBTYPE_FILE_DATA : handleRecvFileData(dynamic_cast<RsTurtleFileDataItem *>(item)) ;
|
||||
break ;
|
||||
default:
|
||||
std::cerr << "Unknown client packet type received: id=" << (void*)(item->PacketSubType()) << std::endl ;
|
||||
exit(-1) ;
|
||||
}
|
||||
switch(item->PacketSubType())
|
||||
{
|
||||
case RS_TURTLE_SUBTYPE_FILE_REQUEST: handleRecvFileRequest(dynamic_cast<RsTurtleFileRequestItem *>(item)) ;
|
||||
break ;
|
||||
|
||||
case RS_TURTLE_SUBTYPE_FILE_DATA : handleRecvFileData(dynamic_cast<RsTurtleFileDataItem *>(item)) ;
|
||||
break ;
|
||||
|
||||
case RS_TURTLE_SUBTYPE_FILE_MAP : handleRecvFileMap(dynamic_cast<RsTurtleFileMapItem *>(item)) ;
|
||||
break ;
|
||||
|
||||
case RS_TURTLE_SUBTYPE_FILE_MAP_REQUEST: handleRecvFileMapRequest(dynamic_cast<RsTurtleFileMapRequestItem *>(item)) ;
|
||||
break ;
|
||||
default:
|
||||
std::cerr << "Unknown packet type received: id=" << (void*)(item->PacketSubType()) << std::endl ;
|
||||
exit(-1) ;
|
||||
}
|
||||
|
||||
delete item ;
|
||||
}
|
||||
@ -908,6 +907,42 @@ void p3turtle::handleRecvFileData(RsTurtleFileDataItem *item)
|
||||
// down _ft_server->getMultiplexer()->recvData()...in ftTransferModule::recvFileData
|
||||
}
|
||||
|
||||
void p3turtle::handleRecvFileMapRequest(RsTurtleFileMapRequestItem *item)
|
||||
{
|
||||
#ifdef P3TURTLE_DEBUG
|
||||
std::cerr << "p3Turtle: received file Map item:" << std::endl ;
|
||||
item->print(std::cerr,1) ;
|
||||
#endif
|
||||
std::string hash,vpid ;
|
||||
{
|
||||
RsStackMutex stack(mTurtleMtx); /********** STACK LOCKED MTX ******/
|
||||
|
||||
std::map<TurtleTunnelId,TurtleTunnel>::iterator it2(_local_tunnels.find(item->tunnel_id)) ;
|
||||
|
||||
if(it2 == _local_tunnels.end())
|
||||
{
|
||||
#ifdef P3TURTLE_DEBUG
|
||||
std::cerr << "p3turtle: got file data with unknown tunnel id " << (void*)item->tunnel_id << std::endl ;
|
||||
#endif
|
||||
return ;
|
||||
}
|
||||
|
||||
TurtleTunnel& tunnel(it2->second) ;
|
||||
#ifdef P3TURTLE_DEBUG
|
||||
assert(!tunnel.hash.empty()) ;
|
||||
|
||||
std::cerr << " This is an endpoint for this file map request." << std::endl ;
|
||||
std::cerr << " Forwarding data to the multiplexer." << std::endl ;
|
||||
std::cerr << " using peer_id=" << tunnel.vpid << ", hash=" << tunnel.hash << std::endl ;
|
||||
#endif
|
||||
// we should check that there is no backward call to the turtle router!
|
||||
//
|
||||
hash = tunnel.hash ;
|
||||
vpid = tunnel.vpid ;
|
||||
}
|
||||
|
||||
_ft_server->getMultiplexer()->recvChunkMapRequest(vpid,hash,item->direction == RsTurtleGenericTunnelItem::DIRECTION_CLIENT) ;
|
||||
}
|
||||
|
||||
void p3turtle::handleRecvFileMap(RsTurtleFileMapItem *item)
|
||||
{
|
||||
@ -915,6 +950,7 @@ void p3turtle::handleRecvFileMap(RsTurtleFileMapItem *item)
|
||||
std::cerr << "p3Turtle: received file Map item:" << std::endl ;
|
||||
item->print(std::cerr,1) ;
|
||||
#endif
|
||||
std::string hash,vpid ;
|
||||
{
|
||||
RsStackMutex stack(mTurtleMtx); /********** STACK LOCKED MTX ******/
|
||||
|
||||
@ -930,31 +966,19 @@ void p3turtle::handleRecvFileMap(RsTurtleFileMapItem *item)
|
||||
|
||||
TurtleTunnel& tunnel(it2->second) ;
|
||||
|
||||
std::map<TurtleFileHash,TurtleFileHashInfo>::iterator it( _incoming_file_hashes.find(tunnel.hash) ) ;
|
||||
#ifdef P3TURTLE_DEBUG
|
||||
assert(!tunnel.hash.empty()) ;
|
||||
#endif
|
||||
if(it==_incoming_file_hashes.end())
|
||||
{
|
||||
#ifdef P3TURTLE_DEBUG
|
||||
std::cerr << "No tunnel for incoming data. Maybe the tunnel is being closed." << std::endl ;
|
||||
#endif
|
||||
return ;
|
||||
}
|
||||
|
||||
const TurtleFileHashInfo& hash_info(it->second) ;
|
||||
#ifdef P3TURTLE_DEBUG
|
||||
std::cerr << " This is an endpoint for this file map." << std::endl ;
|
||||
std::cerr << " Forwarding data to the multiplexer." << std::endl ;
|
||||
std::cerr << " using peer_id=" << tunnel.vpid << ", hash=" << tunnel.hash << std::endl ;
|
||||
#endif
|
||||
// also update the hash time stamp to show that it's actually being downloaded.
|
||||
it->second.time_stamp = time(NULL) ;
|
||||
|
||||
// we should check that there is no backward call to the turtle router!
|
||||
// We should check that there is no backward call to the turtle router!
|
||||
//
|
||||
_ft_server->getMultiplexer()->recvFileMap(tunnel.vpid,tunnel.hash,item->chunk_size,item->nb_chunks,item->compressed_map) ;
|
||||
vpid = tunnel.vpid ;
|
||||
hash = tunnel.hash ;
|
||||
}
|
||||
_ft_server->getMultiplexer()->recvChunkMap(vpid,hash,item->compressed_map,item->direction == RsTurtleGenericTunnelItem::DIRECTION_CLIENT) ;
|
||||
}
|
||||
|
||||
// Send a data request into the correct tunnel for the given file hash
|
||||
@ -1032,6 +1056,95 @@ void p3turtle::sendFileData(const std::string& peerId, const std::string& hash,
|
||||
sendItem(item) ;
|
||||
}
|
||||
|
||||
void p3turtle::sendChunkMapRequest(const std::string& peerId,const std::string& hash)
|
||||
{
|
||||
RsStackMutex stack(mTurtleMtx); /********** STACK LOCKED MTX ******/
|
||||
|
||||
// get the proper tunnel for this file hash and peer id.
|
||||
std::map<TurtleVirtualPeerId,TurtleTunnelId>::const_iterator it(_virtual_peers.find(peerId)) ;
|
||||
|
||||
if(it == _virtual_peers.end())
|
||||
{
|
||||
#ifdef P3TURTLE_DEBUG
|
||||
std::cerr << "p3turtle::senddataRequest: cannot find virtual peer " << peerId << " in VP list." << std::endl ;
|
||||
#endif
|
||||
return ;
|
||||
}
|
||||
TurtleTunnelId tunnel_id = it->second ;
|
||||
TurtleTunnel& tunnel(_local_tunnels[tunnel_id]) ;
|
||||
|
||||
#ifdef P3TURTLE_DEBUG
|
||||
assert(hash == tunnel.hash) ;
|
||||
#endif
|
||||
RsTurtleFileMapRequestItem *item = new RsTurtleFileMapRequestItem ;
|
||||
item->tunnel_id = tunnel_id ;
|
||||
|
||||
std::string ownid = mConnMgr->getOwnId() ;
|
||||
|
||||
if(tunnel.local_src == ownid)
|
||||
{
|
||||
item->direction = RsTurtleGenericTunnelItem::DIRECTION_SERVER ;
|
||||
item->PeerId(tunnel.local_dst) ;
|
||||
}
|
||||
else if(tunnel.local_dst == ownid)
|
||||
{
|
||||
item->direction = RsTurtleGenericTunnelItem::DIRECTION_CLIENT ;
|
||||
item->PeerId(tunnel.local_src) ;
|
||||
}
|
||||
else
|
||||
std::cerr << "p3turtle::sendChunkMap: consistency error!" << std::endl ;
|
||||
|
||||
#ifdef P3TURTLE_DEBUG
|
||||
std::cerr << "p3turtle: sending chunk map req to peer " << peerId << ", hash=0x" << hash << ") through tunnel " << (void*)item->tunnel_id << ", next peer=" << item->PeerId() << std::endl ;
|
||||
#endif
|
||||
sendItem(item) ;
|
||||
}
|
||||
|
||||
void p3turtle::sendChunkMap(const std::string& peerId,const std::string& hash,const CompressedChunkMap& cmap)
|
||||
{
|
||||
RsStackMutex stack(mTurtleMtx); /********** STACK LOCKED MTX ******/
|
||||
|
||||
// get the proper tunnel for this file hash and peer id.
|
||||
std::map<TurtleVirtualPeerId,TurtleTunnelId>::const_iterator it(_virtual_peers.find(peerId)) ;
|
||||
|
||||
if(it == _virtual_peers.end())
|
||||
{
|
||||
#ifdef P3TURTLE_DEBUG
|
||||
std::cerr << "p3turtle::senddataRequest: cannot find virtual peer " << peerId << " in VP list." << std::endl ;
|
||||
#endif
|
||||
return ;
|
||||
}
|
||||
TurtleTunnelId tunnel_id = it->second ;
|
||||
TurtleTunnel& tunnel(_local_tunnels[tunnel_id]) ;
|
||||
|
||||
#ifdef P3TURTLE_DEBUG
|
||||
assert(hash == tunnel.hash) ;
|
||||
#endif
|
||||
RsTurtleFileMapItem *item = new RsTurtleFileMapItem ;
|
||||
item->tunnel_id = tunnel_id ;
|
||||
item->compressed_map = cmap ;
|
||||
|
||||
std::string ownid = mConnMgr->getOwnId() ;
|
||||
|
||||
if(tunnel.local_src == ownid)
|
||||
{
|
||||
item->direction = RsTurtleGenericTunnelItem::DIRECTION_SERVER ;
|
||||
item->PeerId(tunnel.local_dst) ;
|
||||
}
|
||||
else if(tunnel.local_dst == ownid)
|
||||
{
|
||||
item->direction = RsTurtleGenericTunnelItem::DIRECTION_CLIENT ;
|
||||
item->PeerId(tunnel.local_src) ;
|
||||
}
|
||||
else
|
||||
std::cerr << "p3turtle::sendChunkMap: consistency error!" << std::endl ;
|
||||
|
||||
#ifdef P3TURTLE_DEBUG
|
||||
std::cerr << "p3turtle: sending chunk map to peer " << peerId << ", hash=0x" << hash << ") through tunnel " << (void*)item->tunnel_id << ", next peer=" << item->PeerId() << std::endl ;
|
||||
#endif
|
||||
sendItem(item) ;
|
||||
}
|
||||
|
||||
// This function is actually not needed: Search request to the turtle router are:
|
||||
// - distant search requests, handled by the router
|
||||
// - search requests over files being downloaded, handled by rsFiles !!
|
||||
@ -1573,7 +1686,7 @@ static std::string printNumber(uint64_t num,bool hex=false)
|
||||
if(hex)
|
||||
{
|
||||
char tmp[100] ;
|
||||
sprintf(tmp,"0x%08x%08x", uint32_t(num >> 32),uint32_t(num & ( (1<<32)-1 ))) ;
|
||||
sprintf(tmp,"%08x%08x", uint32_t(num >> 32),uint32_t(num & ( (1<<32)-1 ))) ;
|
||||
return std::string(tmp) ;
|
||||
}
|
||||
else
|
||||
|
@ -280,6 +280,13 @@ class p3turtle: public p3Service, public pqiMonitor, public RsTurtle,/* public f
|
||||
|
||||
/// Send file data into the correct tunnel for the given file hash
|
||||
void sendFileData(const std::string& peerId, const std::string& hash, uint64_t size, uint64_t baseoffset, uint32_t chunksize, void *data) ;
|
||||
|
||||
/// Send a request for the chunk map of this file to the given peer
|
||||
void sendChunkMapRequest(const std::string& peerId, const std::string& hash) ;
|
||||
|
||||
/// Send a chunk map of this file to the given peer
|
||||
void sendChunkMap(const std::string& peerId, const std::string& hash,const CompressedChunkMap& cmap) ;
|
||||
|
||||
private:
|
||||
//--------------------------- Admin/Helper functions -------------------------//
|
||||
|
||||
@ -321,6 +328,7 @@ class p3turtle: public p3Service, public pqiMonitor, public RsTurtle,/* public f
|
||||
void handleTunnelResult(RsTurtleTunnelOkItem *item);
|
||||
void handleRecvFileRequest(RsTurtleFileRequestItem *item);
|
||||
void handleRecvFileData(RsTurtleFileDataItem *item);
|
||||
void handleRecvFileMapRequest(RsTurtleFileMapRequestItem*);
|
||||
void handleRecvFileMap(RsTurtleFileMapItem*);
|
||||
|
||||
//------ Functions connecting the turtle router to other components.----------//
|
||||
|
@ -114,17 +114,27 @@ uint32_t RsTurtleFileDataItem::serial_size()
|
||||
return s ;
|
||||
}
|
||||
|
||||
uint32_t RsTurtleFileMapRequestItem::serial_size()
|
||||
{
|
||||
uint32_t s = 0 ;
|
||||
|
||||
s += 8 ; // header
|
||||
s += 4 ; // tunnel id
|
||||
s += 4 ; // direction
|
||||
|
||||
return s ;
|
||||
}
|
||||
|
||||
uint32_t RsTurtleFileMapItem::serial_size()
|
||||
{
|
||||
uint32_t s = 0 ;
|
||||
|
||||
s += 8 ; // header
|
||||
s += 4 ; // tunnel id
|
||||
s += 4 ; // chunk_size
|
||||
s += 4 ; // nb_chunks
|
||||
s += 4 ; // direction
|
||||
s += 4 ; // compressed_map.size()
|
||||
|
||||
s += 4 * compressed_map.size() ;
|
||||
s += 4 * compressed_map._map.size() ;
|
||||
|
||||
return s ;
|
||||
}
|
||||
@ -162,6 +172,7 @@ RsItem *RsTurtleSerialiser::deserialise(void *data, uint32_t *size)
|
||||
case RS_TURTLE_SUBTYPE_TUNNEL_OK : return new RsTurtleTunnelOkItem(data,*size) ;
|
||||
case RS_TURTLE_SUBTYPE_FILE_REQUEST : return new RsTurtleFileRequestItem(data,*size) ;
|
||||
case RS_TURTLE_SUBTYPE_FILE_DATA : return new RsTurtleFileDataItem(data,*size) ;
|
||||
case RS_TURTLE_SUBTYPE_FILE_MAP_REQUEST : return new RsTurtleFileMapRequestItem(data,*size) ;
|
||||
case RS_TURTLE_SUBTYPE_FILE_MAP : return new RsTurtleFileMapItem(data,*size) ;
|
||||
|
||||
default:
|
||||
@ -179,6 +190,39 @@ RsItem *RsTurtleSerialiser::deserialise(void *data, uint32_t *size)
|
||||
|
||||
}
|
||||
|
||||
bool RsTurtleFileMapRequestItem::serialize(void *data,uint32_t& pktsize)
|
||||
{
|
||||
uint32_t tlvsize = serial_size();
|
||||
uint32_t offset = 0;
|
||||
|
||||
if (pktsize < tlvsize)
|
||||
return false; /* not enough space */
|
||||
|
||||
pktsize = tlvsize;
|
||||
|
||||
bool ok = true;
|
||||
|
||||
ok &= setRsItemHeader(data,tlvsize,PacketId(), tlvsize);
|
||||
|
||||
/* skip the header */
|
||||
offset += 8;
|
||||
|
||||
/* add mandatory parts first */
|
||||
|
||||
ok &= setRawUInt32(data, tlvsize, &offset, tunnel_id);
|
||||
ok &= setRawUInt32(data, tlvsize, &offset, direction);
|
||||
|
||||
if (offset != tlvsize)
|
||||
{
|
||||
ok = false;
|
||||
#ifdef RSSERIAL_DEBUG
|
||||
std::cerr << "RsFileConfigSerialiser::serialiseTransfer() Size Error! " << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool RsTurtleFileMapItem::serialize(void *data,uint32_t& pktsize)
|
||||
{
|
||||
uint32_t tlvsize = serial_size();
|
||||
@ -199,12 +243,11 @@ bool RsTurtleFileMapItem::serialize(void *data,uint32_t& pktsize)
|
||||
/* add mandatory parts first */
|
||||
|
||||
ok &= setRawUInt32(data, tlvsize, &offset, tunnel_id);
|
||||
ok &= setRawUInt32(data, tlvsize, &offset, chunk_size);
|
||||
ok &= setRawUInt32(data, tlvsize, &offset, nb_chunks);
|
||||
ok &= setRawUInt32(data, tlvsize, &offset, compressed_map.size());
|
||||
ok &= setRawUInt32(data, tlvsize, &offset, direction);
|
||||
ok &= setRawUInt32(data, tlvsize, &offset, compressed_map._map.size());
|
||||
|
||||
for(uint32_t i=0;i<compressed_map.size() && ok;++i)
|
||||
ok &= setRawUInt32(data, tlvsize, &offset, compressed_map[i]);
|
||||
for(uint32_t i=0;i<compressed_map._map.size() && ok;++i)
|
||||
ok &= setRawUInt32(data, tlvsize, &offset, compressed_map._map[i]);
|
||||
|
||||
if (offset != tlvsize)
|
||||
{
|
||||
@ -409,24 +452,54 @@ RsTurtleFileMapItem::RsTurtleFileMapItem(void *data,uint32_t pktsize)
|
||||
: RsTurtleGenericTunnelItem(RS_TURTLE_SUBTYPE_FILE_MAP)
|
||||
{
|
||||
#ifdef P3TURTLE_DEBUG
|
||||
std::cerr << " type = search result" << std::endl ;
|
||||
std::cerr << " type = file map item" << std::endl ;
|
||||
#endif
|
||||
uint32_t offset = 8; // skip the header
|
||||
uint32_t rssize = getRsItemSize(data);
|
||||
|
||||
/* add mandatory parts first */
|
||||
|
||||
bool ok = true ;
|
||||
uint32_t s ;
|
||||
uint32_t s,d ;
|
||||
ok &= getRawUInt32(data, pktsize, &offset, &tunnel_id);
|
||||
ok &= getRawUInt32(data, pktsize, &offset, &chunk_size);
|
||||
ok &= getRawUInt32(data, pktsize, &offset, &nb_chunks) ;
|
||||
ok &= getRawUInt32(data, pktsize, &offset, &d);
|
||||
direction = d ;
|
||||
ok &= getRawUInt32(data, pktsize, &offset, &s) ;
|
||||
|
||||
compressed_map.resize(s) ;
|
||||
compressed_map._map.resize(s) ;
|
||||
|
||||
for(uint32_t i=0;i<s && ok;++i)
|
||||
ok &= getRawUInt32(data, pktsize, &offset, &(compressed_map[i])) ;
|
||||
ok &= getRawUInt32(data, pktsize, &offset, &(compressed_map._map[i])) ;
|
||||
|
||||
#ifdef WINDOWS_SYS // No Exceptions in Windows compile. (drbobs).
|
||||
#else
|
||||
if (offset != pktsize)
|
||||
throw std::runtime_error("Size error while deserializing.") ;
|
||||
if (!ok)
|
||||
throw std::runtime_error("Unknown error while deserializing.") ;
|
||||
#endif
|
||||
}
|
||||
|
||||
RsTurtleFileMapRequestItem::RsTurtleFileMapRequestItem(void *data,uint32_t pktsize)
|
||||
: RsTurtleGenericTunnelItem(RS_TURTLE_SUBTYPE_FILE_MAP_REQUEST)
|
||||
{
|
||||
#ifdef P3TURTLE_DEBUG
|
||||
std::cerr << " type = file map request item" << std::endl ;
|
||||
#endif
|
||||
uint32_t offset = 8; // skip the header
|
||||
|
||||
/* add mandatory parts first */
|
||||
|
||||
bool ok = true ;
|
||||
ok &= getRawUInt32(data, pktsize, &offset, &tunnel_id);
|
||||
ok &= getRawUInt32(data, pktsize, &offset, &direction);
|
||||
|
||||
#ifdef WINDOWS_SYS // No Exceptions in Windows compile. (drbobs).
|
||||
#else
|
||||
if (offset != pktsize)
|
||||
throw std::runtime_error("Size error while deserializing.") ;
|
||||
if (!ok)
|
||||
throw std::runtime_error("Unknown error while deserializing.") ;
|
||||
#endif
|
||||
}
|
||||
|
||||
RsTurtleSearchResultItem::RsTurtleSearchResultItem(void *data,uint32_t pktsize)
|
||||
@ -826,12 +899,21 @@ std::ostream& RsTurtleFileMapItem::print(std::ostream& o, uint16_t)
|
||||
o << "File map item:" << std::endl ;
|
||||
|
||||
o << " tunnel id : " << (void*)tunnel_id << std::endl ;
|
||||
o << " chunk size: " << chunk_size << std::endl ;
|
||||
o << " nb chunks : " << nb_chunks << std::endl ;
|
||||
o << " direction : " << direction << std::endl ;
|
||||
o << " map : " ;
|
||||
|
||||
for(uint32_t i=0;i<compressed_map.size();++i)
|
||||
o << (void*)compressed_map[i] << std::endl ;
|
||||
for(uint32_t i=0;i<compressed_map._map.size();++i)
|
||||
o << (void*)compressed_map._map[i] << std::endl ;
|
||||
|
||||
return o ;
|
||||
}
|
||||
|
||||
std::ostream& RsTurtleFileMapRequestItem::print(std::ostream& o, uint16_t)
|
||||
{
|
||||
o << "File map request item:" << std::endl ;
|
||||
|
||||
o << " tunnel id : " << (void*)tunnel_id << std::endl ;
|
||||
o << " direction : " << direction << std::endl ;
|
||||
|
||||
return o ;
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "serialiser/rsbaseserial.h"
|
||||
#include "rsiface/rsturtle.h"
|
||||
#include "rsiface/rsexpr.h"
|
||||
#include "rsiface/rstypes.h"
|
||||
#include "serialiser/rsserviceids.h"
|
||||
#include "turtle/turtletypes.h"
|
||||
|
||||
@ -18,6 +19,7 @@ const uint8_t RS_TURTLE_SUBTYPE_FILE_REQUEST = 0x07 ;
|
||||
const uint8_t RS_TURTLE_SUBTYPE_FILE_DATA = 0x08 ;
|
||||
const uint8_t RS_TURTLE_SUBTYPE_REGEXP_SEARCH_REQUEST = 0x09 ;
|
||||
const uint8_t RS_TURTLE_SUBTYPE_FILE_MAP = 0x10 ;
|
||||
const uint8_t RS_TURTLE_SUBTYPE_FILE_MAP_REQUEST = 0x11 ;
|
||||
|
||||
/***********************************************************************************/
|
||||
/* Basic Turtle Item Class */
|
||||
@ -153,7 +155,9 @@ class RsTurtleGenericTunnelItem: public RsTurtleItem
|
||||
public:
|
||||
RsTurtleGenericTunnelItem(uint8_t sub_packet_id) : RsTurtleItem(sub_packet_id) {}
|
||||
|
||||
typedef enum { DIRECTION_CLIENT, DIRECTION_SERVER } Direction ;
|
||||
typedef uint32_t Direction ;
|
||||
static const Direction DIRECTION_CLIENT = 0x001 ;
|
||||
static const Direction DIRECTION_SERVER = 0x002 ;
|
||||
|
||||
/// Does this packet stamps tunnels when it passes through ?
|
||||
/// This is used for keeping trace weither tunnels are active or not.
|
||||
@ -218,6 +222,26 @@ class RsTurtleFileDataItem: public RsTurtleGenericTunnelItem
|
||||
virtual uint32_t serial_size() ;
|
||||
};
|
||||
|
||||
class RsTurtleFileMapRequestItem: public RsTurtleGenericTunnelItem
|
||||
{
|
||||
public:
|
||||
RsTurtleFileMapRequestItem() : RsTurtleGenericTunnelItem(RS_TURTLE_SUBTYPE_FILE_MAP_REQUEST) {}
|
||||
RsTurtleFileMapRequestItem(void *data,uint32_t size) ; // deserialization
|
||||
|
||||
virtual bool shouldStampTunnel() const { return false ; }
|
||||
virtual TurtleTunnelId tunnelId() const { return tunnel_id ; }
|
||||
virtual Direction travelingDirection() const { return direction ; }
|
||||
|
||||
Direction direction ; // travel direction for this packet (server/client)
|
||||
uint32_t tunnel_id ; // id of the tunnel to travel through. Also used for identifying the file source
|
||||
// this info from the file size, but this allows a security check.
|
||||
|
||||
virtual std::ostream& print(std::ostream& o, uint16_t) ;
|
||||
|
||||
virtual bool serialize(void *data,uint32_t& size) ;
|
||||
virtual uint32_t serial_size() ;
|
||||
};
|
||||
|
||||
class RsTurtleFileMapItem: public RsTurtleGenericTunnelItem
|
||||
{
|
||||
public:
|
||||
@ -230,11 +254,9 @@ class RsTurtleFileMapItem: public RsTurtleGenericTunnelItem
|
||||
|
||||
Direction direction ; // travel direction for this packet (server/client)
|
||||
uint32_t tunnel_id ; // id of the tunnel to travel through. Also used for identifying the file source
|
||||
uint32_t chunk_size ; // fixed size of chunks, as seen from the source, for the given map.
|
||||
uint32_t nb_chunks ; // number of chunks in the file. The last two infos are redundant, as we can recompute
|
||||
// this info from the file size, but this allows a security check.
|
||||
|
||||
std::vector<uint32_t> compressed_map ; // Map info for the file in compressed format. Each *bit* in the array uint's says "I have" or "I don't have"
|
||||
CompressedChunkMap compressed_map ; // Map info for the file in compressed format. Each *bit* in the array uint's says "I have" or "I don't have"
|
||||
// by default, we suppose the peer has all the chunks. This info will thus be and-ed
|
||||
// with the default file map for this source.
|
||||
|
||||
|
@ -19,6 +19,7 @@
|
||||
* Boston, MA 02110-1301, USA.
|
||||
****************************************************************/
|
||||
|
||||
#include <rsiface/rstypes.h>
|
||||
#include <QModelIndex>
|
||||
#include <QPainter>
|
||||
#include <QStyleOptionProgressBarV2>
|
||||
@ -27,6 +28,8 @@
|
||||
|
||||
#include "DLListDelegate.h"
|
||||
|
||||
Q_DECLARE_METATYPE(FileProgressInfo)
|
||||
|
||||
DLListDelegate::DLListDelegate(QObject *parent) : QAbstractItemDelegate(parent)
|
||||
{
|
||||
;
|
||||
@ -144,14 +147,14 @@ void DLListDelegate::paint(QPainter * painter, const QStyleOptionViewItem & opti
|
||||
painter->drawText(option.rect, Qt::AlignRight, temp);
|
||||
break;
|
||||
case PROGRESS:
|
||||
{
|
||||
progress = index.data().toDouble();
|
||||
// create a xProgressBar
|
||||
xProgressBar progressBar(option.rect, painter); // the 3rd param is the color schema (0 is the default value)
|
||||
progressBar.setDisplayText(false); // should display % text?
|
||||
progressBar.setValue(progress); // set the progress value
|
||||
progressBar.setVerticalSpan(1);
|
||||
progressBar.paint(); // paint the progress bar
|
||||
{
|
||||
// create a xProgressBar
|
||||
FileProgressInfo pinfo = index.data().value<FileProgressInfo>() ;
|
||||
xProgressBar progressBar(pinfo.cmap,option.rect, painter); // the 3rd param is the color schema (0 is the default value)
|
||||
progressBar.setDisplayText(false); // should display % text?
|
||||
progressBar.setValue(pinfo.progress); // set the progress value
|
||||
progressBar.setVerticalSpan(1);
|
||||
progressBar.paint(); // paint the progress bar
|
||||
}
|
||||
painter->drawText(option.rect, Qt::AlignCenter, newopt.text);
|
||||
break;
|
||||
|
@ -62,23 +62,16 @@ void FileTransferInfoWidget::updateDisplay()
|
||||
{
|
||||
std::cout << "In TaskGraphPainterWidget::updateDisplay()" << std::endl ;
|
||||
|
||||
bool ok=true ;
|
||||
FileInfo nfo ;
|
||||
if(!rsFiles->FileDetails(_file_hash, RS_FILE_HINTS_DOWNLOAD, nfo))
|
||||
return ;
|
||||
ok = false ;
|
||||
FileChunksInfo info ;
|
||||
if(!rsFiles->FileChunksDetails(_file_hash, info))
|
||||
return ;
|
||||
if(!rsFiles->FileDownloadChunksDetails(_file_hash, info))
|
||||
ok = false ;
|
||||
|
||||
std::cout << "got details for file " << nfo.fname << std::endl ;
|
||||
|
||||
uint64_t fileSize = info.file_size;
|
||||
uint32_t blockSize = info.chunk_size ;
|
||||
int blocks = info.chunks.size() ;
|
||||
|
||||
int columns = maxWidth/chunk_square_size;
|
||||
y = blocks/columns*chunk_square_size;
|
||||
x = blocks%columns*chunk_square_size;
|
||||
maxHeight = y+150+info.active_chunks.size()*(block_sep+text_height); // warning: this should be computed from the different size parameter and the number of objects drawn, otherwise the last objects to be displayed will be truncated.
|
||||
pixmap = QPixmap(size());
|
||||
pixmap.fill(this, 0, 0);
|
||||
pixmap = QPixmap(maxWidth, maxHeight);
|
||||
@ -88,7 +81,16 @@ void FileTransferInfoWidget::updateDisplay()
|
||||
QPainter painter(&pixmap);
|
||||
painter.initFrom(this);
|
||||
|
||||
draw(info,&painter) ;
|
||||
if(ok)
|
||||
{
|
||||
int blocks = info.chunks.size() ;
|
||||
int columns = maxWidth/chunk_square_size;
|
||||
y = blocks/columns*chunk_square_size;
|
||||
x = blocks%columns*chunk_square_size;
|
||||
maxHeight = y+150+info.active_chunks.size()*(block_sep+text_height); // warning: this should be computed from the different size parameter and the number of objects drawn, otherwise the last objects to be displayed will be truncated.
|
||||
|
||||
draw(info,&painter) ;
|
||||
}
|
||||
|
||||
pixmap2 = pixmap;
|
||||
}
|
||||
@ -194,8 +196,8 @@ void FileTransferInfoWidget::draw(const FileChunksInfo& info,QPainter *painter)
|
||||
int nb_src = 0 ;
|
||||
int chunk_num = (int)floor(i/float(availability_map_size_X)*(nb_chunks-1)) ;
|
||||
|
||||
for(uint j=0;j<info.compressed_peer_availability_maps.size();++j)
|
||||
nb_src += (bool)(COMPRESSED_MAP_READ(info.compressed_peer_availability_maps[j].second, chunk_num)) ;
|
||||
for(std::map<std::string,CompressedChunkMap>::const_iterator it(info.compressed_peer_availability_maps.begin());it!=info.compressed_peer_availability_maps.end();++it)
|
||||
nb_src += it->second[chunk_num] ;
|
||||
|
||||
painter->setPen(QColor::fromHsv(200,50*nb_src,200)) ; // the more sources, the more saturated
|
||||
painter->drawLine(i,y,i,y+availability_map_size_Y) ;
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include "DLListDelegate.h"
|
||||
#include "ULListDelegate.h"
|
||||
#include "FileTransferInfoWidget.h"
|
||||
#include "xprogressbar.h"
|
||||
|
||||
#include <QContextMenuEvent>
|
||||
#include <QMenu>
|
||||
@ -69,6 +70,34 @@
|
||||
#define IMAGE_PRIORITYHIGH ":/images/priorityhigh.png"
|
||||
#define IMAGE_PRIORITYAUTO ":/images/priorityauto.png"
|
||||
|
||||
//static const CompressedChunkMap *getMap_tmp()
|
||||
//{
|
||||
// static CompressedChunkMap *cmap = NULL ;
|
||||
//
|
||||
// if(cmap == NULL)
|
||||
// {
|
||||
// cmap = new CompressedChunkMap ; // to be passed as a parameter
|
||||
// // Initialize the chunkmap with a dummy value, for testing. To be removed...
|
||||
// cmap->_nb_chunks = 700 ;
|
||||
// cmap->_map.resize(cmap->_nb_chunks/32+1,0) ;
|
||||
// cmap->_progress = 0.34 ;
|
||||
// for(uint i=0;i<10;++i)
|
||||
// {
|
||||
// uint32_t start = rand()%cmap->_nb_chunks;
|
||||
// uint32_t j = std::min((int)cmap->_nb_chunks,(int)start+10+(rand()%5)) ;
|
||||
//
|
||||
// for(uint32_t k=start;k<j;++k)
|
||||
// COMPRESSED_MAP_WRITE(cmap->_map,k,1) ;
|
||||
// }
|
||||
//
|
||||
// std::cerr << "Built cmap = " << (void*)cmap << std::endl ;
|
||||
// }
|
||||
// return cmap ;
|
||||
//}
|
||||
|
||||
|
||||
Q_DECLARE_METATYPE(FileProgressInfo)
|
||||
|
||||
|
||||
/** Constructor */
|
||||
TransfersDialog::TransfersDialog(QWidget *parent)
|
||||
@ -378,11 +407,11 @@ void TransfersDialog::playSelectedTransfer()
|
||||
|
||||
void TransfersDialog::updateProgress(int value)
|
||||
{
|
||||
for(int i = 0; i <= DLListModel->rowCount(); i++) {
|
||||
if(selection->isRowSelected(i, QModelIndex())) {
|
||||
editItem(i, PROGRESS, QVariant((double)value));
|
||||
}
|
||||
}
|
||||
// for(int i = 0; i <= DLListModel->rowCount(); i++) {
|
||||
// if(selection->isRowSelected(i, QModelIndex())) {
|
||||
// editItem(i, PROGRESS, QVariant((double)value));
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
TransfersDialog::~TransfersDialog()
|
||||
@ -391,8 +420,7 @@ TransfersDialog::~TransfersDialog()
|
||||
}
|
||||
|
||||
|
||||
|
||||
int TransfersDialog::addItem(QString symbol, QString name, QString coreID, qlonglong fileSize, double progress, double dlspeed,
|
||||
int TransfersDialog::addItem(QString symbol, QString name, QString coreID, qlonglong fileSize, const FileProgressInfo& pinfo, double dlspeed,
|
||||
QString sources, QString status, QString priority, qlonglong completed, qlonglong remaining)
|
||||
{
|
||||
int row;
|
||||
@ -408,7 +436,7 @@ int TransfersDialog::addItem(QString symbol, QString name, QString coreID, qlong
|
||||
DLListModel->setData(DLListModel->index(row, SIZE), QVariant((qlonglong)fileSize));
|
||||
DLListModel->setData(DLListModel->index(row, COMPLETED), QVariant((qlonglong)completed));
|
||||
DLListModel->setData(DLListModel->index(row, DLSPEED), QVariant((double)dlspeed));
|
||||
DLListModel->setData(DLListModel->index(row, PROGRESS), QVariant((double)progress));
|
||||
DLListModel->setData(DLListModel->index(row, PROGRESS), QVariant::fromValue(pinfo));
|
||||
DLListModel->setData(DLListModel->index(row, SOURCES), QVariant((QString)sources));
|
||||
DLListModel->setData(DLListModel->index(row, STATUS), QVariant((QString)status));
|
||||
DLListModel->setData(DLListModel->index(row, PRIORITY), QVariant((QString)priority));
|
||||
@ -469,7 +497,7 @@ int TransfersDialog::addItem(QString symbol, QString name, QString coreID, qlong
|
||||
return row;
|
||||
}
|
||||
|
||||
bool TransfersDialog::addPeerToItem(int row, QString symbol, QString name, QString coreID, qlonglong fileSize, double progress, double dlspeed, QString sources, QString status, qlonglong completed, qlonglong remaining)
|
||||
bool TransfersDialog::addPeerToItem(int row, QString symbol, QString name, QString coreID, qlonglong fileSize, const FileProgressInfo& pinfo, double dlspeed, QString sources, QString status, qlonglong completed, qlonglong remaining)
|
||||
{
|
||||
QStandardItem *dlItem = DLListModel->item(row);
|
||||
if (!dlItem) return false;
|
||||
@ -484,7 +512,7 @@ bool TransfersDialog::addPeerToItem(int row, QString symbol, QString name, QStri
|
||||
QStandardItem *i2 = new QStandardItem(); i2->setData(QVariant((qlonglong)fileSize), Qt::DisplayRole);
|
||||
QStandardItem *i3 = new QStandardItem(); i3->setData(QVariant((qlonglong)completed), Qt::DisplayRole);
|
||||
QStandardItem *i4 = new QStandardItem(); i4->setData(QVariant((double)dlspeed), Qt::DisplayRole);
|
||||
QStandardItem *i5 = new QStandardItem(); i5->setData(QVariant((double)progress), Qt::DisplayRole);
|
||||
QStandardItem *i5 = new QStandardItem(); i5->setData(QVariant::fromValue(pinfo), Qt::DisplayRole);
|
||||
QStandardItem *i6 = new QStandardItem(); i6->setData(QVariant((QString)sources), Qt::DisplayRole);
|
||||
QStandardItem *i7 = new QStandardItem(); i7->setData(QVariant((QString)status), Qt::DisplayRole);
|
||||
QStandardItem *i8 = new QStandardItem(); i8->setData(QVariant((QString)tr("")), Qt::DisplayRole); // blank field for priority
|
||||
@ -522,7 +550,7 @@ bool TransfersDialog::addPeerToItem(int row, QString symbol, QString name, QStri
|
||||
}
|
||||
|
||||
|
||||
int TransfersDialog::addUploadItem(QString symbol, QString name, QString coreID, qlonglong fileSize, double progress, double dlspeed, QString sources, QString status, qlonglong completed, qlonglong remaining)
|
||||
int TransfersDialog::addUploadItem(QString symbol, QString name, QString coreID, qlonglong fileSize, const FileProgressInfo& pinfo, double dlspeed, QString source, QString status, qlonglong completed, qlonglong remaining)
|
||||
{
|
||||
int row;
|
||||
QString sl;
|
||||
@ -535,9 +563,9 @@ int TransfersDialog::addUploadItem(QString symbol, QString name, QString coreID,
|
||||
ULListModel->setData(ULListModel->index(row, USIZE), QVariant((qlonglong)fileSize));
|
||||
ULListModel->setData(ULListModel->index(row, UTRANSFERRED), QVariant((qlonglong)completed));
|
||||
ULListModel->setData(ULListModel->index(row, ULSPEED), QVariant((double)dlspeed));
|
||||
ULListModel->setData(ULListModel->index(row, UPROGRESS), QVariant((double)progress));
|
||||
ULListModel->setData(ULListModel->index(row, UPROGRESS), QVariant::fromValue(pinfo));
|
||||
ULListModel->setData(ULListModel->index(row, USTATUS), QVariant((QString)status));
|
||||
ULListModel->setData(ULListModel->index(row, USERNAME), QVariant((QString)sources));
|
||||
ULListModel->setData(ULListModel->index(row, USERNAME), QVariant((QString)source));
|
||||
|
||||
return row;
|
||||
}
|
||||
@ -568,9 +596,9 @@ void TransfersDialog::editItem(int row, int column, QVariant data)
|
||||
case SIZE:
|
||||
DLListModel->setData(DLListModel->index(row, SIZE), data);
|
||||
break;
|
||||
case PROGRESS:
|
||||
DLListModel->setData(DLListModel->index(row, PROGRESS), data);
|
||||
break;
|
||||
// case PROGRESS:
|
||||
// DLListModel->setData(DLListModel->index(row, PROGRESS), data);
|
||||
// break;
|
||||
case DLSPEED:
|
||||
DLListModel->setData(DLListModel->index(row, DLSPEED), data);
|
||||
break;
|
||||
@ -670,7 +698,8 @@ void TransfersDialog::insertTransfers()
|
||||
uint32_t ulCount = 0;
|
||||
|
||||
std::list<std::string>::iterator it;
|
||||
for (it = downHashes.begin(); it != downHashes.end(); it++) {
|
||||
for (it = downHashes.begin(); it != downHashes.end(); it++)
|
||||
{
|
||||
FileInfo info;
|
||||
if (!rsFiles->FileDetails(*it, RS_FILE_HINTS_DOWNLOAD, info)) continue;
|
||||
//if file transfer is a cache file index file, don't show it
|
||||
@ -713,7 +742,21 @@ void TransfersDialog::insertTransfers()
|
||||
completed = info.transfered;
|
||||
remaining = (info.size - info.transfered) / (info.tfRate * 1024.0);
|
||||
|
||||
int addedRow = addItem(symbol, name, coreId, fileSize, progress, dlspeed, sources, status, priority, completed, remaining);
|
||||
FileChunksInfo fcinfo ;
|
||||
if(!rsFiles->FileDownloadChunksDetails(*it,fcinfo))
|
||||
continue ;
|
||||
|
||||
FileProgressInfo pinfo ;
|
||||
pinfo.cmap = fcinfo.chunks ;
|
||||
pinfo.progress = completed*100.0/info.size ;
|
||||
|
||||
// std::cerr << "Converting fcinfo to compressed chunk map. Chunks=" << fcinfo.chunks.size() << std::endl ;
|
||||
// std::cerr << "map data = " ;
|
||||
// for(uint k=0;k<cmap._map.size();++k)
|
||||
// std::cout << (void*)cmap._map[k] ;
|
||||
// std::cout << std::endl ;
|
||||
|
||||
int addedRow = addItem(symbol, name, coreId, fileSize, pinfo, dlspeed, sources, status, priority, completed, remaining);
|
||||
|
||||
/* if found in selectedIds -> select again */
|
||||
if (selectedIds.end() != std::find(selectedIds.begin(), selectedIds.end(), info.hash)) {
|
||||
@ -777,7 +820,11 @@ void TransfersDialog::insertTransfers()
|
||||
completed = info.transfered;
|
||||
remaining = (info.size - info.transfered) / (pit->tfRate * 1024.0);
|
||||
|
||||
if (!addPeerToItem(addedRow, symbol, name, coreId, fileSize, progress, dlspeed, sources, status, completed, remaining))
|
||||
FileProgressInfo pinfo ;
|
||||
pinfo.cmap = fcinfo.compressed_peer_availability_maps[pit->peerId] ;
|
||||
pinfo.progress = 0.0 ; // we don't display completion for sources.
|
||||
|
||||
if (!addPeerToItem(addedRow, symbol, name, coreId, fileSize, pinfo, dlspeed, sources, status, completed, remaining))
|
||||
continue;
|
||||
|
||||
/* if peers found in selectedIds, select again */
|
||||
@ -826,7 +873,10 @@ void TransfersDialog::insertTransfers()
|
||||
break;
|
||||
}
|
||||
|
||||
addItem("", name, coreId, fileSize, progress, dlspeed, sources, status, priority, completed, remaining);
|
||||
FileProgressInfo pinfo ;
|
||||
pinfo.progress = 0.0 ;
|
||||
|
||||
addItem("", name, coreId, fileSize, pinfo, dlspeed, sources, status, priority, completed, remaining);
|
||||
|
||||
/* if found in selectedIds -> select again */
|
||||
if (selectedIds.end() != std::find(selectedIds.begin(), selectedIds.end(), dit->hash)) {
|
||||
@ -890,14 +940,36 @@ void TransfersDialog::insertTransfers()
|
||||
// status = "Complete";
|
||||
// }
|
||||
|
||||
FileProgressInfo pinfo ;
|
||||
|
||||
if(!rsFiles->FileUploadChunksDetails(*it,pit->peerId,pinfo.cmap) )
|
||||
continue ;
|
||||
|
||||
dlspeed = pit->tfRate * 1024.0;
|
||||
fileSize = info.size;
|
||||
completed = info.transfered;
|
||||
progress = info.transfered * 100.0 / info.size;
|
||||
remaining = (info.size - info.transfered) / (info.tfRate * 1024.0);
|
||||
|
||||
addUploadItem(symbol, name, coreId, fileSize, progress,
|
||||
dlspeed, sources, status, completed, remaining);
|
||||
// Estimate the completion. We need something more accurate, meaning that we need to
|
||||
// transmit the completion info.
|
||||
//
|
||||
uint32_t chunk_size = 1024*1024 ;
|
||||
uint32_t nb_chunks = (uint32_t)(info.size / (uint64_t)(chunk_size) ) ;
|
||||
if((info.size % (uint64_t)chunk_size) != 0)
|
||||
++nb_chunks ;
|
||||
|
||||
uint32_t filled_chunks = pinfo.cmap.filledChunks(nb_chunks) ;
|
||||
|
||||
if(filled_chunks > 1)
|
||||
{
|
||||
pinfo.progress = filled_chunks*100.0/nb_chunks ;
|
||||
completed = std::min(info.size,((uint64_t)filled_chunks)*chunk_size) ;
|
||||
}
|
||||
else
|
||||
pinfo.progress = progress ;
|
||||
|
||||
addUploadItem(symbol, name, coreId, fileSize, pinfo, dlspeed, sources, status, completed, remaining);
|
||||
ulCount++;
|
||||
}
|
||||
|
||||
@ -935,8 +1007,11 @@ void TransfersDialog::insertTransfers()
|
||||
progress = info.transfered * 100.0 / info.size;
|
||||
remaining = (info.size - info.transfered) / (info.tfRate * 1024.0);
|
||||
|
||||
addUploadItem(symbol, name, coreId, fileSize, progress,
|
||||
dlspeed, sources, status, completed, remaining);
|
||||
FileProgressInfo pinfo ;
|
||||
pinfo.progress = progress ;
|
||||
pinfo.cmap = CompressedChunkMap() ;
|
||||
|
||||
addUploadItem(symbol, name, coreId, fileSize, pinfo, dlspeed, sources, status, completed, remaining);
|
||||
ulCount++;
|
||||
}
|
||||
}
|
||||
@ -1411,6 +1486,8 @@ void TransfersDialog::showFileDetails()
|
||||
std::string file_hash ;
|
||||
int nb_select = 0 ;
|
||||
|
||||
std::cout << "new selection " << std::endl ;
|
||||
|
||||
for(int i = 0; i <= DLListModel->rowCount(); i++)
|
||||
if(selection->isRowSelected(i, QModelIndex()))
|
||||
{
|
||||
@ -1418,15 +1495,19 @@ void TransfersDialog::showFileDetails()
|
||||
++nb_select ;
|
||||
}
|
||||
if(nb_select != 1)
|
||||
return ;
|
||||
dynamic_cast<FileTransferInfoWidget*>(ui.fileTransferInfoWidget->widget())->setFileHash("") ;
|
||||
else
|
||||
dynamic_cast<FileTransferInfoWidget*>(ui.fileTransferInfoWidget->widget())->setFileHash(file_hash) ;
|
||||
|
||||
dynamic_cast<FileTransferInfoWidget*>(ui.fileTransferInfoWidget->widget())->setFileHash(file_hash) ;
|
||||
std::cout << "calling update " << std::endl ;
|
||||
dynamic_cast<FileTransferInfoWidget*>(ui.fileTransferInfoWidget->widget())->updateDisplay() ;
|
||||
std::cout << "done" << std::endl ;
|
||||
}
|
||||
|
||||
double TransfersDialog::getProgress(int row, QStandardItemModel *model)
|
||||
{
|
||||
return model->data(model->index(row, PROGRESS), Qt::DisplayRole).toDouble();
|
||||
// return model->data(model->index(row, PROGRESS), Qt::DisplayRole).toDouble();
|
||||
return 0.0 ;
|
||||
}
|
||||
|
||||
double TransfersDialog::getSpeed(int row, QStandardItemModel *model)
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include <rsiface/rstypes.h>
|
||||
#include "mainpage.h"
|
||||
#include "RsAutoUpdatePage.h"
|
||||
#include "xprogressbar.h"
|
||||
|
||||
#include "ui_TransfersDialog.h"
|
||||
|
||||
@ -165,11 +166,11 @@ class TransfersDialog : public RsAutoUpdatePage
|
||||
Ui::TransfersDialog ui;
|
||||
|
||||
public slots:
|
||||
int addItem(QString symbol, QString name, QString coreID, qlonglong size, double progress, double dlspeed, QString sources, QString status, QString priority, qlonglong completed, qlonglong remaining);
|
||||
bool addPeerToItem(int row, QString symbol, QString name, QString coreID, qlonglong fileSize, double progress, double dlspeed, QString sources, QString status, qlonglong completed, qlonglong remaining);
|
||||
int addItem(QString symbol, QString name, QString coreID, qlonglong size, const FileProgressInfo& pinfo, double dlspeed, QString sources, QString status, QString priority, qlonglong completed, qlonglong remaining);
|
||||
bool addPeerToItem(int row, QString symbol, QString name, QString coreID, qlonglong fileSize, const FileProgressInfo& pinfo, double dlspeed, QString sources, QString status, qlonglong completed, qlonglong remaining);
|
||||
void delItem(int row);
|
||||
|
||||
int addUploadItem(QString symbol, QString name, QString coreID, qlonglong size, double progress, double dlspeed, QString sources, QString status, qlonglong completed, qlonglong remaining);
|
||||
int addUploadItem(QString symbol, QString name, QString coreID, qlonglong size, const FileProgressInfo& pinfo, double dlspeed, QString sources, QString status, qlonglong completed, qlonglong remaining);
|
||||
void delUploadItem(int row);
|
||||
|
||||
void editItem(int row, int column, QVariant data);
|
||||
|
@ -19,6 +19,7 @@
|
||||
* Boston, MA 02110-1301, USA.
|
||||
****************************************************************/
|
||||
|
||||
#include <rsiface/rstypes.h>
|
||||
#include <QModelIndex>
|
||||
#include <QPainter>
|
||||
#include <QStyleOptionProgressBarV2>
|
||||
@ -28,6 +29,8 @@
|
||||
|
||||
#include "ULListDelegate.h"
|
||||
|
||||
Q_DECLARE_METATYPE(FileProgressInfo)
|
||||
|
||||
ULListDelegate::ULListDelegate(QObject *parent) : QAbstractItemDelegate(parent)
|
||||
{
|
||||
;
|
||||
@ -123,25 +126,22 @@ void ULListDelegate::paint(QPainter * painter, const QStyleOptionViewItem & opti
|
||||
painter->drawText(option.rect, Qt::AlignRight, temp);
|
||||
break;
|
||||
case UPROGRESS:
|
||||
{
|
||||
progress = index.data().toDouble();
|
||||
// create a xProgressBar
|
||||
xProgressBar progressBar(option.rect, painter );// the 3rd param is the color schema (0 is the default value)
|
||||
{
|
||||
FileProgressInfo pinfo = index.data().value<FileProgressInfo>() ;
|
||||
|
||||
QString ext = QFileInfo(QString::fromStdString(index.sibling(index.row(), UNAME).data().toString().toStdString())).suffix();;
|
||||
if (ext == "rsfc" || ext == "rsrl" || ext == "dist" || ext == "rsfb")
|
||||
{
|
||||
progressBar.setColorSchema( 9);
|
||||
}
|
||||
else
|
||||
{
|
||||
progressBar.setColorSchema( 8);
|
||||
}
|
||||
// create a xProgressBar
|
||||
xProgressBar progressBar(pinfo.cmap,option.rect,painter,0);// the 3rd param is the color schema (0 is the default value)
|
||||
|
||||
progressBar.setDisplayText(false); // should display % text?
|
||||
progressBar.setValue(progress); // set the progress value
|
||||
progressBar.setVerticalSpan(1);
|
||||
progressBar.paint(); // paint the progress bar
|
||||
QString ext = QFileInfo(QString::fromStdString(index.sibling(index.row(), UNAME).data().toString().toStdString())).suffix();;
|
||||
if (ext == "rsfc" || ext == "rsrl" || ext == "dist" || ext == "rsfb")
|
||||
progressBar.setColorSchema( 9);
|
||||
else
|
||||
progressBar.setColorSchema( 8);
|
||||
|
||||
progressBar.setDisplayText(true); // should display % text?
|
||||
progressBar.setValue(pinfo.progress); // set the progress value
|
||||
progressBar.setVerticalSpan(1);
|
||||
progressBar.paint(); // paint the progress bar
|
||||
}
|
||||
painter->drawText(option.rect, Qt::AlignCenter, newopt.text);
|
||||
break;
|
||||
|
@ -24,9 +24,12 @@
|
||||
* Boston, MA 02110-1301, USA.
|
||||
****************************************************************/
|
||||
|
||||
#include <math.h>
|
||||
#include <rsiface/rstypes.h>
|
||||
#include "xprogressbar.h"
|
||||
|
||||
xProgressBar::xProgressBar(QRect rect, QPainter *painter, int schemaIndex)
|
||||
xProgressBar::xProgressBar(const CompressedChunkMap& cmap,QRect rect, QPainter *painter, int schemaIndex)
|
||||
: _cmap(cmap)
|
||||
{
|
||||
// assign internal data
|
||||
this->schemaIndex = schemaIndex;
|
||||
@ -39,7 +42,7 @@ xProgressBar::xProgressBar(QRect rect, QPainter *painter, int schemaIndex)
|
||||
vSpan = 0;
|
||||
hSpan = 0;
|
||||
// text color
|
||||
textColor = QColor("white");
|
||||
textColor = QColor("black");
|
||||
}
|
||||
|
||||
void xProgressBar::setColor()
|
||||
@ -187,14 +190,41 @@ void xProgressBar::paint()
|
||||
linearGrad.setColorAt(1.00, gradColor1);
|
||||
painter->setPen(gradBorderColor);
|
||||
|
||||
// calculate progress value
|
||||
int preWidth = static_cast<int>((rect.width() - 1 - hSpan)*(progressValue/100));
|
||||
int progressWidth = rect.width() - preWidth;
|
||||
if (progressWidth == rect.width() - hSpan) return;
|
||||
int width = static_cast<int>(rect.width()-1-2*hSpan) ;
|
||||
|
||||
// paint the progress
|
||||
painter->setBrush(linearGrad);
|
||||
painter->drawRect(rect.x() + hSpan, rect.y() + vSpan, rect.width() - progressWidth - hSpan, rect.height() - 1 - vSpan * 2);
|
||||
|
||||
uint32_t ss = _cmap._map.size()*32 ;
|
||||
|
||||
if(ss > 1) // for small files we use a more progressive display
|
||||
for(int i=0;i<ss;++i)
|
||||
{
|
||||
int j=0 ;
|
||||
while(i+j<ss && _cmap[i+j])
|
||||
++j ;
|
||||
|
||||
if(j>0)
|
||||
{
|
||||
float o = std::min(1.0f,j/(float)ss*width) ;
|
||||
painter->setOpacity(o) ;
|
||||
painter->drawRect(rect.x() + hSpan+(int)rint(i*width/(float)ss), rect.y() + vSpan, (int)ceil(j*width/(float)ss), rect.height() - 1 - vSpan * 2);
|
||||
}
|
||||
|
||||
i += j ;
|
||||
}
|
||||
else
|
||||
{
|
||||
// calculate progress value
|
||||
int preWidth = static_cast<int>((rect.width() - 1 - hSpan)*(progressValue/100));
|
||||
int progressWidth = rect.width() - preWidth;
|
||||
if (progressWidth == rect.width() - hSpan) return;
|
||||
|
||||
// paint the progress
|
||||
painter->setBrush(linearGrad);
|
||||
painter->drawRect(rect.x() + hSpan, rect.y() + vSpan, rect.width() - progressWidth - hSpan, rect.height() - 1 - vSpan * 2);
|
||||
}
|
||||
painter->setOpacity(1.0f) ;
|
||||
|
||||
|
||||
// paint text?
|
||||
if (displayText)
|
||||
|
@ -27,11 +27,21 @@
|
||||
#ifndef XPROGRESSBAR_H
|
||||
#define XPROGRESSBAR_H
|
||||
//
|
||||
#include <stdint.h>
|
||||
#include <QRect>
|
||||
#include <QColor>
|
||||
#include <QPainter>
|
||||
#include <QLinearGradient>
|
||||
#include <QLocale>
|
||||
|
||||
#include <rsiface/rstypes.h>
|
||||
|
||||
class FileProgressInfo
|
||||
{
|
||||
public:
|
||||
CompressedChunkMap cmap ;
|
||||
float progress ;
|
||||
};
|
||||
//
|
||||
class xProgressBar : public QObject
|
||||
{
|
||||
@ -56,8 +66,11 @@ Q_OBJECT
|
||||
QColor gradColor2;
|
||||
// configure the color
|
||||
void setColor();
|
||||
|
||||
const CompressedChunkMap& _cmap ;
|
||||
public:
|
||||
xProgressBar(QRect rect, QPainter *painter, int schemaIndex = 0);
|
||||
xProgressBar(const CompressedChunkMap& cmap,QRect rect, QPainter *painter, int schemaIndex = 0);
|
||||
|
||||
void paint();
|
||||
void setColorSchema(const int value);
|
||||
void setValue(const float value);
|
||||
|
Loading…
Reference in New Issue
Block a user