Skip to content

Commit 9eeb291

Browse files
authored
Close sublevels upon closing parent db (#102)
This is a tweak to align state. Operations on the sublevel would already fail with `LEVEL_DATABASE_NOT_OPEN` but `sublevel.status` did not reflect that. Category: fix
1 parent 8444378 commit 9eeb291

File tree

3 files changed

+32
-4
lines changed

3 files changed

+32
-4
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -392,7 +392,7 @@ The optional `options` object may contain:
392392

393393
The `keyEncoding` and `valueEncoding` options are forwarded to the `AbstractLevel` constructor and work the same, as if a new, separate database was created. They default to `'utf8'` regardless of the encodings configured on `db`. Other options are forwarded too but `abstract-level` has no relevant options at the time of writing. For example, setting the `createIfMissing` option will have no effect. Why is that?
394394

395-
Like regular databases, sublevels open themselves but they do not affect the state of the parent database. This means a sublevel can be individually closed and (re)opened. If the sublevel is created while the parent database is opening, it will wait for that to finish. If the parent database is closed, then opening the sublevel will fail and subsequent operations on the sublevel will yield errors with code [`LEVEL_DATABASE_NOT_OPEN`](#errors).
395+
Like regular databases, sublevels open themselves, but they do not affect the state of the parent database. This means a sublevel can be individually closed and (re)opened. If the sublevel is created while the parent database is opening, it will wait for that to finish. Closing the parent database will automatically close the sublevel, along with other resources like iterators.
396396

397397
Lastly, the `name` argument can be an array as a shortcut to create nested sublevels. Those are normally created like so:
398398

lib/abstract-sublevel.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ module.exports = function ({ AbstractLevel }) {
3333
}
3434
}
3535

36-
// TODO: add autoClose option, which if true, does parent.attachResource(this)
3736
constructor (db, name, options) {
3837
// Don't forward AbstractSublevel options to AbstractLevel
3938
const { separator, manifest, ...forward } = AbstractSublevel.defaults(options)
@@ -130,7 +129,14 @@ module.exports = function ({ AbstractLevel }) {
130129
async _open (options) {
131130
// The parent db must open itself or be (re)opened by the user because
132131
// a sublevel should not initiate state changes on the rest of the db.
133-
return this.#parent.open({ passive: true })
132+
await this.#parent.open({ passive: true })
133+
134+
// Close sublevel when parent is closed
135+
this.#parent.attachResource(this)
136+
}
137+
138+
async _close () {
139+
this.#parent.detachResource(this)
134140
}
135141

136142
async _put (key, value, options) {

test/self/sublevel-test.js

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,27 @@ test('opening & closing sublevel', function (t) {
358358
await sub.close()
359359
})
360360

361+
t.test('sublevel is closed by parent', async function (t) {
362+
t.plan(4)
363+
364+
const db = new NoopLevel()
365+
await db.open()
366+
const sub = db.sublevel('test')
367+
368+
await db.open()
369+
await sub.open()
370+
371+
const promise = db.close()
372+
373+
t.is(db.status, 'closing')
374+
t.is(sub.status, 'closing')
375+
376+
await promise
377+
378+
t.is(db.status, 'closed')
379+
t.is(sub.status, 'closed')
380+
})
381+
361382
t.test('sublevel rejects operations if parent db is closed', async function (t) {
362383
t.plan(6)
363384

@@ -401,7 +422,8 @@ test('opening & closing sublevel', function (t) {
401422

402423
const promises = [
403424
db.close().then(async function () {
404-
// TODO: implement autoClose option (see AbstractSublevel)
425+
// Ideally it'd be 'closed' but it's still 'opening' at this point.
426+
// TODO: use a signal to abort the open() to transition to 'closed' faster
405427
// t.is(sub.status, 'closed')
406428

407429
t.is(db.status, 'closed')

0 commit comments

Comments
 (0)