Skip to content

Commit 99df42b

Browse files
feat: use new datastore-idb (#225)
A new fast and smaller browser datastore is used `datastore-idb` https://github.com/ipfs/js-datastore-idb Also removes node globals and reduces bundle size. size: 77.09KB -> 45.07KB ``` datastore-idb up to 44% faster and 69% smaller batch idb x 5.26 ops/sec ±4.57% (29 runs sampled) batch level x 2.92 ops/sec ±3.76% (19 runs sampled) Fastest is batch idb size 37.32KB to 11.41KB ``` Co-authored-by: Alex Potsides <[email protected]>
1 parent ac32e3c commit 99df42b

22 files changed

+115
-99
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ stages:
66
- cov
77

88
node_js:
9-
- '10'
109
- '12'
10+
- '10'
1111

1212
os:
1313
- linux

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -181,21 +181,21 @@ Get a value at the root of the repo.
181181

182182
* `key` can be a buffer, a string or a [Key](https://github.com/ipfs/interface-datastore#keys).
183183

184-
[Blocks](https://github.com/ipfs/js-ipfs-block#readme):
184+
[Blocks](https://github.com/ipfs/js-ipld-block#readme):
185185

186186
#### `Promise<Boolean> repo.isInitialized ()`
187187

188188
The returned promise resolves to `false` if the repo has not been initialized and `true` if it has.
189189

190190
#### `Promise repo.blocks.put (block:Block)`
191191

192-
* `block` should be of type [Block](https://github.com/ipfs/js-ipfs-block#readme).
192+
* `block` should be of type [Block](https://github.com/ipfs/js-ipld-block#readme).
193193

194194
#### `Promise repo.blocks.putMany (blocks)`
195195

196196
Put many blocks.
197197

198-
* `block` should be an Iterable or AsyncIterable that yields entries of type [Block](https://github.com/ipfs/js-ipfs-block#readme).
198+
* `block` should be an Iterable or AsyncIterable that yields entries of type [Block](https://github.com/ipfs/js-ipld-block#readme).
199199

200200
#### `Promise<Buffer> repo.blocks.get (cid)`
201201

package.json

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
],
1111
"browser": {
1212
"rimraf": false,
13-
"datastore-fs": "datastore-level",
13+
"datastore-fs": "datastore-idb",
1414
"./src/lock.js": "./src/lock-memory.js",
1515
"./src/default-options.js": "./src/default-options-browser.js"
1616
},
@@ -43,33 +43,35 @@
4343
"npm": ">=3.0.0"
4444
},
4545
"devDependencies": {
46-
"aegir": "^21.4.5",
46+
"aegir": "^21.8.1",
4747
"chai": "^4.2.0",
4848
"dirty-chai": "^2.0.1",
49-
"lodash": "^4.17.11",
49+
"just-range": "^2.1.0",
5050
"memdown": "^5.1.0",
5151
"multihashes": "~0.4.15",
5252
"multihashing-async": "~0.8.0",
5353
"ncp": "^2.0.0",
5454
"rimraf": "^3.0.0",
55-
"sinon": "^9.0.1"
55+
"sinon": "^9.0.2"
5656
},
5757
"dependencies": {
58-
"base32.js": "~0.1.0",
5958
"bignumber.js": "^9.0.0",
59+
"buffer": "^5.5.0",
6060
"bytes": "^3.1.0",
6161
"cids": "^0.8.0",
62-
"datastore-core": "~0.7.0",
62+
"datastore-core": "^1.0.0",
6363
"datastore-fs": "~0.9.0",
64+
"datastore-idb": "^1.0.0",
6465
"datastore-level": "~0.14.0",
6566
"debug": "^4.1.0",
6667
"err-code": "^2.0.0",
67-
"interface-datastore": "^0.8.0",
68-
"ipfs-block": "~0.8.1",
69-
"ipfs-repo-migrations": "~0.1.0",
68+
"interface-datastore": "^0.8.3",
69+
"ipfs-repo-migrations": "^0.2.0",
70+
"ipfs-utils": "^2.2.0",
71+
"ipld-block": "^0.9.1",
7072
"just-safe-get": "^2.0.0",
7173
"just-safe-set": "^2.1.0",
72-
"lodash.has": "^4.5.2",
74+
"multibase": "^0.7.0",
7375
"p-queue": "^6.0.0",
7476
"proper-lockfile": "^4.0.0",
7577
"sort-keys": "^4.0.0"

src/api-addr.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
'use strict'
22

3+
const { Buffer } = require('buffer')
34
const Key = require('interface-datastore').Key
45

56
const apiFile = new Key('api')

src/blockstore-utils.js

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
'use strict'
22

3-
const base32 = require('base32.js')
43
const { Key } = require('interface-datastore')
54
const CID = require('cids')
5+
const multibase = require('multibase')
66

77
/**
88
* Transform a cid to the appropriate datastore key.
@@ -11,8 +11,7 @@ const CID = require('cids')
1111
* @returns {Key}
1212
*/
1313
exports.cidToKey = cid => {
14-
const enc = new base32.Encoder()
15-
return new Key('/' + enc.write(cid.buffer).finalize(), false)
14+
return new Key('/' + multibase.encode('base32', cid.buffer).toString().slice(1).toUpperCase(), false)
1615
}
1716

1817
/**
@@ -22,8 +21,5 @@ exports.cidToKey = cid => {
2221
* @returns {CID}
2322
*/
2423
exports.keyToCid = key => {
25-
// Block key is of the form /<base32 encoded string>
26-
const decoder = new base32.Decoder()
27-
const buff = decoder.write(key.toString().slice(1)).finalize()
28-
return new CID(Buffer.from(buff))
24+
return new CID(multibase.decode('b' + key.toString().slice(1).toLowerCase()))
2925
}

src/blockstore.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
const core = require('datastore-core')
44
const ShardingStore = core.ShardingDatastore
5-
const Block = require('ipfs-block')
5+
const Block = require('ipld-block')
66
const CID = require('cids')
77
const errcode = require('err-code')
88
const { cidToKey } = require('./blockstore-utils')

src/config.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
'use strict'
22

3+
const { Buffer } = require('buffer')
34
const Key = require('interface-datastore').Key
45
const { default: Queue } = require('p-queue')
56
const _get = require('just-safe-get')
67
const _set = require('just-safe-set')
7-
const _has = require('lodash.has')
88
const errcode = require('err-code')
99
const errors = require('./errors')
1010

@@ -27,7 +27,7 @@ module.exports = (store) => {
2727

2828
const encodedValue = await store.get(configKey)
2929
const config = JSON.parse(encodedValue.toString())
30-
if (key !== undefined && !_has(config, key)) {
30+
if (key !== undefined && _get(config, key) === undefined) {
3131
throw new errors.NotFoundError(`Key ${key} does not exist in config`)
3232
}
3333

src/default-options-browser.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@
44
module.exports = {
55
lock: 'memory',
66
storageBackends: {
7-
root: require('datastore-level'),
8-
blocks: require('datastore-level'),
9-
keys: require('datastore-level'),
10-
datastore: require('datastore-level')
7+
root: require('datastore-idb'),
8+
blocks: require('datastore-idb'),
9+
keys: require('datastore-idb'),
10+
datastore: require('datastore-idb')
1111
},
1212
storageBackendOptions: {
1313
root: {

src/index.js

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
'use strict'
22

33
const _get = require('just-safe-get')
4-
const assert = require('assert')
5-
const path = require('path')
64
const debug = require('debug')
75
const Big = require('bignumber.js')
86
const errcode = require('err-code')
97
const migrator = require('ipfs-repo-migrations')
108
const bytes = require('bytes')
9+
const pathJoin = require('ipfs-utils/src/path-join')
1110

1211
const constants = require('./constants')
1312
const backends = require('./backends')
@@ -40,7 +39,9 @@ class IpfsRepo {
4039
* @param {object} options - Configuration
4140
*/
4241
constructor (repoPath, options) {
43-
assert.strictEqual(typeof repoPath, 'string', 'missing repoPath')
42+
if (typeof repoPath !== 'string') {
43+
throw new Error('missing repoPath')
44+
}
4445

4546
this.options = buildOptions(options)
4647
this.closed = true
@@ -112,13 +113,15 @@ class IpfsRepo {
112113
this.lockfile = await this._openLock(this.path)
113114
log('acquired repo.lock')
114115
log('creating datastore')
115-
this.datastore = backends.create('datastore', path.join(this.path, 'datastore'), this.options)
116+
this.datastore = backends.create('datastore', pathJoin(this.path, 'datastore'), this.options)
117+
await this.datastore.open()
116118
log('creating blocks')
117-
const blocksBaseStore = backends.create('blocks', path.join(this.path, 'blocks'), this.options)
119+
const blocksBaseStore = backends.create('blocks', pathJoin(this.path, 'blocks'), this.options)
120+
await blocksBaseStore.open()
118121
this.blocks = await blockstore(blocksBaseStore, this.options.storageBackendOptions.blocks)
119122
log('creating keystore')
120-
this.keys = backends.create('keys', path.join(this.path, 'keys'), this.options)
121-
123+
this.keys = backends.create('keys', pathJoin(this.path, 'keys'), this.options)
124+
await this.keys.open()
122125
const isCompatible = await this.version.check(constants.repoVersion)
123126
if (!isCompatible) {
124127
if (await this._isAutoMigrationEnabled()) {
@@ -152,11 +155,15 @@ class IpfsRepo {
152155
*/
153156
_getLocker () {
154157
if (typeof this.options.lock === 'string') {
155-
assert(lockers[this.options.lock], 'Unknown lock type: ' + this.options.lock)
158+
if (!lockers[this.options.lock]) {
159+
throw new Error('Unknown lock type: ' + this.options.lock)
160+
}
156161
return lockers[this.options.lock]
157162
}
158163

159-
assert(this.options.lock, 'No lock provided')
164+
if (!this.options.lock) {
165+
throw new Error('No lock provided')
166+
}
160167
return this.options.lock
161168
}
162169

@@ -251,7 +258,13 @@ class IpfsRepo {
251258
}
252259
}
253260

254-
await Promise.all([this.root, this.blocks, this.keys, this.datastore].map((store) => store.close()))
261+
await Promise.all([
262+
this.root,
263+
this.blocks,
264+
this.keys,
265+
this.datastore
266+
].map((store) => store.close()))
267+
255268
log('unlocking')
256269
this.closed = true
257270
await this._closeLock()

src/lock.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
'use strict'
22

3+
const { LockExistsError } = require('./errors')
34
const path = require('path')
45
const debug = require('debug')
56
const { lock } = require('proper-lockfile')
@@ -27,7 +28,16 @@ const STALE_TIME = 20000
2728
exports.lock = async (dir) => {
2829
const file = path.join(dir, lockFile)
2930
log('locking %s', file)
30-
const release = await lock(dir, { lockfilePath: file, stale: STALE_TIME })
31+
let release
32+
try {
33+
release = await lock(dir, { lockfilePath: file, stale: STALE_TIME })
34+
} catch (err) {
35+
if (err.code === 'ELOCKED') {
36+
throw new LockExistsError(`Lock already being held for file: ${file}`)
37+
} else {
38+
throw err
39+
}
40+
}
3141
return {
3242
close: async () => { // eslint-disable-line require-await
3343
release()

0 commit comments

Comments
 (0)