rocksdb-native 3.0.1 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.js CHANGED
@@ -1,4 +1,3 @@
1
- const { ReadBatch, WriteBatch } = require('./lib/batch')
2
1
  const ColumnFamily = require('./lib/column-family')
3
2
  const Iterator = require('./lib/iterator')
4
3
  const Snapshot = require('./lib/snapshot')
@@ -9,12 +8,16 @@ class RocksDB {
9
8
  const {
10
9
  columnFamily,
11
10
  state = new DBState(this, path, opts),
12
- snapshot = null
11
+ snapshot = null,
12
+ keyEncoding = null,
13
+ valueEncoding = null
13
14
  } = opts
14
15
 
15
16
  this._state = state
16
17
  this._snapshot = snapshot
17
18
  this._columnFamily = state.getColumnFamily(columnFamily)
19
+ this._keyEncoding = keyEncoding
20
+ this._valueEncoding = valueEncoding
18
21
  this._index = this._state.addSession(this)
19
22
  }
20
23
 
@@ -36,7 +39,9 @@ class RocksDB {
36
39
 
37
40
  session({
38
41
  columnFamily = this._columnFamily,
39
- snapshot = this._snapshot !== null
42
+ snapshot = this._snapshot !== null,
43
+ keyEncoding = this._keyEncoding,
44
+ valueEncoding = this._valueEncoding
40
45
  } = {}) {
41
46
  let snap = null
42
47
 
@@ -49,12 +54,14 @@ class RocksDB {
49
54
  return new RocksDB(null, {
50
55
  state: this._state,
51
56
  columnFamily,
52
- snapshot: snap
57
+ snapshot: snap,
58
+ keyEncoding,
59
+ valueEncoding
53
60
  })
54
61
  }
55
62
 
56
- columnFamily(name) {
57
- return this.session({ columnFamily: name })
63
+ columnFamily(name, opts) {
64
+ return this.session({ ...opts, columnFamily: name })
58
65
  }
59
66
 
60
67
  snapshot() {
@@ -114,52 +121,36 @@ class RocksDB {
114
121
  }
115
122
 
116
123
  read(opts) {
117
- return new ReadBatch(this, opts)
124
+ return this._state.createReadBatch(this, opts)
118
125
  }
119
126
 
120
127
  write(opts) {
121
- return new WriteBatch(this, opts)
128
+ return this._state.createWriteBatch(this, opts)
122
129
  }
123
130
 
124
131
  async get(key, opts) {
125
- const batch = this.read({ ...opts, capacity: 1 })
126
- try {
127
- const value = batch.get(key)
128
- batch.tryFlush()
129
- return await value
130
- } finally {
131
- batch.destroy()
132
- }
132
+ const batch = this.read({ ...opts, capacity: 1, autoDestroy: true })
133
+ const value = batch.get(key)
134
+ batch.tryFlush()
135
+ return value
133
136
  }
134
137
 
135
138
  async put(key, value, opts) {
136
- const batch = this.write({ ...opts, capacity: 1 })
137
- try {
138
- batch.tryPut(key, value)
139
- await batch.flush()
140
- } finally {
141
- batch.destroy()
142
- }
139
+ const batch = this.write({ ...opts, capacity: 1, autoDestroy: true })
140
+ batch.tryPut(key, value)
141
+ await batch.flush()
143
142
  }
144
143
 
145
144
  async delete(key, opts) {
146
- const batch = this.write({ ...opts, capacity: 1 })
147
- try {
148
- batch.tryDelete(key)
149
- await batch.flush()
150
- } finally {
151
- batch.destroy()
152
- }
145
+ const batch = this.write({ ...opts, capacity: 1, autoDestroy: true })
146
+ batch.tryDelete(key)
147
+ await batch.flush()
153
148
  }
154
149
 
155
150
  async deleteRange(start, end, opts) {
156
- const batch = this.write({ ...opts, capacity: 1 })
157
- try {
158
- batch.tryDeleteRange(start, end)
159
- await batch.flush()
160
- } finally {
161
- batch.destroy()
162
- }
151
+ const batch = this.write({ ...opts, capacity: 1, autoDestroy: true })
152
+ batch.tryDeleteRange(start, end)
153
+ await batch.flush()
163
154
  }
164
155
  }
165
156
 
package/lib/batch.js CHANGED
@@ -6,26 +6,16 @@ const resolved = Promise.resolve()
6
6
 
7
7
  class RocksDBBatch {
8
8
  constructor(db, opts = {}) {
9
- const {
10
- columnFamily = db.defaultColumnFamily,
11
- capacity = 8,
12
- encoding = null,
13
- keyEncoding = encoding,
14
- valueEncoding = encoding
15
- } = opts
9
+ const { capacity = 8, autoDestroy = false } = opts
16
10
 
17
11
  db._state.ref()
18
12
 
19
- this._state = db._state
20
- this._columnFamily = columnFamily
13
+ this._db = db
21
14
  this._destroyed = false
22
15
  this._capacity = capacity
23
16
  this._operations = []
24
17
  this._promises = []
25
18
 
26
- this._keyEncoding = keyEncoding
27
- this._valueEncoding = valueEncoding
28
-
29
19
  this._enqueuePromise = this._enqueuePromise.bind(this)
30
20
 
31
21
  this._request = null
@@ -33,8 +23,19 @@ class RocksDBBatch {
33
23
 
34
24
  this._handle = null
35
25
  this._buffer = null
26
+ this._autoDestroy = autoDestroy
27
+
28
+ if (db._state.opened === true) this.ready()
29
+ }
30
+
31
+ _reuse(db, opts = {}) {
32
+ const { autoDestroy = false } = opts
33
+
34
+ db._state.ref()
36
35
 
37
- if (this._state.opened === true) this.ready()
36
+ this._db = db
37
+ this._destroyed = false
38
+ this._autoDestroy = autoDestroy
38
39
  }
39
40
 
40
41
  _onfinished() {
@@ -45,6 +46,7 @@ class RocksDBBatch {
45
46
  this._request = null
46
47
  this._resolve = null
47
48
 
49
+ if (this._autoDestroy === true) this.destroy()
48
50
  if (resolve !== null) resolve()
49
51
  }
50
52
 
@@ -61,7 +63,7 @@ class RocksDBBatch {
61
63
  async ready() {
62
64
  if (this._handle !== null) return
63
65
 
64
- if (this._state.opened === false) await this._state.ready()
66
+ if (this._db._state.opened === false) await this._db._state.ready()
65
67
 
66
68
  this._init()
67
69
  }
@@ -72,7 +74,22 @@ class RocksDBBatch {
72
74
 
73
75
  this._destroyed = true
74
76
 
75
- this._state.unref()
77
+ if (this._promises.length) this._abort()
78
+
79
+ this._db._state.unref()
80
+ this._onfree()
81
+ }
82
+
83
+ _onfree() {
84
+ this._db._state.freeBatch(this, false)
85
+ this._db = null
86
+ }
87
+
88
+ _abort() {
89
+ for (let i = 0; i < this._promises.length; i++) {
90
+ const promise = this._promises[i]
91
+ if (promise !== null) promise.reject(new Error('Batch is destroyed'))
92
+ }
76
93
  }
77
94
 
78
95
  flush() {
@@ -105,31 +122,25 @@ class RocksDBBatch {
105
122
  }
106
123
 
107
124
  _encodeKey(k) {
108
- if (this._keyEncoding) return c.encode(this._keyEncoding, k)
125
+ if (this._db._keyEncoding) return c.encode(this._db._keyEncoding, k)
109
126
  if (typeof k === 'string') return Buffer.from(k)
110
127
  return k
111
128
  }
112
129
 
113
130
  _encodeValue(v) {
114
- if (this._valueEncoding) return c.encode(this._valueEncoding, v)
131
+ if (this._db._valueEncoding) return c.encode(this._db._valueEncoding, v)
115
132
  if (v === null) return empty
116
133
  if (typeof v === 'string') return Buffer.from(v)
117
134
  return v
118
135
  }
119
136
 
120
137
  _decodeValue(b) {
121
- if (this._valueEncoding) return c.decode(this._valueEncoding, b)
138
+ if (this._db._valueEncoding) return c.decode(this._db._valueEncoding, b)
122
139
  return b
123
140
  }
124
141
  }
125
142
 
126
143
  exports.ReadBatch = class RocksDBReadBatch extends RocksDBBatch {
127
- constructor(db, opts) {
128
- super(db, opts)
129
-
130
- this._snapshot = db._snapshot
131
- }
132
-
133
144
  _init() {
134
145
  this._handle = binding.readInit()
135
146
  this._buffer = binding.readBuffer(this._handle, this._capacity)
@@ -145,10 +156,10 @@ exports.ReadBatch = class RocksDBReadBatch extends RocksDBBatch {
145
156
  await super._flush()
146
157
 
147
158
  binding.read(
148
- this._state.handle,
159
+ this._db._state.handle,
149
160
  this._handle,
150
161
  this._operations,
151
- this._snapshot ? this._snapshot._handle : null,
162
+ this._db._snapshot ? this._db._snapshot._handle : null,
152
163
  this,
153
164
  this._onread
154
165
  )
@@ -179,7 +190,7 @@ exports.ReadBatch = class RocksDBReadBatch extends RocksDBBatch {
179
190
  const promise = new Promise(this._enqueuePromise)
180
191
 
181
192
  this._operations.push(
182
- new RocksDBGet(this._encodeKey(key), this._columnFamily)
193
+ new RocksDBGet(this._encodeKey(key), this._db._columnFamily)
183
194
  )
184
195
 
185
196
  this._resize()
@@ -200,11 +211,15 @@ exports.WriteBatch = class RocksDBWriteBatch extends RocksDBBatch {
200
211
  }
201
212
  }
202
213
 
214
+ _onfree() {
215
+ this._db._state.freeBatch(this, true)
216
+ }
217
+
203
218
  async _flush() {
204
219
  await super._flush()
205
220
 
206
221
  binding.write(
207
- this._state.handle,
222
+ this._db._state.handle,
208
223
  this._handle,
209
224
  this._operations,
210
225
  this,
@@ -233,7 +248,7 @@ exports.WriteBatch = class RocksDBWriteBatch extends RocksDBBatch {
233
248
  new RocksDBPut(
234
249
  this._encodeKey(key),
235
250
  this._encodeValue(value),
236
- this._columnFamily
251
+ this._db._columnFamily
237
252
  )
238
253
  )
239
254
 
@@ -249,7 +264,7 @@ exports.WriteBatch = class RocksDBWriteBatch extends RocksDBBatch {
249
264
  new RocksDBPut(
250
265
  this._encodeKey(key),
251
266
  this._encodeValue(value),
252
- this._columnFamily
267
+ this._db._columnFamily
253
268
  )
254
269
  )
255
270
 
@@ -264,7 +279,7 @@ exports.WriteBatch = class RocksDBWriteBatch extends RocksDBBatch {
264
279
  const promise = new Promise(this._enqueuePromise)
265
280
 
266
281
  this._operations.push(
267
- new RocksDBDelete(this._encodeKey(key), this._columnFamily)
282
+ new RocksDBDelete(this._encodeKey(key), this._db._columnFamily)
268
283
  )
269
284
 
270
285
  this._resize()
@@ -276,7 +291,7 @@ exports.WriteBatch = class RocksDBWriteBatch extends RocksDBBatch {
276
291
  if (this._request) throw new Error('Request already in progress')
277
292
 
278
293
  this._operations.push(
279
- new RocksDBDelete(this._encodeKey(key), this._columnFamily)
294
+ new RocksDBDelete(this._encodeKey(key), this._db._columnFamily)
280
295
  )
281
296
 
282
297
  this._promises.push(null)
@@ -293,7 +308,7 @@ exports.WriteBatch = class RocksDBWriteBatch extends RocksDBBatch {
293
308
  new RocksDBDeleteRange(
294
309
  this._encodeKey(start),
295
310
  this._encodeKey(end),
296
- this._columnFamily
311
+ this._db._columnFamily
297
312
  )
298
313
  )
299
314
 
@@ -309,7 +324,7 @@ exports.WriteBatch = class RocksDBWriteBatch extends RocksDBBatch {
309
324
  new RocksDBDeleteRange(
310
325
  this._encodeKey(start),
311
326
  this._encodeKey(end),
312
- this._columnFamily
327
+ this._db._columnFamily
313
328
  )
314
329
  )
315
330
 
package/lib/iterator.js CHANGED
@@ -7,28 +7,20 @@ const empty = Buffer.alloc(0)
7
7
  module.exports = class RocksDBIterator extends Readable {
8
8
  constructor(db, opts = {}) {
9
9
  const {
10
- columnFamily = db.defaultColumnFamily,
11
10
  gt = null,
12
11
  gte = null,
13
12
  lt = null,
14
13
  lte = null,
15
14
  reverse = false,
16
15
  limit = Infinity,
17
- capacity = 8,
18
- encoding = null,
19
- keyEncoding = encoding,
20
- valueEncoding = encoding
16
+ capacity = 8
21
17
  } = opts
22
18
 
23
19
  super()
24
20
 
25
21
  db._state.ref()
26
22
 
27
- this._state = db._state
28
- this._columnFamily = columnFamily
29
-
30
- this._keyEncoding = keyEncoding
31
- this._valueEncoding = valueEncoding
23
+ this._db = db
32
24
 
33
25
  this._gt = gt ? this._encodeKey(gt) : empty
34
26
  this._gte = gte ? this._encodeKey(gte) : empty
@@ -38,7 +30,6 @@ module.exports = class RocksDBIterator extends Readable {
38
30
  this._reverse = reverse
39
31
  this._limit = limit < 0 ? Infinity : limit
40
32
  this._capacity = capacity
41
- this._snapshot = db._snapshot
42
33
 
43
34
  this._pendingOpen = null
44
35
  this._pendingRead = null
@@ -47,7 +38,7 @@ module.exports = class RocksDBIterator extends Readable {
47
38
  this._buffer = null
48
39
  this._handle = null
49
40
 
50
- if (this._state.opened === true) this.ready()
41
+ if (this._db._state.opened === true) this.ready()
51
42
  }
52
43
 
53
44
  _onopen(err) {
@@ -80,7 +71,7 @@ module.exports = class RocksDBIterator extends Readable {
80
71
  _onclose(err) {
81
72
  const cb = this._pendingDestroy
82
73
  this._pendingDestroy = null
83
- this._state.unref()
74
+ this._db._state.unref()
84
75
  cb(err)
85
76
  }
86
77
 
@@ -93,7 +84,7 @@ module.exports = class RocksDBIterator extends Readable {
93
84
  async ready() {
94
85
  if (this._handle !== null) return
95
86
 
96
- if (this._state.opened === false) await this._state.ready()
87
+ if (this._db._state.opened === false) await this._db._state.ready()
97
88
 
98
89
  this._init()
99
90
  }
@@ -109,15 +100,15 @@ module.exports = class RocksDBIterator extends Readable {
109
100
  this._pendingOpen = cb
110
101
 
111
102
  binding.iteratorOpen(
112
- this._state.handle,
103
+ this._db._state.handle,
113
104
  this._handle,
114
- this._columnFamily._handle,
105
+ this._db._columnFamily._handle,
115
106
  this._gt,
116
107
  this._gte,
117
108
  this._lt,
118
109
  this._lte,
119
110
  this._reverse,
120
- this._snapshot ? this._snapshot._handle : null,
111
+ this._db._snapshot ? this._db._snapshot._handle : null,
121
112
  this,
122
113
  this._onopen,
123
114
  this._onclose,
@@ -140,18 +131,21 @@ module.exports = class RocksDBIterator extends Readable {
140
131
  }
141
132
 
142
133
  _encodeKey(k) {
143
- if (this._keyEncoding) return c.encode(this._keyEncoding, k)
134
+ if (this._db._keyEncoding !== null)
135
+ return c.encode(this._db._keyEncoding, k)
144
136
  if (typeof k === 'string') return Buffer.from(k)
145
137
  return k
146
138
  }
147
139
 
148
140
  _decodeKey(b) {
149
- if (this._keyEncoding) return c.decode(this._keyEncoding, b)
141
+ if (this._db._keyEncoding !== null)
142
+ return c.decode(this._db._keyEncoding, b)
150
143
  return b
151
144
  }
152
145
 
153
146
  _decodeValue(b) {
154
- if (this._valueEncoding) return c.decode(this._valueEncoding, b)
147
+ if (this._db._valueEncoding !== null)
148
+ return c.decode(this._db._valueEncoding, b)
155
149
  return b
156
150
  }
157
151
  }
package/lib/state.js CHANGED
@@ -1,8 +1,11 @@
1
1
  const ReadyResource = require('ready-resource')
2
2
  const RefCounter = require('refcounter')
3
+ const { ReadBatch, WriteBatch } = require('./batch')
3
4
  const ColumnFamily = require('./column-family')
4
5
  const binding = require('../binding')
5
6
 
7
+ const MAX_BATCH_REUSE = 64
8
+
6
9
  module.exports = class DBState extends ReadyResource {
7
10
  constructor(db, path, opts) {
8
11
  super()
@@ -28,6 +31,8 @@ module.exports = class DBState extends ReadyResource {
28
31
  this._suspending = null
29
32
  this._resuming = null
30
33
  this._columnsFlushed = false
34
+ this._readBatches = []
35
+ this._writeBatches = []
31
36
 
32
37
  for (const col of columnFamilies) {
33
38
  this.columnFamilies.push(
@@ -47,9 +52,29 @@ module.exports = class DBState extends ReadyResource {
47
52
  )
48
53
  }
49
54
 
55
+ createReadBatch(db, opts) {
56
+ if (this._readBatches.length === 0) return new ReadBatch(db, opts)
57
+ const batch = this._readBatches.pop()
58
+ batch._reuse(db, opts)
59
+ return batch
60
+ }
61
+
62
+ createWriteBatch(db, opts) {
63
+ if (this._writeBatches.length === 0) return new WriteBatch(db, opts)
64
+ const batch = this._writeBatches.pop()
65
+ batch._reuse(db, opts)
66
+ return batch
67
+ }
68
+
69
+ freeBatch(batch, writable) {
70
+ const queue = writable ? this._writeBatches : this._readBatches
71
+ if (queue.length >= MAX_BATCH_REUSE) return
72
+ queue.push(batch)
73
+ }
74
+
50
75
  addSession(db) {
51
76
  this.sessionRefs.inc()
52
- db._index = this.sessions.push(db) - 1
77
+ return this.sessions.push(db) - 1
53
78
  }
54
79
 
55
80
  removeSession(db) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rocksdb-native",
3
- "version": "3.0.1",
3
+ "version": "3.1.0",
4
4
  "description": "librocksdb bindings for JavaScript",
5
5
  "exports": {
6
6
  ".": "./index.js",