Changeset 10978


Ignore:
Timestamp:
Jul 8, 2010, 5:38:11 PM (12 years ago)
Author:
charles
Message:

(trunk libT) #1521 "memory cache to reduce disk IO" -- apply Longinus' libt_fixCache.patch version 3

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/libtransmission/cache.c

    r10937 r10978  
    6464struct run_info
    6565{
    66   time_t  last_block_time;
    67   tr_bool is_aligned;
     66  int       pos;
     67  int       rank;
     68  time_t    last_block_time;
     69  tr_bool   is_multi_piece;
     70  tr_bool   is_piece_done;
     71  unsigned  len;
    6872};
    6973
     
    8892//fprintf( stderr, "run is %d long from [%d to %d)\n", (int)(i-pos), i, (int)pos );
    8993    if( info != NULL ) {
    90         info->last_block_time = blocks[i-1]->time;
    91         info->is_aligned = (blocks[pos]->block % 2 == 0) ? TRUE : FALSE;
     94        const struct cache_block * b = blocks[i-1];
     95        info->last_block_time = b->time;
     96        info->is_piece_done = tr_cpPieceIsComplete( &b->tor->completion, b->piece );
     97        info->is_multi_piece = b->piece != blocks[pos]->piece ? TRUE : FALSE;
     98        info->len = i - pos;
     99        info->pos = pos;
    92100    }
    93101
     
    95103}
    96104
    97 /* return the starting index of the longest contiguous run of blocks BUT:
    98  *   - Run should begin with a even block and length of run should be even.
    99  *   - Oldest run is preferred.
     105static int
     106compareRuns( const void * va, const void * vb )
     107{
     108    const struct run_info a = *(const struct run_info*)va;
     109    const struct run_info b = *(const struct run_info*)vb;
     110    return b.rank - a.rank;
     111}
     112
     113enum
     114{
     115    MULTIFLAG   = 0x1000,
     116    DONEFLAG    = 0x2000,
     117    SESSIONFLAG = 0x4000
     118};
     119/* Calculte runs
     120 *   - Stale runs, runs sitting in cache for a long time or runs not growing, get priority.
    100121 */
    101 static int
    102 findChunk2Discard( tr_cache * cache, int * setme_n )
     122static void
     123calcRuns( tr_cache * cache, struct run_info * runs )
    103124{
    104125    const int n = tr_ptrArraySize( &cache->blocks );
    105     int pos;
    106     int bestpos = 0;
    107     unsigned bestlen = 1;
    108     unsigned jump;
    109     time_t oldest_time = tr_time() + 1;
    110     struct run_info run;
    111 
    112     for( pos=0; pos<n; pos+=jump )
    113     {
    114         unsigned len = getBlockRun( cache, pos, &run );
    115         jump = len;
    116 
    117         /* shortcut */
    118         if( len < bestlen )
    119             continue;
    120 
    121         /* check alignment */
    122         if( len % 2 == 0 ) {
    123             if( !run.is_aligned ) {
    124                 /* Let it grow. Otherwise we contribute to fragmentation */
    125                 if( bestlen == 1) {
    126                     /* But if all other blocks are non-contiguous, we prefer this one */
    127                     bestpos = pos;
    128                     oldest_time = cache->max_blocks - len;
    129                 }
    130                 continue;
    131             }
    132         } else {
    133             if( len != 1 ) {
    134                 --len;
    135                 if( !run.is_aligned ) {
    136                     ++pos;
    137                     --jump;
    138                 }
    139             }
    140         }
    141 
    142         if( bestlen < len ) {
    143             bestlen = len;
    144             bestpos = pos;
    145             oldest_time = run.last_block_time;
    146         } else if( (bestlen == len) && (oldest_time > run.last_block_time) ) {
    147             bestpos = pos;
    148             oldest_time = run.last_block_time;
    149         }
    150     }
    151 
    152 //fprintf( stderr, "DISCARDED run is %d long from [%d to %d)\n", bestlen, bestpos, bestpos+bestlen );
    153     *setme_n = bestlen;
    154     return bestpos;
    155 }
    156 
    157 static int
    158 flushContiguous( tr_cache * cache, int pos, int n )
     126    int i = 0, pos;
     127    const time_t now = tr_time();
     128
     129    for( pos = 0; pos < n; pos += runs[i++].len )
     130    {
     131        int rank = getBlockRun( cache, pos, &runs[i] );
     132
     133        /* This adds ~2 to the relative length of a run for every minute it has
     134         * languished in the cache. */
     135        rank += ( now - runs[i].last_block_time ) / 32;
     136
     137        /* Flushing stale blocks should be a top priority as the probability of them
     138         * growing is very small, for blocks on piece boundaries, and nonexistant for
     139         * blocks inside pieces. */
     140        rank |= runs[i].is_piece_done ? DONEFLAG : 0;
     141
     142        /* Move the multi piece runs higher */
     143        rank |= runs[i].is_multi_piece ? MULTIFLAG : 0;
     144
     145        runs[i].rank = rank;
     146//fprintf(stderr,"block run at pos %d of length %d and age %ld adjusted +%d\n",runs[i].pos,runs[i].len,now-runs[i].last_block_time,rank-runs[i].len);
     147    }
     148
     149    //fprintf( stderr, "%d block runs\n", i-1 );
     150    qsort( runs, i, sizeof( struct run_info ), compareRuns );
     151    //return i;
     152}
     153
     154static int
     155flushContiguous( tr_cache * cache, int pos, int n, int rank )
    159156{
    160157    int i;
     
    181178
    182179    tr_tordbg( tor, "Writing to disk piece %d, offset %d, len %d", (int)piece, (int)offset, (int)(walk-buf) );
    183     tr_ndbg( MY_NAME, "Removing %d blocks from cache; %d left", n, tr_ptrArraySize(&cache->blocks) );
     180    tr_ndbg( MY_NAME, "Removing %d blocks from cache, rank: %d - %d left", n, rank, tr_ptrArraySize(&cache->blocks) );
    184181    //fprintf( stderr, "%s - Writing to disk piece %d, offset %d, len %d\n", tr_torrentName(tor), (int)piece, (int)offset, (int)(walk-buf) );
    185182    //fprintf( stderr, "%s - Removing %d blocks from cache; %d left\n", MY_NAME, n, tr_ptrArraySize(&cache->blocks) );
     
    194191
    195192static int
     193flushRuns( tr_cache * cache, struct run_info * runs, int n )
     194{
     195    int i, j, err = 0;
     196
     197    for( i = 0; !err && i < n; ++i )
     198    {
     199        err = flushContiguous( cache, runs[i].pos, runs[i].len, runs[i].rank );
     200        for( j = i + 1; j < n; ++j )
     201            if( runs[j].pos > runs[i].pos )
     202                runs[j].pos -= runs[i].len;
     203    }
     204
     205    return err;
     206}
     207
     208static int
    196209cacheTrim( tr_cache * cache )
    197210{
    198211    int err = 0;
    199212
    200     while( !err && ( tr_ptrArraySize( &cache->blocks ) > cache->max_blocks ) )
    201     {
    202         int n;
    203         const int i = findChunk2Discard( cache, &n );
    204         err = flushContiguous( cache, i, n );
     213    if( tr_ptrArraySize( &cache->blocks ) > cache->max_blocks )
     214    {
     215        /* Amount of cache that should be removed by the flush. This influences how large
     216         * runs can grow as well as how often flushes will happen. */
     217        const int cacheCutoff = 1 + cache->max_blocks / 4;
     218        struct run_info * runs = tr_new( struct run_info, tr_ptrArraySize( &cache->blocks ) );
     219        int i = 0, j = 0;
     220
     221        calcRuns( cache, runs );
     222        while( j < cacheCutoff )
     223            j += runs[i++].len;
     224        err = flushRuns( cache, runs, i );
     225        tr_free( runs );
    205226    }
    206227
     
    371392}
    372393
     394int tr_cacheFlushDone( tr_cache * cache )
     395{
     396    int err = 0;
     397
     398    if( tr_ptrArraySize( &cache->blocks ) > 0 )
     399    {
     400        struct run_info * runs = tr_new0( struct run_info, tr_ptrArraySize( &cache->blocks ) );
     401        int i = 0;
     402
     403        calcRuns( cache, runs );
     404        while( runs[i].is_piece_done || runs[i].is_multi_piece )
     405            runs[i++].rank |= SESSIONFLAG;
     406        err = flushRuns( cache, runs, i );
     407        tr_free( runs );
     408    }
     409
     410    return err;
     411}
     412
    373413int
    374414tr_cacheFlushFile( tr_cache * cache, tr_torrent * torrent, tr_file_index_t i )
     
    387427        if( b->tor != torrent ) break;
    388428        if( ( b->block < begin ) || ( b->block >= end ) ) break;
    389         err = flushContiguous( cache, pos, getBlockRun( cache, pos, NULL ) );
     429        err = flushContiguous( cache, pos, getBlockRun( cache, pos, NULL ), 0 );
    390430    }
    391431
     
    404444        const struct cache_block * b = tr_ptrArrayNth( &cache->blocks, pos );
    405445        if( b->tor != torrent ) break;
    406         err = flushContiguous( cache, pos, getBlockRun( cache, pos, NULL ) );
    407     }
    408 
    409     return err;
    410 }
     446        err = flushContiguous( cache, pos, getBlockRun( cache, pos, NULL ), 0 );
     447    }
     448
     449    return err;
     450}
Note: See TracChangeset for help on using the changeset viewer.