From 8369d42600845b4ab412ebe7f6cb7126d78d043f Mon Sep 17 00:00:00 2001 From: csoler Date: Fri, 15 Oct 2010 22:12:29 +0000 Subject: [PATCH] corrected a bug in chunkmaps that affected file creators being providers at the same time, which could corrupt data. Added some debug info to chunk maps. git-svn-id: http://svn.code.sf.net/p/retroshare/code/trunk@3673 b45a01b8-16f6-495d-af2f-9b41ad6348cc --- libretroshare/src/ft/ftchunkmap.cc | 47 ++++++++++++++++-- libretroshare/src/ft/ftcontroller.cc | 9 +++- libretroshare/src/ft/ftfilecreator.cc | 16 ++++++ libretroshare/src/ft/ftfileprovider.cc | 3 ++ libretroshare/src/retroshare/rstypes.h | 2 +- .../tests/ft/ftcrossprovidercreatortest.cc | 49 ++++++++++++++++--- 6 files changed, 114 insertions(+), 12 deletions(-) diff --git a/libretroshare/src/ft/ftchunkmap.cc b/libretroshare/src/ft/ftchunkmap.cc index dc2800e76..9d1e676bd 100644 --- a/libretroshare/src/ft/ftchunkmap.cc +++ b/libretroshare/src/ft/ftchunkmap.cc @@ -1,3 +1,32 @@ +/* + * libretroshare/src/ft: ftdata.cc + * + * File Transfer for RetroShare. + * + * Copyright 2010 by Cyril Soler + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License Version 2 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA. + * + * Please report all bugs and problems to "csoler@users.sourceforge.net". + * + */ + +/******** + * #define DEBUG_FTCHUNK 1 + *********/ + #ifdef DEBUG_FTCHUNK #include #endif @@ -54,6 +83,10 @@ ChunkMap::ChunkMap(uint64_t s) std::cerr << " Strategy: " << _strategy << std::endl ; std::cerr << " ChunkSize: " << _chunk_size << std::endl ; std::cerr << " Number of Chunks: " << n << std::endl ; + std::cerr << " Data: " ; + for(int i=0;i<_map.size();++i) + std::cerr << _map[i] ; + std::cerr << std::endl ; #endif } @@ -252,16 +285,24 @@ 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 ; + 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) + for(uint32_t i=chunk_number_start;i ftController::saveList(bool &cleanup) /* ignore callback ones */ if (fit->second->mDoCallback) + { +#ifdef CONTROL_DEBUG + std::cerr << "ftcontroller::saveList(): Not saving (callback) file entry " << fit->second->mName << ", " << fit->second->mHash << ", " << fit->second->mSize << std::endl ; +#endif continue; + } if ((fit->second)->mCreator->finished()) continue; @@ -2031,6 +2035,9 @@ bool ftController::loadList(std::list load) /* This will get stored on a waiting list - until the * config files are fully loaded */ +#ifdef CONTROL_DEBUG + std::cerr << "ftController::loadList(): requesting " << rsft->file.name << ", " << rsft->file.hash << ", " << rsft->file.filesize << std::endl ; +#endif FileRequest(rsft->file.name, rsft->file.hash, rsft->file.filesize, rsft->file.path, rsft->flags, rsft->allPeerIds.ids); { diff --git a/libretroshare/src/ft/ftfilecreator.cc b/libretroshare/src/ft/ftfilecreator.cc index 6036d3a49..5ace5d79e 100644 --- a/libretroshare/src/ft/ftfilecreator.cc +++ b/libretroshare/src/ft/ftfilecreator.cc @@ -42,12 +42,21 @@ bool ftFileCreator::getFileData(const std::string& peer_id,uint64_t offset, uint { // Only send the data if we actually have it. // +#ifdef FILE_DEBUG + std::cerr << "ftFileCreator::getFileData(). Asked for offset=" << offset << ", size=" << chunk_size << std::endl ; +#endif bool have_it = false ; { RsStackMutex stack(ftcMutex); /********** STACK LOCKED MTX ******/ have_it = chunkMap.isChunkAvailable(offset, chunk_size) ; } +#ifdef FILE_DEBUG + if(have_it) + std::cerr << "ftFileCreator::getFileData(). Have it" << std::endl ; + else + std::cerr << "ftFileCreator::getFileData(). Don't have it" << std::endl ; +#endif if(have_it) return ftFileProvider::getFileData(peer_id,offset, chunk_size, data); @@ -433,6 +442,13 @@ void ftFileCreator::setAvailabilityMap(const CompressedChunkMap& cmap) RsStackMutex stack(ftcMutex); /********** STACK LOCKED MTX ******/ chunkMap.setAvailabilityMap(cmap) ; +#ifdef FILE_DEBUG + std::cerr << "ftFileCreator: setting chunkmap for hash " << hash << ": " ; + + for(uint32_t i=0;ifinished()) && (client2->finished() || (lrand48()&1))) { + //std::cerr << "###### Client 1 asking to " ; tmpclient = client1 ; tmpclient_pid = peer_id_1 ; if(lrand48()&1) { + //std::cerr << "Client 2 " ; tmpserver = client2 ; tmpserver_pid = peer_id_2 ; } else { + //std::cerr << "Server "; tmpserver = server ; tmpserver_pid = server_id ; } } - else + else // client 2 is necessarily unfinished there. { + //std::cerr << "###### Client 2 asking to " ; tmpclient = client2 ; tmpclient_pid = peer_id_2 ; if(lrand48()&1) { + //std::cerr << "Client 1 " ; tmpserver = client1 ; tmpserver_pid = peer_id_1 ; } else { + //std::cerr << "Server " ; tmpserver = server ; tmpserver_pid = server_id ; } @@ -90,6 +103,9 @@ int main() // 2 - transfer from the server to the client. transfer(tmpserver,tmpserver_pid,tmpclient,tmpclient_pid) ; + + printf("Client1: %08lld, Client2: %08lld, transfer from %s to %s\r",client1->getRecvd(),client2->getRecvd(),tmpserver_pid.c_str(),tmpclient_pid.c_str()) ; + fflush(stdout) ; } // hash the received data @@ -117,14 +133,33 @@ void transfer(ftFileProvider *server, const std::string& server_peer_id,ftFileCr uint32_t chunk_size = 0; bool toOld = false ; + //std::cerr << " for a pending chunk of size " << size_hint ; + if(! client->getMissingChunk(server_peer_id, size_hint, offset, chunk_size, toOld)) return ; + //std::cerr << "###### Got chunk " << offset << ", size=" << chunk_size << std::endl ; + void *data = malloc(chunk_size) ; + //std::cerr << "###### Asking data " << offset << ", size=" << chunk_size << std::endl ; if( server->getFileData(client_peer_id,offset,chunk_size,data) ) + { client->addFileData(offset,chunk_size,data) ; + //std::cerr << "###### Added data " << offset << ", size=" << chunk_size << std::endl ; + } + //std::cerr << ", completion=" << client->getRecvd() << std::endl ; + + // Normally this can't be true, because the ChunkMap class assumes availability for non turtle + // peers. + if(toOld) + { + //std::cerr << "###### Map is too old. Transferring" << std::endl ; + CompressedChunkMap map ; + server->getAvailabilityMap(map) ; + client->setSourceMap(server_peer_id,map) ; + } free(data) ; }