Changeset 8161


Ignore:
Timestamp:
Apr 6, 2009, 4:02:51 AM (13 years ago)
Author:
charles
Message:

(trunk libT) faster code for verifying entire torrents. Timing tests @ http://transmission.pastebin.com/m4e1d6ee

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/libtransmission/verify.c

    r8090 r8161  
    1414#include <sys/stat.h>
    1515
     16#include <openssl/sha.h>
     17
    1618#include "transmission.h"
    1719#include "completion.h"
     
    2426#include "verify.h"
    2527
    26 /**
    27 ***
    28 **/
     28
     29/***
     30****
     31***/
     32
     33/* #define STOPWATCH */
     34
     35static tr_bool
     36verifyTorrent( tr_torrent * tor, tr_bool * stopFlag )
     37{
     38    SHA_CTX sha;
     39    FILE * fp = NULL;
     40    size_t filePos = 0;
     41    tr_bool changed = 0;
     42    tr_bool hadPiece = 0;
     43    uint32_t piecePos = 0;
     44    tr_file_index_t fileIndex = 0;
     45    tr_piece_index_t pieceIndex = 0;
     46    const int64_t buflen = tor->info.pieceSize;
     47    uint8_t * buffer = tr_new( uint8_t, buflen );
     48#ifdef STOPWATCH
     49    time_t now = time( NULL );
     50#endif
     51
     52    SHA1_Init( &sha );
     53
     54    while( !*stopFlag && ( pieceIndex < tor->info.pieceCount ) )
     55    {
     56        int64_t leftInPiece;
     57        int64_t leftInFile;
     58        int64_t bytesThisPass;
     59        const tr_file * file = &tor->info.files[fileIndex];
     60
     61        /* if we're starting a new piece... */
     62        if( piecePos == 0 )
     63        {
     64            hadPiece = tr_cpPieceIsComplete( &tor->completion, pieceIndex );
     65            /* fprintf( stderr, "starting piece %d of %d\n", (int)pieceIndex, (int)tor->info.pieceCount ); */
     66        }
     67
     68        /* if we're starting a new file... */
     69        if( !filePos && !fp )
     70        {
     71            char * filename = tr_buildPath( tor->downloadDir, file->name, NULL );
     72            fp = fopen( filename, "rb" );
     73            /* fprintf( stderr, "opening file #%d (%s) -- %p\n", fileIndex, filename, fp ); */
     74            tr_free( filename );
     75        }
     76
     77        /* figure out how much we can read this pass */
     78        leftInPiece = tr_torPieceCountBytes( tor, pieceIndex ) - piecePos;
     79        leftInFile = file->length - filePos;
     80        bytesThisPass = MIN( leftInFile, leftInPiece );
     81        bytesThisPass = MIN( bytesThisPass, buflen );
     82        /* fprintf( stderr, "reading this pass: %d\n", (int)bytesThisPass ); */
     83
     84        /* read a bit */
     85        if( fp && !fseek( fp, filePos, SEEK_SET ) ) {
     86            const int64_t numRead = fread( buffer, 1, bytesThisPass, fp );
     87            if( numRead == bytesThisPass )
     88                SHA1_Update( &sha, buffer, numRead );
     89        }
     90
     91        /* move our offsets */
     92        leftInPiece -= bytesThisPass;
     93        leftInFile -= bytesThisPass;
     94        piecePos += bytesThisPass;
     95        filePos += bytesThisPass;
     96
     97        /* if we're finishing a piece... */
     98        if( leftInPiece == 0 )
     99        {
     100            tr_bool hasPiece;
     101            uint8_t hash[SHA_DIGEST_LENGTH];
     102
     103            SHA1_Final( hash, &sha );
     104            hasPiece = !memcmp( hash, tor->info.pieces[pieceIndex].hash, SHA_DIGEST_LENGTH );
     105            /* fprintf( stderr, "do the hashes match? %s\n", (hasPiece?"yes":"no") ); */
     106
     107            if( hasPiece ) {
     108                tr_torrentSetHasPiece( tor, pieceIndex, TRUE );
     109                if( !hadPiece )
     110                    changed = TRUE;
     111            } else if( hadPiece ) {
     112                tr_torrentSetHasPiece( tor, pieceIndex, FALSE );
     113                changed = TRUE;
     114            }
     115            tr_torrentSetPieceChecked( tor, pieceIndex, TRUE );
     116
     117            SHA1_Init( &sha );
     118            ++pieceIndex;
     119            piecePos = 0;
     120        }
     121
     122        /* if we're finishing a file... */
     123        if( leftInFile == 0 )
     124        {
     125            /* fprintf( stderr, "closing file\n" ); */
     126            if( fp != NULL ) { fclose( fp ); fp = NULL; }
     127            ++fileIndex;
     128            filePos = 0;
     129        }
     130    }
     131
     132    /* cleanup */
     133    if( fp != NULL )
     134        fclose( fp );
     135    tr_free( buffer );
     136
     137#ifdef STOPWATCH
     138{
     139    time_t now2 = time( NULL );
     140    fprintf( stderr, "it took %d seconds to verify %"PRIu64" bytes (%"PRIu64" bytes per second)\n",
     141             (int)(now2-now), tor->info.totalSize, (uint64_t)(tor->info.totalSize/(1+(now2-now))) );
     142}
     143#endif
     144
     145    return changed;
     146}
     147
     148/***
     149****
     150***/
    29151
    30152struct verify_node
     
    46168static tr_list * verifyList = NULL;
    47169static tr_thread * verifyThread = NULL;
    48 static int stopCurrent = FALSE;
     170static tr_bool stopCurrent = FALSE;
    49171
    50172static tr_lock*
     
    58180}
    59181
    60 static int
    61 checkFile( tr_torrent      * tor,
    62            void            * buffer,
    63            size_t            buflen,
    64            tr_file_index_t   fileIndex,
    65            int             * abortFlag )
    66 {
    67     tr_piece_index_t i;
    68     int              changed = FALSE;
    69     int              nofile;
    70     struct stat      sb;
    71     char           * path;
    72     const tr_file  * file = &tor->info.files[fileIndex];
    73 
    74     path = tr_buildPath( tor->downloadDir, file->name, NULL );
    75     nofile = stat( path, &sb ) || !S_ISREG( sb.st_mode );
    76 
    77     for( i = file->firstPiece;
    78          i <= file->lastPiece && i < tor->info.pieceCount && ( !*abortFlag );
    79          ++i )
    80     {
    81         if( nofile )
    82         {
    83             tr_torrentSetHasPiece( tor, i, 0 );
    84         }
    85         else if( !tr_torrentIsPieceChecked( tor, i ) )
    86         {
    87             const int wasComplete = tr_cpPieceIsComplete( &tor->completion, i );
    88 
    89             if( tr_ioTestPiece( tor, i, buffer, buflen ) ) /* yay */
    90             {
    91                 tr_torrentSetHasPiece( tor, i, TRUE );
    92                 if( !wasComplete )
    93                     changed = TRUE;
    94             }
    95             else
    96             {
    97                 /* if we were wrong about it being complete,
    98                  * reset and start again.  if we were right about
    99                  * it being incomplete, do nothing -- we don't
    100                  * want to lose blocks in those incomplete pieces */
    101 
    102                 if( wasComplete )
    103                 {
    104                     tr_torrentSetHasPiece( tor, i, FALSE );
    105                     changed = TRUE;
    106                 }
    107             }
    108         }
    109 
    110         tr_torrentSetPieceChecked( tor, i, TRUE );
    111     }
    112 
    113     tr_free( path );
    114 
    115     return changed;
    116 }
    117 
    118182static void
    119183verifyThreadFunc( void * unused UNUSED )
     
    122186    {
    123187        int                  changed = 0;
    124         tr_file_index_t      i;
    125188        tr_torrent         * tor;
    126189        struct verify_node * node;
    127         void               * buffer;
    128190
    129191        tr_lockLock( getVerifyLock( ) );
     
    144206        tr_torinf( tor, _( "Verifying torrent" ) );
    145207        tr_torrentSetVerifyState( tor, TR_VERIFY_NOW );
    146         buffer = tr_new( uint8_t, tor->info.pieceSize );
    147         for( i = 0; i < tor->info.fileCount && !stopCurrent; ++i )
    148             changed |= checkFile( tor, buffer, tor->info.pieceSize, i, &stopCurrent );
    149         tr_free( buffer );
     208        changed = verifyTorrent( tor, &stopCurrent );
    150209        tr_torrentSetVerifyState( tor, TR_VERIFY_NONE );
    151210        assert( tr_isTorrent( tor ) );
Note: See TracChangeset for help on using the changeset viewer.