@nxtedition/rocksdb 7.0.54 → 7.0.57

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 +310 -309
  2. package/chained-batch.js +10 -5
  3. package/index.js +33 -12
  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,70 @@ 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
+
875
+ template <typename State, typename T1, typename T2>
876
+ void runWorker(const std::string& name,
877
+ napi_env env,
878
+ napi_value callback,
879
+ Database* database,
880
+ bool priority,
881
+ T1&& execute,
882
+ T2&& onOk) {
883
+ auto worker = new GenericWorker<State, typename std::decay<T1>::type, typename std::decay<T2>::type>(
884
+ name, env, callback, database, priority, std::forward<T1>(execute), std::forward<T2>(onOk));
885
+ worker->Queue(env);
886
+ }
887
+
807
888
  /**
808
889
  * Hook for when the environment exits. This hook will be called after
809
890
  * already-scheduled napi_async_work items have finished, which gives us
@@ -864,54 +945,6 @@ NAPI_METHOD(db_init) {
864
945
  return result;
865
946
  }
866
947
 
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
948
  template <typename T, typename U>
916
949
  rocksdb::Status InitOptions(napi_env env, T& columnOptions, const U& options) {
917
950
  rocksdb::ConfigOptions configOptions;
@@ -1088,7 +1121,7 @@ NAPI_METHOD(db_open) {
1088
1121
 
1089
1122
  ROCKS_STATUS_THROWS(InitOptions(env, dbOptions, argv[2]));
1090
1123
 
1091
- std::vector<rocksdb::ColumnFamilyDescriptor> columnsFamilies;
1124
+ std::vector<rocksdb::ColumnFamilyDescriptor> descriptors;
1092
1125
 
1093
1126
  bool hasColumns;
1094
1127
  NAPI_STATUS_THROWS(napi_has_named_property(env, argv[2], "columns", &hasColumns));
@@ -1103,7 +1136,7 @@ NAPI_METHOD(db_open) {
1103
1136
  uint32_t len;
1104
1137
  NAPI_STATUS_THROWS(napi_get_array_length(env, keys, &len));
1105
1138
 
1106
- columnsFamilies.resize(len);
1139
+ descriptors.resize(len);
1107
1140
  for (uint32_t n = 0; n < len; ++n) {
1108
1141
  napi_value key;
1109
1142
  NAPI_STATUS_THROWS(napi_get_element(env, keys, n, &key));
@@ -1111,30 +1144,48 @@ NAPI_METHOD(db_open) {
1111
1144
  napi_value column;
1112
1145
  NAPI_STATUS_THROWS(napi_get_property(env, columns, key, &column));
1113
1146
 
1114
- ROCKS_STATUS_THROWS(InitOptions(env, columnsFamilies[n].options, column));
1147
+ ROCKS_STATUS_THROWS(InitOptions(env, descriptors[n].options, column));
1115
1148
 
1116
- NAPI_STATUS_THROWS(ToString(env, key, columnsFamilies[n].name));
1149
+ NAPI_STATUS_THROWS(ToString(env, key, descriptors[n].name));
1117
1150
  }
1118
1151
  }
1119
1152
 
1120
- auto worker = new OpenWorker(env, database, argv[3], location, dbOptions, columnsFamilies);
1121
- worker->Queue(env);
1153
+ auto callback = argv[3];
1122
1154
 
1123
- return 0;
1124
- }
1155
+ runWorker<std::vector<rocksdb::ColumnFamilyHandle*>>(
1156
+ "leveldown.open", env, callback, database, false,
1157
+ [=](auto& handles, auto& database) -> rocksdb::Status {
1158
+ rocksdb::DB* db = nullptr;
1159
+ const auto status = descriptors.empty()
1160
+ ? rocksdb::DB::Open(dbOptions, location, &db)
1161
+ : rocksdb::DB::Open(dbOptions, location, descriptors, &handles, &db);
1162
+ database.db_.reset(db);
1163
+ return status;
1164
+ },
1165
+ [=](auto& handles, napi_env env, napi_value callback) -> napi_status {
1166
+ napi_value argv[2];
1167
+ NAPI_STATUS_RETURN(napi_get_null(env, &argv[0]));
1125
1168
 
1126
- struct CloseWorker final : public Worker {
1127
- CloseWorker(napi_env env, Database* database, napi_value callback)
1128
- : Worker(env, database, callback, "leveldown.db.close") {}
1169
+ const auto size = handles.size();
1170
+ NAPI_STATUS_RETURN(napi_create_object(env, &argv[1]));
1129
1171
 
1130
- rocksdb::Status Execute(Database& database) override {
1131
- for (auto& it : database.columns_) {
1132
- database.db_->DestroyColumnFamilyHandle(it.second.handle);
1133
- }
1172
+ for (size_t n = 0; n < size; ++n) {
1173
+ ColumnFamily column;
1174
+ column.handle = handles[n];
1175
+ column.descriptor = descriptors[n];
1176
+ NAPI_STATUS_RETURN(napi_create_external(env, column.handle, nullptr, nullptr, &column.val));
1177
+ NAPI_STATUS_RETURN(napi_create_reference(env, column.val, 1, &column.ref));
1134
1178
 
1135
- return database.db_->Close();
1136
- }
1137
- };
1179
+ NAPI_STATUS_RETURN(napi_set_named_property(env, argv[1], descriptors[n].name.c_str(), column.val));
1180
+
1181
+ database->columns_[column.handle->GetID()] = column;
1182
+ }
1183
+
1184
+ return CallFunction(env, callback, 2, argv);
1185
+ });
1186
+
1187
+ return 0;
1188
+ }
1138
1189
 
1139
1190
  napi_value noop_callback(napi_env env, napi_callback_info info) {
1140
1191
  return 0;
@@ -1146,7 +1197,25 @@ NAPI_METHOD(db_close) {
1146
1197
  Database* database;
1147
1198
  NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&database)));
1148
1199
 
1149
- auto worker = new CloseWorker(env, database, argv[1]);
1200
+ auto callback = argv[1];
1201
+
1202
+ struct State {};
1203
+ auto worker = createWorker<State>(
1204
+ "leveldown.close", env, callback, database, false,
1205
+ [=](auto& state, auto& database) -> rocksdb::Status {
1206
+ for (auto& it : database.columns_) {
1207
+ database.db_->DestroyColumnFamilyHandle(it.second.handle);
1208
+ }
1209
+ database.columns_.clear();
1210
+
1211
+ return database.db_->Close();
1212
+ },
1213
+ [](auto& state, napi_env env, napi_value callback) -> napi_status {
1214
+ napi_value argv[1];
1215
+ NAPI_STATUS_RETURN(napi_get_null(env, &argv[0]));
1216
+
1217
+ return CallFunction(env, callback, 1, &argv[0]);
1218
+ });
1150
1219
 
1151
1220
  if (!database->HasPriorityWork()) {
1152
1221
  worker->Queue(env);
@@ -1157,68 +1226,6 @@ NAPI_METHOD(db_close) {
1157
1226
  return 0;
1158
1227
  }
1159
1228
 
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
1229
  NAPI_METHOD(updates_init) {
1223
1230
  NAPI_ARGV(2);
1224
1231
 
@@ -1249,7 +1256,7 @@ NAPI_METHOD(updates_init) {
1249
1256
  const bool valueAsBuffer = EncodingIsBuffer(env, argv[1], "valueEncoding");
1250
1257
 
1251
1258
  rocksdb::ColumnFamilyHandle* column = nullptr;
1252
- // NAPI_STATUS_THROWS(GetColumnFamily(nullptr, env, argv[1], &column));
1259
+ NAPI_STATUS_THROWS(GetColumnFamily(nullptr, env, argv[1], &column));
1253
1260
 
1254
1261
  auto updates = std::make_unique<Updates>(database, since, keys, values, data, column, keyAsBuffer, valueAsBuffer);
1255
1262
 
@@ -1269,8 +1276,46 @@ NAPI_METHOD(updates_next) {
1269
1276
  Updates* updates;
1270
1277
  NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&updates)));
1271
1278
 
1272
- auto worker = new UpdatesNextWorker(env, updates, argv[1]);
1273
- worker->Queue(env);
1279
+ auto callback = argv[1];
1280
+
1281
+ runWorker<rocksdb::BatchResult>(
1282
+ "leveldown.updates.next", env, callback, updates->database_, true,
1283
+ [=](auto& batchResult, auto& database) -> rocksdb::Status {
1284
+ if (!updates->iterator_) {
1285
+ rocksdb::TransactionLogIterator::ReadOptions options;
1286
+ const auto status = database.db_->GetUpdatesSince(updates->start_, &updates->iterator_, options);
1287
+ if (!status.ok()) {
1288
+ return status;
1289
+ }
1290
+ } else if (updates->iterator_->Valid()) {
1291
+ updates->iterator_->Next();
1292
+ }
1293
+
1294
+ if (!updates->iterator_->Valid() || !updates->iterator_->status().ok()) {
1295
+ return updates->iterator_->status();
1296
+ }
1297
+
1298
+ batchResult = updates->iterator_->GetBatch();
1299
+
1300
+ return rocksdb::Status::OK();
1301
+ },
1302
+ [=](auto& batchResult, napi_env env, napi_value callback) -> napi_status {
1303
+ napi_value argv[5];
1304
+
1305
+ NAPI_STATUS_RETURN(napi_get_null(env, &argv[0]));
1306
+
1307
+ if (!batchResult.writeBatchPtr) {
1308
+ return CallFunction(env, callback, 1, argv);
1309
+ }
1310
+
1311
+ NAPI_STATUS_RETURN(updates->Iterate(env, *batchResult.writeBatchPtr, &argv[1]));
1312
+
1313
+ NAPI_STATUS_RETURN(napi_create_int64(env, batchResult.sequence, &argv[2]));
1314
+ NAPI_STATUS_RETURN(napi_create_int64(env, batchResult.writeBatchPtr->Count(), &argv[3]));
1315
+ NAPI_STATUS_RETURN(napi_create_int64(env, updates->start_, &argv[4]));
1316
+
1317
+ return CallFunction(env, callback, 5, argv);
1318
+ });
1274
1319
 
1275
1320
  return 0;
1276
1321
  }
@@ -1287,95 +1332,6 @@ NAPI_METHOD(updates_close) {
1287
1332
  return 0;
1288
1333
  }
1289
1334
 
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
- }
1314
-
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_;
1321
-
1322
- std::vector<rocksdb::Slice> keys;
1323
- keys.reserve(keys_.size());
1324
- for (const auto& key : keys_) {
1325
- keys.emplace_back(key);
1326
- }
1327
-
1328
- statuses_.resize(keys.size());
1329
- values_.resize(keys.size());
1330
-
1331
- database.db_->MultiGet(readOptions, column_, keys.size(), keys.data(), values_.data(), statuses_.data());
1332
-
1333
- for (const auto& status : statuses_) {
1334
- if (!status.ok() && !status.IsNotFound()) {
1335
- return status;
1336
- }
1337
- }
1338
-
1339
- return rocksdb::Status::OK();
1340
- }
1341
-
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]));
1345
-
1346
- const auto size = values_.size();
1347
-
1348
- NAPI_STATUS_RETURN(napi_create_array_with_length(env, size, &argv[1]));
1349
-
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
- }
1359
-
1360
- return CallFunction(env, callback, 2, argv);
1361
- }
1362
-
1363
- void Destroy(napi_env env) override {
1364
- database_->DecrementPriorityWork(env);
1365
- Worker::Destroy(env);
1366
- }
1367
-
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
- };
1378
-
1379
1335
  NAPI_METHOD(db_get_many) {
1380
1336
  NAPI_ARGV(4);
1381
1337
 
@@ -1395,16 +1351,67 @@ NAPI_METHOD(db_get_many) {
1395
1351
  }
1396
1352
  }
1397
1353
 
1398
- const bool asBuffer = EncodingIsBuffer(env, argv[2], "valueEncoding");
1354
+ const bool valueAsBuffer = EncodingIsBuffer(env, argv[2], "valueEncoding");
1399
1355
  const bool fillCache = BooleanProperty(env, argv[2], "fillCache").value_or(true);
1400
1356
  const bool ignoreRangeDeletions = BooleanProperty(env, argv[2], "ignoreRangeDeletions").value_or(false);
1401
1357
 
1402
1358
  rocksdb::ColumnFamilyHandle* column;
1403
1359
  NAPI_STATUS_THROWS(GetColumnFamily(database, env, argv[2], &column));
1404
1360
 
1405
- auto worker =
1406
- new GetManyWorker(env, database, column, std::move(keys), argv[3], asBuffer, fillCache, ignoreRangeDeletions);
1407
- worker->Queue(env);
1361
+ auto callback = argv[3];
1362
+
1363
+ auto snapshot = std::shared_ptr<const rocksdb::Snapshot>(
1364
+ database->db_->GetSnapshot(), [database](auto ptr) { database->db_->ReleaseSnapshot(ptr); });
1365
+
1366
+ runWorker<std::vector<rocksdb::PinnableSlice>>(
1367
+ "leveldown.get.many", env, callback, database, true,
1368
+ [=, keys = std::move(keys)](auto& values, Database& db) -> rocksdb::Status {
1369
+ rocksdb::ReadOptions readOptions;
1370
+ readOptions.fill_cache = fillCache;
1371
+ readOptions.snapshot = snapshot.get();
1372
+ readOptions.async_io = true;
1373
+ readOptions.ignore_range_deletions = ignoreRangeDeletions;
1374
+
1375
+ std::vector<rocksdb::Slice> keys2;
1376
+ keys2.reserve(keys.size());
1377
+ for (const auto& key : keys) {
1378
+ keys2.emplace_back(key);
1379
+ }
1380
+ std::vector<rocksdb::Status> statuses;
1381
+
1382
+ statuses.resize(keys2.size());
1383
+ values.resize(keys2.size());
1384
+
1385
+ db.db_->MultiGet(readOptions, column, keys2.size(), keys2.data(), values.data(), statuses.data());
1386
+
1387
+ for (size_t idx = 0; idx < keys2.size(); idx++) {
1388
+ if (statuses[idx].IsNotFound()) {
1389
+ values[idx] = rocksdb::PinnableSlice(nullptr);
1390
+ } else if (!statuses[idx].ok()) {
1391
+ return statuses[idx];
1392
+ }
1393
+ }
1394
+
1395
+ return rocksdb::Status::OK();
1396
+ },
1397
+ [=](auto& values, napi_env env, napi_value callback) -> napi_status {
1398
+ napi_value argv[2];
1399
+ NAPI_STATUS_RETURN(napi_get_null(env, &argv[0]));
1400
+
1401
+ NAPI_STATUS_RETURN(napi_create_array_with_length(env, values.size(), &argv[1]));
1402
+
1403
+ for (size_t idx = 0; idx < values.size(); idx++) {
1404
+ napi_value element;
1405
+ if (values[idx].GetSelf()) {
1406
+ NAPI_STATUS_RETURN(Convert(env, &values[idx], valueAsBuffer, element));
1407
+ } else {
1408
+ NAPI_STATUS_RETURN(napi_get_undefined(env, &element));
1409
+ }
1410
+ NAPI_STATUS_RETURN(napi_set_element(env, argv[1], static_cast<uint32_t>(idx), element));
1411
+ }
1412
+
1413
+ return CallFunction(env, callback, 2, argv);
1414
+ });
1408
1415
 
1409
1416
  return 0;
1410
1417
  }
@@ -1613,85 +1620,6 @@ NAPI_METHOD(iterator_get_sequence) {
1613
1620
  return result;
1614
1621
  }
1615
1622
 
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
1623
  NAPI_METHOD(iterator_nextv) {
1696
1624
  NAPI_ARGV(3);
1697
1625
 
@@ -1701,8 +1629,81 @@ NAPI_METHOD(iterator_nextv) {
1701
1629
  uint32_t size;
1702
1630
  NAPI_STATUS_THROWS(napi_get_value_uint32(env, argv[1], &size));
1703
1631
 
1704
- auto worker = new NextWorker(env, iterator, size, argv[2]);
1705
- worker->Queue(env);
1632
+ auto callback = argv[2];
1633
+
1634
+ struct State {
1635
+ std::vector<std::optional<std::string>> cache;
1636
+ bool finished = false;
1637
+ };
1638
+
1639
+ runWorker<State>(
1640
+ std::string("leveldown.iterator.next"), env, callback, iterator->database_, true,
1641
+ [=](auto& state, Database& db) -> rocksdb::Status {
1642
+ if (!iterator->DidSeek()) {
1643
+ iterator->SeekToRange();
1644
+ }
1645
+
1646
+ state.cache.reserve(size * 2);
1647
+ size_t bytesRead = 0;
1648
+
1649
+ while (true) {
1650
+ if (!iterator->first_)
1651
+ iterator->Next();
1652
+ else
1653
+ iterator->first_ = false;
1654
+
1655
+ if (!iterator->Valid() || !iterator->Increment())
1656
+ break;
1657
+
1658
+ if (iterator->keys_ && iterator->values_) {
1659
+ auto k = iterator->CurrentKey();
1660
+ auto v = iterator->CurrentValue();
1661
+ bytesRead += k.size() + v.size();
1662
+ state.cache.push_back(k.ToString());
1663
+ state.cache.push_back(v.ToString());
1664
+ } else if (iterator->keys_) {
1665
+ auto k = iterator->CurrentKey();
1666
+ bytesRead += k.size();
1667
+ state.cache.push_back(k.ToString());
1668
+ state.cache.push_back(std::nullopt);
1669
+ } else if (iterator->values_) {
1670
+ auto v = iterator->CurrentValue();
1671
+ bytesRead += v.size();
1672
+ state.cache.push_back(std::nullopt);
1673
+ state.cache.push_back(v.ToString());
1674
+ }
1675
+
1676
+ if (bytesRead > iterator->highWaterMarkBytes_ || state.cache.size() / 2 >= size) {
1677
+ state.finished = false;
1678
+ return rocksdb::Status::OK();
1679
+ }
1680
+ }
1681
+
1682
+ state.finished = true;
1683
+
1684
+ return iterator->Status();
1685
+ },
1686
+ [=](auto& state, napi_env env, napi_value callback) -> napi_status {
1687
+ napi_value argv[3];
1688
+ NAPI_STATUS_RETURN(napi_get_null(env, &argv[0]));
1689
+
1690
+ NAPI_STATUS_RETURN(napi_create_array_with_length(env, state.cache.size(), &argv[1]));
1691
+
1692
+ for (size_t n = 0; n < state.cache.size(); n += 2) {
1693
+ napi_value key;
1694
+ napi_value val;
1695
+
1696
+ NAPI_STATUS_RETURN(Convert(env, state.cache[n + 0], iterator->keyAsBuffer_, key));
1697
+ NAPI_STATUS_RETURN(Convert(env, state.cache[n + 1], iterator->valueAsBuffer_, val));
1698
+
1699
+ NAPI_STATUS_RETURN(napi_set_element(env, argv[1], static_cast<int>(n + 0), key));
1700
+ NAPI_STATUS_RETURN(napi_set_element(env, argv[1], static_cast<int>(n + 1), val));
1701
+ }
1702
+
1703
+ NAPI_STATUS_RETURN(napi_get_boolean(env, state.finished, &argv[2]));
1704
+
1705
+ return CallFunction(env, callback, 3, argv);
1706
+ });
1706
1707
 
1707
1708
  return 0;
1708
1709
  }
@@ -1934,7 +1935,7 @@ NAPI_METHOD(batch_iterate) {
1934
1935
  const bool valueAsBuffer = EncodingIsBuffer(env, argv[1], "valueEncoding");
1935
1936
 
1936
1937
  rocksdb::ColumnFamilyHandle* column = nullptr;
1937
- // NAPI_STATUS_THROWS(GetColumnFamily(nullptr, env, argv[2], &column));
1938
+ NAPI_STATUS_THROWS(GetColumnFamily(nullptr, env, argv[2], &column));
1938
1939
 
1939
1940
  napi_value result;
1940
1941
  BatchIterator iterator(nullptr, keys, values, data, column, keyAsBuffer, valueAsBuffer);