From d540058ebd7f32e613d26c33e8a99b16d39a13d8 Mon Sep 17 00:00:00 2001 From: John Hiesey Date: Wed, 30 Jun 2021 13:19:18 -0700 Subject: [PATCH] feat: Use a cache on the chunk store (#2095) --- docs/api.md | 3 ++- lib/torrent.js | 21 +++++++++++++++++++-- package.json | 1 + 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/docs/api.md b/docs/api.md index f64d2bef89..5302f9519a 100644 --- a/docs/api.md +++ b/docs/api.md @@ -94,6 +94,7 @@ If `opts` is specified, then the default options (shown below) will be overridde private: Boolean, // If true, client will not share the hash with the DHT nor with PEX (default is the privacy of the parsed torrent) store: Function // Custom chunk store (must follow [abstract-chunk-store](https://www.npmjs.com/package/abstract-chunk-store) API) destroyStoreOnDestroy: Boolean // If truthy, client will delete the torrent's chunk store (e.g. files on disk) when the torrent is destroyed + storeCacheSlots: Number // Number of chunk store entries (torrent pieces) to cache in memory [default=20]; 0 to disable caching } ``` @@ -110,7 +111,7 @@ If you provide `opts.store`, it will be called as * `storeOpts.length` - size of all the files in the torrent * `storeOpts.files` - an array of torrent file objects -* `storeOpts.torrent` - the torrent instance being stored +* `storeOpts.name` - the info hash of the torrent instance being stored **Note:** Downloading a torrent automatically seeds it, making it available for download by other peers. diff --git a/lib/torrent.js b/lib/torrent.js index 1f0be5b6ff..b46cde3b01 100644 --- a/lib/torrent.js +++ b/lib/torrent.js @@ -2,6 +2,7 @@ const addrToIPPort = require('addr-to-ip-port') const BitField = require('bitfield').default +const CacheChunkStore = require('cache-chunk-store') const ChunkStoreWriteStream = require('chunk-store-stream/write') const cpus = require('cpus') const debug = require('debug')('webtorrent:torrent') @@ -12,6 +13,7 @@ const FSChunkStore = require('fs-chunk-store') // browser: `memory-chunk-store` const get = require('simple-get') const ImmediateChunkStore = require('immediate-chunk-store') const ltDontHave = require('lt_donthave') +const MemoryChunkStore = require('memory-chunk-store') const MultiStream = require('multistream') const net = require('net') // browser exclude const os = require('os') // browser exclude @@ -75,6 +77,7 @@ class Torrent extends EventEmitter { this.skipVerify = !!opts.skipVerify this._store = opts.store || FSChunkStore this._preloadedStore = opts.preloadedStore || null + this._storeCacheSlots = opts.storeCacheSlots !== undefined ? opts.storeCacheSlots : 20 this._destroyStoreOnDestroy = opts.destroyStoreOnDestroy || false this._getAnnounceOpts = opts.getAnnounceOpts @@ -470,8 +473,11 @@ class Torrent extends EventEmitter { this._rarityMap = new RarityMap(this) - this.store = new ImmediateChunkStore( - this._preloadedStore || new this._store(this.pieceLength, { + let rawStore = this._preloadedStore + if (!rawStore) { + rawStore = new this._store(this.pieceLength, { + // opts.torrent is deprecated (replaced by the name property). + // it doesn't appear to be used by current versions of any stores on npm. torrent: { infoHash: this.infoHash }, @@ -483,6 +489,17 @@ class Torrent extends EventEmitter { length: this.length, name: this.infoHash }) + } + + // don't use the cache if the store is already in memory + if (this._storeCacheSlots > 0 && !(rawStore instanceof MemoryChunkStore)) { + rawStore = new CacheChunkStore(rawStore, { + max: this._storeCacheSlots + }) + } + + this.store = new ImmediateChunkStore( + rawStore ) this.files = this.files.map(file => new File(this, file)) diff --git a/package.json b/package.json index 0a1cb43f5e..b0994e90f9 100644 --- a/package.json +++ b/package.json @@ -40,6 +40,7 @@ "bitfield": "^4.0.0", "bittorrent-dht": "^10.0.0", "bittorrent-protocol": "^3.3.1", + "cache-chunk-store": "^3.2.2", "chrome-net": "^3.3.4", "chunk-store-stream": "^4.3.0", "cpus": "^1.0.3",