-
-
Notifications
You must be signed in to change notification settings - Fork 8
/
abstract-snapshot.js
84 lines (67 loc) · 2.2 KB
/
abstract-snapshot.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
'use strict'
const ModuleError = require('module-error')
const { noop } = require('./lib/common')
class AbstractSnapshot {
#open = true
#referenceCount = 0
#pendingClose = null
#closePromise = null
#owner
constructor (options) {
// Defining this as an option gives sublevels the opportunity to create a snapshot
// via their parent database but still designate themselves as the "owner", which
// just means which database will close the snapshot upon db.close(). This ensures
// that the API of AbstractSublevel is symmetrical to AbstractLevel.
const owner = options.owner
if (typeof owner !== 'object' || owner === null) {
const hint = owner === null ? 'null' : typeof owner
throw new TypeError(`Owner must be an abstract-level database, received ${hint}`)
}
// Also ensures this db will not be garbage collected
this.#owner = owner
this.#owner.attachResource(this)
}
ref () {
if (!this.#open) {
throw new ModuleError('Snapshot is not open: cannot use snapshot after close()', {
code: 'LEVEL_SNAPSHOT_NOT_OPEN'
})
}
this.#referenceCount++
}
unref () {
if (--this.#referenceCount === 0 && this.#pendingClose !== null) {
this.#pendingClose()
}
}
async close () {
if (this.#closePromise !== null) {
// First caller of close() is responsible for error
return this.#closePromise.catch(noop)
}
this.#open = false
// Wrap to avoid race issues on recursive calls
this.#closePromise = new Promise((resolve, reject) => {
this.#pendingClose = () => {
this.#pendingClose = null
privateClose(this, this.#owner).then(resolve, reject)
}
})
// If working we'll delay closing, but still handle the close error (if any) here
if (this.#referenceCount === 0) {
this.#pendingClose()
}
return this.#closePromise
}
async _close () {}
}
if (typeof Symbol.asyncDispose === 'symbol') {
AbstractSnapshot.prototype[Symbol.asyncDispose] = async function () {
return this.close()
}
}
const privateClose = async function (snapshot, owner) {
await snapshot._close()
owner.detachResource(snapshot)
}
exports.AbstractSnapshot = AbstractSnapshot