- 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:
csoler 2010-01-11 16:00:42 +00:00
parent add5d45eeb
commit cfaaec31c7
36 changed files with 1247 additions and 573 deletions

View File

@ -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)) ;
}

View File

@ -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
};

View 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)) ;
}
}
}

View File

@ -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);

View File

@ -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) ******/

View File

@ -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;
}

View File

@ -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;

View File

@ -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

View File

@ -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;
};

View File

@ -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

View File

@ -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

View File

@ -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) ;
}

View File

@ -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:

View File

@ -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: ";

View File

@ -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;
};

View File

@ -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

View File

@ -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:

View File

@ -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

View File

@ -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 */

View File

@ -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();

View File

@ -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

View File

@ -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

View File

@ -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 */

View File

@ -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)
{

View File

@ -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)
};
/**************************************************************************/

View File

@ -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) ;
}
switch(item->PacketSubType())
{
case RS_TURTLE_SUBTYPE_FILE_REQUEST: handleRecvFileRequest(dynamic_cast<RsTurtleFileRequestItem *>(item)) ;
break ;
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) ;
}
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

View File

@ -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.----------//

View File

@ -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 ;
}

View File

@ -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.

View File

@ -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;

View File

@ -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) ;

View File

@ -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)

View File

@ -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);

View File

@ -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)
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(false); // should display % text?
progressBar.setValue(progress); // set the progress value
progressBar.setVerticalSpan(1);
progressBar.paint(); // paint the progress bar
{
FileProgressInfo pinfo = index.data().value<FileProgressInfo>() ;
// create a xProgressBar
xProgressBar progressBar(pinfo.cmap,option.rect,painter,0);// the 3rd param is the color schema (0 is the default value)
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;

View File

@ -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)

View File

@ -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);