Changeset 10978 for trunk/libtransmission/cache.c
- Timestamp:
- Jul 8, 2010, 5:38:11 PM (12 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/libtransmission/cache.c
r10937 r10978 64 64 struct run_info 65 65 { 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; 68 72 }; 69 73 … … 88 92 //fprintf( stderr, "run is %d long from [%d to %d)\n", (int)(i-pos), i, (int)pos ); 89 93 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; 92 100 } 93 101 … … 95 103 } 96 104 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. 105 static int 106 compareRuns( 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 113 enum 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. 100 121 */ 101 static int102 findChunk2Discard( tr_cache * cache, int * setme_n)122 static void 123 calcRuns( tr_cache * cache, struct run_info * runs ) 103 124 { 104 125 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 154 static int 155 flushContiguous( tr_cache * cache, int pos, int n, int rank ) 159 156 { 160 157 int i; … … 181 178 182 179 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) ); 184 181 //fprintf( stderr, "%s - Writing to disk piece %d, offset %d, len %d\n", tr_torrentName(tor), (int)piece, (int)offset, (int)(walk-buf) ); 185 182 //fprintf( stderr, "%s - Removing %d blocks from cache; %d left\n", MY_NAME, n, tr_ptrArraySize(&cache->blocks) ); … … 194 191 195 192 static int 193 flushRuns( 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 208 static int 196 209 cacheTrim( tr_cache * cache ) 197 210 { 198 211 int err = 0; 199 212 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 ); 205 226 } 206 227 … … 371 392 } 372 393 394 int 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 373 413 int 374 414 tr_cacheFlushFile( tr_cache * cache, tr_torrent * torrent, tr_file_index_t i ) … … 387 427 if( b->tor != torrent ) break; 388 428 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 ); 390 430 } 391 431 … … 404 444 const struct cache_block * b = tr_ptrArrayNth( &cache->blocks, pos ); 405 445 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.