diff options
author | DC <dcposch@dcpos.ch> | 2016-04-02 01:00:41 +0300 |
---|---|---|
committer | DC <dcposch@dcpos.ch> | 2016-04-02 03:47:30 +0300 |
commit | 3756ae636c242ea9423874cdfeeb608b4ba1a507 (patch) | |
tree | 93c5de75db623cb3ebb3a3132c4c4b0923fe1809 /lib | |
parent | 715dafe597efb0ae9b332a6681f8934ba380cbcd (diff) |
Optimization: don't re-verify unchanged files
Let the user specify known-good file modtimes. If the files modtime is at least
that old, then the file hasn't changed and does not need to be re-verified.
This is only valid in node when using FS backing storage, not in the browser
Diffstat (limited to 'lib')
-rw-r--r-- | lib/torrent.js | 69 |
1 files changed, 62 insertions, 7 deletions
diff --git a/lib/torrent.js b/lib/torrent.js index 527ba55..475b41f 100644 --- a/lib/torrent.js +++ b/lib/torrent.js @@ -5,12 +5,12 @@ module.exports = Torrent var addrToIPPort = require('addr-to-ip-port') var BitField = require('bitfield') var ChunkStoreWriteStream = require('chunk-store-stream/write') -var cpus = require('cpus') var debug = require('debug')('webtorrent:torrent') var Discovery = require('torrent-discovery') var EventEmitter = require('events').EventEmitter var extend = require('xtend') var extendMutable = require('xtend/mutable') +var fs = require('fs') var FSChunkStore = require('fs-chunk-store') // browser: `memory-chunk-store` var ImmediateChunkStore = require('immediate-chunk-store') var inherits = require('inherits') @@ -45,6 +45,8 @@ var PIPELINE_MAX_DURATION = 1 var RECHOKE_INTERVAL = 10000 // 10 seconds var RECHOKE_OPTIMISTIC_DURATION = 2 // 30 seconds +var FILESYSTEM_CONCURRENCY = 2 + var TMP = typeof pathExists.sync === 'function' ? path.join(pathExists.sync('/tmp') ? '/tmp' : os.tmpDir(), 'webtorrent') : '/tmp/webtorrent' @@ -99,6 +101,9 @@ function Torrent (torrentId, client, opts) { // for cleanup this._servers = [] + // optimization: don't recheck every file if it hasn't changed + this._fileModtimes = opts.fileModtimes + if (torrentId !== null) this._onTorrentId(torrentId) } @@ -403,7 +408,55 @@ Torrent.prototype._onMetadata = function (metadata) { }) self._debug('verifying existing torrent data') - parallelLimit(self.pieces.map(function (piece, index) { + if (self._fileModtimes && self._store === FSChunkStore) { + // don't verify if the files haven't been modified since we last checked + self.getFileModtimes(function (err, fileModtimes) { + if (err) return self._onError(err) + + var unchanged = self.files.map(function (_, index) { + return fileModtimes[index] === self._fileModtimes[index] + }).reduce(function (a, b) { + return a && b + }) + if (unchanged) { + for (var index = 0; index < self.pieces.length; index++) { + self._markVerified(index) + } + self._onStore() + } else { + self._verifyPieces() + } + }) + } else { + self._verifyPieces() + } + + self.emit('metadata') +} + +/* + * Gets the last modified time of every file on disk for this torrent. + * Only valid in Node, not in the browser. + */ +Torrent.prototype.getFileModtimes = function (cb) { + var self = this + var ret = [] + parallelLimit(self.files.map(function (file, index) { + return function (cb) { + fs.stat(path.join(self.path, file.path), function (err, stat) { + ret[index] = stat && stat.mtime.getTime() + cb(err) + }) + } + }), FILESYSTEM_CONCURRENCY, function (err) { + self._debug('done getting file modtimes') + cb(err, ret) + }) +} + +Torrent.prototype._verifyPieces = function () { + var self = this + parallelLimit(self.pieces.map(function (_, index) { return function (cb) { self.store.get(index, function (err, buf) { if (err) return cb(null) // ignore error @@ -411,9 +464,7 @@ Torrent.prototype._onMetadata = function (metadata) { if (hash === self._hashes[index]) { if (!self.pieces[index]) return self._debug('piece verified %s', index) - self.pieces[index] = null - self._reservations[index] = null - self.bitfield.set(index, true) + self._markVerified(index) } else { self._debug('piece invalid %s', index) } @@ -421,13 +472,17 @@ Torrent.prototype._onMetadata = function (metadata) { }) }) } - }), cpus().length, function (err) { + }), FILESYSTEM_CONCURRENCY, function (err) { if (err) return self._onError(err) self._debug('done verifying') self._onStore() }) +} - self.emit('metadata') +Torrent.prototype._markVerified = function (index) { + this.pieces[index] = null + this._reservations[index] = null + this.bitfield.set(index, true) } /** |