@nxtedition/rocksdb 7.0.55 → 7.0.56

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 (149) hide show
  1. package/binding.cc +314 -304
  2. package/chained-batch.js +10 -5
  3. package/index.js +5 -9
  4. package/package.json +1 -1
  5. package/prebuilds/darwin-arm64/node.napi.node +0 -0
  6. package/prebuilds/darwin-x64/node.napi.node +0 -0
  7. package/prebuilds/linux-x64/node.napi.node +0 -0
  8. package/18_04_03/000171.sst +0 -0
  9. package/18_04_03/000681.sst +0 -0
  10. package/18_04_03/000685.sst +0 -0
  11. package/18_04_03/000686.log +0 -0
  12. package/18_04_03/000690.log +0 -0
  13. package/18_04_03/000694.sst +0 -0
  14. package/18_04_03/000697.log +0 -0
  15. package/18_04_03/000701.log +0 -0
  16. package/18_04_03/000705.log +0 -0
  17. package/18_04_03/000709.log +0 -0
  18. package/18_04_03/000713.log +0 -0
  19. package/18_04_03/000717.log +0 -0
  20. package/18_04_03/000721.log +0 -0
  21. package/18_04_03/000725.log +0 -0
  22. package/18_04_03/000729.log +0 -0
  23. package/18_04_03/000733.log +0 -0
  24. package/18_04_03/000737.log +0 -0
  25. package/18_04_03/000741.log +0 -0
  26. package/18_04_03/000745.log +0 -0
  27. package/18_04_03/000749.log +0 -0
  28. package/18_04_03/000753.log +0 -0
  29. package/18_04_03/000757.log +0 -0
  30. package/18_04_03/000761.log +0 -0
  31. package/18_04_03/000765.log +0 -0
  32. package/18_04_03/000769.log +0 -0
  33. package/18_04_03/000773.log +0 -0
  34. package/18_04_03/000777.log +0 -0
  35. package/18_04_03/000781.log +0 -0
  36. package/18_04_03/000785.log +0 -0
  37. package/18_04_03/000789.log +0 -0
  38. package/18_04_03/CURRENT +0 -1
  39. package/18_04_03/IDENTITY +0 -1
  40. package/18_04_03/LOCK +0 -0
  41. package/18_04_03/MANIFEST-000790 +0 -0
  42. package/18_04_03/OPTIONS-000788 +0 -294
  43. package/18_04_03/OPTIONS-000792 +0 -294
  44. package/18_04_03/archive/000004.log +0 -0
  45. package/18_04_03/archive/000011.log +0 -0
  46. package/18_04_03/archive/000015.log +0 -0
  47. package/18_04_03/archive/000019.log +0 -0
  48. package/18_04_03/archive/000023.log +0 -0
  49. package/18_04_03/archive/000027.log +0 -0
  50. package/18_04_03/archive/000031.log +0 -0
  51. package/18_04_03/archive/000035.log +0 -0
  52. package/18_04_03/archive/000039.log +0 -0
  53. package/18_04_03/archive/000043.log +0 -0
  54. package/18_04_03/archive/000047.log +0 -0
  55. package/18_04_03/archive/000051.log +0 -0
  56. package/18_04_03/archive/000055.log +0 -0
  57. package/18_04_03/archive/000059.log +0 -0
  58. package/18_04_03/archive/000063.log +0 -0
  59. package/18_04_03/archive/000067.log +0 -0
  60. package/18_04_03/archive/000071.log +0 -0
  61. package/18_04_03/archive/000075.log +0 -0
  62. package/18_04_03/archive/000079.log +0 -0
  63. package/18_04_03/archive/000083.log +0 -0
  64. package/18_04_03/archive/000087.log +0 -0
  65. package/18_04_03/archive/000091.log +0 -0
  66. package/18_04_03/archive/000095.log +0 -0
  67. package/18_04_03/archive/000099.log +0 -0
  68. package/18_04_03/archive/000103.log +0 -0
  69. package/18_04_03/archive/000107.log +0 -0
  70. package/18_04_03/archive/000111.log +0 -0
  71. package/18_04_03/archive/000115.log +0 -0
  72. package/18_04_03/archive/000119.log +0 -0
  73. package/18_04_03/archive/000123.log +0 -0
  74. package/18_04_03/archive/000127.log +0 -0
  75. package/18_04_03/archive/000131.log +0 -0
  76. package/18_04_03/archive/000135.log +0 -0
  77. package/18_04_03/archive/000139.log +0 -0
  78. package/18_04_03/archive/000143.log +0 -0
  79. package/18_04_03/archive/000147.log +0 -0
  80. package/18_04_03/archive/000151.log +0 -0
  81. package/18_04_03/archive/000155.log +0 -0
  82. package/18_04_03/archive/000159.log +0 -0
  83. package/18_04_03/archive/000163.log +0 -0
  84. package/18_04_03/archive/000167.log +0 -0
  85. package/18_04_03/archive/000176.log +0 -0
  86. package/18_04_03/archive/000183.log +0 -0
  87. package/18_04_03/archive/000187.log +0 -0
  88. package/18_04_03/archive/000191.log +0 -0
  89. package/18_04_03/archive/000195.log +0 -0
  90. package/18_04_03/archive/000199.log +0 -0
  91. package/18_04_03/archive/000203.log +0 -0
  92. package/18_04_03/archive/000212.log +0 -0
  93. package/18_04_03/archive/000219.log +0 -0
  94. package/18_04_03/archive/000223.log +0 -0
  95. package/18_04_03/archive/000227.log +0 -0
  96. package/18_04_03/archive/000231.log +0 -0
  97. package/18_04_03/archive/000237.log +0 -0
  98. package/18_04_03/archive/000246.log +0 -0
  99. package/18_04_03/archive/000255.log +0 -0
  100. package/18_04_03/archive/000264.log +0 -0
  101. package/18_04_03/archive/000273.log +0 -0
  102. package/18_04_03/archive/000282.log +0 -0
  103. package/18_04_03/archive/000291.log +0 -0
  104. package/18_04_03/archive/000300.log +0 -0
  105. package/18_04_03/archive/000309.log +0 -0
  106. package/18_04_03/archive/000318.log +0 -0
  107. package/18_04_03/archive/000327.log +0 -0
  108. package/18_04_03/archive/000336.log +0 -0
  109. package/18_04_03/archive/000345.log +0 -0
  110. package/18_04_03/archive/000352.log +0 -0
  111. package/18_04_03/archive/000358.log +0 -0
  112. package/18_04_03/archive/000367.log +0 -0
  113. package/18_04_03/archive/000376.log +0 -0
  114. package/18_04_03/archive/000385.log +0 -0
  115. package/18_04_03/archive/000394.log +0 -0
  116. package/18_04_03/archive/000403.log +0 -0
  117. package/18_04_03/archive/000412.log +0 -0
  118. package/18_04_03/archive/000421.log +0 -0
  119. package/18_04_03/archive/000430.log +0 -0
  120. package/18_04_03/archive/000439.log +0 -0
  121. package/18_04_03/archive/000448.log +0 -0
  122. package/18_04_03/archive/000457.log +0 -0
  123. package/18_04_03/archive/000466.log +0 -0
  124. package/18_04_03/archive/000475.log +0 -0
  125. package/18_04_03/archive/000482.log +0 -0
  126. package/18_04_03/archive/000488.log +0 -0
  127. package/18_04_03/archive/000497.log +0 -0
  128. package/18_04_03/archive/000506.log +0 -0
  129. package/18_04_03/archive/000515.log +0 -0
  130. package/18_04_03/archive/000524.log +0 -0
  131. package/18_04_03/archive/000533.log +0 -0
  132. package/18_04_03/archive/000542.log +0 -0
  133. package/18_04_03/archive/000551.log +0 -0
  134. package/18_04_03/archive/000560.log +0 -0
  135. package/18_04_03/archive/000569.log +0 -0
  136. package/18_04_03/archive/000578.log +0 -0
  137. package/18_04_03/archive/000587.log +0 -0
  138. package/18_04_03/archive/000596.log +0 -0
  139. package/18_04_03/archive/000605.log +0 -0
  140. package/18_04_03/archive/000614.log +0 -0
  141. package/18_04_03/archive/000623.log +0 -0
  142. package/18_04_03/archive/000632.log +0 -0
  143. package/18_04_03/archive/000641.log +0 -0
  144. package/18_04_03/archive/000650.log +0 -0
  145. package/18_04_03/archive/000659.log +0 -0
  146. package/18_04_03/archive/000668.log +0 -0
  147. package/18_04_03/archive/000677.log +0 -0
  148. package/18_04_03.zip +0 -0
  149. package/tmp.mjs +0 -34
package/binding.cc CHANGED
@@ -570,7 +570,6 @@ struct Updates : public BatchIterator {
570
570
  bool valueAsBuffer)
571
571
  : BatchIterator(database, keys, values, data, column, keyAsBuffer, valueAsBuffer),
572
572
  database_(database),
573
- sequence_(seqNumber),
574
573
  start_(seqNumber) {}
575
574
 
576
575
  void Close() { iterator_.reset(); }
@@ -588,7 +587,6 @@ struct Updates : public BatchIterator {
588
587
  }
589
588
 
590
589
  Database* database_;
591
- int64_t sequence_;
592
590
  int64_t start_;
593
591
  std::unique_ptr<rocksdb::TransactionLogIterator> iterator_;
594
592
 
@@ -794,6 +792,25 @@ static napi_status GetColumnFamily(Database* database,
794
792
  if (hasColumn) {
795
793
  napi_value value = nullptr;
796
794
  NAPI_STATUS_RETURN(napi_get_named_property(env, options, "column", &value));
795
+
796
+ bool nully = false;
797
+
798
+ napi_value nullVal;
799
+ NAPI_STATUS_RETURN(napi_get_null(env, &nullVal));
800
+ NAPI_STATUS_RETURN(napi_strict_equals(env, nullVal, value, &nully));
801
+ if (nully) {
802
+ *column = nullptr;
803
+ return napi_ok;
804
+ }
805
+
806
+ napi_value undefinedVal;
807
+ NAPI_STATUS_RETURN(napi_get_undefined(env, &undefinedVal));
808
+ NAPI_STATUS_RETURN(napi_strict_equals(env, undefinedVal, value, &nully));
809
+ if (nully) {
810
+ *column = nullptr;
811
+ return napi_ok;
812
+ }
813
+
797
814
  NAPI_STATUS_RETURN(napi_get_value_external(env, value, reinterpret_cast<void**>(column)));
798
815
  } else if (database) {
799
816
  *column = database->db_->DefaultColumnFamily();
@@ -804,6 +821,57 @@ static napi_status GetColumnFamily(Database* database,
804
821
  return napi_ok;
805
822
  }
806
823
 
824
+ template <typename State,
825
+ typename ExecuteType = std::function<rocksdb::Status(State& state, Database& database)>,
826
+ typename OnOkType = std::function<napi_status(State& state, napi_env env, napi_value callback)>>
827
+ struct GenericWorker final : public Worker {
828
+ template <typename T1, typename T2>
829
+ GenericWorker(const std::string& name,
830
+ napi_env env,
831
+ napi_value callback,
832
+ Database* database,
833
+ bool priority,
834
+ T1&& execute,
835
+ T2&& onOK)
836
+ : Worker(env, database, callback, name),
837
+ priority_(priority),
838
+ execute_(std::forward<T1>(execute)),
839
+ onOk_(std::forward<T2>(onOK)) {
840
+ if (priority_) {
841
+ database_->IncrementPriorityWork(env);
842
+ }
843
+ }
844
+
845
+ rocksdb::Status Execute(Database& database) override { return execute_(state_, database); }
846
+
847
+ napi_status OnOk(napi_env env, napi_value callback) override { return onOk_(state_, env, callback); }
848
+
849
+ void Destroy(napi_env env) override {
850
+ if (priority_) {
851
+ database_->DecrementPriorityWork(env);
852
+ }
853
+ Worker::Destroy(env);
854
+ }
855
+
856
+ private:
857
+ State state_;
858
+ bool priority_ = false;
859
+ ExecuteType execute_;
860
+ OnOkType onOk_;
861
+ };
862
+
863
+ template <typename State, typename T1, typename T2>
864
+ Worker* createWorker(const std::string& name,
865
+ napi_env env,
866
+ napi_value callback,
867
+ Database* database,
868
+ bool priority,
869
+ T1&& execute,
870
+ T2&& onOk) {
871
+ return new GenericWorker<State, typename std::decay<T1>::type, typename std::decay<T2>::type>(
872
+ name, env, callback, database, priority, std::forward<T1>(execute), std::forward<T2>(onOk));
873
+ }
874
+
807
875
  /**
808
876
  * Hook for when the environment exits. This hook will be called after
809
877
  * already-scheduled napi_async_work items have finished, which gives us
@@ -864,54 +932,6 @@ NAPI_METHOD(db_init) {
864
932
  return result;
865
933
  }
866
934
 
867
- struct OpenWorker final : public Worker {
868
- OpenWorker(napi_env env,
869
- Database* database,
870
- napi_value callback,
871
- const std::string& location,
872
- const rocksdb::Options& options,
873
- std::vector<rocksdb::ColumnFamilyDescriptor> descriptors)
874
- : Worker(env, database, callback, "leveldown.db.open"),
875
- options_(options),
876
- location_(location),
877
- descriptors_(std::move(descriptors)) {}
878
-
879
- rocksdb::Status Execute(Database& database) override {
880
- rocksdb::DB* db = nullptr;
881
- const auto status = descriptors_.empty() ? rocksdb::DB::Open(options_, location_, &db)
882
- : rocksdb::DB::Open(options_, location_, descriptors_, &handles_, &db);
883
- database.db_.reset(db);
884
- return status;
885
- }
886
-
887
- napi_status OnOk(napi_env env, napi_value callback) override {
888
- napi_value argv[2];
889
- NAPI_STATUS_RETURN(napi_get_null(env, &argv[0]));
890
-
891
- const auto size = handles_.size();
892
- NAPI_STATUS_RETURN(napi_create_object(env, &argv[1]));
893
-
894
- for (size_t n = 0; n < size; ++n) {
895
- ColumnFamily column;
896
- column.handle = handles_[n];
897
- column.descriptor = descriptors_[n];
898
- NAPI_STATUS_RETURN(napi_create_external(env, column.handle, nullptr, nullptr, &column.val));
899
- NAPI_STATUS_RETURN(napi_create_reference(env, column.val, 1, &column.ref));
900
-
901
- NAPI_STATUS_RETURN(napi_set_named_property(env, argv[1], descriptors_[n].name.c_str(), column.val));
902
-
903
- database_->columns_[column.handle->GetID()] = column;
904
- }
905
-
906
- return CallFunction(env, callback, 2, argv);
907
- }
908
-
909
- rocksdb::Options options_;
910
- const std::string location_;
911
- std::vector<rocksdb::ColumnFamilyDescriptor> descriptors_;
912
- std::vector<rocksdb::ColumnFamilyHandle*> handles_;
913
- };
914
-
915
935
  template <typename T, typename U>
916
936
  rocksdb::Status InitOptions(napi_env env, T& columnOptions, const U& options) {
917
937
  rocksdb::ConfigOptions configOptions;
@@ -1088,7 +1108,7 @@ NAPI_METHOD(db_open) {
1088
1108
 
1089
1109
  ROCKS_STATUS_THROWS(InitOptions(env, dbOptions, argv[2]));
1090
1110
 
1091
- std::vector<rocksdb::ColumnFamilyDescriptor> columnsFamilies;
1111
+ std::vector<rocksdb::ColumnFamilyDescriptor> descriptors;
1092
1112
 
1093
1113
  bool hasColumns;
1094
1114
  NAPI_STATUS_THROWS(napi_has_named_property(env, argv[2], "columns", &hasColumns));
@@ -1103,7 +1123,7 @@ NAPI_METHOD(db_open) {
1103
1123
  uint32_t len;
1104
1124
  NAPI_STATUS_THROWS(napi_get_array_length(env, keys, &len));
1105
1125
 
1106
- columnsFamilies.resize(len);
1126
+ descriptors.resize(len);
1107
1127
  for (uint32_t n = 0; n < len; ++n) {
1108
1128
  napi_value key;
1109
1129
  NAPI_STATUS_THROWS(napi_get_element(env, keys, n, &key));
@@ -1111,30 +1131,53 @@ NAPI_METHOD(db_open) {
1111
1131
  napi_value column;
1112
1132
  NAPI_STATUS_THROWS(napi_get_property(env, columns, key, &column));
1113
1133
 
1114
- ROCKS_STATUS_THROWS(InitOptions(env, columnsFamilies[n].options, column));
1134
+ ROCKS_STATUS_THROWS(InitOptions(env, descriptors[n].options, column));
1115
1135
 
1116
- NAPI_STATUS_THROWS(ToString(env, key, columnsFamilies[n].name));
1136
+ NAPI_STATUS_THROWS(ToString(env, key, descriptors[n].name));
1117
1137
  }
1118
1138
  }
1119
1139
 
1120
- auto worker = new OpenWorker(env, database, argv[3], location, dbOptions, columnsFamilies);
1121
- worker->Queue(env);
1140
+ auto callback = argv[3];
1122
1141
 
1123
- return 0;
1124
- }
1142
+ struct State {
1143
+ std::vector<rocksdb::ColumnFamilyHandle*> handles;
1144
+ };
1145
+ auto worker = createWorker<State>(
1146
+ "leveldown.open", env, callback, database, false,
1147
+ [=](auto& state, auto& database) -> rocksdb::Status {
1148
+ rocksdb::DB* db = nullptr;
1149
+ const auto status = descriptors.empty()
1150
+ ? rocksdb::DB::Open(dbOptions, location, &db)
1151
+ : rocksdb::DB::Open(dbOptions, location, descriptors, &state.handles, &db);
1152
+ database.db_.reset(db);
1153
+ return status;
1154
+ },
1155
+ [=](auto& state, napi_env env, napi_value callback) -> napi_status {
1156
+ napi_value argv[2];
1157
+ NAPI_STATUS_RETURN(napi_get_null(env, &argv[0]));
1125
1158
 
1126
- struct CloseWorker final : public Worker {
1127
- CloseWorker(napi_env env, Database* database, napi_value callback)
1128
- : Worker(env, database, callback, "leveldown.db.close") {}
1159
+ const auto size = state.handles.size();
1160
+ NAPI_STATUS_RETURN(napi_create_object(env, &argv[1]));
1129
1161
 
1130
- rocksdb::Status Execute(Database& database) override {
1131
- for (auto& it : database.columns_) {
1132
- database.db_->DestroyColumnFamilyHandle(it.second.handle);
1133
- }
1162
+ for (size_t n = 0; n < size; ++n) {
1163
+ ColumnFamily column;
1164
+ column.handle = state.handles[n];
1165
+ column.descriptor = descriptors[n];
1166
+ NAPI_STATUS_RETURN(napi_create_external(env, column.handle, nullptr, nullptr, &column.val));
1167
+ NAPI_STATUS_RETURN(napi_create_reference(env, column.val, 1, &column.ref));
1134
1168
 
1135
- return database.db_->Close();
1136
- }
1137
- };
1169
+ NAPI_STATUS_RETURN(napi_set_named_property(env, argv[1], descriptors[n].name.c_str(), column.val));
1170
+
1171
+ database->columns_[column.handle->GetID()] = column;
1172
+ }
1173
+
1174
+ return CallFunction(env, callback, 2, argv);
1175
+ });
1176
+
1177
+ worker->Queue(env);
1178
+
1179
+ return 0;
1180
+ }
1138
1181
 
1139
1182
  napi_value noop_callback(napi_env env, napi_callback_info info) {
1140
1183
  return 0;
@@ -1146,7 +1189,25 @@ NAPI_METHOD(db_close) {
1146
1189
  Database* database;
1147
1190
  NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&database)));
1148
1191
 
1149
- auto worker = new CloseWorker(env, database, argv[1]);
1192
+ auto callback = argv[1];
1193
+
1194
+ struct State {};
1195
+ auto worker = createWorker<State>(
1196
+ "leveldown.close", env, callback, database, false,
1197
+ [=](auto& state, auto& database) -> rocksdb::Status {
1198
+ for (auto& it : database.columns_) {
1199
+ database.db_->DestroyColumnFamilyHandle(it.second.handle);
1200
+ }
1201
+ database.columns_.clear();
1202
+
1203
+ return database.db_->Close();
1204
+ },
1205
+ [](auto& state, napi_env env, napi_value callback) -> napi_status {
1206
+ napi_value argv[1];
1207
+ NAPI_STATUS_RETURN(napi_get_null(env, &argv[0]));
1208
+
1209
+ return CallFunction(env, callback, 1, &argv[0]);
1210
+ });
1150
1211
 
1151
1212
  if (!database->HasPriorityWork()) {
1152
1213
  worker->Queue(env);
@@ -1157,68 +1218,6 @@ NAPI_METHOD(db_close) {
1157
1218
  return 0;
1158
1219
  }
1159
1220
 
1160
- struct UpdatesNextWorker final : public Worker {
1161
- UpdatesNextWorker(napi_env env, Updates* updates, napi_value callback)
1162
- : Worker(env, updates->database_, callback, "rocks_level.db.get"), updates_(updates) {
1163
- database_->IncrementPriorityWork(env);
1164
- }
1165
-
1166
- rocksdb::Status Execute(Database& database) override {
1167
- if (!updates_->iterator_) {
1168
- rocksdb::TransactionLogIterator::ReadOptions options;
1169
- const auto status = database_->db_->GetUpdatesSince(updates_->sequence_, &updates_->iterator_, options);
1170
- if (!status.ok()) {
1171
- return status;
1172
- }
1173
- } else if (updates_->iterator_->Valid()) {
1174
- updates_->iterator_->Next();
1175
- }
1176
-
1177
- if (!updates_->iterator_->Valid() || !updates_->iterator_->status().ok()) {
1178
- return updates_->iterator_->status();
1179
- }
1180
-
1181
- auto batch = updates_->iterator_->GetBatch();
1182
-
1183
- updates_->sequence_ = batch.sequence;
1184
-
1185
- batch_ = std::move(batch.writeBatchPtr);
1186
- count_ = batch_->Count();
1187
-
1188
- return rocksdb::Status::OK();
1189
- }
1190
-
1191
- napi_status OnOk(napi_env env, napi_value callback) override {
1192
- napi_value argv[5];
1193
-
1194
- NAPI_STATUS_RETURN(napi_get_null(env, &argv[0]));
1195
-
1196
- if (count_ == -1) {
1197
- return CallFunction(env, callback, 1, argv);
1198
- }
1199
-
1200
- NAPI_STATUS_RETURN(updates_->Iterate(env, *batch_, &argv[1]));
1201
-
1202
- NAPI_STATUS_RETURN(napi_create_int64(env, updates_->sequence_, &argv[2]));
1203
-
1204
- NAPI_STATUS_RETURN(napi_create_int64(env, count_, &argv[3]));
1205
-
1206
- NAPI_STATUS_RETURN(napi_create_int64(env, updates_->start_, &argv[4]));
1207
-
1208
- return CallFunction(env, callback, 5, argv);
1209
- }
1210
-
1211
- void Destroy(napi_env env) override {
1212
- database_->DecrementPriorityWork(env);
1213
- Worker::Destroy(env);
1214
- }
1215
-
1216
- private:
1217
- int64_t count_ = -1;
1218
- std::unique_ptr<rocksdb::WriteBatch> batch_;
1219
- Updates* updates_;
1220
- };
1221
-
1222
1221
  NAPI_METHOD(updates_init) {
1223
1222
  NAPI_ARGV(2);
1224
1223
 
@@ -1249,7 +1248,7 @@ NAPI_METHOD(updates_init) {
1249
1248
  const bool valueAsBuffer = EncodingIsBuffer(env, argv[1], "valueEncoding");
1250
1249
 
1251
1250
  rocksdb::ColumnFamilyHandle* column = nullptr;
1252
- // NAPI_STATUS_THROWS(GetColumnFamily(nullptr, env, argv[1], &column));
1251
+ NAPI_STATUS_THROWS(GetColumnFamily(nullptr, env, argv[1], &column));
1253
1252
 
1254
1253
  auto updates = std::make_unique<Updates>(database, since, keys, values, data, column, keyAsBuffer, valueAsBuffer);
1255
1254
 
@@ -1269,112 +1268,71 @@ NAPI_METHOD(updates_next) {
1269
1268
  Updates* updates;
1270
1269
  NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&updates)));
1271
1270
 
1272
- auto worker = new UpdatesNextWorker(env, updates, argv[1]);
1273
- worker->Queue(env);
1271
+ auto callback = argv[1];
1274
1272
 
1275
- return 0;
1276
- }
1273
+ auto result = std::make_shared<rocksdb::BatchResult>();
1277
1274
 
1278
- NAPI_METHOD(updates_close) {
1279
- NAPI_ARGV(1);
1275
+ struct State {
1276
+ rocksdb::BatchResult batchResult;
1277
+ };
1278
+ auto worker = createWorker<State>(
1279
+ "leveldown.updates.next", env, callback, updates->database_, true,
1280
+ [=](auto& state, auto& database) -> rocksdb::Status {
1281
+ if (!updates->iterator_) {
1282
+ rocksdb::TransactionLogIterator::ReadOptions options;
1283
+ const auto status = database.db_->GetUpdatesSince(updates->start_, &updates->iterator_, options);
1284
+ if (!status.ok()) {
1285
+ return status;
1286
+ }
1287
+ } else if (updates->iterator_->Valid()) {
1288
+ updates->iterator_->Next();
1289
+ }
1280
1290
 
1281
- Updates* updates;
1282
- NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&updates)));
1291
+ if (!updates->iterator_->Valid() || !updates->iterator_->status().ok()) {
1292
+ return updates->iterator_->status();
1293
+ }
1283
1294
 
1284
- updates->Detach(env);
1285
- updates->Close();
1295
+ state.batchResult = updates->iterator_->GetBatch();
1286
1296
 
1287
- return 0;
1288
- }
1289
-
1290
- struct GetManyWorker final : public Worker {
1291
- GetManyWorker(napi_env env,
1292
- Database* database,
1293
- rocksdb::ColumnFamilyHandle* column,
1294
- std::vector<std::string> keys,
1295
- napi_value callback,
1296
- const bool valueAsBuffer,
1297
- const bool fillCache,
1298
- const bool ignoreRangeDeletions)
1299
- : Worker(env, database, callback, "leveldown.get.many"),
1300
- column_(column),
1301
- keys_(std::move(keys)),
1302
- valueAsBuffer_(valueAsBuffer),
1303
- fillCache_(fillCache),
1304
- ignoreRangeDeletions_(ignoreRangeDeletions),
1305
- snapshot_(database_->db_->GetSnapshot()) {
1306
- database_->IncrementPriorityWork(env);
1307
- }
1308
-
1309
- ~GetManyWorker() {
1310
- if (snapshot_) {
1311
- database_->db_->ReleaseSnapshot(snapshot_);
1312
- }
1313
- }
1297
+ return rocksdb::Status::OK();
1298
+ },
1299
+ [=](auto& state, napi_env env, napi_value callback) -> napi_status {
1300
+ napi_value argv[5];
1314
1301
 
1315
- rocksdb::Status Execute(Database& database) override {
1316
- rocksdb::ReadOptions readOptions;
1317
- readOptions.fill_cache = fillCache_;
1318
- readOptions.snapshot = snapshot_;
1319
- readOptions.async_io = true;
1320
- readOptions.ignore_range_deletions = ignoreRangeDeletions_;
1302
+ NAPI_STATUS_RETURN(napi_get_null(env, &argv[0]));
1321
1303
 
1322
- std::vector<rocksdb::Slice> keys;
1323
- keys.reserve(keys_.size());
1324
- for (const auto& key : keys_) {
1325
- keys.emplace_back(key);
1326
- }
1304
+ if (!state.batchResult.writeBatchPtr) {
1305
+ return CallFunction(env, callback, 1, argv);
1306
+ }
1327
1307
 
1328
- statuses_.resize(keys.size());
1329
- values_.resize(keys.size());
1308
+ auto batch = std::move(state.batchResult.writeBatchPtr);
1330
1309
 
1331
- database.db_->MultiGet(readOptions, column_, keys.size(), keys.data(), values_.data(), statuses_.data());
1310
+ NAPI_STATUS_RETURN(updates->Iterate(env, *batch, &argv[1]));
1332
1311
 
1333
- for (const auto& status : statuses_) {
1334
- if (!status.ok() && !status.IsNotFound()) {
1335
- return status;
1336
- }
1337
- }
1312
+ NAPI_STATUS_RETURN(napi_create_int64(env, state.batchResult.sequence, &argv[2]));
1338
1313
 
1339
- return rocksdb::Status::OK();
1340
- }
1314
+ NAPI_STATUS_RETURN(napi_create_int64(env, batch->Count(), &argv[3]));
1341
1315
 
1342
- napi_status OnOk(napi_env env, napi_value callback) override {
1343
- napi_value argv[2];
1344
- NAPI_STATUS_RETURN(napi_get_null(env, &argv[0]));
1316
+ NAPI_STATUS_RETURN(napi_create_int64(env, updates->start_, &argv[4]));
1345
1317
 
1346
- const auto size = values_.size();
1318
+ return CallFunction(env, callback, 5, argv);
1319
+ });
1320
+ worker->Queue(env);
1347
1321
 
1348
- NAPI_STATUS_RETURN(napi_create_array_with_length(env, size, &argv[1]));
1322
+ return 0;
1323
+ }
1349
1324
 
1350
- for (size_t idx = 0; idx < size; idx++) {
1351
- napi_value element;
1352
- if (statuses_[idx].ok()) {
1353
- NAPI_STATUS_RETURN(Convert(env, &values_[idx], valueAsBuffer_, element));
1354
- } else {
1355
- NAPI_STATUS_RETURN(napi_get_undefined(env, &element));
1356
- }
1357
- NAPI_STATUS_RETURN(napi_set_element(env, argv[1], static_cast<uint32_t>(idx), element));
1358
- }
1325
+ NAPI_METHOD(updates_close) {
1326
+ NAPI_ARGV(1);
1359
1327
 
1360
- return CallFunction(env, callback, 2, argv);
1361
- }
1328
+ Updates* updates;
1329
+ NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&updates)));
1362
1330
 
1363
- void Destroy(napi_env env) override {
1364
- database_->DecrementPriorityWork(env);
1365
- Worker::Destroy(env);
1366
- }
1331
+ updates->Detach(env);
1332
+ updates->Close();
1367
1333
 
1368
- private:
1369
- rocksdb::ColumnFamilyHandle* column_;
1370
- std::vector<std::string> keys_;
1371
- std::vector<rocksdb::PinnableSlice> values_;
1372
- std::vector<rocksdb::Status> statuses_;
1373
- const bool valueAsBuffer_;
1374
- const bool fillCache_;
1375
- const bool ignoreRangeDeletions_;
1376
- const rocksdb::Snapshot* snapshot_;
1377
- };
1334
+ return 0;
1335
+ }
1378
1336
 
1379
1337
  NAPI_METHOD(db_get_many) {
1380
1338
  NAPI_ARGV(4);
@@ -1395,15 +1353,72 @@ NAPI_METHOD(db_get_many) {
1395
1353
  }
1396
1354
  }
1397
1355
 
1398
- const bool asBuffer = EncodingIsBuffer(env, argv[2], "valueEncoding");
1356
+ const bool valueAsBuffer = EncodingIsBuffer(env, argv[2], "valueEncoding");
1399
1357
  const bool fillCache = BooleanProperty(env, argv[2], "fillCache").value_or(true);
1400
1358
  const bool ignoreRangeDeletions = BooleanProperty(env, argv[2], "ignoreRangeDeletions").value_or(false);
1401
1359
 
1402
1360
  rocksdb::ColumnFamilyHandle* column;
1403
1361
  NAPI_STATUS_THROWS(GetColumnFamily(database, env, argv[2], &column));
1404
1362
 
1405
- auto worker =
1406
- new GetManyWorker(env, database, column, std::move(keys), argv[3], asBuffer, fillCache, ignoreRangeDeletions);
1363
+ auto callback = argv[3];
1364
+
1365
+ auto snapshot = std::shared_ptr<const rocksdb::Snapshot>(
1366
+ database->db_->GetSnapshot(), [database](auto ptr) { database->db_->ReleaseSnapshot(ptr); });
1367
+
1368
+ struct State {
1369
+ std::vector<rocksdb::PinnableSlice> values;
1370
+ std::vector<rocksdb::Status> statuses;
1371
+ };
1372
+
1373
+ auto worker = createWorker<State>(
1374
+ "leveldown.get.many", env, callback, database, true,
1375
+ [=, keys = std::move(keys)](auto& state, Database& db) -> rocksdb::Status {
1376
+ rocksdb::ReadOptions readOptions;
1377
+ readOptions.fill_cache = fillCache;
1378
+ readOptions.snapshot = snapshot.get();
1379
+ readOptions.async_io = true;
1380
+ readOptions.ignore_range_deletions = ignoreRangeDeletions;
1381
+
1382
+ std::vector<rocksdb::Slice> keys2;
1383
+ keys2.reserve(keys.size());
1384
+ for (const auto& key : keys) {
1385
+ keys2.emplace_back(key);
1386
+ }
1387
+
1388
+ state.statuses.resize(keys2.size());
1389
+ state.values.resize(keys2.size());
1390
+
1391
+ db.db_->MultiGet(readOptions, column, keys2.size(), keys2.data(), state.values.data(), state.statuses.data());
1392
+
1393
+ for (const auto& status : state.statuses) {
1394
+ if (!status.ok() && !status.IsNotFound()) {
1395
+ return status;
1396
+ }
1397
+ }
1398
+
1399
+ return rocksdb::Status::OK();
1400
+ },
1401
+ [=](auto& state, napi_env env, napi_value callback) -> napi_status {
1402
+ napi_value argv[2];
1403
+ NAPI_STATUS_RETURN(napi_get_null(env, &argv[0]));
1404
+
1405
+ const auto size = state.values.size();
1406
+
1407
+ NAPI_STATUS_RETURN(napi_create_array_with_length(env, size, &argv[1]));
1408
+
1409
+ for (size_t idx = 0; idx < size; idx++) {
1410
+ napi_value element;
1411
+ if (state.statuses[idx].ok()) {
1412
+ NAPI_STATUS_RETURN(Convert(env, &state.values[idx], valueAsBuffer, element));
1413
+ } else {
1414
+ NAPI_STATUS_RETURN(napi_get_undefined(env, &element));
1415
+ }
1416
+ NAPI_STATUS_RETURN(napi_set_element(env, argv[1], static_cast<uint32_t>(idx), element));
1417
+ }
1418
+
1419
+ return CallFunction(env, callback, 2, argv);
1420
+ });
1421
+
1407
1422
  worker->Queue(env);
1408
1423
 
1409
1424
  return 0;
@@ -1613,85 +1628,6 @@ NAPI_METHOD(iterator_get_sequence) {
1613
1628
  return result;
1614
1629
  }
1615
1630
 
1616
- struct NextWorker final : public Worker {
1617
- NextWorker(napi_env env, Iterator* iterator, uint32_t size, napi_value callback)
1618
- : Worker(env, iterator->database_, callback, "leveldown.iterator.next"), iterator_(iterator), size_(size) {}
1619
-
1620
- rocksdb::Status Execute(Database& database) override {
1621
- if (!iterator_->DidSeek()) {
1622
- iterator_->SeekToRange();
1623
- }
1624
-
1625
- cache_.reserve(size_ * 2);
1626
- size_t bytesRead = 0;
1627
-
1628
- while (true) {
1629
- if (!iterator_->first_)
1630
- iterator_->Next();
1631
- else
1632
- iterator_->first_ = false;
1633
-
1634
- if (!iterator_->Valid() || !iterator_->Increment())
1635
- break;
1636
-
1637
- if (iterator_->keys_ && iterator_->values_) {
1638
- auto k = iterator_->CurrentKey();
1639
- auto v = iterator_->CurrentValue();
1640
- bytesRead += k.size() + v.size();
1641
- cache_.push_back(k.ToString());
1642
- cache_.push_back(v.ToString());
1643
- } else if (iterator_->keys_) {
1644
- auto k = iterator_->CurrentKey();
1645
- bytesRead += k.size();
1646
- cache_.push_back(k.ToString());
1647
- cache_.push_back(std::nullopt);
1648
- } else if (iterator_->values_) {
1649
- auto v = iterator_->CurrentValue();
1650
- bytesRead += v.size();
1651
- cache_.push_back(std::nullopt);
1652
- cache_.push_back(v.ToString());
1653
- }
1654
-
1655
- if (bytesRead > iterator_->highWaterMarkBytes_ || cache_.size() / 2 >= size_) {
1656
- finished_ = false;
1657
- return rocksdb::Status::OK();
1658
- }
1659
- }
1660
-
1661
- finished_ = true;
1662
-
1663
- return iterator_->Status();
1664
- }
1665
-
1666
- napi_status OnOk(napi_env env, napi_value callback) override {
1667
- napi_value argv[3];
1668
- NAPI_STATUS_RETURN(napi_get_null(env, &argv[0]));
1669
-
1670
- NAPI_STATUS_RETURN(napi_create_array_with_length(env, cache_.size(), &argv[1]));
1671
-
1672
- for (size_t n = 0; n < cache_.size(); n += 2) {
1673
- napi_value key;
1674
- napi_value val;
1675
-
1676
- NAPI_STATUS_RETURN(Convert(env, cache_[n + 0], iterator_->keyAsBuffer_, key));
1677
- NAPI_STATUS_RETURN(Convert(env, cache_[n + 1], iterator_->valueAsBuffer_, val));
1678
-
1679
- NAPI_STATUS_RETURN(napi_set_element(env, argv[1], static_cast<int>(n + 0), key));
1680
- NAPI_STATUS_RETURN(napi_set_element(env, argv[1], static_cast<int>(n + 1), val));
1681
- }
1682
-
1683
- NAPI_STATUS_RETURN(napi_get_boolean(env, finished_, &argv[2]));
1684
-
1685
- return CallFunction(env, callback, 3, argv);
1686
- }
1687
-
1688
- private:
1689
- std::vector<std::optional<std::string>> cache_;
1690
- Iterator* iterator_ = nullptr;
1691
- uint32_t size_ = 0;
1692
- bool finished_ = true;
1693
- };
1694
-
1695
1631
  NAPI_METHOD(iterator_nextv) {
1696
1632
  NAPI_ARGV(3);
1697
1633
 
@@ -1701,7 +1637,81 @@ NAPI_METHOD(iterator_nextv) {
1701
1637
  uint32_t size;
1702
1638
  NAPI_STATUS_THROWS(napi_get_value_uint32(env, argv[1], &size));
1703
1639
 
1704
- auto worker = new NextWorker(env, iterator, size, argv[2]);
1640
+ auto callback = argv[2];
1641
+
1642
+ struct State {
1643
+ std::vector<std::optional<std::string>> cache;
1644
+ bool finished = false;
1645
+ };
1646
+
1647
+ auto worker = createWorker<State>(
1648
+ std::string("leveldown.iterator.next"), env, callback, iterator->database_, true,
1649
+ [=](auto& state, Database& db) -> rocksdb::Status {
1650
+ if (!iterator->DidSeek()) {
1651
+ iterator->SeekToRange();
1652
+ }
1653
+
1654
+ state.cache.reserve(size * 2);
1655
+ size_t bytesRead = 0;
1656
+
1657
+ while (true) {
1658
+ if (!iterator->first_)
1659
+ iterator->Next();
1660
+ else
1661
+ iterator->first_ = false;
1662
+
1663
+ if (!iterator->Valid() || !iterator->Increment())
1664
+ break;
1665
+
1666
+ if (iterator->keys_ && iterator->values_) {
1667
+ auto k = iterator->CurrentKey();
1668
+ auto v = iterator->CurrentValue();
1669
+ bytesRead += k.size() + v.size();
1670
+ state.cache.push_back(k.ToString());
1671
+ state.cache.push_back(v.ToString());
1672
+ } else if (iterator->keys_) {
1673
+ auto k = iterator->CurrentKey();
1674
+ bytesRead += k.size();
1675
+ state.cache.push_back(k.ToString());
1676
+ state.cache.push_back(std::nullopt);
1677
+ } else if (iterator->values_) {
1678
+ auto v = iterator->CurrentValue();
1679
+ bytesRead += v.size();
1680
+ state.cache.push_back(std::nullopt);
1681
+ state.cache.push_back(v.ToString());
1682
+ }
1683
+
1684
+ if (bytesRead > iterator->highWaterMarkBytes_ || state.cache.size() / 2 >= size) {
1685
+ state.finished = false;
1686
+ return rocksdb::Status::OK();
1687
+ }
1688
+ }
1689
+
1690
+ state.finished = true;
1691
+
1692
+ return iterator->Status();
1693
+ },
1694
+ [=](auto& state, napi_env env, napi_value callback) -> napi_status {
1695
+ napi_value argv[3];
1696
+ NAPI_STATUS_RETURN(napi_get_null(env, &argv[0]));
1697
+
1698
+ NAPI_STATUS_RETURN(napi_create_array_with_length(env, state.cache.size(), &argv[1]));
1699
+
1700
+ for (size_t n = 0; n < state.cache.size(); n += 2) {
1701
+ napi_value key;
1702
+ napi_value val;
1703
+
1704
+ NAPI_STATUS_RETURN(Convert(env, state.cache[n + 0], iterator->keyAsBuffer_, key));
1705
+ NAPI_STATUS_RETURN(Convert(env, state.cache[n + 1], iterator->valueAsBuffer_, val));
1706
+
1707
+ NAPI_STATUS_RETURN(napi_set_element(env, argv[1], static_cast<int>(n + 0), key));
1708
+ NAPI_STATUS_RETURN(napi_set_element(env, argv[1], static_cast<int>(n + 1), val));
1709
+ }
1710
+
1711
+ NAPI_STATUS_RETURN(napi_get_boolean(env, state.finished, &argv[2]));
1712
+
1713
+ return CallFunction(env, callback, 3, argv);
1714
+ });
1705
1715
  worker->Queue(env);
1706
1716
 
1707
1717
  return 0;
@@ -1934,7 +1944,7 @@ NAPI_METHOD(batch_iterate) {
1934
1944
  const bool valueAsBuffer = EncodingIsBuffer(env, argv[1], "valueEncoding");
1935
1945
 
1936
1946
  rocksdb::ColumnFamilyHandle* column = nullptr;
1937
- // NAPI_STATUS_THROWS(GetColumnFamily(nullptr, env, argv[2], &column));
1947
+ NAPI_STATUS_THROWS(GetColumnFamily(nullptr, env, argv[2], &column));
1938
1948
 
1939
1949
  napi_value result;
1940
1950
  BatchIterator iterator(nullptr, keys, values, data, column, keyAsBuffer, valueAsBuffer);