rocksdb-native 3.3.0 → 3.4.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/CMakeLists.txt CHANGED
@@ -13,7 +13,7 @@ if(target MATCHES "win32")
13
13
  add_compile_options(/MT$<$<CONFIG:Debug>:d>)
14
14
  endif()
15
15
 
16
- fetch_package("github:holepunchto/librocksdb#2b388ab")
16
+ fetch_package("github:holepunchto/librocksdb#049c4c7")
17
17
 
18
18
  add_bare_module(rocksdb_native_bare)
19
19
 
package/binding.c CHANGED
@@ -6,32 +6,6 @@
6
6
  #include <string.h>
7
7
  #include <utf.h>
8
8
 
9
- typedef struct {
10
- uint32_t low;
11
- uint32_t high;
12
- } rocksdb_native_uint64_t;
13
-
14
- typedef struct {
15
- uint32_t read_only;
16
- uint32_t create_if_missing;
17
- uint32_t create_missing_column_families;
18
- uint32_t max_background_jobs;
19
- rocksdb_native_uint64_t bytes_per_sync;
20
- } rocksdb_native_options_t;
21
-
22
- typedef struct {
23
- uint32_t compation_style;
24
- uint32_t enable_blob_files;
25
- rocksdb_native_uint64_t min_blob_size;
26
- rocksdb_native_uint64_t blob_file_size;
27
- uint32_t enable_blob_garbage_collection;
28
- rocksdb_native_uint64_t table_block_size;
29
- uint32_t table_cache_index_and_filter_blocks;
30
- uint32_t table_format_version;
31
- uint32_t optimize_filters_for_memory;
32
- uint32_t no_block_cache;
33
- } rocksdb_native_column_family_options_t;
34
-
35
9
  typedef struct {
36
10
  rocksdb_column_family_t *handle;
37
11
  rocksdb_column_family_descriptor_t descriptor;
@@ -137,11 +111,6 @@ typedef struct {
137
111
  rocksdb_snapshot_t handle;
138
112
  } rocksdb_native_snapshot_t;
139
113
 
140
- static inline uint64_t
141
- rocksdb_native__to_uint64(rocksdb_native_uint64_t n) {
142
- return n.high * 0x100000000 + n.low;
143
- }
144
-
145
114
  static void
146
115
  rocksdb_native__on_free(js_env_t *env, void *data, void *finalize_hint) {
147
116
  free(data);
@@ -325,18 +294,33 @@ static js_value_t *
325
294
  rocksdb_native_init(js_env_t *env, js_callback_info_t *info) {
326
295
  int err;
327
296
 
328
- size_t argc = 1;
329
- js_value_t *argv[1];
297
+ size_t argc = 7;
298
+ js_value_t *argv[7];
330
299
 
331
300
  err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
332
301
  assert(err == 0);
333
302
 
334
- assert(argc == 1);
303
+ assert(argc == 7);
335
304
 
336
- rocksdb_native_options_t *options;
337
- err = js_get_typedarray_info(env, argv[0], NULL, (void **) &options, NULL, NULL, NULL);
305
+ typedef bool bool_t;
306
+
307
+ #define V(name, type) \
308
+ assert(i < argc); \
309
+ type##_t name; \
310
+ err = js_get_value_##type(env, argv[i++], &name); \
338
311
  assert(err == 0);
339
312
 
313
+ int i = 0;
314
+
315
+ V(read_only, bool)
316
+ V(create_if_missing, bool)
317
+ V(create_missing_column_families, bool)
318
+ V(max_background_jobs, int32)
319
+ V(bytes_per_sync, int64)
320
+ V(max_open_files, int32)
321
+ V(use_direct_reads, bool)
322
+ #undef V
323
+
340
324
  uv_loop_t *loop;
341
325
  err = js_get_env_loop(env, &loop);
342
326
  assert(err == 0);
@@ -352,12 +336,14 @@ rocksdb_native_init(js_env_t *env, js_callback_info_t *info) {
352
336
  db->exiting = false;
353
337
 
354
338
  db->options = (rocksdb_options_t) {
355
- 0,
356
- options->read_only,
357
- options->create_if_missing,
358
- options->create_missing_column_families,
359
- options->max_background_jobs,
360
- rocksdb_native__to_uint64(options->bytes_per_sync),
339
+ 1,
340
+ read_only,
341
+ create_if_missing,
342
+ create_missing_column_families,
343
+ max_background_jobs,
344
+ bytes_per_sync,
345
+ max_open_files,
346
+ use_direct_reads
361
347
  };
362
348
 
363
349
  err = rocksdb_init(loop, &db->handle);
@@ -682,13 +668,13 @@ static js_value_t *
682
668
  rocksdb_native_column_family_init(js_env_t *env, js_callback_info_t *info) {
683
669
  int err;
684
670
 
685
- size_t argc = 2;
686
- js_value_t *argv[2];
671
+ size_t argc = 13;
672
+ js_value_t *argv[13];
687
673
 
688
674
  err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
689
675
  assert(err == 0);
690
676
 
691
- assert(argc == 2);
677
+ assert(argc >= 11 && argc <= 13);
692
678
 
693
679
  size_t name_len;
694
680
  err = js_get_value_string_utf8(env, argv[0], NULL, 0, &name_len);
@@ -700,10 +686,56 @@ rocksdb_native_column_family_init(js_env_t *env, js_callback_info_t *info) {
700
686
  err = js_get_value_string_utf8(env, argv[0], name, name_len, NULL);
701
687
  assert(err == 0);
702
688
 
703
- rocksdb_native_column_family_options_t *options;
704
- err = js_get_typedarray_info(env, argv[1], NULL, (void **) &options, NULL, NULL, NULL);
689
+ typedef bool bool_t;
690
+ typedef double double_t;
691
+
692
+ #define V(name, type) \
693
+ assert(i < argc); \
694
+ type##_t name; \
695
+ err = js_get_value_##type(env, argv[i++], &name); \
705
696
  assert(err == 0);
706
697
 
698
+ int i = 1;
699
+
700
+ V(enable_blob_files, bool)
701
+ V(min_blob_size, int64)
702
+ V(blob_file_size, int64)
703
+ V(enable_blob_garbage_collection, bool)
704
+ V(table_block_size, int64)
705
+ V(table_cache_index_and_filter_blocks, bool)
706
+ V(table_format_version, uint32)
707
+ V(optimize_filters_for_memory, bool)
708
+ V(no_block_cache, bool)
709
+ V(filter_policy_type, uint32)
710
+
711
+ rocksdb_filter_policy_t filter_policy = {filter_policy_type};
712
+
713
+ switch (filter_policy_type) {
714
+ case rocksdb_bloom_filter_policy: {
715
+ V(bits_per_key, double)
716
+
717
+ filter_policy.bloom = (rocksdb_bloom_filter_options_t) {
718
+ 0,
719
+ bits_per_key
720
+ };
721
+
722
+ break;
723
+ }
724
+ case rocksdb_ribbon_filter_policy: {
725
+ V(bloom_equivalent_bits_per_key, double)
726
+ V(bloom_before_level, int32)
727
+
728
+ filter_policy.ribbon = (rocksdb_ribbon_filter_options_t) {
729
+ 0,
730
+ bloom_equivalent_bits_per_key,
731
+ bloom_before_level,
732
+ };
733
+
734
+ break;
735
+ }
736
+ }
737
+ #undef V
738
+
707
739
  uv_loop_t *loop;
708
740
  err = js_get_env_loop(env, &loop);
709
741
  assert(err == 0);
@@ -721,17 +753,18 @@ rocksdb_native_column_family_init(js_env_t *env, js_callback_info_t *info) {
721
753
  column_family->descriptor = (rocksdb_column_family_descriptor_t) {
722
754
  (const char *) name,
723
755
  {
724
- 1,
725
- options->compation_style,
726
- options->enable_blob_files,
727
- rocksdb_native__to_uint64(options->min_blob_size),
728
- rocksdb_native__to_uint64(options->blob_file_size),
729
- options->enable_blob_garbage_collection,
730
- rocksdb_native__to_uint64(options->table_block_size),
731
- options->table_cache_index_and_filter_blocks,
732
- options->table_format_version,
733
- options->optimize_filters_for_memory,
734
- options->no_block_cache,
756
+ 2,
757
+ rocksdb_level_compaction,
758
+ enable_blob_files,
759
+ min_blob_size,
760
+ blob_file_size,
761
+ enable_blob_garbage_collection,
762
+ table_block_size,
763
+ table_cache_index_and_filter_blocks,
764
+ table_format_version,
765
+ optimize_filters_for_memory,
766
+ no_block_cache,
767
+ filter_policy,
735
768
  }
736
769
  };
737
770
 
package/index.js CHANGED
@@ -1,13 +1,14 @@
1
1
  const ColumnFamily = require('./lib/column-family')
2
2
  const Iterator = require('./lib/iterator')
3
3
  const Snapshot = require('./lib/snapshot')
4
- const DBState = require('./lib/state')
4
+ const State = require('./lib/state')
5
+ const { BloomFilterPolicy, RibbonFilterPolicy } = require('./lib/filter-policy')
5
6
 
6
7
  class RocksDB {
7
8
  constructor(path, opts = {}) {
8
9
  const {
9
10
  columnFamily,
10
- state = new DBState(this, path, opts),
11
+ state = new State(this, path, opts),
11
12
  snapshot = null,
12
13
  keyEncoding = null,
13
14
  valueEncoding = null
@@ -174,6 +175,8 @@ class RocksDB {
174
175
  module.exports = exports = RocksDB
175
176
 
176
177
  exports.ColumnFamily = ColumnFamily
178
+ exports.BloomFilterPolicy = BloomFilterPolicy
179
+ exports.RibbonFilterPolicy = RibbonFilterPolicy
177
180
 
178
181
  function maybeClosed(db) {
179
182
  if (db._state.closing || db._index === -1)
package/lib/batch.js CHANGED
@@ -20,6 +20,7 @@ class RocksDBBatch {
20
20
 
21
21
  this._request = null
22
22
  this._resolve = null
23
+ this._reject = null
23
24
 
24
25
  this._handle = null
25
26
  this._buffer = null
@@ -38,16 +39,20 @@ class RocksDBBatch {
38
39
  this._autoDestroy = autoDestroy
39
40
  }
40
41
 
41
- _onfinished() {
42
+ _onfinished(err) {
42
43
  const resolve = this._resolve
44
+ const reject = this._reject
43
45
 
44
46
  this._operations = []
45
47
  this._promises = []
46
48
  this._request = null
47
49
  this._resolve = null
50
+ this._reject = null
48
51
 
49
52
  if (this._autoDestroy === true) this.destroy()
50
- if (resolve !== null) resolve()
53
+
54
+ if (reject !== null && err) reject(err)
55
+ else if (resolve !== null) resolve()
51
56
  }
52
57
 
53
58
  _resize() {
@@ -92,12 +97,19 @@ class RocksDBBatch {
92
97
  }
93
98
  }
94
99
 
95
- flush() {
100
+ async flush() {
96
101
  if (this._request) throw new Error('Request in progress')
97
102
  if (this._destroyed) throw new Error('Batch is destroyed')
98
103
 
99
- this._request = new Promise((resolve) => {
104
+ const state = this._db._state
105
+
106
+ if (state._suspending || state._suspended) {
107
+ throw new Error('Database is suspended')
108
+ }
109
+
110
+ this._request = new Promise((resolve, reject) => {
100
111
  this._resolve = resolve
112
+ this._reject = reject
101
113
  })
102
114
 
103
115
  this._flush()
@@ -107,6 +119,13 @@ class RocksDBBatch {
107
119
 
108
120
  tryFlush() {
109
121
  if (this._request) throw new Error('Request in progress')
122
+ if (this._destroyed) throw new Error('Batch is destroyed')
123
+
124
+ const state = this._db._state
125
+
126
+ if (state._suspending || state._suspended) {
127
+ throw new Error('Database is suspended')
128
+ }
110
129
 
111
130
  this._request = resolved
112
131
 
@@ -166,21 +185,26 @@ exports.ReadBatch = class RocksDBReadBatch extends RocksDBBatch {
166
185
  }
167
186
 
168
187
  _onread(errs, values) {
188
+ let applied = true
189
+
169
190
  for (let i = 0, n = this._promises.length; i < n; i++) {
170
191
  const promise = this._promises[i]
171
192
  if (promise === null) continue
172
193
 
173
194
  const err = errs[i]
174
195
 
175
- if (err) promise.reject(new Error(err))
176
- else {
196
+ if (err) {
197
+ applied = false
198
+
199
+ promise.reject(new Error(err))
200
+ } else {
177
201
  promise.resolve(
178
202
  values[i] ? this._decodeValue(Buffer.from(values[i])) : null
179
203
  )
180
204
  }
181
205
  }
182
206
 
183
- this._onfinished()
207
+ this._onfinished(applied ? null : new Error('Batch was not applied'))
184
208
  }
185
209
 
186
210
  get(key) {
@@ -227,15 +251,22 @@ exports.WriteBatch = class RocksDBWriteBatch extends RocksDBBatch {
227
251
  }
228
252
 
229
253
  _onwrite(err) {
254
+ let applied = true
255
+
230
256
  for (let i = 0, n = this._promises.length; i < n; i++) {
231
257
  const promise = this._promises[i]
232
258
  if (promise === null) continue
233
259
 
234
- if (err) promise.reject(new Error(err))
235
- else promise.resolve()
260
+ if (err) {
261
+ applied = false
262
+
263
+ promise.reject(new Error(err))
264
+ } else {
265
+ promise.resolve()
266
+ }
236
267
  }
237
268
 
238
- this._onfinished()
269
+ this._onfinished(applied ? null : new Error('Batch was not applied'))
239
270
  }
240
271
 
241
272
  put(key, value) {
@@ -1,4 +1,5 @@
1
1
  const binding = require('../binding')
2
+ const { BloomFilterPolicy } = require('./filter-policy')
2
3
 
3
4
  class RocksDBColumnFamily {
4
5
  constructor(name, opts = {}) {
@@ -14,34 +15,59 @@ class RocksDBColumnFamily {
14
15
  tableFormatVersion = 6,
15
16
  optimizeFiltersForMemory = false,
16
17
  blockCache = true,
17
- // In case we are cloning
18
- settings = null
18
+ filterPolicy = new BloomFilterPolicy(10)
19
19
  } = opts
20
20
 
21
21
  this._name = name
22
- this._settings =
23
- settings ||
24
- Uint32Array.from([
25
- 0,
26
- enableBlobFiles ? 1 : 0,
27
- minBlobSize & 0xffffffff,
28
- Math.floor(minBlobSize / 0x100000000),
29
- blobFileSize & 0xffffffff,
30
- Math.floor(blobFileSize / 0x100000000),
31
- enableBlobGarbageCollection ? 1 : 0,
32
- tableBlockSize & 0xffffffff,
33
- Math.floor(tableBlockSize / 0x100000000),
34
- tableCacheIndexAndFilterBlocks ? 1 : 0,
35
- tableFormatVersion,
36
- optimizeFiltersForMemory ? 1 : 0,
37
- blockCache ? 0 : 1
38
- ])
39
-
40
- this._handle = binding.columnFamilyInit(name, this._settings)
22
+ this._options = {
23
+ enableBlobFiles,
24
+ minBlobSize,
25
+ blobFileSize,
26
+ enableBlobGarbageCollection,
27
+ tableBlockSize,
28
+ tableCacheIndexAndFilterBlocks,
29
+ tableFormatVersion,
30
+ optimizeFiltersForMemory,
31
+ blockCache,
32
+ filterPolicy
33
+ }
34
+
35
+ const filterPolicyArguments = []
36
+
37
+ if (filterPolicy === null) filterPolicyArguments.push(0)
38
+ else {
39
+ filterPolicyArguments.push(filterPolicy.type)
40
+
41
+ switch (filterPolicy.type) {
42
+ case 1: // Bloom filter policy
43
+ filterPolicyArguments.push(filterPolicy.bitsPerKey)
44
+ break
45
+ case 2: // Ribbon filter policy
46
+ filterPolicyArguments.push(
47
+ filterPolicy.bloomEquivalentBitsPerKey,
48
+ filterPolicy.bloomBeforeLevel
49
+ )
50
+ break
51
+ }
52
+ }
53
+
54
+ this._handle = binding.columnFamilyInit(
55
+ name,
56
+ enableBlobFiles,
57
+ minBlobSize,
58
+ blobFileSize,
59
+ enableBlobGarbageCollection,
60
+ tableBlockSize,
61
+ tableCacheIndexAndFilterBlocks,
62
+ tableFormatVersion,
63
+ optimizeFiltersForMemory,
64
+ blockCache === false,
65
+ ...filterPolicyArguments
66
+ )
41
67
  }
42
68
 
43
69
  cloneSettings(name) {
44
- return new RocksDBColumnFamily(name, { settings: this._settings })
70
+ return new RocksDBColumnFamily(name, this._options)
45
71
  }
46
72
 
47
73
  get name() {
@@ -0,0 +1,20 @@
1
+ exports.BloomFilterPolicy = class RocksDBBloomFilterPolicy {
2
+ get type() {
3
+ return 1
4
+ }
5
+
6
+ constructor(bitsPerKey) {
7
+ this.bitsPerKey = bitsPerKey
8
+ }
9
+ }
10
+
11
+ exports.RibbonFilterPolicy = class RocksDBRibbonFilterPolicy {
12
+ get type() {
13
+ return 2
14
+ }
15
+
16
+ constructor(bloomEquivalentBitsPerKey, bloomBeforeLevel = 0) {
17
+ this.bloomEquivalentBitsPerKey = bloomEquivalentBitsPerKey
18
+ this.bloomBeforeLevel = bloomBeforeLevel
19
+ }
20
+ }
package/lib/iterator.js CHANGED
@@ -97,6 +97,12 @@ module.exports = class RocksDBIterator extends Readable {
97
97
  async _open(cb) {
98
98
  await this.ready()
99
99
 
100
+ const state = this._db._state
101
+
102
+ if (state._suspending || state._suspended) {
103
+ return cb(new Error('Database is suspended'))
104
+ }
105
+
100
106
  this._pendingOpen = cb
101
107
 
102
108
  binding.iteratorOpen(
@@ -117,6 +123,12 @@ module.exports = class RocksDBIterator extends Readable {
117
123
  }
118
124
 
119
125
  _read(cb) {
126
+ const state = this._db._state
127
+
128
+ if (state._suspending || state._suspended) {
129
+ return cb(new Error('Database is suspended'))
130
+ }
131
+
120
132
  this._pendingRead = cb
121
133
 
122
134
  binding.iteratorRead(this._handle, Math.min(this._capacity, this._limit))
package/lib/state.js CHANGED
@@ -6,7 +6,7 @@ const binding = require('../binding')
6
6
 
7
7
  const MAX_BATCH_REUSE = 64
8
8
 
9
- module.exports = class DBState extends ReadyResource {
9
+ module.exports = class RocksDBState extends ReadyResource {
10
10
  constructor(db, path, opts) {
11
11
  super()
12
12
 
@@ -17,7 +17,9 @@ module.exports = class DBState extends ReadyResource {
17
17
  createIfMissing = true,
18
18
  createMissingColumnFamilies = true,
19
19
  maxBackgroundJobs = 6,
20
- bytesPerSync = 1048576
20
+ bytesPerSync = 1048576,
21
+ maxOpenFiles = -1,
22
+ useDirectReads = false
21
23
  } = opts
22
24
 
23
25
  this.path = path
@@ -27,6 +29,7 @@ module.exports = class DBState extends ReadyResource {
27
29
  this.columnFamilies = [columnFamily]
28
30
  this.deferSnapshotInit = true
29
31
 
32
+ this._suspended = false
30
33
  this._suspending = null
31
34
  this._resuming = null
32
35
  this._columnsFlushed = false
@@ -40,14 +43,13 @@ module.exports = class DBState extends ReadyResource {
40
43
  }
41
44
 
42
45
  this.handle = binding.init(
43
- Uint32Array.from([
44
- readOnly ? 1 : 0,
45
- createIfMissing ? 1 : 0,
46
- createMissingColumnFamilies ? 1 : 0,
47
- maxBackgroundJobs,
48
- bytesPerSync & 0xffffffff,
49
- Math.floor(bytesPerSync / 0x100000000)
50
- ])
46
+ readOnly,
47
+ createIfMissing,
48
+ createMissingColumnFamilies,
49
+ maxBackgroundJobs,
50
+ bytesPerSync,
51
+ maxOpenFiles,
52
+ useDirectReads
51
53
  )
52
54
  }
53
55
 
@@ -126,6 +128,7 @@ module.exports = class DBState extends ReadyResource {
126
128
  })
127
129
 
128
130
  this._columnsFlushed = true
131
+
129
132
  req.handle = binding.open(
130
133
  this.handle,
131
134
  this,
@@ -191,9 +194,13 @@ module.exports = class DBState extends ReadyResource {
191
194
 
192
195
  req.handle = binding.suspend(this.handle, req, onsuspend)
193
196
 
194
- await promise
197
+ try {
198
+ await promise
195
199
 
196
- this._suspending = null
200
+ this._suspended = true
201
+ } finally {
202
+ this._suspending = null
203
+ }
197
204
 
198
205
  function onsuspend(err) {
199
206
  if (err) req.reject(new Error(err))
@@ -219,9 +226,13 @@ module.exports = class DBState extends ReadyResource {
219
226
 
220
227
  req.handle = binding.resume(this.handle, req, onresume)
221
228
 
222
- await promise
229
+ try {
230
+ await promise
223
231
 
224
- this._resuming = null
232
+ this._suspended = false
233
+ } finally {
234
+ this._resuming = null
235
+ }
225
236
 
226
237
  function onresume(err) {
227
238
  if (err) req.reject(new Error(err))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rocksdb-native",
3
- "version": "3.3.0",
3
+ "version": "3.4.0",
4
4
  "description": "librocksdb bindings for JavaScript",
5
5
  "exports": {
6
6
  ".": "./index.js",