added method in ftServer to allow retrieving data from shared/downloaded files (patch from electron, modified)

git-svn-id: http://svn.code.sf.net/p/retroshare/code/trunk@7999 b45a01b8-16f6-495d-af2f-9b41ad6348cc
This commit is contained in:
csoler 2015-03-08 13:46:07 +00:00
parent 400d3179e8
commit a1b36cd530
13 changed files with 140 additions and 18 deletions

View File

@ -402,7 +402,17 @@ void ChunkMap::removeInactiveChunks(std::vector<ftChunk::ChunkId>& to_remove)
++it ; ++it ;
} }
bool ChunkMap::isChunkAvailable(uint64_t offset, uint32_t chunk_size) const bool ChunkMap::isChunkAvailable(uint64_t offset, uint32_t chunk_size) const
{
return hasChunkState(offset, chunk_size, FileChunksInfo::CHUNK_DONE);
}
bool ChunkMap::isChunkOutstanding(uint64_t offset, uint32_t chunk_size) const
{
return hasChunkState(offset, chunk_size, FileChunksInfo::CHUNK_OUTSTANDING);
}
bool ChunkMap::hasChunkState(uint64_t offset, uint32_t chunk_size, FileChunksInfo::ChunkState state) const
{ {
uint32_t chunk_number_start = offset/(uint64_t)_chunk_size ; uint32_t chunk_number_start = offset/(uint64_t)_chunk_size ;
uint32_t chunk_number_end = (offset+(uint64_t)chunk_size)/(uint64_t)_chunk_size ; uint32_t chunk_number_end = (offset+(uint64_t)chunk_size)/(uint64_t)_chunk_size ;
@ -414,16 +424,16 @@ bool ChunkMap::isChunkAvailable(uint64_t offset, uint32_t chunk_size) const
// chunk_size=0, and offset%_chunk_size=0, so the response "true" is still valid. // 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) for(uint32_t i=chunk_number_start;i<chunk_number_end;++i)
if(_map[i] != FileChunksInfo::CHUNK_DONE) if(_map[i] != state)
{ {
#ifdef DEBUG_FTCHUNK #ifdef DEBUG_FTCHUNK
std::cerr << "ChunkMap::isChunkAvailable(): (" << offset << "," << chunk_size << ") is not available" << std::endl; std::cerr << "ChunkMap::hasChunkState(): (" << offset << "," << chunk_size << ") has different state" << std::endl;
#endif #endif
return false ; return false ;
} }
#ifdef DEBUG_FTCHUNK #ifdef DEBUG_FTCHUNK
std::cerr << "ChunkMap::isChunkAvailable(): (" << offset << "," << chunk_size << ") is available" << std::endl; std::cerr << "ChunkMap::hasChunkState(): (" << offset << "," << chunk_size << ") check returns true" << std::endl;
#endif #endif
return true ; return true ;
} }

View File

@ -159,6 +159,8 @@ class ChunkMap
/// This function is used by the parent ftFileProvider to know whether the chunk can be sent or not. /// 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 ; bool isChunkAvailable(uint64_t offset, uint32_t chunk_size) const ;
bool isChunkOutstanding(uint64_t offset, uint32_t chunk_size) const ;
/// Remove active chunks that have not received any data for the last 60 seconds, and return /// Remove active chunks that have not received any data for the last 60 seconds, and return
/// the list of slice numbers that should be canceled. /// the list of slice numbers that should be canceled.
void removeInactiveChunks(std::vector<ftChunk::ChunkId>& to_remove) ; void removeInactiveChunks(std::vector<ftChunk::ChunkId>& to_remove) ;
@ -206,6 +208,8 @@ class ChunkMap
uint32_t getAvailableChunk(const RsPeerId& peer_id,bool& chunk_map_too_old) ; uint32_t getAvailableChunk(const RsPeerId& peer_id,bool& chunk_map_too_old) ;
private: private:
bool hasChunkState(uint64_t offset, uint32_t chunk_size, FileChunksInfo::ChunkState state) const;
uint64_t _file_size ; //! total size of the file in bytes. uint64_t _file_size ; //! total size of the file in bytes.
uint32_t _chunk_size ; //! Size of chunks. Common to all chunks. uint32_t _chunk_size ; //! Size of chunks. Common to all chunks.
FileChunksInfo::ChunkStrategy _strategy ; //! how do we allocate new chunks FileChunksInfo::ChunkStrategy _strategy ; //! how do we allocate new chunks

