source: trunk/libtransmission/verify.c @ 7578

Last change on this file since 7578 was 7578, checked in by charles, 12 years ago

(trunk libT) avoid some unnecessary memory fragmentation... for composited objects that have a tr_completion, contain the it directly rather than a pointer to one allocated elsewhere on the heap.

  • Property svn:keywords set to Date Rev Author Id
File size: 6.0 KB
Line 
1/*
2 * This file Copyright (C) 2007-2008 Charles Kerr <charles@transmissionbt.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: verify.c 7578 2009-01-02 17:01:55Z charles $
11 */
12
13#include <unistd.h> /* S_ISREG */
14#include <sys/stat.h>
15
16#include "transmission.h"
17#include "completion.h"
18#include "resume.h" /* tr_torrentSaveResume() */
19#include "inout.h"
20#include "list.h"
21#include "platform.h"
22#include "torrent.h"
23#include "utils.h" /* tr_buildPath */
24#include "verify.h"
25
26/**
27***
28**/
29
30struct verify_node
31{
32    tr_torrent *         torrent;
33    tr_verify_done_cb    verify_done_cb;
34};
35
36static void
37fireCheckDone( tr_torrent *      torrent,
38               tr_verify_done_cb verify_done_cb )
39{
40    if( verify_done_cb )
41        verify_done_cb( torrent );
42}
43
44static struct verify_node currentNode;
45
46static tr_list *          verifyList = NULL;
47
48static tr_thread *        verifyThread = NULL;
49
50static int                stopCurrent = FALSE;
51
52static tr_lock*
53getVerifyLock( void )
54{
55    static tr_lock * lock = NULL;
56
57    if( lock == NULL )
58        lock = tr_lockNew( );
59    return lock;
60}
61
62static int
63checkFile( tr_torrent      * tor,
64           void            * buffer,
65           size_t            buflen,
66           tr_file_index_t   fileIndex,
67           int             * abortFlag )
68{
69    tr_piece_index_t i;
70    int              changed = FALSE;
71    int              nofile;
72    struct stat      sb;
73    char           * path;
74    const tr_file  * file = &tor->info.files[fileIndex];
75
76    path = tr_buildPath( tor->downloadDir, file->name, NULL );
77    nofile = stat( path, &sb ) || !S_ISREG( sb.st_mode );
78
79    for( i = file->firstPiece;
80         i <= file->lastPiece && i < tor->info.pieceCount && ( !*abortFlag );
81         ++i )
82    {
83        if( nofile )
84        {
85            tr_torrentSetHasPiece( tor, i, 0 );
86        }
87        else if( !tr_torrentIsPieceChecked( tor, i ) )
88        {
89            const int wasComplete = tr_cpPieceIsComplete( &tor->completion, i );
90
91            if( tr_ioTestPiece( tor, i, buffer, buflen ) ) /* yay */
92            {
93                tr_torrentSetHasPiece( tor, i, TRUE );
94                if( !wasComplete )
95                    changed = TRUE;
96            }
97            else
98            {
99                /* if we were wrong about it being complete,
100                 * reset and start again.  if we were right about
101                 * it being incomplete, do nothing -- we don't
102                 * want to lose blocks in those incomplete pieces */
103
104                if( wasComplete )
105                {
106                    tr_torrentSetHasPiece( tor, i, FALSE );
107                    changed = TRUE;
108                }
109            }
110        }
111
112        tr_torrentSetPieceChecked( tor, i, TRUE );
113    }
114
115    tr_free( path );
116
117    return changed;
118}
119
120static void
121verifyThreadFunc( void * unused UNUSED )
122{
123    for( ;; )
124    {
125        int                  changed = 0;
126        tr_file_index_t      i;
127        tr_torrent         * tor;
128        struct verify_node * node;
129        void               * buffer;
130
131        tr_lockLock( getVerifyLock( ) );
132        stopCurrent = FALSE;
133        node = (struct verify_node*) verifyList ? verifyList->data : NULL;
134        if( node == NULL )
135        {
136            currentNode.torrent = NULL;
137            break;
138        }
139
140        currentNode = *node;
141        tor = currentNode.torrent;
142        tr_list_remove_data( &verifyList, node );
143        tr_free( node );
144        tr_lockUnlock( getVerifyLock( ) );
145
146        tr_torinf( tor, _( "Verifying torrent" ) );
147        tor->verifyState = TR_VERIFY_NOW;
148        buffer = tr_new( uint8_t, tor->info.pieceSize );
149        for( i = 0; i < tor->info.fileCount && !stopCurrent; ++i )
150            changed |= checkFile( tor, buffer, tor->info.pieceSize, i, &stopCurrent );
151        tr_free( buffer );
152        tor->verifyState = TR_VERIFY_NONE;
153
154        if( !stopCurrent )
155        {
156            if( changed )
157                tr_torrentSaveResume( tor );
158            fireCheckDone( tor, currentNode.verify_done_cb );
159        }
160    }
161
162    verifyThread = NULL;
163    tr_lockUnlock( getVerifyLock( ) );
164}
165
166void
167tr_verifyAdd( tr_torrent *      tor,
168              tr_verify_done_cb verify_done_cb )
169{
170    const int uncheckedCount = tr_torrentCountUncheckedPieces( tor );
171
172    if( !uncheckedCount )
173    {
174        /* doesn't need to be checked... */
175        fireCheckDone( tor, verify_done_cb );
176    }
177    else
178    {
179        struct verify_node * node;
180
181        tr_torinf( tor, _( "Queued for verification" ) );
182
183        node = tr_new( struct verify_node, 1 );
184        node->torrent = tor;
185        node->verify_done_cb = verify_done_cb;
186
187        tr_lockLock( getVerifyLock( ) );
188        tor->verifyState = verifyList ? TR_VERIFY_WAIT : TR_VERIFY_NOW;
189        tr_list_append( &verifyList, node );
190        if( verifyThread == NULL )
191            verifyThread = tr_threadNew( verifyThreadFunc, NULL );
192        tr_lockUnlock( getVerifyLock( ) );
193    }
194}
195
196static int
197compareVerifyByTorrent( const void * va,
198                        const void * vb )
199{
200    const struct verify_node * a = va;
201    const tr_torrent *         b = vb;
202
203    return a->torrent - b;
204}
205
206int
207tr_verifyInProgress( const tr_torrent * tor )
208{
209    int found = FALSE;
210    tr_lock * lock = getVerifyLock( );
211    tr_lockLock( lock );
212
213    found = ( tor == currentNode.torrent )
214         || ( tr_list_find( verifyList, tor, compareVerifyByTorrent ) != NULL );
215
216    tr_lockUnlock( lock );
217    return found;
218}
219
220void
221tr_verifyRemove( tr_torrent * tor )
222{
223    tr_lock * lock = getVerifyLock( );
224
225    tr_lockLock( lock );
226
227    if( tor == currentNode.torrent )
228    {
229        stopCurrent = TRUE;
230        while( stopCurrent )
231        {
232            tr_lockUnlock( lock );
233            tr_wait( 100 );
234            tr_lockLock( lock );
235        }
236    }
237    else
238    {
239        tr_free( tr_list_remove( &verifyList, tor, compareVerifyByTorrent ) );
240        tor->verifyState = TR_VERIFY_NONE;
241    }
242
243    tr_lockUnlock( lock );
244}
245
Note: See TracBrowser for help on using the repository browser.