set default torrent ul/dl speed limits from global ul/dl speed. as a side effect, totally decouples fastresume from inout.
This commit is contained in:
parent
d5d68fb1f8
commit
eaca893b4c
|
@ -146,7 +146,8 @@ static void fastResumeWriteData( uint8_t id, void * data, uint32_t size,
|
|||
fwrite( data, size, count, file );
|
||||
}
|
||||
|
||||
void fastResumeSave( const tr_torrent_t * tor )
|
||||
void
|
||||
tr_fastResumeSave( const tr_torrent_t * tor )
|
||||
{
|
||||
char path[MAX_PATH_LENGTH];
|
||||
FILE * file;
|
||||
|
@ -390,17 +391,20 @@ fastResumeLoadProgress( const tr_torrent_t * tor,
|
|||
bitfield.len = FR_BLOCK_BITFIELD_LEN( tor );
|
||||
bitfield.bits = walk;
|
||||
tr_cpBlockBitfieldSet( tor->completion, &bitfield );
|
||||
/* FIXME: remove the "unchecked pieces" */
|
||||
}
|
||||
|
||||
free( buf );
|
||||
return TR_OK;
|
||||
}
|
||||
|
||||
static int
|
||||
static uint64_t
|
||||
fastResumeLoadOld( tr_torrent_t * tor,
|
||||
tr_bitfield_t * uncheckedPieces,
|
||||
FILE * file )
|
||||
{
|
||||
uint64_t ret = 0;
|
||||
|
||||
/* Check the size */
|
||||
const int size = 4 + FR_PROGRESS_LEN( tor );
|
||||
fseek( file, 0, SEEK_END );
|
||||
|
@ -422,21 +426,22 @@ fastResumeLoadOld( tr_torrent_t * tor,
|
|||
|
||||
fclose( file );
|
||||
|
||||
ret |= TR_FR_PROGRESS;
|
||||
tr_inf( "Fast resuming successful (version 0)" );
|
||||
|
||||
return 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
fastResumeLoad( tr_torrent_t * tor,
|
||||
tr_bitfield_t * uncheckedPieces )
|
||||
static uint64_t
|
||||
fastResumeLoadImpl ( tr_torrent_t * tor,
|
||||
tr_bitfield_t * uncheckedPieces )
|
||||
{
|
||||
char path[MAX_PATH_LENGTH];
|
||||
FILE * file;
|
||||
int version = 0;
|
||||
uint8_t id;
|
||||
uint32_t len;
|
||||
int ret;
|
||||
uint64_t ret = 0;
|
||||
|
||||
assert( tor != NULL );
|
||||
assert( uncheckedPieces != NULL );
|
||||
|
@ -444,22 +449,21 @@ fastResumeLoad( tr_torrent_t * tor,
|
|||
/* Open resume file */
|
||||
fastResumeFileName( path, sizeof path, tor, 1 );
|
||||
file = fopen( path, "r" );
|
||||
if( NULL == file )
|
||||
if( !file )
|
||||
{
|
||||
if( ENOENT == errno )
|
||||
{
|
||||
fastResumeFileName( path, sizeof path, tor, 0 );
|
||||
file = fopen( path, "r" );
|
||||
if( NULL != file )
|
||||
if( !file )
|
||||
{
|
||||
goto good;
|
||||
fastResumeFileName( path, sizeof path, tor, 1 );
|
||||
tr_inf( "Couldn't open '%s' for reading", path );
|
||||
return ret;
|
||||
}
|
||||
fastResumeFileName( path, sizeof path, tor, 1 );
|
||||
}
|
||||
tr_inf( "Could not open '%s' for reading", path );
|
||||
return 1;
|
||||
}
|
||||
good:
|
||||
|
||||
tr_dbg( "Resume file '%s' loaded", path );
|
||||
|
||||
/* Check format version */
|
||||
|
@ -472,10 +476,9 @@ fastResumeLoad( tr_torrent_t * tor,
|
|||
{
|
||||
tr_inf( "Resume file has version %d, not supported", version );
|
||||
fclose( file );
|
||||
return 1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = 1;
|
||||
/* read each block of data */
|
||||
while( 1 == fread( &id, 1, 1, file ) && 1 == fread( &len, 4, 1, file ) )
|
||||
{
|
||||
|
@ -485,14 +488,15 @@ fastResumeLoad( tr_torrent_t * tor,
|
|||
/* read progress data */
|
||||
if( (uint32_t)FR_PROGRESS_LEN( tor ) == len )
|
||||
{
|
||||
ret = fastResumeLoadProgress( tor, uncheckedPieces, file );
|
||||
const int rret = fastResumeLoadProgress( tor, uncheckedPieces, file );
|
||||
|
||||
if( ret && ( feof(file) || ferror(file) ) )
|
||||
if( rret && ( feof(file) || ferror(file) ) )
|
||||
{
|
||||
fclose( file );
|
||||
return 1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret |= TR_FR_PROGRESS;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
@ -502,14 +506,15 @@ fastResumeLoad( tr_torrent_t * tor,
|
|||
/* read priority data */
|
||||
if( len == (uint32_t)(2 * tor->info.fileCount) )
|
||||
{
|
||||
ret = loadPriorities( tor, file );
|
||||
const int rret = loadPriorities( tor, file );
|
||||
|
||||
if( ret && ( feof(file) || ferror(file) ) )
|
||||
if( rret && ( feof(file) || ferror(file) ) )
|
||||
{
|
||||
fclose( file );
|
||||
return 1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret |= TR_FR_PRIORITY;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
@ -518,14 +523,15 @@ fastResumeLoad( tr_torrent_t * tor,
|
|||
/* read speed data */
|
||||
if( len == FR_SPEED_LEN )
|
||||
{
|
||||
ret = loadSpeeds( tor, file );
|
||||
const int rret = loadSpeeds( tor, file );
|
||||
|
||||
if( ret && ( feof(file) || ferror(file) ) )
|
||||
if( rret && ( feof(file) || ferror(file) ) )
|
||||
{
|
||||
fclose( file );
|
||||
return 1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret |= TR_FR_SPEEDLIMIT;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
@ -537,9 +543,10 @@ fastResumeLoad( tr_torrent_t * tor,
|
|||
if( 1 != fread( &tor->downloadedPrev, 8, 1, file ) )
|
||||
{
|
||||
fclose( file );
|
||||
return 1;
|
||||
return ret;
|
||||
}
|
||||
tor->downloadedCur = 0;
|
||||
ret |= TR_FR_DOWNLOADED;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
@ -551,8 +558,10 @@ fastResumeLoad( tr_torrent_t * tor,
|
|||
if( 1 != fread( &tor->uploadedPrev, 8, 1, file ) )
|
||||
{
|
||||
fclose( file );
|
||||
return 1;
|
||||
return ret;
|
||||
}
|
||||
tor->uploadedCur = 0;
|
||||
ret |= TR_FR_UPLOADED;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
@ -566,13 +575,14 @@ fastResumeLoad( tr_torrent_t * tor,
|
|||
{
|
||||
free( buf );
|
||||
fclose( file );
|
||||
return 1;
|
||||
return ret;
|
||||
}
|
||||
used = tr_torrentAddCompact( tor, TR_PEER_FROM_CACHE,
|
||||
buf, len / 6 );
|
||||
tr_dbg( "found %i peers in resume file, used %i",
|
||||
len / 6, used );
|
||||
free( buf );
|
||||
ret |= TR_FR_PEERS;
|
||||
}
|
||||
continue;
|
||||
|
||||
|
@ -586,11 +596,17 @@ fastResumeLoad( tr_torrent_t * tor,
|
|||
}
|
||||
|
||||
fclose( file );
|
||||
|
||||
if( !ret )
|
||||
{
|
||||
tr_inf( "Fast resuming successful" );
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
tr_fastResumeLoad( tr_torrent_t * tor,
|
||||
tr_bitfield_t * uncheckedPieces )
|
||||
{
|
||||
const uint64_t ret = fastResumeLoadImpl( tor, uncheckedPieces );
|
||||
|
||||
if( ! ( ret & TR_FR_PROGRESS ) )
|
||||
tr_bitfieldAddRange( uncheckedPieces, 0, tor->info.pieceCount );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -25,9 +25,22 @@
|
|||
#ifndef TR_FAST_RESUME_H
|
||||
#define TR_FAST_RESUME_H
|
||||
|
||||
void fastResumeSave( const tr_torrent_t * tor );
|
||||
void tr_fastResumeSave( const tr_torrent_t * tor );
|
||||
|
||||
int fastResumeLoad( tr_torrent_t * tor,
|
||||
tr_bitfield_t * uncheckedPieces );
|
||||
enum
|
||||
{
|
||||
TR_FR_DOWNLOADED = (1<<0),
|
||||
TR_FR_UPLOADED = (1<<1),
|
||||
TR_FR_PEERS = (1<<2),
|
||||
TR_FR_PROGRESS = (1<<3),
|
||||
TR_FR_PRIORITY = (1<<4),
|
||||
TR_FR_SPEEDLIMIT = (1<<5)
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a bitwise-or'ed set of the data loaded from fastresume
|
||||
*/
|
||||
uint64_t tr_fastResumeLoad( tr_torrent_t * tor,
|
||||
tr_bitfield_t * uncheckedPieces );
|
||||
|
||||
#endif
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include "transmission.h"
|
||||
#include "fastresume.h"
|
||||
#include "fdlimit.h"
|
||||
|
||||
struct tr_io_s
|
||||
|
@ -211,46 +210,28 @@ checkPiece ( tr_torrent_t * tor, int pieceIndex )
|
|||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
tr_ioCheckFiles( tr_torrent_t * tor, int mode )
|
||||
void
|
||||
tr_ioCheckFiles( tr_torrent_t * tor )
|
||||
{
|
||||
int i;
|
||||
tr_bitfield_t * uncheckedPieces = tr_bitfieldNew( tor->info.pieceCount );
|
||||
|
||||
tr_cpReset( tor->completion );
|
||||
|
||||
tr_bitfieldClear( uncheckedPieces );
|
||||
|
||||
if( (mode==TR_RECHECK_FORCE) || fastResumeLoad( tor, uncheckedPieces ) )
|
||||
tr_bitfieldAddRange( uncheckedPieces, 0, tor->info.pieceCount );
|
||||
|
||||
if( tr_bitfieldIsEmpty( uncheckedPieces ) ) {
|
||||
tr_bitfieldFree( uncheckedPieces );
|
||||
return TR_OK;
|
||||
}
|
||||
|
||||
if( mode == TR_RECHECK_FAST ) {
|
||||
tr_bitfieldFree( uncheckedPieces );
|
||||
return TR_ERROR_IO_OTHER;
|
||||
}
|
||||
|
||||
tr_inf( "Verifying some pieces of \"%s\"", tor->info.name );
|
||||
|
||||
for( i=0; i<tor->info.pieceCount; ++i )
|
||||
if( tor->uncheckedPieces != NULL )
|
||||
{
|
||||
if( !tr_bitfieldHas( uncheckedPieces, i ) )
|
||||
continue;
|
||||
int i;
|
||||
tr_bitfield_t * p = tor->uncheckedPieces;
|
||||
tor->uncheckedPieces = NULL;
|
||||
|
||||
tr_dbg ( "Checking piece %d because it's not in fast-resume", i );
|
||||
tr_inf( "Verifying some pieces of \"%s\"", tor->info.name );
|
||||
|
||||
tr_torrentSetHasPiece( tor, i, !checkPiece( tor, i ) );
|
||||
for( i=0; i<tor->info.pieceCount; ++i )
|
||||
{
|
||||
if( !tr_bitfieldHas( p, i ) )
|
||||
continue;
|
||||
|
||||
tr_bitfieldRem( uncheckedPieces, i );
|
||||
tr_torrentSetHasPiece( tor, i, !checkPiece( tor, i ) );
|
||||
}
|
||||
|
||||
tr_bitfieldFree( p );
|
||||
tor->fastResumeDirty = TRUE;
|
||||
}
|
||||
|
||||
fastResumeSave( tor );
|
||||
tr_bitfieldFree( uncheckedPieces );
|
||||
return TR_OK;
|
||||
}
|
||||
|
||||
/****
|
||||
|
@ -258,17 +239,10 @@ tr_ioCheckFiles( tr_torrent_t * tor, int mode )
|
|||
****/
|
||||
|
||||
tr_io_t*
|
||||
tr_ioInitFast( tr_torrent_t * tor )
|
||||
tr_ioNew ( tr_torrent_t * tor )
|
||||
{
|
||||
tr_io_t * io = tr_calloc( 1, sizeof( tr_io_t ) );
|
||||
io->tor = tor;
|
||||
|
||||
if( tr_ioCheckFiles( tor, TR_RECHECK_FAST ) )
|
||||
{
|
||||
tr_free( io );
|
||||
io = NULL;
|
||||
}
|
||||
|
||||
return io;
|
||||
}
|
||||
|
||||
|
@ -283,8 +257,6 @@ tr_ioSync( tr_io_t * io )
|
|||
|
||||
for( i=0; i<info->fileCount; ++i )
|
||||
tr_fdFileClose( io->tor->destination, info->files[i].name );
|
||||
|
||||
fastResumeSave( io->tor );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -298,14 +270,6 @@ tr_ioClose( tr_io_t * io )
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/* try to load the fast resume file */
|
||||
int
|
||||
tr_ioLoadResume( tr_torrent_t * tor )
|
||||
{
|
||||
return tr_ioCheckFiles ( tor, TR_RECHECK_FAST );
|
||||
}
|
||||
|
||||
int
|
||||
tr_ioHash( tr_io_t * io, int pieceIndex )
|
||||
{
|
||||
|
|
|
@ -27,18 +27,9 @@
|
|||
|
||||
typedef struct tr_io_s tr_io_t;
|
||||
|
||||
int tr_ioLoadResume ( tr_torrent_t * );
|
||||
void tr_ioCheckFiles ( tr_torrent_t * );
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
TR_RECHECK_FAST, /* only try the fast resume, even if it's incomplete */
|
||||
TR_RECHECK_FORCE /* ignore the fast resume data; recheck from disk */
|
||||
};
|
||||
int tr_ioCheckFiles ( tr_torrent_t *, int recheckMode );
|
||||
|
||||
|
||||
tr_io_t * tr_ioInitFast ( tr_torrent_t * );
|
||||
tr_io_t * tr_ioNew ( tr_torrent_t * );
|
||||
|
||||
/***********************************************************************
|
||||
* tr_ioRead, tr_ioWrite
|
||||
|
|
|
@ -97,6 +97,7 @@ typedef enum { TR_NET_OK, TR_NET_ERROR, TR_NET_WAIT } tr_tristate_t;
|
|||
#include "peer.h"
|
||||
#include "inout.h"
|
||||
#include "ratecontrol.h"
|
||||
#include "utils.h"
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
|
@ -189,7 +190,7 @@ struct tr_torrent_s
|
|||
tr_completion_t * completion;
|
||||
|
||||
volatile char dieFlag;
|
||||
volatile char recheckFlag;
|
||||
tr_bitfield_t * uncheckedPieces;
|
||||
run_status_t runStatus;
|
||||
cp_status_t cpStatus;
|
||||
tr_thread_t thread;
|
||||
|
|
|
@ -180,7 +180,9 @@ torrentRealInit( tr_handle_t * h,
|
|||
int flags )
|
||||
{
|
||||
int i;
|
||||
uint64_t loaded;
|
||||
char name[512];
|
||||
tr_bitfield_t * uncheckedPieces;
|
||||
|
||||
tor->info.flags |= flags;
|
||||
|
||||
|
@ -231,7 +233,25 @@ torrentRealInit( tr_handle_t * h,
|
|||
|
||||
tor->error = TR_OK;
|
||||
tor->runStatus = flags & TR_FLAG_PAUSED ? TR_RUN_STOPPED : TR_RUN_RUNNING;
|
||||
tor->recheckFlag = tr_ioCheckFiles( tor, TR_RECHECK_FAST );
|
||||
|
||||
uncheckedPieces = tr_bitfieldNew( tor->info.pieceCount );
|
||||
loaded = tr_fastResumeLoad( tor, uncheckedPieces );
|
||||
if( tr_bitfieldIsEmpty( uncheckedPieces ) )
|
||||
tr_bitfieldFree( uncheckedPieces );
|
||||
else {
|
||||
tor->uncheckedPieces = uncheckedPieces;
|
||||
fprintf( stderr, "torrent %s has %d unchecked pieces\n", tor->info.name, (int)tr_bitfieldCountTrueBits(tor->uncheckedPieces) );
|
||||
}
|
||||
|
||||
|
||||
if( !(loaded & TR_FR_SPEEDLIMIT ) ) {
|
||||
int limit, enabled;
|
||||
tr_getGlobalSpeedLimit( tor->handle, TR_UP, &enabled, &limit );
|
||||
tr_torrentSetSpeedLimit( tor, TR_UP, limit );
|
||||
tr_getGlobalSpeedLimit( tor->handle, TR_DOWN, &enabled, &limit );
|
||||
tr_torrentSetSpeedLimit( tor, TR_DOWN, limit );
|
||||
}
|
||||
|
||||
tor->cpStatus = tr_cpGetStatus( tor->completion );
|
||||
|
||||
tr_sharedLock( h->shared );
|
||||
|
@ -444,16 +464,23 @@ int tr_torrentScrape( tr_torrent_t * tor, int * s, int * l, int * d )
|
|||
}
|
||||
#endif
|
||||
|
||||
void tr_torrentSetFolder( tr_torrent_t * tor, const char * path )
|
||||
static void
|
||||
fastResumeSave( tr_torrent_t * tor )
|
||||
{
|
||||
tr_fastResumeSave( tor );
|
||||
tor->fastResumeDirty = FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
tr_torrentSetFolder( tr_torrent_t * tor, const char * path )
|
||||
{
|
||||
tr_free( tor->destination );
|
||||
tor->destination = tr_strdup( path );
|
||||
|
||||
if( !tor->ioLoaded )
|
||||
tor->ioLoaded = tr_ioLoadResume( tor ) == TR_OK;
|
||||
fastResumeSave( tor );
|
||||
}
|
||||
|
||||
const char* tr_torrentGetFolder( const tr_torrent_t * tor )
|
||||
const char*
|
||||
tr_torrentGetFolder( const tr_torrent_t * tor )
|
||||
{
|
||||
return tor->destination;
|
||||
}
|
||||
|
@ -582,7 +609,7 @@ tr_torrentStat( tr_torrent_t * tor )
|
|||
s->left = tr_cpLeftUntilDone ( tor->completion );
|
||||
|
||||
|
||||
if( tor->recheckFlag )
|
||||
if( tor->uncheckedPieces )
|
||||
s->status = TR_STATUS_CHECK_WAIT;
|
||||
else switch( tor->runStatus ) {
|
||||
case TR_RUN_STOPPING: /* fallthrough */
|
||||
|
@ -855,7 +882,9 @@ void tr_torrentRemoveSaved( tr_torrent_t * tor )
|
|||
|
||||
void tr_torrentRecheck( tr_torrent_t * tor )
|
||||
{
|
||||
tor->recheckFlag = TRUE;
|
||||
if( !tor->uncheckedPieces )
|
||||
tor->uncheckedPieces = tr_bitfieldNew( tor->info.pieceCount );
|
||||
tr_bitfieldAddRange( tor->uncheckedPieces, 0, tor->info.pieceCount );
|
||||
}
|
||||
|
||||
|
||||
|
@ -997,6 +1026,7 @@ recheckCpState( tr_torrent_t * tor )
|
|||
tr_trackerCompleted( tor->tracker ); /* tell the tracker */
|
||||
}
|
||||
tr_ioSync( tor->io );
|
||||
fastResumeSave( tor );
|
||||
}
|
||||
tr_torrentWriterUnlock( tor );
|
||||
}
|
||||
|
@ -1022,7 +1052,6 @@ torrentThreadLoop ( void * _tor )
|
|||
|
||||
if( tor->fastResumeDirty )
|
||||
{
|
||||
tor->fastResumeDirty = FALSE;
|
||||
fastResumeSave( tor );
|
||||
recheckCpState( tor );
|
||||
}
|
||||
|
@ -1038,6 +1067,7 @@ torrentThreadLoop ( void * _tor )
|
|||
/* close the IO */
|
||||
tr_ioClose( tor->io );
|
||||
tor->io = NULL;
|
||||
fastResumeSave( tor );
|
||||
|
||||
/* close the peers */
|
||||
for( i=0; i<tor->peerCount; ++i )
|
||||
|
@ -1078,7 +1108,7 @@ torrentThreadLoop ( void * _tor )
|
|||
}
|
||||
|
||||
/* do we need to check files? */
|
||||
if( tor->recheckFlag )
|
||||
if( tor->uncheckedPieces )
|
||||
{
|
||||
if( !tr_lockTryLock( &checkFilesLock ) )
|
||||
{
|
||||
|
@ -1086,11 +1116,10 @@ torrentThreadLoop ( void * _tor )
|
|||
|
||||
tr_torrentWriterLock( tor );
|
||||
realStatus = tor->runStatus;
|
||||
tor->recheckFlag = FALSE;
|
||||
tor->runStatus = TR_RUN_CHECKING;
|
||||
tr_torrentWriterUnlock( tor );
|
||||
|
||||
tr_ioCheckFiles( tor, TR_RECHECK_FORCE );
|
||||
tr_ioCheckFiles( tor );
|
||||
setRunState( tor, realStatus );
|
||||
|
||||
tr_torrentWriterLock( tor );
|
||||
|
@ -1117,11 +1146,7 @@ torrentThreadLoop ( void * _tor )
|
|||
if( tor->io == NULL ) {
|
||||
*tor->errorString = '\0';
|
||||
tr_torrentResetTransferStats( tor );
|
||||
tor->io = tr_ioInitFast( tor );
|
||||
if( tor->io == NULL ) {
|
||||
tor->recheckFlag = TRUE;
|
||||
continue;
|
||||
}
|
||||
tor->io = tr_ioNew( tor );
|
||||
tr_peerIdNew ( tor->peer_id, sizeof(tor->peer_id) );
|
||||
tor->tracker = tr_trackerInit( tor );
|
||||
tor->startDate = tr_date();
|
||||
|
|
Loading…
Reference in New Issue