(trunk) #1521 "memory cache to reduce disk IO" -- commit block-cache-rc1.diff to trunk for the nightlies.
This commit is contained in:
parent
dbcd1c942f
commit
e70bebf930
|
@ -207,6 +207,7 @@ static tr_option opts[] =
|
|||
{ 'b', "debug", "Print debugging information", "b", 0, NULL },
|
||||
{ 'd', "downlimit", "Set the max download speed in KiB/s for the current torrent(s) or globally", "d", 1, "<speed>" },
|
||||
{ 'D', "no-downlimit", "Disable max download speed for the current torrent(s) or globally", "D", 0, NULL },
|
||||
{ 'e', "cache", "Set the maximum size of the session's memory cache (in MiB)", "e", 1, "<size>" },
|
||||
{ 910, "encryption-required", "Encrypt all peer connections", "er", 0, NULL },
|
||||
{ 911, "encryption-preferred", "Prefer encrypted peer connections", "ep", 0, NULL },
|
||||
{ 912, "encryption-tolerated", "Prefer unencrypted peer connections", "et", 0, NULL },
|
||||
|
@ -322,6 +323,7 @@ getOptMode( int val )
|
|||
|
||||
case 'c': /* incomplete-dir */
|
||||
case 'C': /* no-incomplete-dir */
|
||||
case 'e': /* cache */
|
||||
case 'm': /* portmap */
|
||||
case 'M': /* "no-portmap */
|
||||
case 'o': /* dht */
|
||||
|
@ -1329,9 +1331,11 @@ printSession( tr_benc * top )
|
|||
tr_benc *args;
|
||||
if( ( tr_bencDictFindDict( top, "arguments", &args ) ) )
|
||||
{
|
||||
double d;
|
||||
const char * str;
|
||||
int64_t i;
|
||||
tr_bool boolVal;
|
||||
char buf[64];
|
||||
|
||||
printf( "VERSION\n" );
|
||||
if( tr_bencDictFindStr( args, "version", &str ) )
|
||||
|
@ -1359,6 +1363,8 @@ printSession( tr_benc * top )
|
|||
printf( " Peer exchange allowed: %s\n", ( boolVal ? "Yes" : "No" ) );
|
||||
if( tr_bencDictFindStr( args, TR_PREFS_KEY_ENCRYPTION, &str ) )
|
||||
printf( " Encryption: %s\n", str );
|
||||
if( tr_bencDictFindReal( args, TR_PREFS_KEY_MAX_CACHE_SIZE_MiB, &d ) )
|
||||
printf( " Maximum memory cache size: %s\n", strlsize( buf, d*MiB, sizeof( buf ) ) );
|
||||
printf( "\n" );
|
||||
|
||||
{
|
||||
|
@ -1816,6 +1822,8 @@ processArgs( const char * host, int port, int argc, const char ** argv )
|
|||
break;
|
||||
case 'C': tr_bencDictAddBool( args, TR_PREFS_KEY_INCOMPLETE_DIR_ENABLED, FALSE );
|
||||
break;
|
||||
case 'e': tr_bencDictAddReal( args, TR_PREFS_KEY_MAX_CACHE_SIZE_MiB, atof(optarg) );
|
||||
break;
|
||||
case 910: tr_bencDictAddStr( args, TR_PREFS_KEY_ENCRYPTION, "required" );
|
||||
break;
|
||||
case 911: tr_bencDictAddStr( args, TR_PREFS_KEY_ENCRYPTION, "preferred" );
|
||||
|
|
|
@ -21,6 +21,7 @@ and
|
|||
.Op Fl b
|
||||
.Op Fl c Ar path | Fl C
|
||||
.Op Fl d Ar number | Fl D
|
||||
.Op Fl e Ar size
|
||||
.Op Fl er | ep | et
|
||||
.Op Fl f
|
||||
.Op Fl g Ar files
|
||||
|
@ -124,6 +125,8 @@ If current torrent(s) are selected this operates on them. Otherwise, it changes
|
|||
.It Fl D Fl -no-downlimit
|
||||
Disable download speed limits.
|
||||
If current torrent(s) are selected this operates on them. Otherwise, it changes the global setting.
|
||||
.It Fl e Fl -cache Ar size
|
||||
Set the session's maximum memory cache size in MiB. This cache is used to reduce disk IO.
|
||||
.It Fl er Fl -encryption-required
|
||||
Encrypt all peer connections.
|
||||
.It Fl ep Fl -encryption-preferred
|
||||
|
|
|
@ -399,6 +399,7 @@
|
|||
"alt-speed-up" | number max global upload speed (in K/s)
|
||||
"blocklist-enabled" | boolean true means enabled
|
||||
"blocklist-size" | number number of rules in the blocklist
|
||||
"cache-size-MiB" | number size (in MiB) of the disk cache
|
||||
"config-dir" | string location of transmission's configuration directory
|
||||
"download-dir" | string default path to download torrents
|
||||
"dht-enabled" | boolean true means allow dht in public torrents
|
||||
|
@ -597,4 +598,5 @@
|
|||
| 2.00 | yes | session-set | new arg "trash-original-torrent-files"
|
||||
| 2.00 | yes | session-get | new arg "start-added-torrents"
|
||||
| 2.00 | yes | session-get | new arg "trash-original-torrent-files"
|
||||
| 2.00 | yes | session-get | new arg "cache-size-MiB"
|
||||
| 2.00 | yes | torrent-get | new arg "isFinished"
|
||||
|
|
|
@ -2,4 +2,5 @@
|
|||
export G_SLICE=always-malloc
|
||||
export G_DEBUG=gc-friendly
|
||||
export GLIBCXX_FORCE_NEW=1
|
||||
valgrind --tool=memcheck --leak-check=full --leak-resolution=high --num-callers=48 --log-file=x-valgrind --show-reachable=yes ./transmission -p 2>&1 | tee runlog
|
||||
valgrind --tool=cachegrind ./transmission -p -g /tmp/transmission-test/what 2>&1 | tee runlog
|
||||
#valgrind --tool=memcheck --leak-check=full --leak-resolution=high --num-callers=48 --log-file=x-valgrind --show-reachable=yes ./transmission -p -g /tmp/transmission-test/what 2>&1 | tee runlog
|
||||
|
|
|
@ -21,6 +21,7 @@ libtransmission_a_SOURCES = \
|
|||
bencode.c \
|
||||
bitfield.c \
|
||||
blocklist.c \
|
||||
cache.c \
|
||||
clients.c \
|
||||
completion.c \
|
||||
ConvertUTF.c \
|
||||
|
@ -71,6 +72,7 @@ noinst_HEADERS = \
|
|||
bitfield.h \
|
||||
bitset.h \
|
||||
blocklist.h \
|
||||
cache.h \
|
||||
clients.h \
|
||||
ConvertUTF.h \
|
||||
crypto.h \
|
||||
|
|
|
@ -0,0 +1,352 @@
|
|||
/*
|
||||
* This file Copyright (C) 2010 Mnemosyne LLC
|
||||
*
|
||||
* This file is licensed by the GPL version 2. Works owned by the
|
||||
* Transmission project are granted a special exemption to clause 2(b)
|
||||
* so that the bulk of its code can remain under the MIT license.
|
||||
* This exemption does not extend to derived works not owned by
|
||||
* the Transmission project.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include "transmission.h"
|
||||
#include "cache.h"
|
||||
#include "inout.h"
|
||||
#include "peer-common.h" /* MAX_BLOCK_SIZE */
|
||||
#include "ptrarray.h"
|
||||
#include "torrent.h"
|
||||
#include "utils.h"
|
||||
|
||||
#define MY_NAME "Cache"
|
||||
|
||||
/****
|
||||
*****
|
||||
****/
|
||||
|
||||
struct cache_block
|
||||
{
|
||||
tr_torrent * tor;
|
||||
|
||||
tr_piece_index_t piece;
|
||||
uint32_t offset;
|
||||
uint32_t length;
|
||||
|
||||
tr_block_index_t block;
|
||||
|
||||
uint8_t * buf;
|
||||
};
|
||||
|
||||
struct tr_cache
|
||||
{
|
||||
tr_ptrArray blocks;
|
||||
int maxBlocks;
|
||||
size_t maxMiB;
|
||||
|
||||
size_t disk_writes;
|
||||
size_t disk_write_bytes;
|
||||
size_t cache_writes;
|
||||
size_t cache_write_bytes;
|
||||
};
|
||||
|
||||
/****
|
||||
*****
|
||||
****/
|
||||
|
||||
/* return a count of how many contiguous blocks there are starting at this pos */
|
||||
static int
|
||||
getBlockRun( const tr_cache * cache, int pos )
|
||||
{
|
||||
int i;
|
||||
const int n = tr_ptrArraySize( &cache->blocks );
|
||||
const struct cache_block ** blocks = (const struct cache_block**) tr_ptrArrayBase( &cache->blocks );
|
||||
const struct cache_block * ref = blocks[pos];
|
||||
tr_block_index_t block = ref->block;
|
||||
|
||||
for( i=pos; i<n; ++i, ++block ) {
|
||||
const struct cache_block * b = blocks[i];
|
||||
if( b->block != block ) break;
|
||||
if( b->tor != ref->tor ) break;
|
||||
//fprintf( stderr, "pos %d tor %d block %zu\n", i, b->tor->uniqueId, (size_t)b->block );
|
||||
}
|
||||
|
||||
//fprintf( stderr, "run is %d long from [%d to %d)\n", (int)(i-pos), i, (int)pos );
|
||||
return i-pos;
|
||||
}
|
||||
|
||||
/* return the starting index of the longest contiguous run of blocks */
|
||||
static int
|
||||
findLargestChunk( tr_cache * cache, int * setme_n )
|
||||
{
|
||||
const int n = tr_ptrArraySize( &cache->blocks );
|
||||
int pos;
|
||||
int bestpos = 0;
|
||||
int bestlen = getBlockRun( cache, bestpos );
|
||||
|
||||
for( pos=bestlen; pos<n; )
|
||||
{
|
||||
const int len = getBlockRun( cache, pos );
|
||||
|
||||
if( bestlen < len ) {
|
||||
bestlen = len;
|
||||
bestpos = pos;
|
||||
}
|
||||
|
||||
pos += len;
|
||||
}
|
||||
|
||||
//fprintf( stderr, "LONGEST run is %d long from [%d to %d)\n", bestlen, bestpos, bestpos+bestlen );
|
||||
*setme_n = bestlen;
|
||||
return bestpos;
|
||||
}
|
||||
|
||||
static int
|
||||
flushContiguous( tr_cache * cache, int pos, int n )
|
||||
{
|
||||
int i;
|
||||
int err = 0;
|
||||
uint8_t * buf = tr_new( uint8_t, n * MAX_BLOCK_SIZE );
|
||||
uint8_t * walk = buf;
|
||||
struct cache_block ** blocks = (struct cache_block**) tr_ptrArrayBase( &cache->blocks );
|
||||
|
||||
struct cache_block * b = blocks[pos];
|
||||
tr_torrent * tor = b->tor;
|
||||
const tr_piece_index_t piece = b->piece;
|
||||
const uint32_t offset = b->offset;
|
||||
|
||||
//fprintf( stderr, "flushing %d contiguous blocks from [%d to %d)\n", n, pos, n+pos );
|
||||
|
||||
for( i=pos; i<pos+n; ++i ) {
|
||||
b = blocks[i];
|
||||
memcpy( walk, b->buf, b->length );
|
||||
walk += b->length;
|
||||
tr_free( b->buf );
|
||||
tr_free( b );
|
||||
}
|
||||
tr_ptrArrayErase( &cache->blocks, pos, pos+n );
|
||||
|
||||
tr_tordbg( tor, "Writing to disk piece %d, offset %d, len %d", (int)piece, (int)offset, (int)(walk-buf) );
|
||||
tr_ndbg( MY_NAME, "Removing %d blocks from cache; %d left", n, tr_ptrArraySize(&cache->blocks) );
|
||||
//fprintf( stderr, "%s - Writing to disk piece %d, offset %d, len %d\n", tr_torrentName(tor), (int)piece, (int)offset, (int)(walk-buf) );
|
||||
//fprintf( stderr, "%s - Removing %d blocks from cache; %d left\n", MY_NAME, n, tr_ptrArraySize(&cache->blocks) );
|
||||
|
||||
err = tr_ioWrite( tor, piece, offset, walk-buf, buf );
|
||||
tr_free( buf );
|
||||
|
||||
++cache->disk_writes;
|
||||
cache->disk_write_bytes += walk-buf;
|
||||
return err;
|
||||
}
|
||||
|
||||
static int
|
||||
cacheTrim( tr_cache * cache )
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
while( !err && ( tr_ptrArraySize( &cache->blocks ) > cache->maxBlocks ) )
|
||||
{
|
||||
int n;
|
||||
const int i = findLargestChunk( cache, &n );
|
||||
err = flushContiguous( cache, i, n );
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/***
|
||||
****
|
||||
***/
|
||||
|
||||
static int
|
||||
getMaxBlocks( size_t maxMiB )
|
||||
{
|
||||
const double maxBytes = maxMiB * 1024 * 1024;
|
||||
return maxBytes / MAX_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
int
|
||||
tr_cacheSetLimit( tr_cache * cache, double maxMiB )
|
||||
{
|
||||
cache->maxMiB = maxMiB;
|
||||
cache->maxBlocks = getMaxBlocks( maxMiB );
|
||||
tr_ndbg( MY_NAME, "Maximum cache size set to %.2f MiB (%d blocks)", maxMiB, cache->maxBlocks );
|
||||
return cacheTrim( cache );
|
||||
}
|
||||
|
||||
double
|
||||
tr_cacheGetLimit( const tr_cache * cache )
|
||||
{
|
||||
return cache->maxMiB;
|
||||
}
|
||||
|
||||
tr_cache *
|
||||
tr_cacheNew( double maxMiB )
|
||||
{
|
||||
tr_cache * cache = tr_new( tr_cache, 1 );
|
||||
cache->blocks = TR_PTR_ARRAY_INIT;
|
||||
cache->maxBlocks = getMaxBlocks( maxMiB );
|
||||
return cache;
|
||||
}
|
||||
|
||||
void
|
||||
tr_cacheFree( tr_cache * cache )
|
||||
{
|
||||
assert( tr_ptrArrayEmpty( &cache->blocks ) );
|
||||
tr_ptrArrayDestruct( &cache->blocks, NULL );
|
||||
tr_free( cache );
|
||||
}
|
||||
|
||||
/***
|
||||
****
|
||||
***/
|
||||
|
||||
static int
|
||||
cache_block_compare( const void * va, const void * vb )
|
||||
{
|
||||
const struct cache_block * a = va;
|
||||
const struct cache_block * b = vb;
|
||||
|
||||
/* primary key: torrent id */
|
||||
if( a->tor->uniqueId != b->tor->uniqueId )
|
||||
return a->tor->uniqueId < b->tor->uniqueId ? -1 : 1;
|
||||
|
||||
/* secondary key: block # */
|
||||
if( a->block != b->block )
|
||||
return a->block < b->block ? -1 : 1;
|
||||
|
||||
if( a->block < b->block ) return -1;
|
||||
if( a->block > b->block ) return 1;
|
||||
|
||||
/* they'r eequal */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct cache_block *
|
||||
findBlock( tr_cache * cache,
|
||||
tr_torrent * torrent,
|
||||
tr_piece_index_t piece,
|
||||
uint32_t offset )
|
||||
{
|
||||
struct cache_block key;
|
||||
key.tor = torrent;
|
||||
key.block = _tr_block( torrent, piece, offset );
|
||||
return tr_ptrArrayFindSorted( &cache->blocks, &key, cache_block_compare );
|
||||
}
|
||||
|
||||
int
|
||||
tr_cacheWriteBlock( tr_cache * cache,
|
||||
tr_torrent * torrent,
|
||||
tr_piece_index_t piece,
|
||||
uint32_t offset,
|
||||
uint32_t length,
|
||||
const uint8_t * writeme )
|
||||
{
|
||||
struct cache_block * cb = findBlock( cache, torrent, piece, offset );
|
||||
|
||||
if( cb == NULL )
|
||||
{
|
||||
cb = tr_new( struct cache_block, 1 );
|
||||
cb->tor = torrent;
|
||||
cb->piece = piece;
|
||||
cb->offset = offset;
|
||||
cb->length = length;
|
||||
cb->block = _tr_block( torrent, piece, offset );
|
||||
cb->buf = NULL;
|
||||
tr_ptrArrayInsertSorted( &cache->blocks, cb, cache_block_compare );
|
||||
}
|
||||
|
||||
tr_free( cb->buf );
|
||||
cb->buf = tr_memdup( writeme, cb->length );
|
||||
|
||||
++cache->cache_writes;
|
||||
cache->cache_write_bytes += cb->length;
|
||||
|
||||
return cacheTrim( cache );
|
||||
}
|
||||
|
||||
int
|
||||
tr_cacheReadBlock( tr_cache * cache,
|
||||
tr_torrent * torrent,
|
||||
tr_piece_index_t piece,
|
||||
uint32_t offset,
|
||||
uint32_t len,
|
||||
uint8_t * setme )
|
||||
{
|
||||
int err = 0;
|
||||
struct cache_block * cb = findBlock( cache, torrent, piece, offset );
|
||||
|
||||
if( cb )
|
||||
memcpy( setme, cb->buf, len );
|
||||
else
|
||||
err = tr_ioRead( torrent, piece, offset, len, setme );
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int
|
||||
tr_cachePrefetchBlock( tr_cache * cache,
|
||||
tr_torrent * torrent,
|
||||
tr_piece_index_t piece,
|
||||
uint32_t offset,
|
||||
uint32_t len )
|
||||
{
|
||||
int err = 0;
|
||||
struct cache_block * cb = findBlock( cache, torrent, piece, offset );
|
||||
|
||||
if( cb == NULL )
|
||||
err = tr_ioPrefetch( torrent, piece, offset, len );
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/***
|
||||
****
|
||||
***/
|
||||
|
||||
static int
|
||||
findPiece( tr_cache * cache, tr_torrent * torrent, tr_piece_index_t piece )
|
||||
{
|
||||
struct cache_block key;
|
||||
key.tor = torrent;
|
||||
key.block = tr_torPieceFirstBlock( torrent, piece );
|
||||
return tr_ptrArrayLowerBound( &cache->blocks, &key, cache_block_compare, NULL );
|
||||
}
|
||||
|
||||
int
|
||||
tr_cacheFlushFile( tr_cache * cache, tr_torrent * torrent, tr_file_index_t i )
|
||||
{
|
||||
int err = 0;
|
||||
const tr_file * file = &torrent->info.files[i];
|
||||
const tr_block_index_t begin = tr_torPieceFirstBlock( torrent, file->firstPiece );
|
||||
const tr_block_index_t end = tr_torPieceFirstBlock( torrent, file->lastPiece ) + tr_torPieceCountBlocks( torrent, file->lastPiece );
|
||||
const int pos = findPiece( cache, torrent, file->firstPiece );
|
||||
//fprintf( stderr, "flushing file %d, which is blocks [%zu...%zu)\n", (int)i, (size_t)begin, (size_t)end );
|
||||
|
||||
/* flush out all the blocks in that file */
|
||||
while( !err && ( pos < tr_ptrArraySize( &cache->blocks ) ) )
|
||||
{
|
||||
const struct cache_block * b = tr_ptrArrayNth( &cache->blocks, pos );
|
||||
if( b->tor != torrent ) break;
|
||||
if( ( b->block < begin ) || ( b->block >= end ) ) break;
|
||||
err = flushContiguous( cache, pos, getBlockRun( cache, pos ) );
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int
|
||||
tr_cacheFlushTorrent( tr_cache * cache, tr_torrent * torrent )
|
||||
{
|
||||
int err = 0;
|
||||
const int pos = findPiece( cache, torrent, 0 );
|
||||
|
||||
/* flush out all the blocks in that torrent */
|
||||
while( !err && ( pos < tr_ptrArraySize( &cache->blocks ) ) )
|
||||
{
|
||||
const struct cache_block * b = tr_ptrArrayNth( &cache->blocks, pos );
|
||||
if( b->tor != torrent ) break;
|
||||
err = flushContiguous( cache, pos, getBlockRun( cache, pos ) );
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* This file Copyright (C) 2010 Mnemosyne LLC
|
||||
*
|
||||
* This file is licensed by the GPL version 2. Works owned by the
|
||||
* Transmission project are granted a special exemption to clause 2(b)
|
||||
* so that the bulk of its code can remain under the MIT license.
|
||||
* This exemption does not extend to derived works not owned by
|
||||
* the Transmission project.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef __TRANSMISSION__
|
||||
#error only libtransmission should #include this header.
|
||||
#endif
|
||||
|
||||
#ifndef TR_CACHE_H
|
||||
#define TR_CACHE_H
|
||||
|
||||
typedef struct tr_cache tr_cache;
|
||||
|
||||
/***
|
||||
****
|
||||
***/
|
||||
|
||||
tr_cache * tr_cacheNew( double max_MiB );
|
||||
|
||||
void tr_cacheFree( tr_cache * );
|
||||
|
||||
/***
|
||||
****
|
||||
***/
|
||||
|
||||
int tr_cacheSetLimit( tr_cache * cache, double max_MiB );
|
||||
|
||||
double tr_cacheGetLimit( const tr_cache * );
|
||||
|
||||
int tr_cacheWriteBlock( tr_cache * cache,
|
||||
tr_torrent * torrent,
|
||||
tr_piece_index_t piece,
|
||||
uint32_t offset,
|
||||
uint32_t len,
|
||||
const uint8_t * writeme );
|
||||
|
||||
int tr_cacheReadBlock( tr_cache * cache,
|
||||
tr_torrent * torrent,
|
||||
tr_piece_index_t piece,
|
||||
uint32_t offset,
|
||||
uint32_t len,
|
||||
uint8_t * setme );
|
||||
|
||||
int tr_cachePrefetchBlock( tr_cache * cache,
|
||||
tr_torrent * torrent,
|
||||
tr_piece_index_t piece,
|
||||
uint32_t offset,
|
||||
uint32_t len );
|
||||
|
||||
/***
|
||||
****
|
||||
***/
|
||||
|
||||
int tr_cacheFlushTorrent( tr_cache * cache,
|
||||
tr_torrent * torrent );
|
||||
|
||||
int tr_cacheFlushFile( tr_cache * cache,
|
||||
tr_torrent * torrent,
|
||||
tr_file_index_t file );
|
||||
|
||||
#endif
|
|
@ -26,9 +26,11 @@
|
|||
#include <openssl/sha.h>
|
||||
|
||||
#include "transmission.h"
|
||||
#include "cache.h"
|
||||
#include "crypto.h"
|
||||
#include "fdlimit.h"
|
||||
#include "inout.h"
|
||||
#include "peer-common.h" /* MAX_BLOCK_SIZE */
|
||||
#include "platform.h"
|
||||
#include "stats.h"
|
||||
#include "torrent.h"
|
||||
|
@ -84,6 +86,9 @@ readOrWriteBytes( tr_session * session,
|
|||
int err = 0;
|
||||
const tr_bool doWrite = ioMode >= TR_IO_WRITE;
|
||||
|
||||
if( doWrite )
|
||||
fprintf( stderr, "in file %s at offset %zu, writing %zu bytes; file length is %zu\n", file->name, (size_t)fileOffset, buflen, (size_t)file->length );
|
||||
|
||||
assert( fileIndex < info->fileCount );
|
||||
assert( !file->length || ( fileOffset < file->length ) );
|
||||
assert( fileOffset + buflen <= file->length );
|
||||
|
@ -223,8 +228,8 @@ readOrWritePiece( tr_torrent * tor,
|
|||
|
||||
if( pieceIndex >= tor->info.pieceCount )
|
||||
return EINVAL;
|
||||
if( pieceOffset + buflen > tr_torPieceCountBytes( tor, pieceIndex ) )
|
||||
return EINVAL;
|
||||
//if( pieceOffset + buflen > tr_torPieceCountBytes( tor, pieceIndex ) )
|
||||
// return EINVAL;
|
||||
|
||||
tr_ioFindFileLocation( tor, pieceIndex, pieceOffset,
|
||||
&fileIndex, &fileOffset );
|
||||
|
@ -237,6 +242,7 @@ readOrWritePiece( tr_torrent * tor,
|
|||
err = readOrWriteBytes( tor->session, tor, ioMode, fileIndex, fileOffset, buf, bytesThisPass );
|
||||
buf += bytesThisPass;
|
||||
buflen -= bytesThisPass;
|
||||
//fprintf( stderr, "++fileIndex to %d\n", (int)fileIndex );
|
||||
++fileIndex;
|
||||
fileOffset = 0;
|
||||
|
||||
|
@ -295,8 +301,8 @@ recalculateHash( tr_torrent * tor,
|
|||
size_t bytesLeft;
|
||||
uint32_t offset = 0;
|
||||
tr_bool success = TRUE;
|
||||
uint8_t * buffer = tr_sessionGetBuffer( tor->session );
|
||||
const size_t buflen = SESSION_BUFFER_SIZE;
|
||||
const size_t buflen = MAX_BLOCK_SIZE;
|
||||
uint8_t * buffer = tr_new( uint8_t, buflen );
|
||||
SHA_CTX sha;
|
||||
|
||||
assert( tor != NULL );
|
||||
|
@ -313,7 +319,7 @@ recalculateHash( tr_torrent * tor,
|
|||
while( bytesLeft )
|
||||
{
|
||||
const int len = MIN( bytesLeft, buflen );
|
||||
success = !tr_ioRead( tor, pieceIndex, offset, len, buffer );
|
||||
success = !tr_cacheReadBlock( tor->session->cache, tor, pieceIndex, offset, len, buffer );
|
||||
if( !success )
|
||||
break;
|
||||
SHA1_Update( &sha, buffer, len );
|
||||
|
@ -324,7 +330,7 @@ recalculateHash( tr_torrent * tor,
|
|||
if( success )
|
||||
SHA1_Final( setme, &sha );
|
||||
|
||||
tr_sessionReleaseBuffer( tor->session );
|
||||
tr_free( buffer );
|
||||
return success;
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "bandwidth.h"
|
||||
#include "bencode.h"
|
||||
#include "blocklist.h"
|
||||
#include "cache.h"
|
||||
#include "clients.h"
|
||||
#include "completion.h"
|
||||
#include "crypto.h"
|
||||
|
@ -1498,9 +1499,13 @@ peerCallbackFunc( void * vpeer, void * vevent, void * vt )
|
|||
|
||||
for( fileIndex=0; fileIndex<tor->info.fileCount; ++fileIndex ) {
|
||||
const tr_file * file = &tor->info.files[fileIndex];
|
||||
if( ( file->firstPiece <= p ) && ( p <= file->lastPiece ) )
|
||||
if( tr_cpFileIsComplete( &tor->completion, fileIndex ) )
|
||||
if( ( file->firstPiece <= p ) && ( p <= file->lastPiece ) ) {
|
||||
if( tr_cpFileIsComplete( &tor->completion, fileIndex ) ) {
|
||||
fprintf( stderr, "flushing complete file %d (%s)\n", fileIndex, tor->info.files[fileIndex].name );
|
||||
tr_cacheFlushFile( tor->session->cache, tor, fileIndex );
|
||||
tr_torrentFileCompleted( tor, fileIndex );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pieceListRemovePiece( t, p );
|
||||
|
|
|
@ -22,9 +22,9 @@
|
|||
|
||||
#include "transmission.h"
|
||||
#include "bencode.h"
|
||||
#include "cache.h"
|
||||
#include "completion.h"
|
||||
#include "crypto.h"
|
||||
#include "inout.h"
|
||||
#ifdef WIN32
|
||||
#include "net.h" /* for ECONN */
|
||||
#endif
|
||||
|
@ -1211,7 +1211,7 @@ prefetchPieces( tr_peermsgs *msgs )
|
|||
for( i=msgs->prefetchCount; i<msgs->peer->pendingReqsToClient && i<12; ++i )
|
||||
{
|
||||
const struct peer_request * req = msgs->peerAskedFor + i;
|
||||
tr_ioPrefetch( msgs->torrent, req->index, req->offset, req->length );
|
||||
tr_cachePrefetchBlock( getSession(msgs)->cache, msgs->torrent, req->index, req->offset, req->length );
|
||||
++msgs->prefetchCount;
|
||||
}
|
||||
}
|
||||
|
@ -1601,7 +1601,7 @@ clientGotBlock( tr_peermsgs * msgs,
|
|||
*** Save the block
|
||||
**/
|
||||
|
||||
if(( err = tr_ioWrite( tor, req->index, req->offset, req->length, data )))
|
||||
if(( err = tr_cacheWriteBlock( getSession(msgs)->cache, tor, req->index, req->offset, req->length, data )))
|
||||
return err;
|
||||
|
||||
addPeerToBlamefield( msgs, req->index );
|
||||
|
@ -1913,7 +1913,7 @@ fillOutputBuffer( tr_peermsgs * msgs, time_t now )
|
|||
tr_peerIoWriteUint32( io, out, req.index );
|
||||
tr_peerIoWriteUint32( io, out, req.offset );
|
||||
|
||||
err = tr_ioRead( msgs->torrent, req.index, req.offset, req.length, EVBUFFER_DATA(out)+EVBUFFER_LENGTH(out) );
|
||||
err = tr_cacheReadBlock( getSession(msgs)->cache, msgs->torrent, req.index, req.offset, req.length, EVBUFFER_DATA(out)+EVBUFFER_LENGTH(out) );
|
||||
if( err )
|
||||
{
|
||||
if( fext )
|
||||
|
|
|
@ -102,7 +102,7 @@ tr_ptrArrayPop( tr_ptrArray* t )
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
void
|
||||
tr_ptrArrayErase( tr_ptrArray * t,
|
||||
int begin,
|
||||
int end )
|
||||
|
@ -123,7 +123,7 @@ tr_ptrArrayErase( tr_ptrArray * t,
|
|||
***
|
||||
**/
|
||||
|
||||
static int
|
||||
int
|
||||
tr_ptrArrayLowerBound( const tr_ptrArray * t,
|
||||
const void * ptr,
|
||||
int compare( const void *,
|
||||
|
@ -184,7 +184,7 @@ tr_ptrArrayInsertSorted( tr_ptrArray * t,
|
|||
const int pos = tr_ptrArrayLowerBound( t, ptr, compare, NULL );
|
||||
const int ret = tr_ptrArrayInsert( t, ptr, pos );
|
||||
|
||||
assertSortedAndUnique( t, compare );
|
||||
//assertSortedAndUnique( t, compare );
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -65,6 +65,9 @@ static inline void* tr_ptrArrayBack( tr_ptrArray * array )
|
|||
: NULL;
|
||||
}
|
||||
|
||||
void tr_ptrArrayErase( tr_ptrArray * t, int begin, int end );
|
||||
|
||||
|
||||
|
||||
/** @brief Peek at the array pointer and its size, for easy iteration */
|
||||
void** tr_ptrArrayPeek( tr_ptrArray * array, int * size );
|
||||
|
@ -100,6 +103,11 @@ static inline tr_bool tr_ptrArrayEmpty( const tr_ptrArray * a )
|
|||
return tr_ptrArraySize(a) == 0;
|
||||
}
|
||||
|
||||
int tr_ptrArrayLowerBound( const tr_ptrArray * array,
|
||||
const void * key,
|
||||
int compare( const void * arrayItem, const void * key ),
|
||||
tr_bool * exact_match );
|
||||
|
||||
/** @brief Insert a pointer into the array at the position determined by the sort function
|
||||
@return the index of the stored pointer */
|
||||
int tr_ptrArrayInsertSorted( tr_ptrArray * array,
|
||||
|
|
|
@ -1184,6 +1184,8 @@ sessionSet( tr_session * session,
|
|||
|
||||
assert( idle_data == NULL );
|
||||
|
||||
if( tr_bencDictFindReal( args_in, TR_PREFS_KEY_MAX_CACHE_SIZE_MiB, &d ) )
|
||||
tr_sessionSetCacheLimit( session, d );
|
||||
if( tr_bencDictFindInt( args_in, TR_PREFS_KEY_ALT_SPEED_UP, &i ) )
|
||||
tr_sessionSetAltSpeed( session, TR_UP, i );
|
||||
if( tr_bencDictFindInt( args_in, TR_PREFS_KEY_ALT_SPEED_DOWN, &i ) )
|
||||
|
@ -1323,6 +1325,7 @@ sessionGet( tr_session * s,
|
|||
tr_bencDictAddInt ( d, TR_PREFS_KEY_ALT_SPEED_TIME_DAY,tr_sessionGetAltSpeedDay(s) );
|
||||
tr_bencDictAddBool( d, TR_PREFS_KEY_ALT_SPEED_TIME_ENABLED, tr_sessionUsesAltSpeedTime(s) );
|
||||
tr_bencDictAddBool( d, TR_PREFS_KEY_BLOCKLIST_ENABLED, tr_blocklistIsEnabled( s ) );
|
||||
tr_bencDictAddReal( d, TR_PREFS_KEY_MAX_CACHE_SIZE_MiB, tr_sessionGetCacheLimit( s ) );
|
||||
tr_bencDictAddInt ( d, "blocklist-size", tr_blocklistGetRuleCount( s ) );
|
||||
tr_bencDictAddStr ( d, "config-dir", tr_sessionGetConfigDir( s ) );
|
||||
tr_bencDictAddStr ( d, TR_PREFS_KEY_DOWNLOAD_DIR, tr_sessionGetDownloadDir( s ) );
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "bandwidth.h"
|
||||
#include "bencode.h"
|
||||
#include "blocklist.h"
|
||||
#include "cache.h"
|
||||
#include "crypto.h"
|
||||
#include "fdlimit.h"
|
||||
#include "list.h"
|
||||
|
@ -51,7 +52,9 @@
|
|||
|
||||
enum
|
||||
{
|
||||
SAVE_INTERVAL_SECS = 120
|
||||
SAVE_INTERVAL_SECS = 120,
|
||||
|
||||
DEFAULT_CACHE_SIZE_MiB = 2 /* 2 MiB */
|
||||
};
|
||||
|
||||
|
||||
|
@ -242,8 +245,9 @@ tr_sessionGetDefaultSettings( const char * configDir UNUSED, tr_benc * d )
|
|||
{
|
||||
assert( tr_bencIsDict( d ) );
|
||||
|
||||
tr_bencDictReserve( d, 35 );
|
||||
tr_bencDictReserve( d, 60 );
|
||||
tr_bencDictAddBool( d, TR_PREFS_KEY_BLOCKLIST_ENABLED, FALSE );
|
||||
tr_bencDictAddReal( d, TR_PREFS_KEY_MAX_CACHE_SIZE_MiB, DEFAULT_CACHE_SIZE_MiB );
|
||||
tr_bencDictAddBool( d, TR_PREFS_KEY_DHT_ENABLED, TRUE );
|
||||
tr_bencDictAddBool( d, TR_PREFS_KEY_LPD_ENABLED, FALSE );
|
||||
tr_bencDictAddStr ( d, TR_PREFS_KEY_DOWNLOAD_DIR, tr_getDefaultDownloadDir( ) );
|
||||
|
@ -307,8 +311,9 @@ tr_sessionGetSettings( tr_session * s, struct tr_benc * d )
|
|||
{
|
||||
assert( tr_bencIsDict( d ) );
|
||||
|
||||
tr_bencDictReserve( d, 30 );
|
||||
tr_bencDictReserve( d, 60 );
|
||||
tr_bencDictAddBool( d, TR_PREFS_KEY_BLOCKLIST_ENABLED, tr_blocklistIsEnabled( s ) );
|
||||
tr_bencDictAddReal( d, TR_PREFS_KEY_MAX_CACHE_SIZE_MiB, tr_cacheGetLimit( s->cache ) );
|
||||
tr_bencDictAddBool( d, TR_PREFS_KEY_DHT_ENABLED, s->isDHTEnabled );
|
||||
tr_bencDictAddBool( d, TR_PREFS_KEY_LPD_ENABLED, s->isLPDEnabled );
|
||||
tr_bencDictAddStr ( d, TR_PREFS_KEY_DOWNLOAD_DIR, s->downloadDir );
|
||||
|
@ -506,6 +511,7 @@ tr_sessionInit( const char * tag,
|
|||
session = tr_new0( tr_session, 1 );
|
||||
session->bandwidth = tr_bandwidthNew( session, NULL );
|
||||
session->lock = tr_lockNew( );
|
||||
session->cache = tr_cacheNew( DEFAULT_CACHE_SIZE_MiB );
|
||||
session->tag = tr_strdup( tag );
|
||||
session->magicNumber = SESSION_MAGIC_NUMBER;
|
||||
session->buffer = tr_valloc( SESSION_BUFFER_SIZE );
|
||||
|
@ -671,6 +677,8 @@ sessionSetImpl( void * vdata )
|
|||
}
|
||||
|
||||
/* misc features */
|
||||
if( tr_bencDictFindReal( settings, TR_PREFS_KEY_MAX_CACHE_SIZE_MiB, &d ) )
|
||||
tr_sessionSetCacheLimit( session, d );
|
||||
if( tr_bencDictFindBool( settings, TR_PREFS_KEY_LAZY_BITFIELD, &boolVal ) )
|
||||
tr_sessionSetLazyBitfieldEnabled( session, boolVal );
|
||||
if( tr_bencDictFindInt( settings, TR_PREFS_KEY_PEER_LIMIT_TORRENT, &i ) )
|
||||
|
@ -1605,6 +1613,8 @@ sessionCloseImpl( void * vsession )
|
|||
tr_torrentFree( torrents[i] );
|
||||
tr_free( torrents );
|
||||
|
||||
tr_cacheFree( session->cache );
|
||||
session->cache = NULL;
|
||||
tr_announcerClose( session );
|
||||
tr_statsClose( session );
|
||||
tr_peerMgrFree( session->peerMgr );
|
||||
|
@ -1838,6 +1848,26 @@ tr_sessionAllowsLPD( const tr_session * session )
|
|||
****
|
||||
***/
|
||||
|
||||
void
|
||||
tr_sessionSetCacheLimit( tr_session * session, double maxMiB )
|
||||
{
|
||||
assert( tr_isSession( session ) );
|
||||
|
||||
tr_cacheSetLimit( session->cache, maxMiB );
|
||||
}
|
||||
|
||||
double
|
||||
tr_sessionGetCacheLimit( const tr_session * session )
|
||||
{
|
||||
assert( tr_isSession( session ) );
|
||||
|
||||
return tr_cacheGetLimit( session->cache );
|
||||
}
|
||||
|
||||
/***
|
||||
****
|
||||
***/
|
||||
|
||||
void
|
||||
tr_sessionSetLazyBitfieldEnabled( tr_session * session,
|
||||
tr_bool enabled )
|
||||
|
|
|
@ -40,6 +40,7 @@ struct tr_address;
|
|||
struct tr_announcer;
|
||||
struct tr_bandwidth;
|
||||
struct tr_bindsockets;
|
||||
struct tr_cache;
|
||||
struct tr_fdInfo;
|
||||
|
||||
struct tr_turtle_info
|
||||
|
@ -149,6 +150,8 @@ struct tr_session
|
|||
struct tr_peerMgr * peerMgr;
|
||||
struct tr_shared * shared;
|
||||
|
||||
struct tr_cache * cache;
|
||||
|
||||
struct tr_lock * lock;
|
||||
|
||||
struct tr_web * web;
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "announcer.h"
|
||||
#include "bandwidth.h"
|
||||
#include "bencode.h"
|
||||
#include "cache.h"
|
||||
#include "completion.h"
|
||||
#include "crypto.h" /* for tr_sha1 */
|
||||
#include "resume.h"
|
||||
|
@ -1516,6 +1517,7 @@ stopTorrent( void * vtor )
|
|||
tr_verifyRemove( tor );
|
||||
tr_peerMgrStopTorrent( tor );
|
||||
tr_announcerTorrentStopped( tor );
|
||||
tr_cacheFlushTorrent( tor->session->cache, tor );
|
||||
|
||||
tr_fdTorrentClose( tor->session, tor->uniqueId );
|
||||
|
||||
|
|
|
@ -163,6 +163,7 @@ const char* tr_getDefaultDownloadDir( void );
|
|||
#define TR_PREFS_KEY_BIND_ADDRESS_IPV4 "bind-address-ipv4"
|
||||
#define TR_PREFS_KEY_BIND_ADDRESS_IPV6 "bind-address-ipv6"
|
||||
#define TR_PREFS_KEY_BLOCKLIST_ENABLED "blocklist-enabled"
|
||||
#define TR_PREFS_KEY_MAX_CACHE_SIZE_MiB "cache-size-MiB"
|
||||
#define TR_PREFS_KEY_DHT_ENABLED "dht-enabled"
|
||||
#define TR_PREFS_KEY_LPD_ENABLED "lpd-enabled"
|
||||
#define TR_PREFS_KEY_DOWNLOAD_DIR "download-dir"
|
||||
|
@ -586,26 +587,23 @@ void tr_sessionClearStats( tr_session * session );
|
|||
* PEX is always disabled in private torrents regardless of this.
|
||||
* In public torrents, PEX is enabled by default.
|
||||
*/
|
||||
void tr_sessionSetPexEnabled( tr_session * session, tr_bool isEnabled );
|
||||
void tr_sessionSetPexEnabled( tr_session * session, tr_bool isEnabled );
|
||||
tr_bool tr_sessionIsPexEnabled( const tr_session * session );
|
||||
|
||||
tr_bool tr_sessionIsPexEnabled( const tr_session * session );
|
||||
tr_bool tr_sessionIsDHTEnabled( const tr_session * session );
|
||||
void tr_sessionSetDHTEnabled( tr_session * session, tr_bool );
|
||||
|
||||
tr_bool tr_sessionIsDHTEnabled( const tr_session * session );
|
||||
tr_bool tr_sessionIsLPDEnabled( const tr_session * session );
|
||||
void tr_sessionSetLPDEnabled( tr_session * session, tr_bool enabled );
|
||||
|
||||
void tr_sessionSetDHTEnabled( tr_session * session, tr_bool );
|
||||
void tr_sessionSetCacheLimit( tr_session * session, double MiB );
|
||||
double tr_sessionGetCacheLimit( const tr_session * session );
|
||||
|
||||
tr_bool tr_sessionIsLPDEnabled( const tr_session * session );
|
||||
|
||||
void tr_sessionSetLPDEnabled( tr_session * session, tr_bool enabled );
|
||||
|
||||
void tr_sessionSetLazyBitfieldEnabled( tr_session * session,
|
||||
tr_bool enabled );
|
||||
|
||||
tr_bool tr_sessionIsLazyBitfieldEnabled( const tr_session * session );
|
||||
void tr_sessionSetLazyBitfieldEnabled( tr_session * session, tr_bool enabled );
|
||||
tr_bool tr_sessionIsLazyBitfieldEnabled( const tr_session * session );
|
||||
|
||||
tr_encryption_mode tr_sessionGetEncryption( tr_session * session );
|
||||
|
||||
void tr_sessionSetEncryption( tr_session * session,
|
||||
void tr_sessionSetEncryption( tr_session * session,
|
||||
tr_encryption_mode mode );
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue