@nxtedition/rocksdb 7.0.4 → 7.0.7

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.
Files changed (128) hide show
  1. package/binding.cc +320 -324
  2. package/chained-batch.js +6 -1
  3. package/deps/rocksdb/rocksdb/CMakeLists.txt +8 -3
  4. package/deps/rocksdb/rocksdb/Makefile +10 -4
  5. package/deps/rocksdb/rocksdb/TARGETS +6 -4
  6. package/deps/rocksdb/rocksdb/cache/cache_bench_tool.cc +9 -0
  7. package/deps/rocksdb/rocksdb/cache/cache_test.cc +14 -0
  8. package/deps/rocksdb/rocksdb/cache/clock_cache.cc +8 -8
  9. package/deps/rocksdb/rocksdb/cache/fast_lru_cache.cc +272 -174
  10. package/deps/rocksdb/rocksdb/cache/fast_lru_cache.h +201 -57
  11. package/deps/rocksdb/rocksdb/cache/lru_cache.cc +19 -19
  12. package/deps/rocksdb/rocksdb/cache/lru_cache.h +2 -1
  13. package/deps/rocksdb/rocksdb/db/blob/blob_source.cc +170 -0
  14. package/deps/rocksdb/rocksdb/db/blob/blob_source.h +95 -0
  15. package/deps/rocksdb/rocksdb/db/blob/blob_source_test.cc +298 -0
  16. package/deps/rocksdb/rocksdb/db/blob/db_blob_basic_test.cc +172 -0
  17. package/deps/rocksdb/rocksdb/db/column_family.cc +8 -3
  18. package/deps/rocksdb/rocksdb/db/column_family.h +6 -3
  19. package/deps/rocksdb/rocksdb/db/compaction/compaction_job.cc +10 -0
  20. package/deps/rocksdb/rocksdb/db/compaction/compaction_job_test.cc +6 -6
  21. package/deps/rocksdb/rocksdb/db/compaction/compaction_picker_level.cc +22 -2
  22. package/deps/rocksdb/rocksdb/db/compaction/compaction_picker_test.cc +38 -0
  23. package/deps/rocksdb/rocksdb/db/db_basic_test.cc +17 -5
  24. package/deps/rocksdb/rocksdb/db/db_block_cache_test.cc +4 -7
  25. package/deps/rocksdb/rocksdb/db/db_bloom_filter_test.cc +74 -71
  26. package/deps/rocksdb/rocksdb/db/db_compaction_test.cc +70 -1
  27. package/deps/rocksdb/rocksdb/db/db_impl/db_impl.cc +13 -12
  28. package/deps/rocksdb/rocksdb/db/db_impl/db_impl.h +36 -0
  29. package/deps/rocksdb/rocksdb/db/db_impl/db_impl_compaction_flush.cc +11 -4
  30. package/deps/rocksdb/rocksdb/db/db_impl/db_impl_files.cc +1 -1
  31. package/deps/rocksdb/rocksdb/db/db_impl/db_impl_open.cc +139 -91
  32. package/deps/rocksdb/rocksdb/db/db_impl/db_impl_write.cc +48 -14
  33. package/deps/rocksdb/rocksdb/db/db_kv_checksum_test.cc +90 -55
  34. package/deps/rocksdb/rocksdb/db/db_rate_limiter_test.cc +9 -4
  35. package/deps/rocksdb/rocksdb/db/db_test.cc +3 -1
  36. package/deps/rocksdb/rocksdb/db/db_wal_test.cc +12 -7
  37. package/deps/rocksdb/rocksdb/db/db_write_test.cc +35 -0
  38. package/deps/rocksdb/rocksdb/db/dbformat.cc +3 -1
  39. package/deps/rocksdb/rocksdb/db/dbformat.h +5 -3
  40. package/deps/rocksdb/rocksdb/db/flush_job_test.cc +1 -1
  41. package/deps/rocksdb/rocksdb/db/memtable.cc +1 -0
  42. package/deps/rocksdb/rocksdb/db/memtable_list_test.cc +4 -2
  43. package/deps/rocksdb/rocksdb/db/repair.cc +1 -1
  44. package/deps/rocksdb/rocksdb/db/version_builder.cc +43 -1
  45. package/deps/rocksdb/rocksdb/db/version_edit.cc +13 -5
  46. package/deps/rocksdb/rocksdb/db/version_edit.h +22 -1
  47. package/deps/rocksdb/rocksdb/db/version_edit_handler.cc +4 -5
  48. package/deps/rocksdb/rocksdb/db/version_set.cc +109 -41
  49. package/deps/rocksdb/rocksdb/db/version_set.h +36 -3
  50. package/deps/rocksdb/rocksdb/db/version_set_sync_and_async.h +1 -4
  51. package/deps/rocksdb/rocksdb/db/version_set_test.cc +10 -10
  52. package/deps/rocksdb/rocksdb/db/version_util.h +1 -1
  53. package/deps/rocksdb/rocksdb/db/wal_manager_test.cc +1 -1
  54. package/deps/rocksdb/rocksdb/db/write_batch.cc +34 -10
  55. package/deps/rocksdb/rocksdb/db/write_batch_internal.h +2 -0
  56. package/deps/rocksdb/rocksdb/db/write_callback_test.cc +4 -0
  57. package/deps/rocksdb/rocksdb/db_stress_tool/batched_ops_stress.cc +2 -0
  58. package/deps/rocksdb/rocksdb/db_stress_tool/cf_consistency_stress.cc +4 -1
  59. package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_common.h +1 -1
  60. package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_gflags.cc +7 -5
  61. package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_test_base.cc +5 -10
  62. package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_tool.cc +0 -7
  63. package/deps/rocksdb/rocksdb/db_stress_tool/no_batched_ops_stress.cc +2 -0
  64. package/deps/rocksdb/rocksdb/file/random_access_file_reader.cc +24 -3
  65. package/deps/rocksdb/rocksdb/file/writable_file_writer.cc +8 -0
  66. package/deps/rocksdb/rocksdb/file/writable_file_writer.h +10 -0
  67. package/deps/rocksdb/rocksdb/include/rocksdb/advanced_options.h +5 -0
  68. package/deps/rocksdb/rocksdb/include/rocksdb/cache.h +4 -4
  69. package/deps/rocksdb/rocksdb/include/rocksdb/options.h +9 -5
  70. package/deps/rocksdb/rocksdb/include/rocksdb/statistics.h +5 -0
  71. package/deps/rocksdb/rocksdb/include/rocksdb/types.h +1 -0
  72. package/deps/rocksdb/rocksdb/include/rocksdb/utilities/write_batch_with_index.h +1 -1
  73. package/deps/rocksdb/rocksdb/include/rocksdb/version.h +1 -1
  74. package/deps/rocksdb/rocksdb/include/rocksdb/write_batch.h +0 -3
  75. package/deps/rocksdb/rocksdb/microbench/ribbon_bench.cc +8 -6
  76. package/deps/rocksdb/rocksdb/monitoring/statistics.cc +3 -1
  77. package/deps/rocksdb/rocksdb/options/options_helper.cc +4 -2
  78. package/deps/rocksdb/rocksdb/options/options_test.cc +1 -11
  79. package/deps/rocksdb/rocksdb/port/port_posix.h +7 -0
  80. package/deps/rocksdb/rocksdb/port/win/port_win.h +11 -3
  81. package/deps/rocksdb/rocksdb/src.mk +6 -2
  82. package/deps/rocksdb/rocksdb/table/block_based/block_based_table_builder.cc +4 -33
  83. package/deps/rocksdb/rocksdb/table/block_based/block_based_table_iterator.h +3 -3
  84. package/deps/rocksdb/rocksdb/table/block_based/block_based_table_reader.cc +38 -118
  85. package/deps/rocksdb/rocksdb/table/block_based/block_based_table_reader.h +6 -8
  86. package/deps/rocksdb/rocksdb/table/block_based/block_based_table_reader_sync_and_async.h +10 -13
  87. package/deps/rocksdb/rocksdb/table/block_based/block_like_traits.h +4 -9
  88. package/deps/rocksdb/rocksdb/table/block_based/block_type.h +0 -1
  89. package/deps/rocksdb/rocksdb/table/block_based/filter_block.h +10 -28
  90. package/deps/rocksdb/rocksdb/table/block_based/filter_block_reader_common.cc +2 -3
  91. package/deps/rocksdb/rocksdb/table/block_based/filter_policy.cc +0 -91
  92. package/deps/rocksdb/rocksdb/table/block_based/filter_policy_internal.h +2 -30
  93. package/deps/rocksdb/rocksdb/table/block_based/full_filter_block.cc +6 -27
  94. package/deps/rocksdb/rocksdb/table/block_based/full_filter_block.h +11 -13
  95. package/deps/rocksdb/rocksdb/table/block_based/full_filter_block_test.cc +28 -40
  96. package/deps/rocksdb/rocksdb/table/block_based/mock_block_based_table.h +0 -1
  97. package/deps/rocksdb/rocksdb/table/block_based/partitioned_filter_block.cc +22 -43
  98. package/deps/rocksdb/rocksdb/table/block_based/partitioned_filter_block.h +11 -22
  99. package/deps/rocksdb/rocksdb/table/block_based/partitioned_filter_block_test.cc +24 -25
  100. package/deps/rocksdb/rocksdb/table/block_fetcher.cc +0 -1
  101. package/deps/rocksdb/rocksdb/table/get_context.h +0 -1
  102. package/deps/rocksdb/rocksdb/table/table_test.cc +3 -18
  103. package/deps/rocksdb/rocksdb/tools/db_bench_tool.cc +3 -16
  104. package/deps/rocksdb/rocksdb/tools/ldb_cmd.cc +3 -3
  105. package/deps/rocksdb/rocksdb/tools/ldb_cmd_test.cc +1 -1
  106. package/deps/rocksdb/rocksdb/util/bloom_test.cc +0 -201
  107. package/deps/rocksdb/rocksdb/util/distributed_mutex.h +48 -0
  108. package/deps/rocksdb/rocksdb/util/filter_bench.cc +5 -11
  109. package/deps/rocksdb/rocksdb/utilities/backup/backup_engine.cc +3 -0
  110. package/deps/rocksdb/rocksdb/utilities/cache_dump_load_impl.cc +7 -21
  111. package/deps/rocksdb/rocksdb/utilities/cache_dump_load_impl.h +1 -1
  112. package/deps/rocksdb/rocksdb/utilities/checkpoint/checkpoint_test.cc +45 -0
  113. package/deps/rocksdb/rocksdb/utilities/transactions/pessimistic_transaction_db.h +21 -14
  114. package/deps/rocksdb/rocksdb/utilities/transactions/transaction_base.cc +10 -1
  115. package/deps/rocksdb/rocksdb/utilities/transactions/write_prepared_txn.cc +3 -1
  116. package/deps/rocksdb/rocksdb/utilities/transactions/write_prepared_txn_db.cc +9 -0
  117. package/deps/rocksdb/rocksdb/utilities/transactions/write_unprepared_txn.cc +3 -2
  118. package/deps/rocksdb/rocksdb/utilities/transactions/write_unprepared_txn_db.cc +3 -1
  119. package/deps/rocksdb/rocksdb/utilities/write_batch_with_index/write_batch_with_index.cc +5 -4
  120. package/deps/rocksdb/rocksdb.gyp +1 -1
  121. package/index.js +36 -14
  122. package/package-lock.json +2 -2
  123. package/package.json +1 -1
  124. package/prebuilds/darwin-arm64/node.napi.node +0 -0
  125. package/prebuilds/linux-x64/node.napi.node +0 -0
  126. package/deps/rocksdb/rocksdb/table/block_based/block_based_filter_block.cc +0 -358
  127. package/deps/rocksdb/rocksdb/table/block_based/block_based_filter_block.h +0 -127
  128. package/deps/rocksdb/rocksdb/table/block_based/block_based_filter_block_test.cc +0 -219
