Ignore:
Timestamp:
Dec 9, 2010, 8:43:23 PM (11 years ago)
Author:
charles
Message:

(trunk libT) #2955 "Lazy Verification (aka Just-in-Time Verification)" -- implemented.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/libtransmission/verify.c

    r11398 r11506  
    1111 */
    1212
    13 #include <unistd.h> /* S_ISREG */
    14 #include <sys/stat.h>
    15 
    1613#ifdef HAVE_POSIX_FADVISE
    1714 #define _XOPEN_SOURCE 600
    18 #endif
    19 #if defined(HAVE_POSIX_FADVISE) || defined(SYS_DARWIN)
    20  #include <fcntl.h> /* posix_fadvise() / fcntl() */
     15 #include <fcntl.h> /* posix_fadvise() */
    2116#endif
    2217
     
    2621#include "completion.h"
    2722#include "fdlimit.h"
    28 #include "inout.h"
    2923#include "list.h"
    30 #include "platform.h"
     24#include "platform.h" /* tr_lock() */
    3125#include "torrent.h"
    32 #include "utils.h" /* tr_buildPath */
     26#include "utils.h" /* tr_valloc(), tr_free() */
    3327#include "verify.h"
    34 
    3528
    3629/***
     
    4336};
    4437
    45 /* #define STOPWATCH */
    46 
    4738static tr_bool
    4839verifyTorrent( tr_torrent * tor, tr_bool * stopFlag )
    4940{
     41    time_t end;
    5042    SHA_CTX sha;
    5143    int fd = -1;
     
    5951    tr_piece_index_t pieceIndex = 0;
    6052    const time_t begin = tr_time( );
    61     time_t end;
    6253    const size_t buflen = 1024 * 128; /* 128 KiB buffer */
    6354    uint8_t * buffer = tr_valloc( buflen );
    6455
    65     tr_torrentUncheck( tor );
    66 
    6756    SHA1_Init( &sha );
    6857
     58    tr_tordbg( tor, "%s", "[LAZY] verifying torrent..." );
     59    tr_torrentSetChecked( tor, 0 );
    6960    while( !*stopFlag && ( pieceIndex < tor->info.pieceCount ) )
    7061    {
     
    7667        /* if we're starting a new piece... */
    7768        if( piecePos == 0 )
    78         {
    7969            hadPiece = tr_cpPieceIsComplete( &tor->completion, pieceIndex );
    80             /* fprintf( stderr, "starting piece %d of %d\n", (int)pieceIndex, (int)tor->info.pieceCount ); */
    81         }
    8270
    8371        /* if we're starting a new file... */
     
    8674            char * filename = tr_torrentFindFile( tor, fileIndex );
    8775            fd = filename == NULL ? -1 : tr_open_file_for_scanning( filename );
    88             /* fprintf( stderr, "opening file #%d (%s) -- %d\n", fileIndex, filename, fd ); */
    8976            tr_free( filename );
    9077            prevFileIndex = fileIndex;
     
    9683        bytesThisPass = MIN( leftInFile, leftInPiece );
    9784        bytesThisPass = MIN( bytesThisPass, buflen );
    98         /* fprintf( stderr, "reading this pass: %d\n", (int)bytesThisPass ); */
    9985
    10086        /* read a bit */
     
    125111            SHA1_Final( hash, &sha );
    126112            hasPiece = !memcmp( hash, tor->info.pieces[pieceIndex].hash, SHA_DIGEST_LENGTH );
    127             /* fprintf( stderr, "do the hashes match? %s\n", (hasPiece?"yes":"no") ); */
    128 
    129             if( hasPiece ) {
    130                 tr_torrentSetHasPiece( tor, pieceIndex, TRUE );
    131                 if( !hadPiece )
    132                     changed = TRUE;
    133             } else if( hadPiece ) {
    134                 tr_torrentSetHasPiece( tor, pieceIndex, FALSE );
    135                 changed = TRUE;
     113
     114            if( hasPiece || hadPiece ) {
     115                tr_torrentSetHasPiece( tor, pieceIndex, hasPiece );
     116                changed |= hasPiece != hadPiece;
    136117            }
    137             tr_torrentSetPieceChecked( tor, pieceIndex, TRUE );
     118            tr_torrentSetPieceChecked( tor, pieceIndex );
    138119            now = tr_time( );
    139120            tor->anyDate = now;
     
    154135        if( leftInFile == 0 )
    155136        {
    156             /* fprintf( stderr, "closing file\n" ); */
    157137            if( fd >= 0 ) { tr_close_file( fd ); fd = -1; }
    158138            ++fileIndex;
     
    160140        }
    161141    }
     142    tr_tordbg( tor, "%s", "[LAZY] DONE verifying torrent..." );
    162143
    163144    /* cleanup */
     
    169150    end = tr_time( );
    170151    tr_tordbg( tor, "it took %d seconds to verify %"PRIu64" bytes (%"PRIu64" bytes per second)",
    171                (int)(end-begin), tor->info.totalSize, (uint64_t)(tor->info.totalSize/(1+(end-begin))) );
     152               (int)(end-begin), tor->info.totalSize,
     153               (uint64_t)(tor->info.totalSize/(1+(end-begin))) );
    172154
    173155    return changed;
     
    203185{
    204186    static tr_lock * lock = NULL;
    205 
    206187    if( lock == NULL )
    207188        lock = tr_lockNew( );
     
    214195    for( ;; )
    215196    {
    216         int                  changed = 0;
    217         tr_torrent         * tor;
     197        int changed = 0;
     198        tr_torrent * tor;
    218199        struct verify_node * node;
    219200
     
    251232}
    252233
    253 static uint64_t
    254 getCurrentSize( tr_torrent * tor )
    255 {
    256     tr_file_index_t i;
    257     uint64_t byte_count = 0;
    258     const tr_file_index_t n = tor->info.fileCount;
    259 
    260     for( i=0; i<n; ++i )
    261     {
    262         struct stat sb;
    263         char * filename = tr_torrentFindFile( tor, i );
    264 
    265         sb.st_size = 0;
    266         if( filename && !stat( filename, &sb ) )
    267             byte_count += sb.st_size;
    268 
    269         tr_free( filename );
    270     }
    271 
    272     return byte_count;
    273 }
    274 
    275234static int
    276235compareVerifyByPriorityAndSize( const void * va, const void * vb )
     
    280239
    281240    /* higher priority comes before lower priority */
    282     const tr_priority_t pa =  tr_torrentGetPriority( a->torrent );
    283     const tr_priority_t pb =  tr_torrentGetPriority( b->torrent );
     241    const tr_priority_t pa = tr_torrentGetPriority( a->torrent );
     242    const tr_priority_t pb = tr_torrentGetPriority( b->torrent );
    284243    if( pa != pb )
    285244        return pa > pb ? -1 : 1;
    286245
    287     /* smaller size comes before larger size... smaller sizes are faster to verify */
     246    /* smaller torrents come before larger ones because they verify faster */
    288247    if( a->current_size < b->current_size ) return -1;
    289248    if( a->current_size > b->current_size ) return  1;
     
    292251
    293252void
    294 tr_verifyAdd( tr_torrent *      tor,
    295               tr_verify_done_cb verify_done_cb )
    296 {
     253tr_verifyAdd( tr_torrent * tor, tr_verify_done_cb verify_done_cb )
     254{
     255    struct verify_node * node;
     256
    297257    assert( tr_isTorrent( tor ) );
    298 
    299     if( tr_torrentCountUncheckedPieces( tor ) == 0 )
    300     {
    301         /* doesn't need to be checked... */
    302         fireCheckDone( tor, verify_done_cb );
    303     }
    304     else
    305     {
    306         const uint64_t current_size = getCurrentSize( tor );
    307 
    308         if( !current_size )
    309         {
    310             /* we haven't downloaded anything for this torrent yet...
    311              * no need to leave it waiting in the back of the queue.
    312              * we can mark it as all-missing from here and fire
    313              * the "done" callback */
    314             const tr_bool hadAny = tr_cpHaveTotal( &tor->completion ) != 0;
    315             tr_piece_index_t i;
    316             for( i=0; i<tor->info.pieceCount; ++i ) {
    317                 tr_torrentSetHasPiece( tor, i, FALSE );
    318                 tr_torrentSetPieceChecked( tor, i, TRUE );
    319             }
    320             if( hadAny ) /* if we thought we had some, flag as dirty */
    321                 tr_torrentSetDirty( tor );
    322             fireCheckDone( tor, verify_done_cb );
    323         }
    324         else
    325         {
    326             struct verify_node * node;
    327 
    328             tr_torinf( tor, "%s", _( "Queued for verification" ) );
    329 
    330             node = tr_new( struct verify_node, 1 );
    331             node->torrent = tor;
    332             node->verify_done_cb = verify_done_cb;
    333             node->current_size = current_size;
    334 
    335             tr_lockLock( getVerifyLock( ) );
    336             tr_torrentSetVerifyState( tor, TR_VERIFY_WAIT );
    337             tr_list_insert_sorted( &verifyList, node, compareVerifyByPriorityAndSize );
    338             if( verifyThread == NULL )
    339                 verifyThread = tr_threadNew( verifyThreadFunc, NULL );
    340             tr_lockUnlock( getVerifyLock( ) );
    341         }
    342     }
     258    tr_torinf( tor, "%s", _( "Queued for verification" ) );
     259
     260    node = tr_new( struct verify_node, 1 );
     261    node->torrent = tor;
     262    node->verify_done_cb = verify_done_cb;
     263    node->current_size = tr_torrentGetCurrentSizeOnDisk( tor );
     264
     265    tr_lockLock( getVerifyLock( ) );
     266    tr_torrentSetVerifyState( tor, TR_VERIFY_WAIT );
     267    tr_list_insert_sorted( &verifyList, node, compareVerifyByPriorityAndSize );
     268    if( verifyThread == NULL )
     269        verifyThread = tr_threadNew( verifyThreadFunc, NULL );
     270    tr_lockUnlock( getVerifyLock( ) );
    343271}
    344272
Note: See TracChangeset for help on using the changeset viewer.