View File

@ -1524,7 +1524,7 @@ bool ftController::FileClearCompleted()
} }
/* get Details of File Transfers */ /* get Details of File Transfers */
bool ftController::FileDownloads(std::list<RsFileHash> &hashs) void ftController::FileDownloads(std::list<RsFileHash> &hashs)
{ {
RsStackMutex stack(ctrlMutex); /******* LOCKED ********/ RsStackMutex stack(ctrlMutex); /******* LOCKED ********/
@ -1537,7 +1537,6 @@ bool ftController::FileDownloads(std::list<RsFileHash> &hashs)
{ {
hashs.push_back(it->second->mHash); hashs.push_back(it->second->mHash);
} }
return true;
} }

View File

@ -167,7 +167,7 @@ class ftController: public CacheTransfer, public RsThread, public pqiServiceMoni
uint32_t getMinPrioritizedTransfers() ; uint32_t getMinPrioritizedTransfers() ;
/* get Details of File Transfers */ /* get Details of File Transfers */
bool FileDownloads(std::list<RsFileHash> &hashs); void FileDownloads(std::list<RsFileHash> &hashs);
/* Directory Handling */ /* Directory Handling */
bool setDownloadDirectory(std::string path); bool setDownloadDirectory(std::string path);

View File

@ -77,6 +77,42 @@ ftDataMultiplex::ftDataMultiplex(const RsPeerId& ownId, ftDataSend *server, ftSe
return; return;
} }
bool ftDataMultiplex::getFileData(const RsFileHash& hash, uint64_t offset, uint32_t& requested_size, uint8_t *data)
{
RsStackMutex stack(dataMtx); /******* LOCK MUTEX ******/
ftFileProvider* provider = 0;
std::map<RsFileHash, ftClient>::iterator cit;
std::map<RsFileHash, ftFileProvider *>::iterator sit;
// check if file is currently downloading
if (mClients.end() != (cit = mClients.find(hash)))
provider = (cit->second).mCreator;
// else check if its already uploading
else if (mServers.end() != (sit = mServers.find(hash)))
provider = sit->second;
// else create a new provider
else
{
FileInfo info;
FileSearchFlags hintflags = RS_FILE_HINTS_EXTRA | RS_FILE_HINTS_LOCAL | RS_FILE_HINTS_SPEC_ONLY | RS_FILE_HINTS_NETWORK_WIDE;
if(mSearch->search(hash, hintflags, info))
{
provider = new ftFileProvider(info.path, info.size, hash);
mServers[hash] = provider;
}
}
if(!provider || ! provider->getFileData(mOwnId, offset, requested_size, data, true))
{
requested_size = 0 ;
return false ;
}
return true ;
}
bool ftDataMultiplex::addTransferModule(ftTransferModule *mod, ftFileCreator *f) bool ftDataMultiplex::addTransferModule(ftTransferModule *mod, ftFileCreator *f)
{ {
RsStackMutex stack(dataMtx); /******* LOCK MUTEX ******/ RsStackMutex stack(dataMtx); /******* LOCK MUTEX ******/

View File

@ -95,6 +95,16 @@ class ftDataMultiplex: public ftDataRecv, public RsQueueThread
ftDataMultiplex(const RsPeerId& ownId, ftDataSend *server, ftSearch *search); ftDataMultiplex(const RsPeerId& ownId, ftDataSend *server, ftSearch *search);
/**
* @see RsFiles::getFileData
*
* data should be pre-allocated by the client with size sufficient gfor requested_size bytes.
* requested_size will be changed so as to contain the actual number of bytes copied from the file,
* in case where the full size wasn't available.
* False is returned if no data can be obtained from that file.
*/
bool getFileData(const RsFileHash& hash, uint64_t offset,uint32_t& requested_size, uint8_t *data);
/* ftController Interface */ /* ftController Interface */
bool addTransferModule(ftTransferModule *mod, ftFileCreator *f); bool addTransferModule(ftTransferModule *mod, ftFileCreator *f);
bool removeTransferModule(const RsFileHash& hash); bool removeTransferModule(const RsFileHash& hash);

View File

@ -65,7 +65,7 @@ ftFileCreator::ftFileCreator(const std::string& path, uint64_t size, const RsFil
#endif #endif
} }
bool ftFileCreator::getFileData(const RsPeerId& peer_id,uint64_t offset, uint32_t &chunk_size, void *data) bool ftFileCreator::getFileData(const RsPeerId& peer_id,uint64_t offset, uint32_t &chunk_size, void *data, bool allow_unverified)
{ {
// Only send the data if we actually have it. // Only send the data if we actually have it.
// //
@ -77,6 +77,37 @@ bool ftFileCreator::getFileData(const RsPeerId& peer_id,uint64_t offset, uint32_
RsStackMutex stack(ftcMutex); /********** STACK LOCKED MTX ******/ RsStackMutex stack(ftcMutex); /********** STACK LOCKED MTX ******/
have_it = chunkMap.isChunkAvailable(offset, chunk_size) ; have_it = chunkMap.isChunkAvailable(offset, chunk_size) ;
#define ENABLE_SLICES
#ifdef ENABLE_SLICES
// try if we have data from an incomplete or not veryfied chunk
if(!have_it && allow_unverified)
{
std::map<uint64_t, ftChunk>::iterator it;
have_it = true;
// this map contains chunks which are currently being downloaded
for(std::map<uint64_t,ftChunk>::iterator it=mChunks.begin(); it!=mChunks.end(); ++it)
{
ftChunk chunk = it->second;
// begin of slice is in requested range
if(chunk.offset >= offset && chunk.offset < (offset+chunk_size))
{
// reduce the requested size
chunk_size = chunk.offset - offset;
}
// end of slice is in requested range
if((chunk.offset+chunk.size) >= offset && (chunk.offset+chunk.size) < (offset+chunk_size))
{
// can do nothing about this
have_it = false;
}
}
// check if the chunk was already started to download
// if not, we don't have it
if(chunkMap.isChunkOutstanding(offset, chunk_size))
have_it = false;
}
#endif
} }
#ifdef FILE_DEBUG #ifdef FILE_DEBUG
if(have_it) if(have_it)

View File

@ -52,7 +52,7 @@ class ftFileCreator: public ftFileProvider
~ftFileCreator(); ~ftFileCreator();
/* overloaded from FileProvider */ /* overloaded from FileProvider */
virtual bool getFileData(const RsPeerId& peer_id,uint64_t offset, uint32_t &chunk_size, void *data); virtual bool getFileData(const RsPeerId& peer_id,uint64_t offset, uint32_t &chunk_size, void *data, bool allow_unverified = false);
bool finished() ; bool finished() ;
uint64_t getRecvd(); uint64_t getRecvd();

View File

@ -139,7 +139,7 @@ void ftFileProvider::getAvailabilityMap(CompressedChunkMap& cmap)
} }
bool ftFileProvider::getFileData(const RsPeerId& peer_id,uint64_t offset, uint32_t &chunk_size, void *data) bool ftFileProvider::getFileData(const RsPeerId& peer_id,uint64_t offset, uint32_t &chunk_size, void *data, bool /*allow_unverified*/)
{ {
/* dodgey checking outside of mutex... /* dodgey checking outside of mutex...
* much check again inside FileAttrs(). * much check again inside FileAttrs().

View File

@ -41,7 +41,16 @@ class ftFileProvider
ftFileProvider(const std::string& path, uint64_t size, const RsFileHash& hash); ftFileProvider(const std::string& path, uint64_t size, const RsFileHash& hash);
virtual ~ftFileProvider(); virtual ~ftFileProvider();
virtual bool getFileData(const RsPeerId& peer_id,uint64_t offset, uint32_t &chunk_size, void *data); /**
* read a block of data from the file
* @param peer_id for the uploading stats: to which peer the data will be send
* @param offset begin of the requested data range
* @param chunk_size how many bytes to read. Will be set to the number of valid bytes in data on return.
* @param data pointer to a buffer of size chunk_size. Contains the data on success.
* @param allow_unverified for ftFileCreator: set to true to return data from unverified chunks. Use it if you want data asap.
* @return true if data was read
*/
virtual bool getFileData(const RsPeerId& peer_id,uint64_t offset, uint32_t &chunk_size, void *data, bool allow_unverified = false);
virtual bool FileDetails(FileInfo &info); virtual bool FileDetails(FileInfo &info);
RsFileHash getHash(); RsFileHash getHash();
uint64_t getFileSize(); uint64_t getFileSize();

View File

@ -262,6 +262,11 @@ bool ftServer::checkHash(const RsFileHash& hash,std::string& error_string)
return true ; return true ;
} }
bool ftServer::getFileData(const RsFileHash& hash, uint64_t offset, uint32_t& requested_size,uint8_t *data)
{
return mFtDataplex->getFileData(hash, offset, requested_size,data);
}
bool ftServer::alreadyHaveFile(const RsFileHash& hash, FileInfo &info) bool ftServer::alreadyHaveFile(const RsFileHash& hash, FileInfo &info)
{ {
return mFtController->alreadyHaveFile(hash, info); return mFtController->alreadyHaveFile(hash, info);
@ -403,9 +408,9 @@ std::string ftServer::getPartialsDirectory()
/************************* Other Access ************************/ /************************* Other Access ************************/
/***************************************************************/ /***************************************************************/
bool ftServer::FileDownloads(std::list<RsFileHash> &hashs) void ftServer::FileDownloads(std::list<RsFileHash> &hashs)
{ {
return mFtController->FileDownloads(hashs); mFtController->FileDownloads(hashs);
/* this only contains downloads.... not completed */ /* this only contains downloads.... not completed */
//return mFtDataplex->FileDownloads(hashs); //return mFtDataplex->FileDownloads(hashs);
} }

View File

@ -124,6 +124,11 @@ class ftServer: public p3Service, public RsFiles, public ftDataSend, public RsTu
ftDataMultiplex *getMultiplexer() const { return mFtDataplex ; } ftDataMultiplex *getMultiplexer() const { return mFtDataplex ; }
ftController *getController() const { return mFtController ; } ftController *getController() const { return mFtController ; }
/**
* @see RsFiles::getFileData
*/
bool getFileData(const RsFileHash& hash, uint64_t offset, uint32_t& requested_size,uint8_t *data);
/*** /***
* Control of Downloads * Control of Downloads
***/ ***/
@ -157,7 +162,7 @@ class ftServer: public p3Service, public RsFiles, public ftDataSend, public RsTu
/*** /***
* Download/Upload Details * Download/Upload Details
***/ ***/
virtual bool FileDownloads(std::list<RsFileHash> &hashs); virtual void FileDownloads(std::list<RsFileHash> &hashs);
virtual bool FileUploads(std::list<RsFileHash> &hashs); virtual bool FileUploads(std::list<RsFileHash> &hashs);
virtual bool FileDetails(const RsFileHash &hash, FileSearchFlags hintflags, FileInfo &info); virtual bool FileDetails(const RsFileHash &hash, FileSearchFlags hintflags, FileInfo &info);
virtual bool FileDownloadChunksDetails(const RsFileHash& hash,FileChunksInfo& info) ; virtual bool FileDownloadChunksDetails(const RsFileHash& hash,FileChunksInfo& info) ;

View File

@ -109,9 +109,22 @@ class RsFiles
RsFiles() { return; } RsFiles() { return; }
virtual ~RsFiles() { return; } virtual ~RsFiles() { return; }
/****************************************/ /**
/* download */ * Provides file data for the gui: media streaming or rpc clients.
* It may return unverified chunks. This allows streaming without having to wait for hashes or completion of the file.
* This function returns an unspecified amount of bytes. Either as much data as available or a sensible maximum. Expect a block size of around 1MiB.
* To get more data, call this function repeatedly with different offsets.
* Returns false in case
* - the files is not available on the local node
* - not downloading
* - the requested data was not downloaded yet
* - end of file was reached
* @param hash hash of a file. The file has to be available on this node or it has to be in downloading state.
* @param offset where the desired block starts
* @param requested_size size of pre-allocated data. Will be updated by the function.
* @param data pre-allocated memory chunk of size 'requested_size' by the client
*/
virtual bool getFileData(const RsFileHash& hash, uint64_t offset, uint32_t& requested_size,uint8_t *data)=0;
/*** /***
* Control of Downloads. * Control of Downloads.
@ -147,7 +160,7 @@ class RsFiles
/*** /***
* Download / Upload Details. * Download / Upload Details.
***/ ***/
virtual bool FileDownloads(std::list<RsFileHash> &hashs) = 0; virtual void FileDownloads(std::list<RsFileHash> &hashs) = 0;
virtual bool FileUploads(std::list<RsFileHash> &hashs) = 0; virtual bool FileUploads(std::list<RsFileHash> &hashs) = 0;
virtual bool FileDetails(const RsFileHash &hash, FileSearchFlags hintflags, FileInfo &info) = 0; virtual bool FileDetails(const RsFileHash &hash, FileSearchFlags hintflags, FileInfo &info) = 0;