source: trunk/libtransmission/verify.c @ 5046

Last change on this file since 5046 was 5046, checked in by charles, 14 years ago

fix bug that could cause some pieces to be unnecessarily rechecked the second time they were loaded.

File size: 5.1 KB
Line 
1/*
2 * This file Copyright (C) 2007-2008 Charles Kerr <charles@rebelbase.com>
3 *
4 * This file is licensed by the GPL version 2.  Works owned by the
5 * Transmission project are granted a special exemption to clause 2(b)
6 * so that the bulk of its code can remain under the MIT license.
7 * This exemption does not extend to derived works not owned by
8 * the Transmission project.
9 *
10 * $Id: inout.c 4886 2008-02-01 01:54:04Z charles $
11 */
12
13#include <sys/stat.h>
14
15#include "transmission.h"
16#include "completion.h"
17#include "fastresume.h" /* tr_fastResumeSave() */
18#include "inout.h"
19#include "list.h"
20#include "platform.h"
21#include "torrent.h"
22#include "utils.h" /* tr_buildPath */
23#include "verify.h"
24
25/**
26***
27**/
28
29struct verify_node
30{
31    tr_torrent * torrent;
32    tr_verify_done_cb verify_done_cb;
33};
34
35static void
36fireCheckDone( tr_torrent          * torrent,
37               tr_verify_done_cb    verify_done_cb )
38{
39    if( verify_done_cb != NULL )
40        (*verify_done_cb)( torrent );
41}
42
43static struct verify_node currentNode;
44
45static tr_list * verifyList = NULL;
46
47static tr_thread * verifyThread = NULL;
48
49static int stopCurrent = FALSE;
50
51static tr_lock* getVerifyLock( void )
52{
53    static tr_lock * lock = NULL;
54    if( lock == NULL )
55        lock = tr_lockNew( );
56    return lock;
57}
58
59static void
60checkFile( tr_torrent   * tor,
61           int            fileIndex,
62           int          * abortFlag )
63{
64    int i;
65    int nofile;
66    struct stat sb;
67    char path[MAX_PATH_LENGTH];
68    const tr_file * file = &tor->info.files[fileIndex];
69
70    tr_buildPath ( path, sizeof(path), tor->destination, file->name, NULL );
71    nofile = stat( path, &sb ) || !S_ISREG( sb.st_mode );
72
73    for( i=file->firstPiece; i<=file->lastPiece && i<tor->info.pieceCount && (!*abortFlag); ++i )
74    {
75        if( nofile )
76        {
77            tr_torrentSetHasPiece( tor, i, 0 );
78        }
79        else if( !tr_torrentIsPieceChecked( tor, i ) )
80        {
81            const tr_errno err = tr_ioTestPiece( tor, i );
82
83            if( !err ) /* yay */
84            {
85                tr_torrentSetHasPiece( tor, i, TRUE );
86            }
87            else
88            {
89                /* if we were wrong about it being complete,
90                 * reset and start again.  if we were right about
91                 * it being incomplete, do nothing -- we don't
92                 * want to lose blocks in those incomplete pieces */
93
94                if( tr_cpPieceIsComplete( tor->completion, i ) )
95                    tr_torrentSetHasPiece( tor, i, FALSE );
96            }
97        }
98
99        tr_torrentSetPieceChecked( tor, i, TRUE );
100    }
101}
102
103static void
104verifyThreadFunc( void * unused UNUSED )
105{
106    for( ;; )
107    {
108        int i;
109        tr_torrent * tor;
110        struct verify_node * node;
111
112        tr_lockLock( getVerifyLock( ) );
113        stopCurrent = FALSE;
114        node = (struct verify_node*) verifyList ? verifyList->data : NULL;
115        if( node == NULL ) {
116            currentNode.torrent = NULL;
117            break;
118        }
119
120        currentNode = *node;
121        tor = currentNode.torrent;
122        tr_list_remove_data( &verifyList, node );
123        tr_free( node );
124        tr_lockUnlock( getVerifyLock( ) );
125
126        tor->verifyState = TR_VERIFY_NOW;
127
128        tr_inf( "Verifying some pieces of \"%s\"", tor->info.name );
129        for( i=0; i<tor->info.fileCount && !stopCurrent; ++i )
130            checkFile( tor, i, &stopCurrent );
131
132        tor->verifyState = TR_VERIFY_NONE;
133
134        if( !stopCurrent )
135        {
136            tr_fastResumeSave( tor );
137            fireCheckDone( tor, currentNode.verify_done_cb );
138        }
139    }
140
141    verifyThread = NULL;
142    tr_lockUnlock( getVerifyLock( ) );
143}
144
145void
146tr_verifyAdd( tr_torrent          * tor,
147              tr_verify_done_cb    verify_done_cb )
148{
149    const int uncheckedCount = tr_torrentCountUncheckedPieces( tor );
150
151    if( !uncheckedCount )
152    {
153        /* doesn't need to be checked... */
154        verify_done_cb( tor );
155    }
156    else
157    {
158        struct verify_node * node;
159
160        tr_inf( "Queueing %s to verify %d local file pieces", tor->info.name, uncheckedCount );
161
162        node = tr_new( struct verify_node, 1 );
163        node->torrent = tor;
164        node->verify_done_cb = verify_done_cb;
165
166        tr_lockLock( getVerifyLock( ) );
167        tor->verifyState = verifyList ? TR_VERIFY_WAIT : TR_VERIFY_NOW;
168        tr_list_append( &verifyList, node );
169        if( verifyThread == NULL )
170            verifyThread = tr_threadNew( verifyThreadFunc, NULL, "verifyThreadFunc" );
171        tr_lockUnlock( getVerifyLock( ) );
172    }
173}
174
175static int
176compareVerifyByTorrent( const void * va, const void * vb )
177{
178    const struct verify_node * a = va;
179    const tr_torrent * b = vb;
180    return a->torrent - b;
181}
182
183void
184tr_verifyRemove( tr_torrent * tor )
185{
186    tr_lock * lock = getVerifyLock( );
187    tr_lockLock( lock );
188
189    if( tor == currentNode.torrent )
190    {
191        stopCurrent = TRUE;
192        while( stopCurrent )
193        {
194            tr_lockUnlock( lock );
195            tr_wait( 100 );
196            tr_lockLock( lock );
197        }
198    }
199    else
200    {
201        tr_free( tr_list_remove( &verifyList, tor, compareVerifyByTorrent ) );
202        tor->verifyState = TR_VERIFY_NONE;
203    }
204
205    tr_lockUnlock( lock );
206}
Note: See TracBrowser for help on using the repository browser.