2 * This file Copyright (C) 2007-2014 Mnemosyne LLC
4 * It may be used under the GNU GPL versions 2 or 3
5 * or any future license endorsed by Mnemosyne LLC.
7 * $Id: verify.c 14241 2014-01-21 03:10:30Z jordan $
10 #include <string.h> /* memcmp () */
11 #include <stdlib.h> /* free () */
13 #ifdef HAVE_POSIX_FADVISE
14 #define _XOPEN_SOURCE 600
15 #include <fcntl.h> /* posix_fadvise () */
18 #include <openssl/sha.h>
20 #include "transmission.h"
21 #include "completion.h"
25 #include "platform.h" /* tr_lock () */
27 #include "utils.h" /* tr_valloc (), tr_free () */
36 MSEC_TO_SLEEP_PER_SECOND_DURING_VERIFY
= 100
40 verifyTorrent (tr_torrent
* tor
, bool * stopFlag
)
48 time_t lastSleptAt
= 0;
49 uint32_t piecePos
= 0;
50 tr_file_index_t fileIndex
= 0;
51 tr_file_index_t prevFileIndex
= !fileIndex
;
52 tr_piece_index_t pieceIndex
= 0;
53 const time_t begin
= tr_time ();
54 const size_t buflen
= 1024 * 128; /* 128 KiB buffer */
55 uint8_t * buffer
= tr_valloc (buflen
);
59 tr_logAddTorDbg (tor
, "%s", "verifying torrent...");
60 tr_torrentSetChecked (tor
, 0);
61 while (!*stopFlag
&& (pieceIndex
< tor
->info
.pieceCount
))
64 uint32_t bytesThisPass
;
66 const tr_file
* file
= &tor
->info
.files
[fileIndex
];
68 /* if we're starting a new piece... */
70 hadPiece
= tr_torrentPieceIsComplete (tor
, pieceIndex
);
72 /* if we're starting a new file... */
73 if (!filePos
&& (fd
<0) && (fileIndex
!=prevFileIndex
))
75 char * filename
= tr_torrentFindFile (tor
, fileIndex
);
76 fd
= filename
== NULL
? -1 : tr_open_file_for_scanning (filename
);
78 prevFileIndex
= fileIndex
;
81 /* figure out how much we can read this pass */
82 leftInPiece
= tr_torPieceCountBytes (tor
, pieceIndex
) - piecePos
;
83 leftInFile
= file
->length
- filePos
;
84 bytesThisPass
= MIN (leftInFile
, leftInPiece
);
85 bytesThisPass
= MIN (bytesThisPass
, buflen
);
90 const ssize_t numRead
= tr_pread (fd
, buffer
, bytesThisPass
, filePos
);
93 bytesThisPass
= (uint32_t)numRead
;
94 SHA1_Update (&sha
, buffer
, bytesThisPass
);
95 #if defined HAVE_POSIX_FADVISE && defined POSIX_FADV_DONTNEED
96 posix_fadvise (fd
, filePos
, bytesThisPass
, POSIX_FADV_DONTNEED
);
101 /* move our offsets */
102 leftInPiece
-= bytesThisPass
;
103 leftInFile
-= bytesThisPass
;
104 piecePos
+= bytesThisPass
;
105 filePos
+= bytesThisPass
;
107 /* if we're finishing a piece... */
108 if (leftInPiece
== 0)
112 uint8_t hash
[SHA_DIGEST_LENGTH
];
114 SHA1_Final (hash
, &sha
);
115 hasPiece
= !memcmp (hash
, tor
->info
.pieces
[pieceIndex
].hash
, SHA_DIGEST_LENGTH
);
117 if (hasPiece
|| hadPiece
)
119 tr_torrentSetHasPiece (tor
, pieceIndex
, hasPiece
);
120 changed
|= hasPiece
!= hadPiece
;
123 tr_torrentSetPieceChecked (tor
, pieceIndex
);
127 /* sleeping even just a few msec per second goes a long
128 * way towards reducing IO load... */
129 if (lastSleptAt
!= now
)
132 tr_wait_msec (MSEC_TO_SLEEP_PER_SECOND_DURING_VERIFY
);
140 /* if we're finishing a file... */
160 tr_logAddTorDbg (tor
, "Verification is done. It took %d seconds to verify %"PRIu64
" bytes (%"PRIu64
" bytes per second)",
161 (int)(end
-begin
), tor
->info
.totalSize
,
162 (uint64_t)(tor
->info
.totalSize
/ (1+ (end
-begin
))));
173 tr_torrent
* torrent
;
174 tr_verify_done_func callback_func
;
175 void * callback_data
;
176 uint64_t current_size
;
179 static struct verify_node currentNode
;
180 static tr_list
* verifyList
= NULL
;
181 static tr_thread
* verifyThread
= NULL
;
182 static bool stopCurrent
= false;
187 static tr_lock
* lock
= NULL
;
190 lock
= tr_lockNew ();
196 verifyThreadFunc (void * unused UNUSED
)
202 struct verify_node
* node
;
204 tr_lockLock (getVerifyLock ());
206 node
= (struct verify_node
*) verifyList
? verifyList
->data
: NULL
;
209 currentNode
.torrent
= NULL
;
214 tor
= currentNode
.torrent
;
215 tr_list_remove_data (&verifyList
, node
);
217 tr_lockUnlock (getVerifyLock ());
219 tr_logAddTorInfo (tor
, "%s", _("Verifying torrent"));
220 tr_torrentSetVerifyState (tor
, TR_VERIFY_NOW
);
221 changed
= verifyTorrent (tor
, &stopCurrent
);
222 tr_torrentSetVerifyState (tor
, TR_VERIFY_NONE
);
223 assert (tr_isTorrent (tor
));
225 if (!stopCurrent
&& changed
)
226 tr_torrentSetDirty (tor
);
228 if (currentNode
.callback_func
)
229 (*currentNode
.callback_func
)(tor
, stopCurrent
, currentNode
.callback_data
);
233 tr_lockUnlock (getVerifyLock ());
237 compareVerifyByPriorityAndSize (const void * va
, const void * vb
)
239 const struct verify_node
* a
= va
;
240 const struct verify_node
* b
= vb
;
242 /* higher priority comes before lower priority */
243 const tr_priority_t pa
= tr_torrentGetPriority (a
->torrent
);
244 const tr_priority_t pb
= tr_torrentGetPriority (b
->torrent
);
246 return pa
> pb
? -1 : 1;
248 /* smaller torrents come before larger ones because they verify faster */
249 if (a
->current_size
< b
->current_size
)
251 if (a
->current_size
> b
->current_size
)
257 tr_verifyAdd (tr_torrent
* tor
,
258 tr_verify_done_func callback_func
,
259 void * callback_data
)
261 struct verify_node
* node
;
263 assert (tr_isTorrent (tor
));
264 tr_logAddTorInfo (tor
, "%s", _("Queued for verification"));
266 node
= tr_new (struct verify_node
, 1);
268 node
->callback_func
= callback_func
;
269 node
->callback_data
= callback_data
;
270 node
->current_size
= tr_torrentGetCurrentSizeOnDisk (tor
);
272 tr_lockLock (getVerifyLock ());
273 tr_torrentSetVerifyState (tor
, TR_VERIFY_WAIT
);
274 tr_list_insert_sorted (&verifyList
, node
, compareVerifyByPriorityAndSize
);
275 if (verifyThread
== NULL
)
276 verifyThread
= tr_threadNew (verifyThreadFunc
, NULL
);
277 tr_lockUnlock (getVerifyLock ());
281 compareVerifyByTorrent (const void * va
, const void * vb
)
283 const struct verify_node
* a
= va
;
284 const tr_torrent
* b
= vb
;
285 return a
->torrent
- b
;
289 tr_verifyRemove (tr_torrent
* tor
)
291 tr_lock
* lock
= getVerifyLock ();
294 assert (tr_isTorrent (tor
));
296 if (tor
== currentNode
.torrent
)
302 tr_lockUnlock (lock
);
309 struct verify_node
* node
= tr_list_remove (&verifyList
, tor
, compareVerifyByTorrent
);
311 tr_torrentSetVerifyState (tor
, TR_VERIFY_NONE
);
315 if (node
->callback_func
!= NULL
)
316 (*node
->callback_func
)(tor
, true, node
->callback_data
);
322 tr_lockUnlock (lock
);
326 tr_verifyClose (tr_session
* session UNUSED
)
328 tr_lockLock (getVerifyLock ());
331 tr_list_free (&verifyList
, tr_free
);
333 tr_lockUnlock (getVerifyLock ());