diff --git a/libtransmission/fdlimit.c b/libtransmission/fdlimit.c index 6ab9ce792..fdc651ace 100644 --- a/libtransmission/fdlimit.c +++ b/libtransmission/fdlimit.c @@ -86,6 +86,7 @@ struct tr_openfile tr_bool isCheckedOut; tr_bool isWritable; tr_bool closeWhenDone; + int torrentId; char filename[MAX_PATH_LENGTH]; int fd; uint64_t date; @@ -380,7 +381,8 @@ fileIsCheckedOut( const struct tr_openfile * o ) /* returns an fd on success, or a -1 on failure and sets errno */ int -tr_fdFileCheckout( const char * folder, +tr_fdFileCheckout( int torrentId, + const char * folder, const char * torrentFile, tr_bool doWrite, tr_preallocation_mode preallocationMode, @@ -390,6 +392,7 @@ tr_fdFileCheckout( const char * folder, struct tr_openfile * o; char filename[MAX_PATH_LENGTH]; + assert( torrentId > 0 ); assert( folder && *folder ); assert( torrentFile && *torrentFile ); assert( doWrite == 0 || doWrite == 1 ); @@ -399,14 +402,15 @@ tr_fdFileCheckout( const char * folder, tr_lockLock( gFd->lock ); - /* Is it already open? */ - for( i = 0; i < gFd->openFileLimit; ++i ) + /* is it already open? */ + for( i=0; iopenFileLimit; ++i ) { o = &gFd->openFiles[i]; if( !fileIsOpen( o ) ) continue; - + if( torrentId != o->torrentId ) + continue; if( strcmp( filename, o->filename ) ) continue; @@ -422,8 +426,7 @@ tr_fdFileCheckout( const char * folder, if( doWrite && !o->isWritable ) { - dbgmsg( - "found it! it's open and available, but isn't writable. closing..." ); + dbgmsg( "found it! it's open and available, but isn't writable. closing..." ); TrCloseFile( i ); break; } @@ -433,14 +436,13 @@ tr_fdFileCheckout( const char * folder, break; } - dbgmsg( - "it's not already open. looking for an open slot or an old file." ); + dbgmsg( "it's not already open. looking for an open slot or an old file." ); while( winner < 0 ) { uint64_t date = tr_date( ) + 1; /* look for the file that's been open longest */ - for( i = 0; i < gFd->openFileLimit; ++i ) + for( i=0; iopenFileLimit; ++i ) { o = &gFd->openFiles[i]; @@ -495,6 +497,7 @@ tr_fdFileCheckout( const char * folder, } dbgmsg( "checking out '%s' in slot %d", filename, winner ); + o->torrentId = torrentId; o->isCheckedOut = 1; o->closeWhenDone = 0; o->date = tr_date( ); @@ -530,10 +533,9 @@ void tr_fdFileClose( const char * filename ) { int i; - tr_lockLock( gFd->lock ); - for( i = 0; i < gFd->openFileLimit; ++i ) + for( i=0; iopenFileLimit; ++i ) { struct tr_openfile * o = &gFd->openFiles[i]; if( !fileIsOpen( o ) || strcmp( filename, o->filename ) ) @@ -541,23 +543,34 @@ tr_fdFileClose( const char * filename ) dbgmsg( "tr_fdFileClose closing '%s'", filename ); - if( !o->isCheckedOut ) - { - dbgmsg( "not checked out, so closing it now... '%s'", filename ); - TrCloseFile( i ); - } - else - { - dbgmsg( - "flagging file '%s', slot #%d to be closed when checked in", - gFd->openFiles[i].filename, i ); - o->closeWhenDone = 1; - } + assert( !o->isCheckedOut && "this is a test assertion... I *think* this is always true now" ); + + TrCloseFile( i ); } tr_lockUnlock( gFd->lock ); } +void +tr_fdTorrentClose( int torrentId ) +{ + int i; + tr_lockLock( gFd->lock ); + + for( i=0; iopenFileLimit; ++i ) + { + struct tr_openfile * o = &gFd->openFiles[i]; + + assert( !o->isCheckedOut && "this is a test assertion... I *think* this is always true now" ); + + if( fileIsOpen( o ) && o->torrentId == torrentId ) + TrCloseFile( i ); + } + + tr_lockUnlock( gFd->lock ); +} + + /*** **** **** Sockets @@ -736,4 +749,3 @@ tr_fdGetPeerLimit( void ) { return gFd ? gFd->socketLimit : -1; } - diff --git a/libtransmission/fdlimit.h b/libtransmission/fdlimit.h index 1570da796..377496dd0 100644 --- a/libtransmission/fdlimit.h +++ b/libtransmission/fdlimit.h @@ -67,7 +67,8 @@ int64_t tr_lseek( int fd, int64_t offset, int whence ); * @see tr_fdFileReturn * @see tr_fdFileClose */ -int tr_fdFileCheckout( const char * folder, +int tr_fdFileCheckout( int torrentId, + const char * folder, const char * torrentFile, tr_bool doWrite, tr_preallocation_mode preallocationMode, @@ -93,6 +94,12 @@ void tr_fdFileReturn( int file ); void tr_fdFileClose( const char * filename ); +/** + * Closes all the files associated with a given torrent id + */ +void tr_fdTorrentClose( int torrentId ); + + /*********************************************************************** * Sockets **********************************************************************/ diff --git a/libtransmission/inout.c b/libtransmission/inout.c index c35c69ede..45f2a6b14 100644 --- a/libtransmission/inout.c +++ b/libtransmission/inout.c @@ -101,7 +101,7 @@ readOrWriteBytes( const tr_torrent * tor, if( ( ioMode == TR_IO_READ ) && !fileExists ) /* does file exist? */ err = errno; - else if( ( fd = tr_fdFileCheckout ( tor->downloadDir, file->name, ioMode == TR_IO_WRITE, preallocationMode, file->length ) ) < 0 ) + else if( ( fd = tr_fdFileCheckout ( tor->uniqueId, tor->downloadDir, file->name, ioMode == TR_IO_WRITE, preallocationMode, file->length ) ) < 0 ) err = errno; else if( tr_lseek( fd, (int64_t)fileOffset, SEEK_SET ) == -1 ) err = errno; diff --git a/libtransmission/torrent.c b/libtransmission/torrent.c index 3b60dbd61..4bbce89dc 100644 --- a/libtransmission/torrent.c +++ b/libtransmission/torrent.c @@ -1329,30 +1329,6 @@ tr_torrentVerify( tr_torrent * tor ) tr_globalUnlock( tor->session ); } -static void -tr_torrentCloseLocalFiles( const tr_torrent * tor ) -{ - tr_file_index_t i; - struct evbuffer * buf = evbuffer_new( ); - - assert( tr_isTorrent( tor ) ); - - /* FIXME(libevent2) we're just using the evbuffer to build a key here anyway. - so we do (tor->info.fileCount * fd.openFileLimit) strcmps for these keys. :/ - it would be more efficient to remove this code altogether and - add "int torrentId;" to "struct tr_openfile", and a new function - tr_fdCloseTorrentFiles( tr_session*, int torrentId ) */ - for( i=0; iinfo.fileCount; ++i ) - { - const tr_file * file = &tor->info.files[i]; - evbuffer_drain( buf, EVBUFFER_LENGTH( buf ) ); - evbuffer_add_printf( buf, "%s%s%s", tor->downloadDir, TR_PATH_DELIMITER_STR, file->name ); - tr_fdFileClose( (const char*) EVBUFFER_DATA( buf ) ); - } - - evbuffer_free( buf ); -} - static void stopTorrent( void * vtor ) { @@ -1364,7 +1340,7 @@ stopTorrent( void * vtor ) tr_peerMgrStopTorrent( tor ); tr_trackerStop( tor->tracker ); - tr_torrentCloseLocalFiles( tor ); + tr_fdTorrentClose( tor->uniqueId ); } void @@ -1529,7 +1505,7 @@ tr_torrentRecheckCompleteness( tr_torrent * tor ) tor->completeness = completeness; tor->needsSeedRatioCheck = TRUE; - tr_torrentCloseLocalFiles( tor ); + tr_fdTorrentClose( tor->uniqueId ); fireCompletenessChange( tor, completeness ); if( recentChange && ( completeness == TR_SEED ) ) @@ -2218,7 +2194,7 @@ tr_torrentDeleteLocalData( tr_torrent * tor, tr_fileFunc fileFunc ) fileFunc = remove; /* close all the files because we're about to delete them */ - tr_torrentCloseLocalFiles( tor ); + tr_fdTorrentClose( tor->uniqueId ); if( tor->info.fileCount > 1 ) deleteLocalData( tor, fileFunc );