Changeset 11506


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.

Location:
trunk/libtransmission
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/libtransmission/peer-mgr.c

    r11457 r11506  
    2929#include "crypto.h"
    3030#include "handshake.h"
    31 #include "inout.h" /* tr_ioTestPiece */
    3231#include "net.h"
    3332#include "peer-io.h"
     
    14541453                {
    14551454                    const tr_piece_index_t p = e->pieceIndex;
    1456                     const tr_bool ok = tr_ioTestPiece( tor, p );
     1455                    const tr_bool ok = tr_torrentCheckPiece( tor, p );
     1456
     1457                    tr_tordbg( tor, "[LAZY] checked just-completed piece %zu", (size_t)p );
    14571458
    14581459                    if( !ok )
     
    14621463                    }
    14631464
    1464                     tr_torrentSetHasPiece( tor, p, ok );
    1465                     tr_torrentSetPieceChecked( tor, p, TRUE );
    14661465                    tr_peerMgrSetBlame( tor, p, ok );
    14671466
  • trunk/libtransmission/peer-msgs.c

    r11425 r11506  
    19211921
    19221922            err = tr_cacheReadBlock( getSession(msgs)->cache, msgs->torrent, req.index, req.offset, req.length, EVBUFFER_DATA(out)+EVBUFFER_LENGTH(out) );
     1923
     1924            /* check the piece if it needs checking... */
     1925            if( !err && tr_torrentPieceNeedsCheck( msgs->torrent, req.index ) )
     1926                if(( err = !tr_torrentCheckPiece( msgs->torrent, req.index )))
     1927                    tr_torrentSetLocalError( msgs->torrent, _( "Piece #%zu is corrupt!  Please Verify Local Data." ), (size_t)piece );
     1928
    19231929            if( err )
    19241930            {
  • trunk/libtransmission/resume.c

    r11455 r11506  
    6161#define KEY_IDLELIMIT_MODE         "idle-mode"
    6262
    63 #define KEY_PROGRESS_MTIMES    "mtimes"
     63#define KEY_PROGRESS_CHECKTIME "time-checked"
    6464#define KEY_PROGRESS_BITFIELD  "bitfield"
    6565#define KEY_PROGRESS_HAVE      "have"
     
    416416{
    417417    size_t              i, n;
    418     time_t *            mtimes;
    419418    tr_benc *           p;
    420419    tr_benc *           m;
     
    424423    tr_bencInitDict( p, 2 );
    425424
    426     /* add the mtimes */
    427     mtimes = tr_torrentGetMTimes( tor, &n );
    428     m = tr_bencDictAddList( p, KEY_PROGRESS_MTIMES, n );
    429     for( i = 0; i < n; ++i )
    430     {
    431         if( !tr_torrentIsFileChecked( tor, i ) )
    432             mtimes[i] = ~(time_t)0; /* force a recheck */
    433         tr_bencListAddInt( m, mtimes[i] );
    434     }
     425    /* add each piece's timeChecked */
     426    n = tor->info.pieceCount;
     427    m = tr_bencDictAddList( p, KEY_PROGRESS_CHECKTIME, n );
     428    for( i=0; i<n; ++i )
     429        tr_bencListAddInt( m, tor->info.pieces[i].timeChecked );
    435430
    436431    /* add the progress */
     
    440435    tr_bencDictAddRaw( p, KEY_PROGRESS_BITFIELD,
    441436                       bitfield->bits, bitfield->byteCount );
    442 
    443     /* cleanup */
    444     tr_free( mtimes );
    445437}
    446438
     
    449441              tr_torrent * tor )
    450442{
     443    size_t    i, n;
    451444    uint64_t  ret = 0;
    452445    tr_benc * p;
     446
     447    for( i=0, n=tor->info.pieceCount; i<n; ++i )
     448        tor->info.pieces[i].timeChecked = 0;
    453449
    454450    if( tr_bencDictFindDict( dict, KEY_PROGRESS, &p ) )
     
    459455        size_t          rawlen;
    460456        tr_benc *       m;
    461         size_t          n;
    462         time_t *        curMTimes = tr_torrentGetMTimes( tor, &n );
    463 
    464         if( tr_bencDictFindList( p, KEY_PROGRESS_MTIMES, &m )
    465           && ( n == tor->info.fileCount )
    466           && ( n == tr_bencListSize( m ) ) )
    467         {
    468             size_t i;
    469             for( i = 0; i < n; ++i )
    470             {
    471                 int64_t tmp;
    472                 if( !tr_bencGetInt( tr_bencListChild( m, i ), &tmp ) )
    473                 {
    474                     tr_tordbg(
    475                         tor,
    476                         "File #%zu needs to be verified - couldn't find benc entry",
    477                         i );
    478                     tr_torrentSetFileChecked( tor, i, FALSE );
    479                 }
    480                 else
    481                 {
    482                     const time_t t = (time_t) tmp;
    483                     if( t == curMTimes[i] )
    484                         tr_torrentSetFileChecked( tor, i, TRUE );
    485                     else
    486                     {
    487                         tr_tordbg(
    488                             tor,
    489                             "File #%zu needs to be verified - times %lu and %lu don't match",
    490                             i, t, curMTimes[i] );
    491                         tr_torrentSetFileChecked( tor, i, FALSE );
    492                     }
    493                 }
    494             }
    495         }
    496         else
    497         {
    498             tr_torrentUncheck( tor );
    499             tr_tordbg(
    500                 tor, "Torrent needs to be verified - unable to find mtimes" );
    501         }
     457        int64_t  timeChecked;
     458
     459        /* load in the timestamp of when we last checked each piece */
     460        if( tr_bencDictFindList( p, KEY_PROGRESS_CHECKTIME, &m ) )
     461            for( i=0, n=tor->info.pieceCount; i<n; ++i )
     462                if( tr_bencGetInt( tr_bencListChild( m, i ), &timeChecked ) )
     463                    tor->info.pieces[i].timeChecked = (time_t)timeChecked;
    502464
    503465        err = NULL;
     
    519481        }
    520482        else err = "Couldn't find 'have' or 'bitfield'";
     483
    521484        if( err != NULL )
    522         {
    523             tr_torrentUncheck( tor );
    524485            tr_tordbg( tor, "Torrent needs to be verified - %s", err );
    525         }
    526 
    527         tr_free( curMTimes );
     486
    528487        ret = TR_FR_PROGRESS;
    529488    }
  • trunk/libtransmission/torrent.c

    r11301 r11506  
    3535#include "resume.h"
    3636#include "fdlimit.h" /* tr_fdTorrentClose */
     37#include "inout.h" /* tr_ioTestPiece() */
    3738#include "magnet.h"
    3839#include "metainfo.h"
     
    460461    va_end( ap );
    461462
     463    tr_torerr( tor, "%s", tor->errorString );
     464
    462465    if( tor->isRunning )
    463466        tor->isStopping = TRUE;
     
    605608tr_torrentInitFilePieces( tr_torrent * tor )
    606609{
    607     tr_file_index_t  f;
     610    int * firstFiles;
     611    tr_file_index_t f;
    608612    tr_piece_index_t p;
    609613    uint64_t offset = 0;
    610614    tr_info * inf = &tor->info;
    611     int * firstFiles;
    612615
    613616    /* assign the file offsets */
     
    721724    tr_torrentInitFilePieces( tor );
    722725
    723     tr_bitfieldConstruct( &tor->checkedPieces, tor->info.pieceCount );
    724 
    725726    tor->completeness = tr_cpGetStatus( &tor->completion );
    726727}
     
    734735
    735736    tr_torrentFireMetadataCompleted( tor );
     737}
     738
     739static tr_bool
     740setLocalErrorIfFilesDisappeared( tr_torrent * tor )
     741{
     742    const tr_bool disappeared = ( tr_cpHaveTotal( &tor->completion ) > 0 ) && ( tr_torrentGetCurrentSizeOnDisk( tor ) == 0 );
     743
     744    if( disappeared )
     745    {
     746        tr_tordbg( tor, "%s", "[LAZY] uh oh, the files disappeared" );
     747        tr_torrentSetLocalError( tor, "%s", _( "No data found!  Ensure your drives are connected or use \"Set Location\".  To re-download, remove the torrent and re-add it." ) );
     748    }
     749
     750    return disappeared;
    736751}
    737752
     
    742757    uint64_t loaded;
    743758    const char * dir;
     759    tr_bool isNewTorrent;
     760    struct stat st;
    744761    static int nextUniqueId = 1;
    745762    tr_session * session = tr_ctorGetSession( ctor );
     
    779796    assert( !tor->uploadedCur );
    780797
    781     tr_torrentUncheck( tor );
    782 
    783798    tr_torrentSetAddedDate( tor, tr_time( ) ); /* this is a default value to be
    784799                                                  overwritten by the resume file */
     
    787802    loaded = tr_torrentLoadResume( tor, ~0, ctor );
    788803    tor->completeness = tr_cpGetStatus( &tor->completion );
     804    setLocalErrorIfFilesDisappeared( tor );
    789805
    790806    tr_ctorInitTorrentPriorities( ctor, tor );
     
    829845        ++session->torrentCount;
    830846    }
     847
     848    /* if we don't have a local .torrent file already, assume the torrent is new */
     849    isNewTorrent = stat( tor->info.torrent, &st );
    831850
    832851    /* maybe save our own copy of the metainfo */
     
    846865    tor->tiers = tr_announcerAddTorrent( tor->session->announcer, tor, onTrackerResponse, NULL );
    847866
    848     if( doStart )
     867    if( isNewTorrent )
     868    {
     869        tor->startAfterVerify = doStart;
     870        tr_torrentVerify( tor );
     871    }
     872    else if( doStart )
     873    {
    849874        torrentStart( tor );
     875    }
    850876
    851877    tr_sessionUnlock( session );
     
    10491075}
    10501076
     1077static double
     1078getVerifyProgress( const tr_torrent * tor )
     1079{
     1080    tr_piece_index_t i, n;
     1081    tr_piece_index_t checked = 0;
     1082
     1083    assert( tr_isTorrent( tor ) );
     1084
     1085    for( i=0, n=tor->info.pieceCount; i!=n; ++i )
     1086        if( tor->info.pieces[i].timeChecked )
     1087            ++checked;
     1088
     1089    return checked / (double)tor->info.pieceCount;
     1090}
     1091
    10511092const tr_stat *
    10521093tr_torrentStat( tr_torrent * tor )
     
    10981139    s->metadataPercentComplete = tr_torrentGetMetadataPercent( tor );
    10991140
    1100     s->percentDone   = tr_cpPercentDone  ( &tor->completion );
    1101     s->leftUntilDone = tr_cpLeftUntilDone( &tor->completion );
    1102     s->sizeWhenDone  = tr_cpSizeWhenDone ( &tor->completion );
    1103 
    1104     s->recheckProgress = s->activity == TR_STATUS_CHECK
    1105                        ? 1.0 - ( tr_torrentCountUncheckedPieces( tor ) / (float) tor->info.pieceCount )
    1106                        : 0.0;
    1107 
    1108     s->activityDate = tor->activityDate;
    1109     s->addedDate    = tor->addedDate;
    1110     s->doneDate     = tor->doneDate;
    1111     s->startDate    = tor->startDate;
     1141    s->percentDone      = tr_cpPercentDone  ( &tor->completion );
     1142    s->leftUntilDone    = tr_cpLeftUntilDone( &tor->completion );
     1143    s->sizeWhenDone     = tr_cpSizeWhenDone ( &tor->completion );
     1144    s->recheckProgress  = s->activity == TR_STATUS_CHECK ? getVerifyProgress( tor ) : 0;
     1145    s->activityDate     = tor->activityDate;
     1146    s->addedDate        = tor->addedDate;
     1147    s->doneDate         = tor->doneDate;
     1148    s->startDate        = tor->startDate;
    11121149
    11131150    if ((s->activity == TR_STATUS_DOWNLOAD || s->activity == TR_STATUS_SEED) && s->startDate != 0)
     
    14421479    tr_announcerRemoveTorrent( session->announcer, tor );
    14431480
    1444     tr_bitfieldDestruct( &tor->checkedPieces );
    1445 
    14461481    tr_free( tor->downloadDir );
    14471482    tr_free( tor->incompleteDir );
     
    14731508
    14741509static void
    1475 checkAndStartImpl( void * vtor )
    1476 {
     1510torrentStartImpl( void * vtor )
     1511{
     1512    time_t now;
    14771513    tr_torrent * tor = vtor;
    14781514
     
    14811517    tr_sessionLock( tor->session );
    14821518
    1483     /** If we had local data before, but it's disappeared,
    1484         stop the torrent and log an error. */
    1485     if( tor->preVerifyTotal && !tr_cpHaveTotal( &tor->completion ) )
    1486     {
    1487         tr_torrentSetLocalError( tor, "%s", _( "No data found!  Reconnect any disconnected drives, use \"Set Location\", or restart the torrent to re-download." ) );
    1488     }
    1489     else
    1490     {
    1491         const time_t now = tr_time( );
    1492         tor->isRunning = TRUE;
    1493         tor->completeness = tr_cpGetStatus( &tor->completion );
    1494         tor->startDate = tor->anyDate = now;
    1495         tr_torrentClearError( tor );
    1496         tor->finishedSeedingByIdle = FALSE;
    1497 
    1498         tr_torrentResetTransferStats( tor );
    1499         tr_announcerTorrentStarted( tor );
    1500         tor->dhtAnnounceAt = now + tr_cryptoWeakRandInt( 20 );
    1501         tor->dhtAnnounce6At = now + tr_cryptoWeakRandInt( 20 );
    1502         tor->lpdAnnounceAt = now;
    1503         tr_peerMgrStartTorrent( tor );
    1504     }
     1519    tr_torrentRecheckCompleteness( tor );
     1520
     1521    now = tr_time( );
     1522    tor->isRunning = TRUE;
     1523    tor->completeness = tr_cpGetStatus( &tor->completion );
     1524    tor->startDate = tor->anyDate = now;
     1525    tr_torrentClearError( tor );
     1526    tor->finishedSeedingByIdle = FALSE;
     1527
     1528    tr_torrentResetTransferStats( tor );
     1529    tr_announcerTorrentStarted( tor );
     1530    tor->dhtAnnounceAt = now + tr_cryptoWeakRandInt( 20 );
     1531    tor->dhtAnnounce6At = now + tr_cryptoWeakRandInt( 20 );
     1532    tor->lpdAnnounceAt = now;
     1533    tr_peerMgrStartTorrent( tor );
    15051534
    15061535    tr_sessionUnlock( tor->session );
    15071536}
    15081537
    1509 static void
    1510 checkAndStartCB( tr_torrent * tor )
    1511 {
    1512     assert( tr_isTorrent( tor ) );
    1513     assert( tr_isSession( tor->session ) );
    1514 
    1515     tr_runInEventThread( tor->session, checkAndStartImpl, tor );
     1538uint64_t
     1539tr_torrentGetCurrentSizeOnDisk( const tr_torrent * tor )
     1540{
     1541    tr_file_index_t i;
     1542    uint64_t byte_count = 0;
     1543    const tr_file_index_t n = tor->info.fileCount;
     1544
     1545    for( i=0; i<n; ++i )
     1546    {
     1547        struct stat sb;
     1548        char * filename = tr_torrentFindFile( tor, i );
     1549
     1550        sb.st_size = 0;
     1551        if( filename && !stat( filename, &sb ) )
     1552            byte_count += sb.st_size;
     1553
     1554        tr_free( filename );
     1555    }
     1556
     1557    return byte_count;
    15161558}
    15171559
     
    15211563    assert( tr_isTorrent( tor ) );
    15221564
     1565    /* already running... */
     1566    if( tor->isRunning )
     1567        return;
     1568
     1569    /* don't allow the torrent to be started if the files disappeared */
     1570    if( setLocalErrorIfFilesDisappeared( tor ) )
     1571        return;
     1572
     1573    /* otherwise, start it now... */
    15231574    tr_sessionLock( tor->session );
    15241575
    1525     if( !tor->isRunning )
    1526     {
    1527         /* allow finished torrents to be resumed */
    1528         if( tr_torrentIsSeedRatioDone( tor ) )
    1529         {
    1530             tr_torinf( tor, "Restarted manually -- disabling its seed ratio" );
    1531             tr_torrentSetRatioMode( tor, TR_RATIOLIMIT_UNLIMITED );
    1532         }
    1533 
    1534         tr_verifyRemove( tor );
    1535 
    1536         /* corresponds to the peer_id sent as a tracker request parameter.
    1537          * one tracker admin says: "When the same torrent is opened and
    1538          * closed and opened again without quitting Transmission ...
    1539          * change the peerid. It would help sometimes if a stopped event
    1540          * was missed to ensure that we didn't think someone was cheating. */
    1541         tr_free( tor->peer_id );
    1542         tor->peer_id = tr_peerIdNew( );
    1543 
    1544         tor->isRunning = 1;
    1545         tr_torrentSetDirty( tor );
    1546         tor->preVerifyTotal = tr_cpHaveTotal( &tor->completion );
    1547         tr_verifyAdd( tor, checkAndStartCB );
    1548     }
     1576    /* allow finished torrents to be resumed */
     1577    if( tr_torrentIsSeedRatioDone( tor ) ) {
     1578        tr_torinf( tor, _( "Restarted manually -- disabling its seed ratio" ) );
     1579        tr_torrentSetRatioMode( tor, TR_RATIOLIMIT_UNLIMITED );
     1580    }
     1581
     1582    tr_verifyRemove( tor );
     1583
     1584    /* corresponds to the peer_id sent as a tracker request parameter.
     1585     * one tracker admin says: "When the same torrent is opened and
     1586     * closed and opened again without quitting Transmission ...
     1587     * change the peerid. It would help sometimes if a stopped event
     1588     * was missed to ensure that we didn't think someone was cheating. */
     1589    tr_free( tor->peer_id );
     1590    tor->peer_id = tr_peerIdNew( );
     1591    tor->isRunning = 1;
     1592    tr_torrentSetDirty( tor );
     1593    tr_runInEventThread( tor->session, torrentStartImpl, tor );
    15491594
    15501595    tr_sessionUnlock( tor->session );
     
    15621607{
    15631608    tr_torrent * tor = vtor;
    1564 
    1565     assert( tr_isTorrent( tor ) );
     1609    assert( tr_isTorrent( tor ) );
     1610
    15661611    tr_torrentRecheckCompleteness( tor );
    15671612
    1568     if( tor->preVerifyTotal && !tr_cpHaveTotal( &tor->completion ) )
    1569     {
    1570         tr_torrentSetLocalError( tor, "%s", _( "Can't find local data.  Try \"Set Location\" to find it, or restart the torrent to re-download." ) );
    1571     }
    1572     else if( tor->startAfterVerify )
    1573     {
     1613    if( tor->startAfterVerify ) {
    15741614        tor->startAfterVerify = FALSE;
    1575 
    1576         tr_torrentStart( tor );
     1615        torrentStart( tor );
    15771616    }
    15781617}
     
    16051644    }
    16061645
    1607     /* add the torrent to the recheck queue */
    1608     tor->preVerifyTotal = tr_cpHaveTotal( &tor->completion );
    1609     tr_torrentUncheck( tor );
    1610     tr_verifyAdd( tor, torrentRecheckDoneCB );
     1646    if( setLocalErrorIfFilesDisappeared( tor ) )
     1647        tor->startAfterVerify = FALSE;
     1648    else
     1649        tr_verifyAdd( tor, torrentRecheckDoneCB );
    16111650
    16121651    tr_sessionUnlock( tor->session );
     
    22092248
    22102249void
    2211 tr_torrentSetPieceChecked( tr_torrent        * tor,
    2212                            tr_piece_index_t    piece,
    2213                            tr_bool             isChecked )
    2214 {
    2215     assert( tr_isTorrent( tor ) );
    2216 
    2217     if( isChecked )
    2218         tr_bitfieldAdd( &tor->checkedPieces, piece );
    2219     else
    2220         tr_bitfieldRem( &tor->checkedPieces, piece );
    2221 }
    2222 
    2223 void
    2224 tr_torrentSetFileChecked( tr_torrent *    tor,
    2225                           tr_file_index_t fileIndex,
    2226                           tr_bool         isChecked )
    2227 {
    2228     const tr_file *        file = &tor->info.files[fileIndex];
    2229     const tr_piece_index_t begin = file->firstPiece;
    2230     const tr_piece_index_t end = file->lastPiece + 1;
    2231 
    2232     assert( tr_isTorrent( tor ) );
    2233 
    2234     if( isChecked )
    2235         tr_bitfieldAddRange( &tor->checkedPieces, begin, end );
    2236     else
    2237         tr_bitfieldRemRange( &tor->checkedPieces, begin, end );
     2250tr_torrentSetPieceChecked( tr_torrent * tor, tr_piece_index_t pieceIndex )
     2251{
     2252    assert( tr_isTorrent( tor ) );
     2253    assert( pieceIndex < tor->info.pieceCount );
     2254
     2255    tr_tordbg( tor, "[LAZY] setting piece %zu timeChecked to now", (size_t)pieceIndex );
     2256    tor->info.pieces[pieceIndex].timeChecked = tr_time( );
     2257}
     2258
     2259void
     2260tr_torrentSetChecked( tr_torrent * tor, time_t when )
     2261{
     2262    tr_piece_index_t i, n;
     2263
     2264    assert( tr_isTorrent( tor ) );
     2265
     2266    for( i=0, n=tor->info.pieceCount; i!=n; ++i )
     2267        tor->info.pieces[i].timeChecked = when;
    22382268}
    22392269
    22402270tr_bool
    2241 tr_torrentIsFileChecked( const tr_torrent * tor,
    2242                          tr_file_index_t    fileIndex )
    2243 {
    2244     const tr_file *        file = &tor->info.files[fileIndex];
    2245     const tr_piece_index_t begin = file->firstPiece;
    2246     const tr_piece_index_t end = file->lastPiece + 1;
    2247     tr_piece_index_t       i;
    2248     tr_bool                isChecked = TRUE;
    2249 
    2250     assert( tr_isTorrent( tor ) );
    2251 
    2252     for( i = begin; isChecked && i < end; ++i )
    2253         if( !tr_torrentIsPieceChecked( tor, i ) )
    2254             isChecked = FALSE;
    2255 
    2256     return isChecked;
    2257 }
    2258 
    2259 void
    2260 tr_torrentUncheck( tr_torrent * tor )
    2261 {
    2262     assert( tr_isTorrent( tor ) );
    2263 
    2264     tr_bitfieldRemRange( &tor->checkedPieces, 0, tor->info.pieceCount );
    2265 }
    2266 
    2267 int
    2268 tr_torrentCountUncheckedPieces( const tr_torrent * tor )
    2269 {
    2270     assert( tr_isTorrent( tor ) );
    2271 
    2272     return tor->info.pieceCount - tr_bitfieldCountTrueBits( &tor->checkedPieces );
    2273 }
    2274 
    2275 time_t*
    2276 tr_torrentGetMTimes( const tr_torrent * tor, size_t * setme_n )
    2277 {
    2278     size_t       i;
    2279     const size_t n = tor->info.fileCount;
    2280     time_t *     m = tr_new0( time_t, n );
    2281 
    2282     assert( tr_isTorrent( tor ) );
    2283 
    2284     for( i = 0; i < n; ++i )
    2285     {
    2286         struct stat sb;
    2287         char * path = tr_torrentFindFile( tor, i );
    2288         if( ( path != NULL ) && !stat( path, &sb ) && S_ISREG( sb.st_mode ) )
    2289         {
     2271tr_torrentCheckPiece( tr_torrent * tor, tr_piece_index_t pieceIndex )
     2272{
     2273    const tr_bool pass = tr_ioTestPiece( tor, pieceIndex );
     2274
     2275    tr_tordbg( tor, "[LAZY] tr_torrentCheckPiece tested piece %zu, pass==%d", (size_t)pieceIndex, (int)pass );
     2276    tr_torrentSetHasPiece( tor, pieceIndex, pass );
     2277    tr_torrentSetPieceChecked( tor, pieceIndex );
     2278    tor->anyDate = tr_time( );
     2279    tr_torrentSetDirty( tor );
     2280
     2281    return pass;
     2282}
     2283
     2284static time_t
     2285getFileMTime( const tr_torrent * tor, tr_file_index_t i )
     2286{
     2287    struct stat sb;
     2288    time_t mtime = 0;
     2289    char * path = tr_torrentFindFile( tor, i );
     2290
     2291    if( ( path != NULL ) && !stat( path, &sb ) && S_ISREG( sb.st_mode ) )
     2292    {
    22902293#ifdef SYS_DARWIN
    2291             m[i] = sb.st_mtimespec.tv_sec;
     2294        mtime = sb.st_mtimespec.tv_sec;
    22922295#else
    2293             m[i] = sb.st_mtime;
     2296        mtime = sb.st_mtime;
    22942297#endif
     2298    }
     2299
     2300    tr_free( path );
     2301    return mtime;
     2302}
     2303
     2304tr_bool
     2305tr_torrentPieceNeedsCheck( const tr_torrent * tor, tr_piece_index_t p )
     2306{
     2307    uint64_t unused;
     2308    tr_file_index_t f;
     2309    const tr_info * inf = tr_torrentInfo( tor );
     2310 
     2311    /* if we've never checked this piece, then it needs to be checked */
     2312    if( !inf->pieces[p].timeChecked ) {
     2313        tr_tordbg( tor, "[LAZY] piece %zu needs to be tested because it's never been tested", (size_t)p );
     2314        return TRUE;
     2315    }
     2316
     2317    /* If we think we've completed one of the files in this piece,
     2318     * but it's been modified since we last checked it,
     2319     * then it needs to be rechecked */
     2320    tr_ioFindFileLocation( tor, p, 0, &f, &unused );
     2321    for( ; f < inf->fileCount && pieceHasFile( p, &inf->files[f] ); ++f ) {
     2322        if( tr_cpFileIsComplete( &tor->completion, f ) ) {
     2323            if( getFileMTime( tor, f ) > inf->pieces[p].timeChecked ) {
     2324                tr_tordbg( tor, "[LAZY] piece %zu needs to be tested because file %zu mtime is newer than check time %zu", (size_t)p, (size_t)f, (size_t)inf->pieces[p].timeChecked );
     2325                return TRUE;
     2326            }
    22952327        }
    2296         tr_free( path );
    2297     }
    2298 
    2299     *setme_n = n;
    2300     return m;
     2328    }
     2329
     2330    tr_tordbg( tor, "[LAZY] piece %zu does not need to be tested", (size_t)p );
     2331    return FALSE;
    23012332}
    23022333
  • trunk/libtransmission/torrent.h

    r11204 r11506  
    8787                                             tr_priority_t      priority );
    8888
    89 int              tr_torrentCountUncheckedPieces( const tr_torrent * );
    90 
    91 tr_bool          tr_torrentIsFileChecked( const tr_torrent  * tor,
    92                                           tr_file_index_t     file );
    93 
    9489void             tr_torrentSetPieceChecked( tr_torrent       * tor,
    95                                             tr_piece_index_t   piece,
    96                                             tr_bool            isChecked );
    97 
    98 void             tr_torrentSetFileChecked( tr_torrent       * tor,
    99                                            tr_file_index_t    file,
    100                                            tr_bool            isChecked );
    101 
    102 void             tr_torrentUncheck( tr_torrent * tor );
    103 
    104 time_t*          tr_torrentGetMTimes( const tr_torrent  * tor,
    105                                       size_t            * setmeCount );
     90                                            tr_piece_index_t   piece );
     91
     92void             tr_torrentSetChecked( tr_torrent * tor, time_t when );
    10693
    10794tr_torrent*      tr_torrentNext( tr_session  * session,
     
    191178    struct tr_completion       completion;
    192179
    193     struct tr_bitfield         checkedPieces;
    194180    tr_completeness            completeness;
    195181
     
    262248    tr_idlelimit               idleLimitMode;
    263249    tr_bool                    finishedSeedingByIdle;
    264 
    265     uint64_t                   preVerifyTotal;
    266250};
    267251
     
    352336        && ( tr_sessionAllowsLPD( tor->session ) )
    353337        && ( !tr_torrentIsPrivate( tor ) );
    354 }
    355 
    356 static inline tr_bool tr_torrentIsPieceChecked( const tr_torrent  * tor,
    357                                                    tr_piece_index_t    i )
    358 {
    359     return tr_bitfieldHasFast( &tor->checkedPieces, i );
    360338}
    361339
     
    432410int tr_torrentGetSpeedLimit_Bps  ( const tr_torrent *, tr_direction );
    433411
     412/**
     413 * @return true if this piece needs to be tested
     414 */
     415tr_bool tr_torrentPieceNeedsCheck( const tr_torrent * tor, tr_piece_index_t pieceIndex );
     416
     417/**
     418 * @brief Test a piece against its info dict checksum
     419 * @return true if the piece's passes the checksum test
     420 */
     421tr_bool tr_torrentCheckPiece( tr_torrent * tor, tr_piece_index_t pieceIndex );
     422
     423uint64_t tr_torrentGetCurrentSizeOnDisk( const tr_torrent * tor );
     424
    434425
    435426#endif
  • trunk/libtransmission/transmission.h

    r11373 r11506  
    16101610typedef struct tr_piece
    16111611{
     1612    time_t     timeChecked;             /* the last time we tested this piece */
    16121613    uint8_t    hash[SHA_DIGEST_LENGTH]; /* pieces hash */
    16131614    int8_t     priority;               /* TR_PRI_HIGH, _NORMAL, or _LOW */
  • 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.