package/binding.cc CHANGED
@@ -34,33 +34,21 @@ struct Updates;
34
34
 
35
35
  #define NAPI_STATUS_RETURN(call) \
36
36
  { \
37
- const auto status = (call); \
38
- if (status != napi_ok) { \
39
- return status; \
37
+ auto _status = (call); \
38
+ if (_status != napi_ok) { \
39
+ return _status; \
40
40
  } \
41
41
  }
42
42
 
43
- #define ROCKS_STATUS_THROWS(call) \
44
- { \
45
- const auto status = (call); \
46
- if (!status.ok()) { \
47
- napi_throw(env, ToError(env, status)); \
48
- return NULL; \
49
- } \
43
+ #define ROCKS_STATUS_THROWS(call) \
44
+ { \
45
+ auto _status = (call); \
46
+ if (!_status.ok()) { \
47
+ napi_throw(env, ToError(env, _status)); \
48
+ return NULL; \
49
+ } \
50
50
  }
51
51
 
52
- static bool IsString(napi_env env, napi_value value) {
53
- napi_valuetype type;
54
- napi_typeof(env, value, &type);
55
- return type == napi_string;
56
- }
57
-
58
- static bool IsBuffer(napi_env env, napi_value value) {
59
- bool isBuffer;
60
- napi_is_buffer(env, value, &isBuffer);
61
- return isBuffer;
62
- }
63
-
64
52
  static napi_value CreateError(napi_env env, const std::optional<std::string_view>& code, const std::string_view& msg) {
65
53
  napi_value codeValue = nullptr;
66
54
  if (code) {
@@ -109,20 +97,6 @@ static bool EncodingIsBuffer(napi_env env, napi_value obj, const std::string_vie
109
97
  return false;
110
98
  }
111
99
 
112
- template <typename T>
113
- static std::optional<T*> ExternalValueProperty(napi_env env, napi_value obj, const std::string_view& key) {
114
- if (HasProperty(env, obj, key.data())) {
115
- const auto value = GetProperty(env, obj, key.data());
116
-
117
- T* result;
118
- if (napi_get_value_external(env, value, reinterpret_cast<void**>(&result)) == napi_ok) {
119
- return result;
120
- }
121
- }
122
-
123
- return {};
124
- }
125
-
126
100
  static std::optional<uint32_t> Uint32Property(napi_env env, napi_value obj, const std::string_view& key) {
127
101
  if (HasProperty(env, obj, key.data())) {
128
102
  const auto value = GetProperty(env, obj, key.data());
@@ -157,27 +131,38 @@ static std::optional<int64_t> Int64Property(napi_env env, napi_value obj, const
157
131
  return {};
158
132
  }
159
133
 
160
- static std::string ToString(napi_env env, napi_value from, const std::string& defaultValue = "") {
161
- if (IsString(env, from)) {
162
- size_t length = 0;
163
- napi_get_value_string_utf8(env, from, nullptr, 0, &length);
164
- std::string value(length, '\0');
165
- napi_get_value_string_utf8(env, from, &value[0], value.length() + 1, &length);
166
- return value;
167
- } else if (IsBuffer(env, from)) {
168
- char* buf = nullptr;
134
+ static napi_status ToString(napi_env env, napi_value from, std::string& to) {
135
+ napi_valuetype type;
136
+ NAPI_STATUS_RETURN(napi_typeof(env, from, &type));
137
+
138
+ if (type == napi_string) {
169
139
  size_t length = 0;
170
- napi_get_buffer_info(env, from, reinterpret_cast<void**>(&buf), &length);
171
- return std::string(buf, length);
140
+ NAPI_STATUS_RETURN(napi_get_value_string_utf8(env, from, nullptr, 0, &length));
141
+ to.resize(length, '\0');
142
+ NAPI_STATUS_RETURN(napi_get_value_string_utf8(env, from, &to[0], length + 1, &length));
143
+ } else {
144
+ bool isBuffer;
145
+ NAPI_STATUS_RETURN(napi_is_buffer(env, from, &isBuffer));
146
+
147
+ if (isBuffer) {
148
+ char* buf = nullptr;
149
+ size_t length = 0;
150
+ NAPI_STATUS_RETURN(napi_get_buffer_info(env, from, reinterpret_cast<void**>(&buf), &length));
151
+ to.assign(buf, length);
152
+ } else {
153
+ return napi_invalid_arg;
154
+ }
172
155
  }
173
156
 
174
- return defaultValue;
157
+ return napi_ok;
175
158
  }
176
159
 
177
160
  static std::optional<std::string> StringProperty(napi_env env, napi_value opts, const std::string_view& name) {
178
161
  if (HasProperty(env, opts, name)) {
179
- const auto value = GetProperty(env, opts, name);
180
- return ToString(env, value);
162
+ const auto property = GetProperty(env, opts, name);
163
+ std::string value;
164
+ ToString(env, property, value);
165
+ return value;
181
166
  }
182
167
  return {};
183
168
  }
@@ -224,54 +209,17 @@ static void Finalize(napi_env env, void* data, void* hint) {
224
209
  }
225
210
  }
226
211
 
227
- napi_status Convert(napi_env env, rocksdb::PinnableSlice& s, bool asBuffer, napi_value& result) {
228
- if (asBuffer) {
229
- auto ptr = new rocksdb::PinnableSlice(std::move(s));
230
- return napi_create_external_buffer(env, ptr->size(), const_cast<char*>(ptr->data()),
231
- Finalize<rocksdb::PinnableSlice>, ptr, &result);
232
- } else {
233
- return napi_create_string_utf8(env, s.data(), s.size(), &result);
234
- }
235
- }
236
-
237
- napi_status Convert(napi_env env, std::optional<std::string>& s, bool asBuffer, napi_value& result) {
212
+ template <typename T>
213
+ napi_status Convert(napi_env env, T&& s, bool asBuffer, napi_value& result) {
238
214
  if (!s) {
239
215
  return napi_get_null(env, &result);
240
216
  } else if (asBuffer) {
241
- auto ptr = new std::string(std::move(*s));
242
- return napi_create_external_buffer(env, ptr->size(), const_cast<char*>(ptr->data()), Finalize<std::string>, ptr,
243
- &result);
217
+ return napi_create_buffer_copy(env, s->size(), s->data(), NULL, &result);
244
218
  } else {
245
219
  return napi_create_string_utf8(env, s->data(), s->size(), &result);
246
220
  }
247
221
  }
248
222
 
249
- struct NapiSlice : public rocksdb::Slice {
250
- std::unique_ptr<char[]> heap_;
251
- std::array<char, 128> stack_;
252
- };
253
-
254
- napi_status ToNapiSlice(napi_env env, napi_value from, NapiSlice& slice) {
255
- if (IsString(env, from)) {
256
- NAPI_STATUS_RETURN(napi_get_value_string_utf8(env, from, nullptr, 0, &slice.size_));
257
- char* data;
258
- if (slice.size_ + 1 < slice.stack_.size()) {
259
- data = slice.stack_.data();
260
- } else {
261
- slice.heap_.reset(new char[slice.size_ + 1]);
262
- data = slice.heap_.get();
263
- }
264
- data[slice.size_] = 0;
265
- NAPI_STATUS_RETURN(napi_get_value_string_utf8(env, from, data, slice.size_ + 1, &slice.size_));
266
- slice.data_ = data;
267
- } else if (IsBuffer(env, from)) {
268
- void* data;
269
- NAPI_STATUS_RETURN(napi_get_buffer_info(env, from, &data, &slice.size_));
270
- slice.data_ = static_cast<char*>(data);
271
- }
272
- return napi_ok;
273
- }
274
-
275
223
  /**
276
224
  * Base worker class. Handles the async work. Derived classes can override the
277
225
  * following virtual methods (listed in the order in which they're called):
@@ -322,9 +270,10 @@ struct Worker {
322
270
  virtual rocksdb::Status Execute(Database& database) = 0;
323
271
 
324
272
  virtual napi_status OnOk(napi_env env, napi_value callback) {
325
- napi_value argv;
326
- NAPI_STATUS_RETURN(napi_get_null(env, &argv));
327
- return CallFunction(env, callback, 1, &argv);
273
+ napi_value argv[1];
274
+ NAPI_STATUS_RETURN(napi_get_null(env, &argv[0]));
275
+
276
+ return CallFunction(env, callback, 1, &argv[0]);
328
277
  }
329
278
 
330
279
  virtual napi_status OnError(napi_env env, napi_value callback, napi_value err) {
@@ -466,22 +415,39 @@ struct BaseIterator {
466
415
  iterator_.reset();
467
416
  }
468
417
 
469
- bool Valid() const { return iterator_->Valid(); }
418
+ bool Valid() const {
419
+ assert(iterator_);
420
+ return iterator_->Valid();
421
+ }
470
422
 
471
- bool Increment() { return limit_ < 0 || ++count_ <= limit_; }
423
+ bool Increment() {
424
+ assert(iterator_);
425
+ return limit_ < 0 || ++count_ <= limit_;
426
+ }
472
427
 
473
428
  void Next() {
429
+ assert(iterator_);
430
+
474
431
  if (reverse_)
475
432
  iterator_->Prev();
476
433
  else
477
434
  iterator_->Next();
478
435
  }
479
436
 
480
- rocksdb::Slice CurrentKey() const { return iterator_->key(); }
437
+ rocksdb::Slice CurrentKey() const {
438
+ assert(iterator_);
439
+ return iterator_->key();
440
+ }
481
441
 
482
- rocksdb::Slice CurrentValue() const { return iterator_->value(); }
442
+ rocksdb::Slice CurrentValue() const {
443
+ assert(iterator_);
444
+ return iterator_->value();
445
+ }
483
446
 
484
- rocksdb::Status Status() const { return iterator_->status(); }
447
+ rocksdb::Status Status() const {
448
+ assert(iterator_);
449
+ return iterator_->status();
450
+ }
485
451
 
486
452
  Database* database_;
487
453
  rocksdb::ColumnFamilyHandle* column_;
@@ -489,26 +455,27 @@ struct BaseIterator {
489
455
 
490
456
  private:
491
457
  void Init() {
492
- rocksdb::ReadOptions options;
458
+ rocksdb::ReadOptions readOptions;
493
459
  if (upper_bound_) {
494
- options.iterate_upper_bound = &*upper_bound_;
460
+ readOptions.iterate_upper_bound = &*upper_bound_;
495
461
  }
496
462
  if (lower_bound_) {
497
- options.iterate_lower_bound = &*lower_bound_;
463
+ readOptions.iterate_lower_bound = &*lower_bound_;
498
464
  }
499
- options.fill_cache = fillCache_;
500
- options.snapshot = snapshot_.get();
501
- options.async_io = true;
465
+ readOptions.fill_cache = fillCache_;
466
+ readOptions.snapshot = snapshot_.get();
467
+ readOptions.async_io = true;
468
+ readOptions.adaptive_readahead = true;
502
469
 
503
- iterator_.reset(database_->db_->NewIterator(options, column_));
470
+ iterator_.reset(database_->db_->NewIterator(readOptions, column_));
504
471
  }
505
472
 
473
+ int count_ = 0;
506
474
  std::optional<rocksdb::PinnableSlice> lower_bound_;
507
475
  std::optional<rocksdb::PinnableSlice> upper_bound_;
508
476
  std::unique_ptr<rocksdb::Iterator> iterator_;
509
477
  const bool reverse_;
510
478
  const int limit_;
511
- int count_ = 0;
512
479
  const bool fillCache_;
513
480
  };
514
481
 
@@ -526,7 +493,7 @@ struct Iterator final : public BaseIterator {
526
493
  const bool fillCache,
527
494
  const bool keyAsBuffer,
528
495
  const bool valueAsBuffer,
529
- const int32_t highWaterMarkBytes,
496
+ const size_t highWaterMarkBytes,
530
497
  std::shared_ptr<const rocksdb::Snapshot> snapshot)
531
498
  : BaseIterator(database, column, reverse, lt, lte, gt, gte, limit, fillCache, snapshot),
532
499
  keys_(keys),
@@ -551,7 +518,7 @@ struct Iterator final : public BaseIterator {
551
518
  const bool values_;
552
519
  const bool keyAsBuffer_;
553
520
  const bool valueAsBuffer_;
554
- const int32_t highWaterMarkBytes_;
521
+ const size_t highWaterMarkBytes_;
555
522
  bool first_ = true;
556
523
 
557
524
  private:
@@ -559,8 +526,12 @@ struct Iterator final : public BaseIterator {
559
526
  };
560
527
 
561
528
  struct Updates {
562
- Updates(Database* database, const bool keyAsBuffer, const bool valueAsBuffer, int64_t seqNumber)
563
- : database_(database), keyAsBuffer_(keyAsBuffer), valueAsBuffer_(valueAsBuffer), seqNumber_(seqNumber) {}
529
+ Updates(Database* database, bool values, bool keyAsBuffer, bool valueAsBuffer, int64_t seqNumber)
530
+ : database_(database),
531
+ values_(values),
532
+ keyAsBuffer_(keyAsBuffer),
533
+ valueAsBuffer_(valueAsBuffer),
534
+ seqNumber_(seqNumber) {}
564
535
 
565
536
  void Close() { iterator_.reset(); }
566
537
 
@@ -577,6 +548,7 @@ struct Updates {
577
548
  }
578
549
 
579
550
  Database* database_;
551
+ const bool values_;
580
552
  const bool keyAsBuffer_;
581
553
  const bool valueAsBuffer_;
582
554
  int64_t seqNumber_;
@@ -586,9 +558,22 @@ struct Updates {
586
558
  napi_ref ref_ = nullptr;
587
559
  };
588
560
 
589
- static rocksdb::ColumnFamilyHandle* GetColumnFamily(Database* database, napi_env env, napi_value options) {
590
- auto column_opt = ExternalValueProperty<rocksdb::ColumnFamilyHandle>(env, options, "column");
591
- return column_opt ? *column_opt : database->db_->DefaultColumnFamily();
561
+ static napi_status GetColumnFamily(Database* database,
562
+ napi_env env,
563
+ napi_value options,
564
+ rocksdb::ColumnFamilyHandle** column) {
565
+ bool hasColumn = false;
566
+ NAPI_STATUS_RETURN(napi_has_named_property(env, options, "column", &hasColumn));
567
+
568
+ if (hasColumn) {
569
+ napi_value value = nullptr;
570
+ NAPI_STATUS_RETURN(napi_get_named_property(env, options, "column", &value));
571
+ NAPI_STATUS_RETURN(napi_get_value_external(env, value, reinterpret_cast<void**>(column)));
572
+ } else {
573
+ *column = database->db_->DefaultColumnFamily();
574
+ }
575
+
576
+ return napi_ok;
592
577
  }
593
578
 
594
579
  /**
@@ -670,19 +655,18 @@ struct OpenWorker final : public Worker {
670
655
  }
671
656
 
672
657
  napi_status OnOk(napi_env env, napi_value callback) override {
658
+ napi_value argv[2];
659
+ NAPI_STATUS_RETURN(napi_get_null(env, &argv[0]));
660
+
673
661
  const auto size = database_->columns_.size();
674
- napi_value result;
675
- NAPI_STATUS_RETURN(napi_create_object(env, &result));
662
+ NAPI_STATUS_RETURN(napi_create_object(env, &argv[1]));
676
663
 
677
664
  for (size_t n = 0; n < size; ++n) {
678
665
  napi_value column;
679
666
  NAPI_STATUS_RETURN(napi_create_external(env, database_->columns_[n], nullptr, nullptr, &column));
680
- NAPI_STATUS_RETURN(napi_set_named_property(env, result, column_families_[n].name.c_str(), column));
667
+ NAPI_STATUS_RETURN(napi_set_named_property(env, argv[1], column_families_[n].name.c_str(), column));
681
668
  }
682
669
 
683
- napi_value argv[2];
684
- NAPI_STATUS_RETURN(napi_get_null(env, &argv[0]));
685
- argv[1] = result;
686
670
  return CallFunction(env, callback, 2, argv);
687
671
  }
688
672
 
@@ -733,7 +717,7 @@ napi_status InitOptions(napi_env env, T& columnOptions, const U& options) {
733
717
  if (columnOptions.compression == rocksdb::kZSTD) {
734
718
  columnOptions.compression_opts.max_dict_bytes = 16 * 1024;
735
719
  columnOptions.compression_opts.zstd_max_train_bytes = 16 * 1024 * 100;
736
- // columnOptions.compression_opts.parallel_threads
720
+ // TODO (perf): compression_opts.parallel_threads
737
721
  }
738
722
 
739
723
  const auto cacheSize = Uint32Property(env, options, "cacheSize").value_or(8 << 20);
@@ -779,30 +763,29 @@ NAPI_METHOD(db_open) {
779
763
  NAPI_ARGV(4);
780
764
 
781
765
  Database* database;
782
- NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], (void**)&database));
766
+ NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&database)));
783
767
 
784
- const auto location = ToString(env, argv[1]);
785
- const auto options = argv[2];
786
- const auto callback = argv[3];
768
+ std::string location;
769
+ NAPI_STATUS_THROWS(ToString(env, argv[1], location));
787
770
 
788
771
  rocksdb::Options dbOptions;
789
772
 
790
- dbOptions.IncreaseParallelism(Uint32Property(env, options, "parallelism")
773
+ dbOptions.IncreaseParallelism(Uint32Property(env, argv[2], "parallelism")
791
774
  .value_or(std::max<uint32_t>(1, std::thread::hardware_concurrency() / 2)));
792
775
 
793
- dbOptions.create_if_missing = BooleanProperty(env, options, "createIfMissing").value_or(true);
794
- dbOptions.error_if_exists = BooleanProperty(env, options, "errorIfExists").value_or(false);
776
+ dbOptions.create_if_missing = BooleanProperty(env, argv[2], "createIfMissing").value_or(true);
777
+ dbOptions.error_if_exists = BooleanProperty(env, argv[2], "errorIfExists").value_or(false);
795
778
  dbOptions.avoid_unnecessary_blocking_io = true;
796
- dbOptions.use_adaptive_mutex = true;
797
- dbOptions.enable_pipelined_write = false;
798
- dbOptions.max_background_jobs = Uint32Property(env, options, "maxBackgroundJobs")
779
+ dbOptions.use_adaptive_mutex = true; // We don't have soo many threads in the libuv thread pool...
780
+ dbOptions.enable_pipelined_write = false; // We only write in the main thread...
781
+ dbOptions.max_background_jobs = Uint32Property(env, argv[2], "maxBackgroundJobs")
799
782
  .value_or(std::max<uint32_t>(2, std::thread::hardware_concurrency() / 8));
800
- dbOptions.WAL_ttl_seconds = Uint32Property(env, options, "walTTL").value_or(0) / 1e3;
801
- dbOptions.WAL_size_limit_MB = Uint32Property(env, options, "walSizeLimit").value_or(0) / 1e6;
783
+ dbOptions.WAL_ttl_seconds = Uint32Property(env, argv[2], "walTTL").value_or(0) / 1e3;
784
+ dbOptions.WAL_size_limit_MB = Uint32Property(env, argv[2], "walSizeLimit").value_or(0) / 1e6;
802
785
  dbOptions.create_missing_column_families = true;
803
- dbOptions.unordered_write = BooleanProperty(env, options, "unorderedWrite").value_or(false);
786
+ dbOptions.unordered_write = BooleanProperty(env, argv[2], "unorderedWrite").value_or(false);
804
787
 
805
- const auto infoLogLevel = StringProperty(env, options, "infoLogLevel").value_or("");
788
+ const auto infoLogLevel = StringProperty(env, argv[2], "infoLogLevel").value_or("");
806
789
  if (infoLogLevel.size() > 0) {
807
790
  rocksdb::InfoLogLevel lvl = {};
808
791
 
@@ -829,13 +812,16 @@ NAPI_METHOD(db_open) {
829
812
  dbOptions.info_log.reset(new NullLogger());
830
813
  }
831
814
 
832
- NAPI_STATUS_THROWS(InitOptions(env, dbOptions, options));
815
+ NAPI_STATUS_THROWS(InitOptions(env, dbOptions, argv[2]));
816
+
817
+ std::vector<rocksdb::ColumnFamilyDescriptor> columnsFamilies;
833
818
 
834
- std::vector<rocksdb::ColumnFamilyDescriptor> column_families;
819
+ bool hasColumns;
820
+ NAPI_STATUS_THROWS(napi_has_named_property(env, argv[2], "columns", &hasColumns));
835
821
 
836
- if (HasProperty(env, options, "columns")) {
822
+ if (hasColumns) {
837
823
  napi_value columns;
838
- NAPI_STATUS_THROWS(napi_get_named_property(env, options, "columns", &columns));
824
+ NAPI_STATUS_THROWS(napi_get_named_property(env, argv[2], "columns", &columns));
839
825
 
840
826
  napi_value keys;
841
827
  NAPI_STATUS_THROWS(napi_get_property_names(env, columns, &keys));
@@ -843,6 +829,7 @@ NAPI_METHOD(db_open) {
843
829
  uint32_t len;
844
830
  NAPI_STATUS_THROWS(napi_get_array_length(env, keys, &len));
845
831
 
832
+ columnsFamilies.resize(len);
846
833
  for (uint32_t n = 0; n < len; ++n) {
847
834
  napi_value key;
848
835
  NAPI_STATUS_THROWS(napi_get_element(env, keys, n, &key));
@@ -850,14 +837,13 @@ NAPI_METHOD(db_open) {
850
837
  napi_value column;
851
838
  NAPI_STATUS_THROWS(napi_get_property(env, columns, key, &column));
852
839
 
853
- rocksdb::ColumnFamilyOptions columnOptions;
854
- NAPI_STATUS_THROWS(InitOptions(env, columnOptions, column));
840
+ NAPI_STATUS_THROWS(InitOptions(env, columnsFamilies[n].options, column));
855
841
 
856
- column_families.emplace_back(ToString(env, key), columnOptions);
842
+ NAPI_STATUS_THROWS(ToString(env, key, columnsFamilies[n].name));
857
843
  }
858
844
  }
859
845
 
860
- auto worker = new OpenWorker(env, database, callback, location, dbOptions, column_families);
846
+ auto worker = new OpenWorker(env, database, argv[3], location, dbOptions, columnsFamilies);
861
847
  worker->Queue(env);
862
848
 
863
849
  return 0;
@@ -884,11 +870,9 @@ NAPI_METHOD(db_close) {
884
870
  NAPI_ARGV(2);
885
871
 
886
872
  Database* database;
887
- NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], (void**)&database));
873
+ NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&database)));
888
874
 
889
- const auto callback = argv[1];
890
-
891
- auto worker = new CloseWorker(env, database, callback);
875
+ auto worker = new CloseWorker(env, database, argv[1]);
892
876
 
893
877
  if (!database->HasPriorityWork()) {
894
878
  worker->Queue(env);
@@ -899,8 +883,8 @@ NAPI_METHOD(db_close) {
899
883
  return 0;
900
884
  }
901
885
 
902
- struct UpdateNextWorker final : public rocksdb::WriteBatch::Handler, public Worker {
903
- UpdateNextWorker(napi_env env, Updates* updates, napi_value callback)
886
+ struct UpdatesNextWorker final : public rocksdb::WriteBatch::Handler, public Worker {
887
+ UpdatesNextWorker(napi_env env, Updates* updates, napi_value callback)
904
888
  : Worker(env, updates->database_, callback, "rocks_level.db.get"), updates_(updates) {
905
889
  database_->IncrementPriorityWork(env);
906
890
  }
@@ -913,53 +897,45 @@ struct UpdateNextWorker final : public rocksdb::WriteBatch::Handler, public Work
913
897
  if (!status.ok()) {
914
898
  return status;
915
899
  }
900
+ } else {
901
+ updates_->iterator_->Next();
916
902
  }
917
903
 
918
904
  if (!updates_->iterator_->Valid()) {
919
- return rocksdb::Status::OK();
905
+ return updates_->iterator_->status();
920
906
  }
921
907
 
922
908
  auto batch = updates_->iterator_->GetBatch();
923
909
 
924
910
  updates_->seqNumber_ = batch.sequence;
925
911
 
926
- const auto status = batch.writeBatchPtr->Iterate(this);
927
- if (!status.ok()) {
928
- return status;
929
- }
912
+ cache_.reserve(batch.writeBatchPtr->Count() * 2);
930
913
 
931
- updates_->iterator_->Next();
932
-
933
- return rocksdb::Status::OK();
914
+ return batch.writeBatchPtr->Iterate(this);
934
915
  }
935
916
 
936
917
  napi_status OnOk(napi_env env, napi_value callback) override {
937
- const auto size = cache_.size();
938
- napi_value result;
939
-
940
- if (cache_.size()) {
941
- NAPI_STATUS_RETURN(napi_create_array_with_length(env, size, &result));
918
+ napi_value argv[3];
919
+ NAPI_STATUS_RETURN(napi_get_null(env, &argv[0]));
942
920
 
943
- for (size_t idx = 0; idx < cache_.size(); idx += 2) {
944
- napi_value key;
945
- napi_value val;
921
+ if (cache_.empty()) {
922
+ return CallFunction(env, callback, 1, argv);
923
+ }
946
924
 
947
- NAPI_STATUS_RETURN(Convert(env, cache_[idx + 0], updates_->keyAsBuffer_, key));
948
- NAPI_STATUS_RETURN(Convert(env, cache_[idx + 1], updates_->valueAsBuffer_, val));
925
+ NAPI_STATUS_RETURN(napi_create_array_with_length(env, cache_.size(), &argv[1]));
949
926
 
950
- NAPI_STATUS_RETURN(napi_set_element(env, result, static_cast<int>(idx + 0), key));
951
- NAPI_STATUS_RETURN(napi_set_element(env, result, static_cast<int>(idx + 1), val));
952
- }
927
+ for (size_t idx = 0; idx < cache_.size(); idx += 2) {
928
+ napi_value key;
929
+ NAPI_STATUS_RETURN(Convert(env, cache_[idx + 0], updates_->keyAsBuffer_, key));
930
+ NAPI_STATUS_RETURN(napi_set_element(env, argv[1], static_cast<int>(idx + 0), key));
953
931
 
954
- cache_.clear();
955
- } else {
956
- NAPI_STATUS_RETURN(napi_get_null(env, &result));
932
+ napi_value val;
933
+ NAPI_STATUS_RETURN(Convert(env, cache_[idx + 1], updates_->valueAsBuffer_, val));
934
+ NAPI_STATUS_RETURN(napi_set_element(env, argv[1], static_cast<int>(idx + 1), val));
957
935
  }
958
936
 
959
- napi_value argv[3];
960
- NAPI_STATUS_RETURN(napi_get_null(env, &argv[0]));
961
- argv[1] = result;
962
937
  NAPI_STATUS_RETURN(napi_create_bigint_int64(env, updates_->seqNumber_, &argv[2]));
938
+
963
939
  return CallFunction(env, callback, 3, argv);
964
940
  }
965
941
 
@@ -970,7 +946,11 @@ struct UpdateNextWorker final : public rocksdb::WriteBatch::Handler, public Work
970
946
 
971
947
  void Put(const rocksdb::Slice& key, const rocksdb::Slice& value) override {
972
948
  cache_.emplace_back(key.ToString());
973
- cache_.emplace_back(value.ToString());
949
+ if (updates_->values_) {
950
+ cache_.emplace_back(value.ToString());
951
+ } else {
952
+ cache_.emplace_back(std::nullopt);
953
+ }
974
954
  }
975
955
 
976
956
  void Delete(const rocksdb::Slice& key) override {
@@ -989,15 +969,14 @@ NAPI_METHOD(updates_init) {
989
969
  NAPI_ARGV(2);
990
970
 
991
971
  Database* database;
992
- NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], (void**)&database));
972
+ NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&database)));
993
973
 
994
- const auto options = argv[1];
974
+ const auto values = BooleanProperty(env, argv[1], "values").value_or(true);
975
+ const bool keyAsBuffer = EncodingIsBuffer(env, argv[1], "keyEncoding");
976
+ const bool valueAsBuffer = EncodingIsBuffer(env, argv[1], "valueEncoding");
977
+ const auto seqNumber = Int64Property(env, argv[1], "since").value_or(database->db_->GetLatestSequenceNumber());
995
978
 
996
- const bool keyAsBuffer = EncodingIsBuffer(env, options, "keyEncoding");
997
- const bool valueAsBuffer = EncodingIsBuffer(env, options, "valueEncoding");
998
- const auto seqNumber = Int64Property(env, options, "since").value_or(database->db_->GetLatestSequenceNumber());
999
-
1000
- auto updates = std::make_unique<Updates>(database, keyAsBuffer, valueAsBuffer, seqNumber);
979
+ auto updates = std::make_unique<Updates>(database, values, keyAsBuffer, valueAsBuffer, seqNumber);
1001
980
 
1002
981
  napi_value result;
1003
982
  NAPI_STATUS_THROWS(napi_create_external(env, updates.get(), Finalize<Updates>, updates.get(), &result));
@@ -1015,9 +994,7 @@ NAPI_METHOD(updates_next) {
1015
994
  Updates* updates;
1016
995
  NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], (void**)&updates));
1017
996
 
1018
- const auto callback = argv[1];
1019
-
1020
- auto worker = new UpdateNextWorker(env, updates, callback);
997
+ auto worker = new UpdatesNextWorker(env, updates, argv[1]);
1021
998
  worker->Queue(env);
1022
999
 
1023
1000
  return 0;
@@ -1039,16 +1016,18 @@ NAPI_METHOD(db_put) {
1039
1016
  NAPI_ARGV(4);
1040
1017
 
1041
1018
  Database* database;
1042
- NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], (void**)&database));
1019
+ NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&database)));
1043
1020
 
1044
- NapiSlice key;
1045
- NAPI_STATUS_THROWS(ToNapiSlice(env, argv[1], key));
1021
+ std::string key;
1022
+ NAPI_STATUS_THROWS(ToString(env, argv[1], key));
1046
1023
 
1047
- NapiSlice val;
1048
- NAPI_STATUS_THROWS(ToNapiSlice(env, argv[2], val));
1024
+ std::string val;
1025
+ NAPI_STATUS_THROWS(ToString(env, argv[2], val));
1049
1026
 
1050
1027
  rocksdb::WriteOptions writeOptions;
1051
- return ToError(env, database->db_->Put(writeOptions, key, val));
1028
+ ROCKS_STATUS_THROWS(database->db_->Put(writeOptions, key, val));
1029
+
1030
+ return 0;
1052
1031
  }
1053
1032
 
1054
1033
  struct GetWorker final : public Worker {
@@ -1085,7 +1064,9 @@ struct GetWorker final : public Worker {
1085
1064
  napi_status OnOk(napi_env env, napi_value callback) override {
1086
1065
  napi_value argv[2];
1087
1066
  NAPI_STATUS_RETURN(napi_get_null(env, &argv[0]));
1088
- NAPI_STATUS_RETURN(Convert(env, value_, asBuffer_, argv[1]));
1067
+
1068
+ NAPI_STATUS_RETURN(Convert(env, &value_, asBuffer_, argv[1]));
1069
+
1089
1070
  return CallFunction(env, callback, 2, argv);
1090
1071
  }
1091
1072
 
@@ -1107,16 +1088,18 @@ NAPI_METHOD(db_get) {
1107
1088
  NAPI_ARGV(4);
1108
1089
 
1109
1090
  Database* database;
1110
- NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], (void**)&database));
1091
+ NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&database)));
1092
+
1093
+ std::string key;
1094
+ NAPI_STATUS_THROWS(ToString(env, argv[1], key));
1111
1095
 
1112
- const auto key = ToString(env, argv[1]);
1113
- const auto options = argv[2];
1114
- const auto asBuffer = EncodingIsBuffer(env, options, "valueEncoding");
1115
- const auto fillCache = BooleanProperty(env, options, "fillCache").value_or(true);
1116
- const auto column = GetColumnFamily(database, env, options);
1117
- const auto callback = argv[3];
1096
+ const auto asBuffer = EncodingIsBuffer(env, argv[2], "valueEncoding");
1097
+ const auto fillCache = BooleanProperty(env, argv[2], "fillCache").value_or(true);
1118
1098
 
1119
- auto worker = new GetWorker(env, database, column, callback, key, asBuffer, fillCache);
1099
+ rocksdb::ColumnFamilyHandle* column;
1100
+ NAPI_STATUS_THROWS(GetColumnFamily(database, env, argv[2], &column));
1101
+
1102
+ auto worker = new GetWorker(env, database, column, argv[3], key, asBuffer, fillCache);
1120
1103
  worker->Queue(env);
1121
1104
 
1122
1105
  return 0;
@@ -1144,6 +1127,7 @@ struct GetManyWorker final : public Worker {
1144
1127
  readOptions.fill_cache = fillCache_;
1145
1128
  readOptions.snapshot = snapshot_.get();
1146
1129
  readOptions.async_io = true;
1130
+ readOptions.adaptive_readahead = true;
1147
1131
 
1148
1132
  std::vector<rocksdb::Slice> keys;
1149
1133
  keys.reserve(keys_.size());
@@ -1154,12 +1138,7 @@ struct GetManyWorker final : public Worker {
1154
1138
  statuses_.resize(keys.size());
1155
1139
  values_.resize(keys.size());
1156
1140
 
1157
- // database.db_->MultiGet(readOptions, column_, keys.size(), keys.data(), values_.data(), statuses_.data());
1158
-
1159
- // TODO (fix): Use MultiGet once https://github.com/facebook/rocksdb/issues/10186 is resolved.
1160
- for (auto n = 0; n < keys.size(); ++n) {
1161
- statuses_[n] = database.db_->Get(readOptions, column_, keys[n], &values_[n]);
1162
- }
1141
+ database.db_->MultiGet(readOptions, column_, keys.size(), keys.data(), values_.data(), statuses_.data());
1163
1142
 
1164
1143
  for (const auto& status : statuses_) {
1165
1144
  if (!status.ok() && !status.IsNotFound()) {
@@ -1171,24 +1150,23 @@ struct GetManyWorker final : public Worker {
1171
1150
  }
1172
1151
 
1173
1152
  napi_status OnOk(napi_env env, napi_value callback) override {
1153
+ napi_value argv[2];
1154
+ NAPI_STATUS_RETURN(napi_get_null(env, &argv[0]));
1155
+
1174
1156
  const auto size = values_.size();
1175
1157
 
1176
- napi_value array;
1177
- NAPI_STATUS_RETURN(napi_create_array_with_length(env, size, &array));
1158
+ NAPI_STATUS_RETURN(napi_create_array_with_length(env, size, &argv[1]));
1178
1159
 
1179
1160
  for (size_t idx = 0; idx < size; idx++) {
1180
1161
  napi_value element;
1181
1162
  if (statuses_[idx].ok()) {
1182
- NAPI_STATUS_RETURN(Convert(env, values_[idx], valueAsBuffer_, element));
1163
+ NAPI_STATUS_RETURN(Convert(env, &values_[idx], valueAsBuffer_, element));
1183
1164
  } else {
1184
1165
  NAPI_STATUS_RETURN(napi_get_undefined(env, &element));
1185
1166
  }
1186
- NAPI_STATUS_RETURN(napi_set_element(env, array, static_cast<uint32_t>(idx), element));
1167
+ NAPI_STATUS_RETURN(napi_set_element(env, argv[1], static_cast<uint32_t>(idx), element));
1187
1168
  }
1188
1169
 
1189
- napi_value argv[2];
1190
- NAPI_STATUS_RETURN(napi_get_null(env, &argv[0]));
1191
- argv[1] = array;
1192
1170
  return CallFunction(env, callback, 2, argv);
1193
1171
  }
1194
1172
 
@@ -1211,30 +1189,28 @@ NAPI_METHOD(db_get_many) {
1211
1189
  NAPI_ARGV(4);
1212
1190
 
1213
1191
  Database* database;
1214
- NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], (void**)&database));
1192
+ NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&database)));
1215
1193
 
1216
1194
  std::vector<std::string> keys;
1217
1195
  {
1218
1196
  uint32_t length;
1219
1197
  NAPI_STATUS_THROWS(napi_get_array_length(env, argv[1], &length));
1220
1198
 
1221
- keys.reserve(length);
1222
-
1223
- for (uint32_t i = 0; i < length; i++) {
1199
+ keys.resize(length);
1200
+ for (uint32_t n = 0; n < length; n++) {
1224
1201
  napi_value element;
1225
-
1226
- NAPI_STATUS_THROWS(napi_get_element(env, argv[1], i, &element));
1227
- keys.push_back(ToString(env, element));
1202
+ NAPI_STATUS_THROWS(napi_get_element(env, argv[1], n, &element));
1203
+ NAPI_STATUS_THROWS(ToString(env, element, keys[n]));
1228
1204
  }
1229
1205
  }
1230
1206
 
1231
- const auto options = argv[2];
1232
- const bool asBuffer = EncodingIsBuffer(env, options, "valueEncoding");
1233
- const bool fillCache = BooleanProperty(env, options, "fillCache").value_or(true);
1234
- const auto column = GetColumnFamily(database, env, options);
1235
- const auto callback = argv[3];
1207
+ const bool asBuffer = EncodingIsBuffer(env, argv[2], "valueEncoding");
1208
+ const bool fillCache = BooleanProperty(env, argv[2], "fillCache").value_or(true);
1209
+
1210
+ rocksdb::ColumnFamilyHandle* column;
1211
+ NAPI_STATUS_THROWS(GetColumnFamily(database, env, argv[2], &column));
1236
1212
 
1237
- auto worker = new GetManyWorker(env, database, column, std::move(keys), callback, asBuffer, fillCache);
1213
+ auto worker = new GetManyWorker(env, database, column, std::move(keys), argv[3], asBuffer, fillCache);
1238
1214
  worker->Queue(env);
1239
1215
 
1240
1216
  return 0;
@@ -1244,60 +1220,67 @@ NAPI_METHOD(db_del) {
1244
1220
  NAPI_ARGV(3);
1245
1221
 
1246
1222
  Database* database;
1247
- NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], (void**)&database));
1223
+ NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&database)));
1248
1224
 
1249
- NapiSlice key;
1250
- NAPI_STATUS_THROWS(ToNapiSlice(env, argv[1], key));
1225
+ std::string key;
1226
+ NAPI_STATUS_THROWS(ToString(env, argv[1], key));
1251
1227
 
1252
- const auto options = argv[2];
1253
- const auto column = GetColumnFamily(database, env, options);
1228
+ rocksdb::ColumnFamilyHandle* column;
1229
+ NAPI_STATUS_THROWS(GetColumnFamily(database, env, argv[2], &column));
1254
1230
 
1255
1231
  rocksdb::WriteOptions writeOptions;
1256
- return ToError(env, database->db_->Delete(writeOptions, column, key));
1232
+ ROCKS_STATUS_THROWS(database->db_->Delete(writeOptions, column, key));
1233
+
1234
+ return 0;
1257
1235
  }
1258
1236
 
1259
1237
  NAPI_METHOD(db_clear) {
1260
1238
  NAPI_ARGV(2);
1261
1239
 
1262
1240
  Database* database;
1263
- NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], (void**)&database));
1241
+ NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&database)));
1264
1242
 
1265
- const auto options = argv[1];
1266
- const auto reverse = BooleanProperty(env, options, "reverse").value_or(false);
1267
- const auto limit = Int32Property(env, options, "limit").value_or(-1);
1243
+ const auto reverse = BooleanProperty(env, argv[1], "reverse").value_or(false);
1244
+ const auto limit = Int32Property(env, argv[1], "limit").value_or(-1);
1268
1245
 
1269
- const auto lt = StringProperty(env, options, "lt");
1270
- const auto lte = StringProperty(env, options, "lte");
1271
- const auto gt = StringProperty(env, options, "gt");
1272
- const auto gte = StringProperty(env, options, "gte");
1273
- const auto column = GetColumnFamily(database, env, options);
1246
+ rocksdb::ColumnFamilyHandle* column;
1247
+ NAPI_STATUS_THROWS(GetColumnFamily(database, env, argv[1], &column));
1274
1248
 
1275
- if (!reverse && limit == -1 && (lte || lt)) {
1276
- rocksdb::Slice begin;
1249
+ auto lt = StringProperty(env, argv[1], "lt");
1250
+ auto lte = StringProperty(env, argv[1], "lte");
1251
+ auto gt = StringProperty(env, argv[1], "gt");
1252
+ auto gte = StringProperty(env, argv[1], "gte");
1253
+
1254
+ if (limit == -1) {
1255
+ rocksdb::PinnableSlice begin;
1277
1256
  if (gte) {
1278
- begin = *gte;
1257
+ *begin.GetSelf() = std::move(*gte);
1279
1258
  } else if (gt) {
1280
- begin = *gt + '\0';
1259
+ *begin.GetSelf() = std::move(*gt) + '\0';
1281
1260
  }
1261
+ begin.PinSelf();
1282
1262
 
1283
- rocksdb::Slice end;
1263
+ rocksdb::PinnableSlice end;
1284
1264
  if (lte) {
1285
- end = *lte + '\0';
1265
+ *end.GetSelf() = std::move(*lte) + '\0';
1286
1266
  } else if (lt) {
1287
- end = *lt;
1267
+ *end.GetSelf() = std::move(*lt);
1288
1268
  } else {
1289
- assert(false);
1269
+ // HACK: Assume no key that starts with 0xFF is larger than 1MiB.
1270
+ end.GetSelf()->resize(1e6);
1271
+ memset(end.GetSelf()->data(), 255, end.GetSelf()->size());
1290
1272
  }
1273
+ end.PinSelf();
1291
1274
 
1292
- if (begin.compare(end) > 0) {
1293
- return ToError(env, rocksdb::Status::OK());
1275
+ if (begin.compare(end) < 0) {
1276
+ rocksdb::WriteOptions writeOptions;
1277
+ ROCKS_STATUS_THROWS(database->db_->DeleteRange(writeOptions, column, begin, end));
1294
1278
  }
1295
1279
 
1296
- rocksdb::WriteOptions writeOptions;
1297
- const auto status = database->db_->DeleteRange(writeOptions, column, begin, end);
1298
- return ToError(env, status);
1280
+ return 0;
1299
1281
  } else {
1300
- // TODO (perf): Use DeleteRange.
1282
+ // TODO (fix): Error handling.
1283
+ // TODO (fix): This should be async...
1301
1284
 
1302
1285
  std::shared_ptr<const rocksdb::Snapshot> snapshot(database->db_->GetSnapshot(),
1303
1286
  [=](const auto ptr) { database->db_->ReleaseSnapshot(ptr); });
@@ -1305,9 +1288,6 @@ NAPI_METHOD(db_clear) {
1305
1288
 
1306
1289
  it.SeekToRange();
1307
1290
 
1308
- // TODO: add option
1309
- const uint32_t hwm = 16 * 1024;
1310
-
1311
1291
  rocksdb::WriteBatch batch;
1312
1292
  rocksdb::WriteOptions writeOptions;
1313
1293
  rocksdb::Status status;
@@ -1315,7 +1295,7 @@ NAPI_METHOD(db_clear) {
1315
1295
  while (true) {
1316
1296
  size_t bytesRead = 0;
1317
1297
 
1318
- while (bytesRead <= hwm && it.Valid() && it.Increment()) {
1298
+ while (bytesRead <= 16 * 1024 && it.Valid() && it.Increment()) {
1319
1299
  const auto key = it.CurrentKey();
1320
1300
  batch.Delete(column, key);
1321
1301
  bytesRead += key.size();
@@ -1337,7 +1317,11 @@ NAPI_METHOD(db_clear) {
1337
1317
 
1338
1318
  it.Close();
1339
1319
 
1340
- return ToError(env, status);
1320
+ if (!status.ok()) {
1321
+ ROCKS_STATUS_THROWS(status);
1322
+ }
1323
+
1324
+ return 0;
1341
1325
  }
1342
1326
  }
1343
1327
 
@@ -1345,10 +1329,10 @@ NAPI_METHOD(db_get_property) {
1345
1329
  NAPI_ARGV(2);
1346
1330
 
1347
1331
  Database* database;
1348
- NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], (void**)&database));
1332
+ NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&database)));
1349
1333
 
1350
- NapiSlice property;
1351
- NAPI_STATUS_THROWS(ToNapiSlice(env, argv[1], property));
1334
+ std::string property;
1335
+ NAPI_STATUS_THROWS(ToString(env, argv[1], property));
1352
1336
 
1353
1337
  std::string value;
1354
1338
  database->db_->GetProperty(property, &value);
@@ -1363,7 +1347,7 @@ NAPI_METHOD(iterator_init) {
1363
1347
  NAPI_ARGV(2);
1364
1348
 
1365
1349
  Database* database;
1366
- NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], (void**)&database));
1350
+ NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&database)));
1367
1351
 
1368
1352
  const auto options = argv[1];
1369
1353
  const auto reverse = BooleanProperty(env, options, "reverse").value_or(false);
@@ -1373,14 +1357,15 @@ NAPI_METHOD(iterator_init) {
1373
1357
  const bool keyAsBuffer = EncodingIsBuffer(env, options, "keyEncoding");
1374
1358
  const bool valueAsBuffer = EncodingIsBuffer(env, options, "valueEncoding");
1375
1359
  const auto limit = Int32Property(env, options, "limit").value_or(-1);
1376
- const auto highWaterMarkBytes = Int32Property(env, options, "highWaterMarkBytes").value_or(16 * 1024);
1360
+ const auto highWaterMarkBytes = Uint32Property(env, options, "highWaterMarkBytes").value_or(64 * 1024);
1377
1361
 
1378
1362
  const auto lt = StringProperty(env, options, "lt");
1379
1363
  const auto lte = StringProperty(env, options, "lte");
1380
1364
  const auto gt = StringProperty(env, options, "gt");
1381
1365
  const auto gte = StringProperty(env, options, "gte");
1382
1366
 
1383
- const auto column = GetColumnFamily(database, env, options);
1367
+ rocksdb::ColumnFamilyHandle* column;
1368
+ NAPI_STATUS_THROWS(GetColumnFamily(database, env, options, &column));
1384
1369
 
1385
1370
  std::shared_ptr<const rocksdb::Snapshot> snapshot(database->db_->GetSnapshot(),
1386
1371
  [=](const auto ptr) { database->db_->ReleaseSnapshot(ptr); });
@@ -1402,13 +1387,13 @@ NAPI_METHOD(iterator_seek) {
1402
1387
  NAPI_ARGV(2);
1403
1388
 
1404
1389
  Iterator* iterator;
1405
- NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], (void**)&iterator));
1390
+ NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&iterator)));
1406
1391
 
1407
- NapiSlice target;
1408
- NAPI_STATUS_THROWS(ToNapiSlice(env, argv[1], target));
1392
+ std::string target;
1393
+ NAPI_STATUS_THROWS(ToString(env, argv[1], target));
1409
1394
 
1410
1395
  iterator->first_ = true;
1411
- iterator->Seek(target);
1396
+ iterator->Seek(target); // TODO: Does seek causing blocking IO?
1412
1397
 
1413
1398
  return 0;
1414
1399
  }
@@ -1417,7 +1402,7 @@ NAPI_METHOD(iterator_close) {
1417
1402
  NAPI_ARGV(1);
1418
1403
 
1419
1404
  Iterator* iterator;
1420
- NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], (void**)&iterator));
1405
+ NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&iterator)));
1421
1406
 
1422
1407
  iterator->Detach(env);
1423
1408
  iterator->Close();
@@ -1429,7 +1414,7 @@ NAPI_METHOD(iterator_get_sequence) {
1429
1414
  NAPI_ARGV(1);
1430
1415
 
1431
1416
  Iterator* iterator;
1432
- NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], (void**)&iterator));
1417
+ NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&iterator)));
1433
1418
 
1434
1419
  const auto seq = iterator->snapshot_->GetSequenceNumber();
1435
1420
 
@@ -1478,8 +1463,7 @@ struct NextWorker final : public Worker {
1478
1463
  cache_.push_back(v.ToString());
1479
1464
  }
1480
1465
 
1481
- if ((iterator_->highWaterMarkBytes_ != -1 && bytesRead > static_cast<size_t>(iterator_->highWaterMarkBytes_)) ||
1482
- cache_.size() / 2 >= size_) {
1466
+ if (bytesRead > iterator_->highWaterMarkBytes_ || cache_.size() / 2 >= size_) {
1483
1467
  finished_ = false;
1484
1468
  return rocksdb::Status::OK();
1485
1469
  }
@@ -1491,27 +1475,24 @@ struct NextWorker final : public Worker {
1491
1475
  }
1492
1476
 
1493
1477
  napi_status OnOk(napi_env env, napi_value callback) override {
1494
- const auto size = cache_.size();
1495
- napi_value result;
1496
- NAPI_STATUS_RETURN(napi_create_array_with_length(env, size, &result));
1478
+ napi_value argv[3];
1479
+ NAPI_STATUS_RETURN(napi_get_null(env, &argv[0]));
1480
+
1481
+ NAPI_STATUS_RETURN(napi_create_array_with_length(env, cache_.size(), &argv[1]));
1497
1482
 
1498
- for (size_t n = 0; n < size; n += 2) {
1483
+ for (size_t n = 0; n < cache_.size(); n += 2) {
1499
1484
  napi_value key;
1500
1485
  napi_value val;
1501
1486
 
1502
1487
  NAPI_STATUS_RETURN(Convert(env, cache_[n + 0], iterator_->keyAsBuffer_, key));
1503
1488
  NAPI_STATUS_RETURN(Convert(env, cache_[n + 1], iterator_->valueAsBuffer_, val));
1504
1489
 
1505
- NAPI_STATUS_RETURN(napi_set_element(env, result, static_cast<int>(n + 0), key));
1506
- NAPI_STATUS_RETURN(napi_set_element(env, result, static_cast<int>(n + 1), val));
1490
+ NAPI_STATUS_RETURN(napi_set_element(env, argv[1], static_cast<int>(n + 0), key));
1491
+ NAPI_STATUS_RETURN(napi_set_element(env, argv[1], static_cast<int>(n + 1), val));
1507
1492
  }
1508
1493
 
1509
- cache_.clear();
1510
-
1511
- napi_value argv[3];
1512
- NAPI_STATUS_RETURN(napi_get_null(env, &argv[0]));
1513
- argv[1] = result;
1514
1494
  NAPI_STATUS_RETURN(napi_get_boolean(env, finished_, &argv[2]));
1495
+
1515
1496
  return CallFunction(env, callback, 3, argv);
1516
1497
  }
1517
1498
 
@@ -1526,14 +1507,12 @@ NAPI_METHOD(iterator_nextv) {
1526
1507
  NAPI_ARGV(3);
1527
1508
 
1528
1509
  Iterator* iterator;
1529
- NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], (void**)&iterator));
1510
+ NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&iterator)));
1530
1511
 
1531
1512
  uint32_t size;
1532
1513
  NAPI_STATUS_THROWS(napi_get_value_uint32(env, argv[1], &size));
1533
1514
 
1534
- const auto callback = argv[2];
1535
-
1536
- auto worker = new NextWorker(env, iterator, size, callback);
1515
+ auto worker = new NextWorker(env, iterator, size, argv[2]);
1537
1516
  worker->Queue(env);
1538
1517
 
1539
1518
  return 0;
@@ -1543,51 +1522,66 @@ NAPI_METHOD(batch_do) {
1543
1522
  NAPI_ARGV(3);
1544
1523
 
1545
1524
  Database* database;
1546
- NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], (void**)&database));
1547
-
1548
- const auto operations = argv[1];
1525
+ NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&database)));
1549
1526
 
1550
1527
  rocksdb::WriteBatch batch;
1551
1528
 
1529
+ std::string type;
1530
+ std::string key;
1531
+ std::string value;
1532
+
1552
1533
  uint32_t length;
1553
- NAPI_STATUS_THROWS(napi_get_array_length(env, operations, &length));
1534
+ NAPI_STATUS_THROWS(napi_get_array_length(env, argv[1], &length));
1554
1535
 
1555
1536
  for (uint32_t i = 0; i < length; i++) {
1556
1537
  napi_value element;
1557
- NAPI_STATUS_THROWS(napi_get_element(env, operations, i, &element));
1538
+ NAPI_STATUS_THROWS(napi_get_element(env, argv[1], i, &element));
1558
1539
 
1559
- NapiSlice type;
1560
- NAPI_STATUS_THROWS(ToNapiSlice(env, GetProperty(env, element, "type"), type));
1540
+ napi_value typeProperty;
1541
+ NAPI_STATUS_THROWS(napi_get_named_property(env, element, "type", &typeProperty));
1542
+ NAPI_STATUS_THROWS(ToString(env, typeProperty, type));
1561
1543
 
1562
- const auto column = GetColumnFamily(database, env, element);
1544
+ rocksdb::ColumnFamilyHandle* column;
1545
+ NAPI_STATUS_THROWS(GetColumnFamily(database, env, element, &column));
1563
1546
 
1564
1547
  if (type == "del") {
1565
- NapiSlice key;
1566
- NAPI_STATUS_THROWS(ToNapiSlice(env, GetProperty(env, element, "key"), key));
1567
- batch.Delete(column, key);
1548
+ napi_value keyProperty;
1549
+ NAPI_STATUS_THROWS(napi_get_named_property(env, element, "key", &keyProperty));
1550
+ NAPI_STATUS_THROWS(ToString(env, keyProperty, key));
1551
+
1552
+ ROCKS_STATUS_THROWS(batch.Delete(column, key));
1568
1553
  } else if (type == "put") {
1569
- NapiSlice key;
1570
- NAPI_STATUS_THROWS(ToNapiSlice(env, GetProperty(env, element, "key"), key));
1571
- NapiSlice value;
1572
- NAPI_STATUS_THROWS(ToNapiSlice(env, GetProperty(env, element, "value"), value));
1573
- batch.Put(column, key, value);
1554
+ napi_value keyProperty;
1555
+ NAPI_STATUS_THROWS(napi_get_named_property(env, element, "key", &keyProperty));
1556
+ NAPI_STATUS_THROWS(ToString(env, keyProperty, key));
1557
+
1558
+ napi_value valueProperty;
1559
+ NAPI_STATUS_THROWS(napi_get_named_property(env, element, "value", &valueProperty));
1560
+ NAPI_STATUS_THROWS(ToString(env, valueProperty, value));
1561
+
1562
+ ROCKS_STATUS_THROWS(batch.Put(column, key, value));
1563
+ } else {
1564
+ ROCKS_STATUS_THROWS(rocksdb::Status::InvalidArgument());
1574
1565
  }
1575
1566
  }
1576
1567
 
1577
1568
  rocksdb::WriteOptions writeOptions;
1578
- return ToError(env, database->db_->Write(writeOptions, &batch));
1569
+ ROCKS_STATUS_THROWS(database->db_->Write(writeOptions, &batch));
1570
+
1571
+ return 0;
1579
1572
  }
1580
1573
 
1581
1574
  NAPI_METHOD(batch_init) {
1582
1575
  NAPI_ARGV(1);
1583
1576
 
1584
1577
  Database* database;
1585
- NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], (void**)&database));
1578
+ NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&database)));
1586
1579
 
1587
1580
  auto batch = new rocksdb::WriteBatch();
1588
1581
 
1589
1582
  napi_value result;
1590
1583
  NAPI_STATUS_THROWS(napi_create_external(env, batch, Finalize<rocksdb::WriteBatch>, batch, &result));
1584
+
1591
1585
  return result;
1592
1586
  }
1593
1587
 
@@ -1595,21 +1589,21 @@ NAPI_METHOD(batch_put) {
1595
1589
  NAPI_ARGV(5);
1596
1590
 
1597
1591
  Database* database;
1598
- NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], (void**)&database));
1592
+ NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&database)));
1599
1593
 
1600
1594
  rocksdb::WriteBatch* batch;
1601
1595
  NAPI_STATUS_THROWS(napi_get_value_external(env, argv[1], (void**)(&batch)));
1602
1596
 
1603
- NapiSlice key;
1604
- NAPI_STATUS_THROWS(ToNapiSlice(env, argv[2], key));
1597
+ std::string key;
1598
+ NAPI_STATUS_THROWS(ToString(env, argv[2], key));
1605
1599
 
1606
- NapiSlice val;
1607
- NAPI_STATUS_THROWS(ToNapiSlice(env, argv[3], val));
1600
+ std::string val;
1601
+ NAPI_STATUS_THROWS(ToString(env, argv[3], val));
1608
1602
 
1609
- const auto options = argv[4];
1610
- const auto column = GetColumnFamily(database, env, options);
1603
+ rocksdb::ColumnFamilyHandle* column;
1604
+ NAPI_STATUS_THROWS(GetColumnFamily(database, env, argv[4], &column));
1611
1605
 
1612
- batch->Put(column, key, val);
1606
+ ROCKS_STATUS_THROWS(batch->Put(column, key, val));
1613
1607
 
1614
1608
  return 0;
1615
1609
  }
@@ -1618,18 +1612,18 @@ NAPI_METHOD(batch_del) {
1618
1612
  NAPI_ARGV(4);
1619
1613
 
1620
1614
  Database* database;
1621
- NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], (void**)&database));
1615
+ NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&database)));
1622
1616
 
1623
1617
  rocksdb::WriteBatch* batch;
1624
1618
  NAPI_STATUS_THROWS(napi_get_value_external(env, argv[1], reinterpret_cast<void**>(&batch)));
1625
1619
 
1626
- NapiSlice key;
1627
- NAPI_STATUS_THROWS(ToNapiSlice(env, argv[2], key));
1620
+ std::string key;
1621
+ NAPI_STATUS_THROWS(ToString(env, argv[2], key));
1628
1622
 
1629
- const auto options = argv[3];
1630
- const auto column = GetColumnFamily(database, env, options);
1623
+ rocksdb::ColumnFamilyHandle* column;
1624
+ NAPI_STATUS_THROWS(GetColumnFamily(database, env, argv[3], &column));
1631
1625
 
1632
- batch->Delete(column, key);
1626
+ ROCKS_STATUS_THROWS(batch->Delete(column, key));
1633
1627
 
1634
1628
  return 0;
1635
1629
  }
@@ -1649,13 +1643,15 @@ NAPI_METHOD(batch_write) {
1649
1643
  NAPI_ARGV(3);
1650
1644
 
1651
1645
  Database* database;
1652
- NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], (void**)&database));
1646
+ NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&database)));
1653
1647
 
1654
1648
  rocksdb::WriteBatch* batch;
1655
1649
  NAPI_STATUS_THROWS(napi_get_value_external(env, argv[1], reinterpret_cast<void**>(&batch)));
1656
1650
 
1657
1651
  rocksdb::WriteOptions writeOptions;
1658
- return ToError(env, database->db_->Write(writeOptions, batch));
1652
+ ROCKS_STATUS_THROWS(database->db_->Write(writeOptions, batch));
1653
+
1654
+ return 0;
1659
1655
  }
1660
1656
 
1661
1657
  NAPI_INIT() {