-
Notifications
You must be signed in to change notification settings - Fork 50
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Refactor js-repo away from callbacks leaning on async/await #189
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall I think the updates look good so far
src/index.js
Outdated
return this.root.open() | ||
.then(() => this.config.set(buildConfig(config))) | ||
.then(() => this.spec.set(buildDatastoreSpec(config))) | ||
.then(() => this.version.set(repoVersion)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This stack could probably just become await calls to make it cleaner.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Apologies, I haven't finished reviewing this but there's enough here that I thought I'd submit it and re-review when I have another moment.
src/blockstore.js
Outdated
store.put(k, block.data, callback) | ||
return store.has(k).then((exists) => { | ||
if (exists) { return } | ||
return store.put(k, block.data) | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please await instead:
const exists = await store.has(k)
if (exists) return
return store.put(k, block.data)
src/blockstore.js
Outdated
}) | ||
|
||
batch.commit(callback) | ||
const batch = await store.batch() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't need to await a batch object - this should be sync.
src/blockstore.js
Outdated
|
||
batch.commit(callback) | ||
const batch = await store.batch() | ||
const newKeys = await Promise.all(keys.filter((k) => { store.has(k.key) })) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const newKeys = await Promise.all(keys.filter((k) => { store.has(k.key) })) | |
const newKeys = (await Promise.all(keys.map(async k => { | |
const exists = await store.has(k.key) | |
return exists ? null : k | |
}))).filter(Boolean) |
src/blockstore.js
Outdated
const otherCid = cidToOtherVersion(cid) | ||
if (!otherCid) return false | ||
return store.has(cidToDsKey(otherCid)) | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use await
src/blockstore.js
Outdated
* @param {Block} block | ||
* @returns {Promise<void>} | ||
*/ | ||
put (block) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use async
keyword since this is an async API. If the caller is using traditional then
/catch
and the function throws then it'll cause an uncaught exception. e.g.
const b = 'INVALID BLOCK'
repo.put(b).catch(errHandler)
// uncaught exception, errHandler is not called
src/blockstore.js
Outdated
*/ | ||
has (cid, callback) { | ||
has (cid) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use async
keyword since this is an async API. See previous comment for explanation.
src/blockstore.js
Outdated
*/ | ||
delete (cid, callback) { | ||
delete (cid) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use async
keyword since this is an async API. See previous comment for explanation.
src/index.js
Outdated
*/ | ||
_isInitialized (callback) { | ||
async _isInitialized () { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should now return true/false
src/index.js
Outdated
await this.root.open() | ||
await this.config.set(buildConfig(config)) | ||
await this.spec.set(buildDatastoreSpec(config)) | ||
await this.version.set(repoVersion) | ||
} | ||
|
||
/** | ||
* Open the repo. If the repo is already open no action will be taken. | ||
* If the repo is not initialized it will return an error. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe that "If the repo is already open no action will be taken." is not really correct, because according to the L77, it will throw an error. Maybe lets update it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch, the comment is definitely off 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe the error thrown should be bit more custom (eq. creating a new category in ./errors/index.js
) so people could detect if the opening of repo failed because it is locked and handle it? But not sure if it is in the scope of this PR though...
src/version.js
Outdated
callback(null, parseInt(buf.toString().trim(), 10)) | ||
}) | ||
async get () { | ||
const buf = await this.get(versionKey) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This line causes a stack overflow, I think it should be
const buf = await this.get(versionKey) | |
const buf = await store.get(versionKey) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It does, I have some pending changes stored locally for this, that I haven't pushed back up yet. Do you mind if I drop a PTAL when I push the various fixes I have going locally, this PR was a bit tricker to write and is probably more error prone in places, because I wrote it before the other PRs. Thanks for looking into it!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No worries, I just noticed this when testing some code that has this as a dependency. The rest of it looks great to me.
src/index.js
Outdated
cb() | ||
} | ||
], (err) => callback(err)) | ||
await this.apiAddr.delete() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This refactored part will fail if the /api does not exists; see original this.apiAddr.delete(ignoringNotFound(cb))
.
src/index.js
Outdated
(cb) => this.spec.set(buildDatastoreSpec(config), cb), | ||
(cb) => this.version.set(repoVersion, cb) | ||
], callback) | ||
await this.root.open() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a reminder to make sure we cover the case where the repo is already open
src/index.js
Outdated
this.keys = backends.create('keys', path.join(this.path, 'keys'), this.options) | ||
this.closed = false | ||
log('all opened') | ||
} catch (err) { | ||
if (err && this.lockfile) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you still want to throw here if there is no lock file.
} catch (err2) { | ||
log('error removing lock', err2) | ||
} | ||
this.lockfile = null |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you only want to set this.lockfile
to null if there was not an error thrown from this._closeLock()
src/config.js
Outdated
} | ||
|
||
if (value === undefined || Buffer.isBuffer(value)) { | ||
return callback(new Error('Invalid value type')) | ||
throw new Error('Invalid value type') | ||
} | ||
|
||
setQueue.push({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd suggest using a p-queue so that you can return a Promise here
package.json
Outdated
@@ -49,15 +49,14 @@ | |||
"rimraf": "^2.6.2" | |||
}, | |||
"dependencies": { | |||
"async": "^2.6.1", | |||
"base32.js": "~0.1.0", | |||
"bignumber.js": "^8.0.2", | |||
"cids": "~0.5.7", | |||
"datastore-core": "~0.6.0", | |||
"datastore-fs": "~0.7.0", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you please add a dependency on ipfs/js-datastore-fs#22 ?
"dlv": "^1.1.2", | ||
"interface-datastore": "~0.6.0", | ||
"err-code": "^1.1.2", | ||
"interface-datastore": "git://github.com/ipfs/interface-datastore.git#refactor/async-iterators", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As the refactor/async-iterators
PR was merged and the branch deleted this is outdated and breaks things.
Superseded by #199 |
Initial pull request for the async await refactor. Some notes.
I don't anticipate test to past just yet. There are upstream dependencies on async-multihashing and the various datastore interfaces. I modeled the interface changes based off of the current inflight async api refactor PRs for the dependencies(multiformats/js-multihashing-async#37, ipfs/interface-datastore#25, ipfs/js-datastore-level#12).
Another thing to note is that some of the error handling for opening/deleting a repo, might be up for question. It was a bit unclear what errors should be handled, given the ongoing refactor.
js-ipfs-repo/src/index.js
Line 71 in 41e042b
Let me know what you think and what needs to be patched up or changed, happy to jam on it. If the interface seems good. I'll try to push testing the interface as far as I can go prior to the upstream package changes landing.