@nxtedition/rocksdb 7.0.5 → 7.0.8

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 (262) hide show
  1. package/binding.cc +363 -329
  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/cmake/modules/CxxFlags.cmake +7 -0
  14. package/deps/rocksdb/rocksdb/cmake/modules/FindJeMalloc.cmake +29 -0
  15. package/deps/rocksdb/rocksdb/cmake/modules/FindNUMA.cmake +29 -0
  16. package/deps/rocksdb/rocksdb/cmake/modules/FindSnappy.cmake +29 -0
  17. package/deps/rocksdb/rocksdb/cmake/modules/FindTBB.cmake +33 -0
  18. package/deps/rocksdb/rocksdb/cmake/modules/Findgflags.cmake +29 -0
  19. package/deps/rocksdb/rocksdb/cmake/modules/Findlz4.cmake +29 -0
  20. package/deps/rocksdb/rocksdb/cmake/modules/Finduring.cmake +26 -0
  21. package/deps/rocksdb/rocksdb/cmake/modules/Findzstd.cmake +29 -0
  22. package/deps/rocksdb/rocksdb/cmake/modules/ReadVersion.cmake +10 -0
  23. package/deps/rocksdb/rocksdb/db/blob/blob_source.cc +170 -0
  24. package/deps/rocksdb/rocksdb/db/blob/blob_source.h +95 -0
  25. package/deps/rocksdb/rocksdb/db/blob/blob_source_test.cc +298 -0
  26. package/deps/rocksdb/rocksdb/db/blob/db_blob_basic_test.cc +172 -0
  27. package/deps/rocksdb/rocksdb/db/column_family.cc +8 -3
  28. package/deps/rocksdb/rocksdb/db/column_family.h +6 -3
  29. package/deps/rocksdb/rocksdb/db/compaction/compaction_job.cc +10 -0
  30. package/deps/rocksdb/rocksdb/db/compaction/compaction_job_test.cc +6 -6
  31. package/deps/rocksdb/rocksdb/db/compaction/compaction_picker_level.cc +22 -2
  32. package/deps/rocksdb/rocksdb/db/compaction/compaction_picker_test.cc +38 -0
  33. package/deps/rocksdb/rocksdb/db/db_basic_test.cc +17 -5
  34. package/deps/rocksdb/rocksdb/db/db_block_cache_test.cc +4 -7
  35. package/deps/rocksdb/rocksdb/db/db_bloom_filter_test.cc +74 -71
  36. package/deps/rocksdb/rocksdb/db/db_compaction_test.cc +70 -1
  37. package/deps/rocksdb/rocksdb/db/db_impl/db_impl.cc +13 -12
  38. package/deps/rocksdb/rocksdb/db/db_impl/db_impl.h +36 -0
  39. package/deps/rocksdb/rocksdb/db/db_impl/db_impl_compaction_flush.cc +11 -4
  40. package/deps/rocksdb/rocksdb/db/db_impl/db_impl_files.cc +1 -1
  41. package/deps/rocksdb/rocksdb/db/db_impl/db_impl_open.cc +139 -91
  42. package/deps/rocksdb/rocksdb/db/db_impl/db_impl_write.cc +48 -14
  43. package/deps/rocksdb/rocksdb/db/db_kv_checksum_test.cc +90 -55
  44. package/deps/rocksdb/rocksdb/db/db_rate_limiter_test.cc +9 -4
  45. package/deps/rocksdb/rocksdb/db/db_test.cc +3 -1
  46. package/deps/rocksdb/rocksdb/db/db_wal_test.cc +12 -7
  47. package/deps/rocksdb/rocksdb/db/db_write_test.cc +35 -0
  48. package/deps/rocksdb/rocksdb/db/dbformat.cc +3 -1
  49. package/deps/rocksdb/rocksdb/db/dbformat.h +5 -3
  50. package/deps/rocksdb/rocksdb/db/flush_job_test.cc +1 -1
  51. package/deps/rocksdb/rocksdb/db/memtable.cc +1 -0
  52. package/deps/rocksdb/rocksdb/db/memtable_list_test.cc +4 -2
  53. package/deps/rocksdb/rocksdb/db/repair.cc +1 -1
  54. package/deps/rocksdb/rocksdb/db/version_builder.cc +43 -1
  55. package/deps/rocksdb/rocksdb/db/version_edit.cc +13 -5
  56. package/deps/rocksdb/rocksdb/db/version_edit.h +22 -1
  57. package/deps/rocksdb/rocksdb/db/version_edit_handler.cc +4 -5
  58. package/deps/rocksdb/rocksdb/db/version_set.cc +109 -41
  59. package/deps/rocksdb/rocksdb/db/version_set.h +36 -3
  60. package/deps/rocksdb/rocksdb/db/version_set_sync_and_async.h +1 -4
  61. package/deps/rocksdb/rocksdb/db/version_set_test.cc +10 -10
  62. package/deps/rocksdb/rocksdb/db/version_util.h +1 -1
  63. package/deps/rocksdb/rocksdb/db/wal_manager_test.cc +1 -1
  64. package/deps/rocksdb/rocksdb/db/write_batch.cc +34 -10
  65. package/deps/rocksdb/rocksdb/db/write_batch_internal.h +2 -0
  66. package/deps/rocksdb/rocksdb/db/write_callback_test.cc +4 -0
  67. package/deps/rocksdb/rocksdb/db_stress_tool/batched_ops_stress.cc +2 -0
  68. package/deps/rocksdb/rocksdb/db_stress_tool/cf_consistency_stress.cc +4 -1
  69. package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_common.h +1 -1
  70. package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_gflags.cc +7 -5
  71. package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_test_base.cc +5 -10
  72. package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_tool.cc +0 -7
  73. package/deps/rocksdb/rocksdb/db_stress_tool/no_batched_ops_stress.cc +2 -0
  74. package/deps/rocksdb/rocksdb/file/random_access_file_reader.cc +24 -3
  75. package/deps/rocksdb/rocksdb/file/writable_file_writer.cc +8 -0
  76. package/deps/rocksdb/rocksdb/file/writable_file_writer.h +10 -0
  77. package/deps/rocksdb/rocksdb/include/rocksdb/advanced_options.h +5 -0
  78. package/deps/rocksdb/rocksdb/include/rocksdb/cache.h +4 -4
  79. package/deps/rocksdb/rocksdb/include/rocksdb/options.h +9 -5
  80. package/deps/rocksdb/rocksdb/include/rocksdb/statistics.h +5 -0
  81. package/deps/rocksdb/rocksdb/include/rocksdb/types.h +1 -0
  82. package/deps/rocksdb/rocksdb/include/rocksdb/utilities/write_batch_with_index.h +1 -1
  83. package/deps/rocksdb/rocksdb/include/rocksdb/version.h +1 -1
  84. package/deps/rocksdb/rocksdb/include/rocksdb/write_batch.h +0 -3
  85. package/deps/rocksdb/rocksdb/microbench/ribbon_bench.cc +8 -6
  86. package/deps/rocksdb/rocksdb/monitoring/statistics.cc +3 -1
  87. package/deps/rocksdb/rocksdb/options/options_helper.cc +4 -2
  88. package/deps/rocksdb/rocksdb/options/options_test.cc +1 -11
  89. package/deps/rocksdb/rocksdb/port/port_posix.h +7 -0
  90. package/deps/rocksdb/rocksdb/port/win/port_win.h +11 -3
  91. package/deps/rocksdb/rocksdb/src.mk +6 -2
  92. package/deps/rocksdb/rocksdb/table/block_based/block_based_table_builder.cc +4 -33
  93. package/deps/rocksdb/rocksdb/table/block_based/block_based_table_iterator.h +3 -3
  94. package/deps/rocksdb/rocksdb/table/block_based/block_based_table_reader.cc +38 -118
  95. package/deps/rocksdb/rocksdb/table/block_based/block_based_table_reader.h +6 -8
  96. package/deps/rocksdb/rocksdb/table/block_based/block_based_table_reader_sync_and_async.h +10 -13
  97. package/deps/rocksdb/rocksdb/table/block_based/block_like_traits.h +4 -9
  98. package/deps/rocksdb/rocksdb/table/block_based/block_type.h +0 -1
  99. package/deps/rocksdb/rocksdb/table/block_based/filter_block.h +10 -28
  100. package/deps/rocksdb/rocksdb/table/block_based/filter_block_reader_common.cc +2 -3
  101. package/deps/rocksdb/rocksdb/table/block_based/filter_policy.cc +0 -91
  102. package/deps/rocksdb/rocksdb/table/block_based/filter_policy_internal.h +2 -30
  103. package/deps/rocksdb/rocksdb/table/block_based/full_filter_block.cc +6 -27
  104. package/deps/rocksdb/rocksdb/table/block_based/full_filter_block.h +11 -13
  105. package/deps/rocksdb/rocksdb/table/block_based/full_filter_block_test.cc +28 -40
  106. package/deps/rocksdb/rocksdb/table/block_based/mock_block_based_table.h +0 -1
  107. package/deps/rocksdb/rocksdb/table/block_based/partitioned_filter_block.cc +22 -43
  108. package/deps/rocksdb/rocksdb/table/block_based/partitioned_filter_block.h +11 -22
  109. package/deps/rocksdb/rocksdb/table/block_based/partitioned_filter_block_test.cc +24 -25
  110. package/deps/rocksdb/rocksdb/table/block_fetcher.cc +0 -1
  111. package/deps/rocksdb/rocksdb/table/get_context.h +0 -1
  112. package/deps/rocksdb/rocksdb/table/table_test.cc +3 -18
  113. package/deps/rocksdb/rocksdb/tools/db_bench_tool.cc +3 -16
  114. package/deps/rocksdb/rocksdb/tools/ldb_cmd.cc +3 -3
  115. package/deps/rocksdb/rocksdb/tools/ldb_cmd_test.cc +1 -1
  116. package/deps/rocksdb/rocksdb/util/bloom_test.cc +0 -201
  117. package/deps/rocksdb/rocksdb/util/distributed_mutex.h +48 -0
  118. package/deps/rocksdb/rocksdb/util/filter_bench.cc +5 -11
  119. package/deps/rocksdb/rocksdb/utilities/backup/backup_engine.cc +3 -0
  120. package/deps/rocksdb/rocksdb/utilities/cache_dump_load_impl.cc +7 -21
  121. package/deps/rocksdb/rocksdb/utilities/cache_dump_load_impl.h +1 -1
  122. package/deps/rocksdb/rocksdb/utilities/checkpoint/checkpoint_test.cc +45 -0
  123. package/deps/rocksdb/rocksdb/utilities/transactions/pessimistic_transaction_db.h +21 -14
  124. package/deps/rocksdb/rocksdb/utilities/transactions/transaction_base.cc +10 -1
  125. package/deps/rocksdb/rocksdb/utilities/transactions/write_prepared_txn.cc +3 -1
  126. package/deps/rocksdb/rocksdb/utilities/transactions/write_prepared_txn_db.cc +9 -0
  127. package/deps/rocksdb/rocksdb/utilities/transactions/write_unprepared_txn.cc +3 -2
  128. package/deps/rocksdb/rocksdb/utilities/transactions/write_unprepared_txn_db.cc +3 -1
  129. package/deps/rocksdb/rocksdb/utilities/write_batch_with_index/write_batch_with_index.cc +5 -4
  130. package/deps/rocksdb/rocksdb.gyp +1 -1
  131. package/index.js +36 -14
  132. package/package-lock.json +23687 -0
  133. package/package.json +1 -1
  134. package/prebuilds/darwin-arm64/node.napi.node +0 -0
  135. package/prebuilds/darwin-x64/node.napi.node +0 -0
  136. package/prebuilds/linux-x64/node.napi.node +0 -0
  137. package/deps/liburing/liburing/README +0 -46
  138. package/deps/liburing/liburing/test/232c93d07b74-test.c +0 -305
  139. package/deps/liburing/liburing/test/35fa71a030ca-test.c +0 -329
  140. package/deps/liburing/liburing/test/500f9fbadef8-test.c +0 -89
  141. package/deps/liburing/liburing/test/7ad0e4b2f83c-test.c +0 -93
  142. package/deps/liburing/liburing/test/8a9973408177-test.c +0 -106
  143. package/deps/liburing/liburing/test/917257daa0fe-test.c +0 -53
  144. package/deps/liburing/liburing/test/Makefile +0 -312
  145. package/deps/liburing/liburing/test/a0908ae19763-test.c +0 -58
  146. package/deps/liburing/liburing/test/a4c0b3decb33-test.c +0 -180
  147. package/deps/liburing/liburing/test/accept-link.c +0 -251
  148. package/deps/liburing/liburing/test/accept-reuse.c +0 -164
  149. package/deps/liburing/liburing/test/accept-test.c +0 -79
  150. package/deps/liburing/liburing/test/accept.c +0 -476
  151. package/deps/liburing/liburing/test/across-fork.c +0 -283
  152. package/deps/liburing/liburing/test/b19062a56726-test.c +0 -53
  153. package/deps/liburing/liburing/test/b5837bd5311d-test.c +0 -77
  154. package/deps/liburing/liburing/test/ce593a6c480a-test.c +0 -135
  155. package/deps/liburing/liburing/test/close-opath.c +0 -122
  156. package/deps/liburing/liburing/test/config +0 -10
  157. package/deps/liburing/liburing/test/connect.c +0 -398
  158. package/deps/liburing/liburing/test/cq-full.c +0 -96
  159. package/deps/liburing/liburing/test/cq-overflow.c +0 -294
  160. package/deps/liburing/liburing/test/cq-peek-batch.c +0 -102
  161. package/deps/liburing/liburing/test/cq-ready.c +0 -94
  162. package/deps/liburing/liburing/test/cq-size.c +0 -58
  163. package/deps/liburing/liburing/test/d4ae271dfaae-test.c +0 -96
  164. package/deps/liburing/liburing/test/d77a67ed5f27-test.c +0 -65
  165. package/deps/liburing/liburing/test/defer.c +0 -307
  166. package/deps/liburing/liburing/test/double-poll-crash.c +0 -186
  167. package/deps/liburing/liburing/test/eeed8b54e0df-test.c +0 -114
  168. package/deps/liburing/liburing/test/empty-eownerdead.c +0 -42
  169. package/deps/liburing/liburing/test/eventfd-disable.c +0 -151
  170. package/deps/liburing/liburing/test/eventfd-ring.c +0 -97
  171. package/deps/liburing/liburing/test/eventfd.c +0 -112
  172. package/deps/liburing/liburing/test/fadvise.c +0 -202
  173. package/deps/liburing/liburing/test/fallocate.c +0 -249
  174. package/deps/liburing/liburing/test/fc2a85cb02ef-test.c +0 -138
  175. package/deps/liburing/liburing/test/file-register.c +0 -843
  176. package/deps/liburing/liburing/test/file-update.c +0 -173
  177. package/deps/liburing/liburing/test/files-exit-hang-poll.c +0 -128
  178. package/deps/liburing/liburing/test/files-exit-hang-timeout.c +0 -134
  179. package/deps/liburing/liburing/test/fixed-link.c +0 -90
  180. package/deps/liburing/liburing/test/fsync.c +0 -224
  181. package/deps/liburing/liburing/test/hardlink.c +0 -136
  182. package/deps/liburing/liburing/test/helpers.c +0 -135
  183. package/deps/liburing/liburing/test/helpers.h +0 -67
  184. package/deps/liburing/liburing/test/io-cancel.c +0 -537
  185. package/deps/liburing/liburing/test/io_uring_enter.c +0 -296
  186. package/deps/liburing/liburing/test/io_uring_register.c +0 -664
  187. package/deps/liburing/liburing/test/io_uring_setup.c +0 -192
  188. package/deps/liburing/liburing/test/iopoll.c +0 -366
  189. package/deps/liburing/liburing/test/lfs-openat-write.c +0 -117
  190. package/deps/liburing/liburing/test/lfs-openat.c +0 -273
  191. package/deps/liburing/liburing/test/link-timeout.c +0 -1107
  192. package/deps/liburing/liburing/test/link.c +0 -496
  193. package/deps/liburing/liburing/test/link_drain.c +0 -229
  194. package/deps/liburing/liburing/test/madvise.c +0 -195
  195. package/deps/liburing/liburing/test/mkdir.c +0 -108
  196. package/deps/liburing/liburing/test/multicqes_drain.c +0 -383
  197. package/deps/liburing/liburing/test/nop-all-sizes.c +0 -107
  198. package/deps/liburing/liburing/test/nop.c +0 -115
  199. package/deps/liburing/liburing/test/open-close.c +0 -146
  200. package/deps/liburing/liburing/test/openat2.c +0 -240
  201. package/deps/liburing/liburing/test/personality.c +0 -204
  202. package/deps/liburing/liburing/test/pipe-eof.c +0 -81
  203. package/deps/liburing/liburing/test/pipe-reuse.c +0 -105
  204. package/deps/liburing/liburing/test/poll-cancel-ton.c +0 -139
  205. package/deps/liburing/liburing/test/poll-cancel.c +0 -135
  206. package/deps/liburing/liburing/test/poll-link.c +0 -227
  207. package/deps/liburing/liburing/test/poll-many.c +0 -208
  208. package/deps/liburing/liburing/test/poll-mshot-update.c +0 -273
  209. package/deps/liburing/liburing/test/poll-ring.c +0 -48
  210. package/deps/liburing/liburing/test/poll-v-poll.c +0 -353
  211. package/deps/liburing/liburing/test/poll.c +0 -109
  212. package/deps/liburing/liburing/test/probe.c +0 -137
  213. package/deps/liburing/liburing/test/read-write.c +0 -876
  214. package/deps/liburing/liburing/test/register-restrictions.c +0 -633
  215. package/deps/liburing/liburing/test/rename.c +0 -134
  216. package/deps/liburing/liburing/test/ring-leak.c +0 -173
  217. package/deps/liburing/liburing/test/ring-leak2.c +0 -249
  218. package/deps/liburing/liburing/test/rsrc_tags.c +0 -449
  219. package/deps/liburing/liburing/test/runtests-loop.sh +0 -16
  220. package/deps/liburing/liburing/test/runtests.sh +0 -170
  221. package/deps/liburing/liburing/test/rw_merge_test.c +0 -97
  222. package/deps/liburing/liburing/test/self.c +0 -91
  223. package/deps/liburing/liburing/test/send_recv.c +0 -291
  224. package/deps/liburing/liburing/test/send_recvmsg.c +0 -345
  225. package/deps/liburing/liburing/test/sendmsg_fs_cve.c +0 -198
  226. package/deps/liburing/liburing/test/shared-wq.c +0 -84
  227. package/deps/liburing/liburing/test/short-read.c +0 -75
  228. package/deps/liburing/liburing/test/shutdown.c +0 -163
  229. package/deps/liburing/liburing/test/sigfd-deadlock.c +0 -74
  230. package/deps/liburing/liburing/test/socket-rw-eagain.c +0 -156
  231. package/deps/liburing/liburing/test/socket-rw.c +0 -147
  232. package/deps/liburing/liburing/test/splice.c +0 -511
  233. package/deps/liburing/liburing/test/sq-full-cpp.cc +0 -45
  234. package/deps/liburing/liburing/test/sq-full.c +0 -45
  235. package/deps/liburing/liburing/test/sq-poll-dup.c +0 -200
  236. package/deps/liburing/liburing/test/sq-poll-kthread.c +0 -168
  237. package/deps/liburing/liburing/test/sq-poll-share.c +0 -137
  238. package/deps/liburing/liburing/test/sq-space_left.c +0 -159
  239. package/deps/liburing/liburing/test/sqpoll-cancel-hang.c +0 -159
  240. package/deps/liburing/liburing/test/sqpoll-disable-exit.c +0 -195
  241. package/deps/liburing/liburing/test/sqpoll-exit-hang.c +0 -77
  242. package/deps/liburing/liburing/test/sqpoll-sleep.c +0 -68
  243. package/deps/liburing/liburing/test/statx.c +0 -172
  244. package/deps/liburing/liburing/test/stdout.c +0 -232
  245. package/deps/liburing/liburing/test/submit-link-fail.c +0 -154
  246. package/deps/liburing/liburing/test/submit-reuse.c +0 -239
  247. package/deps/liburing/liburing/test/symlink.c +0 -116
  248. package/deps/liburing/liburing/test/teardowns.c +0 -58
  249. package/deps/liburing/liburing/test/thread-exit.c +0 -131
  250. package/deps/liburing/liburing/test/timeout-new.c +0 -246
  251. package/deps/liburing/liburing/test/timeout-overflow.c +0 -204
  252. package/deps/liburing/liburing/test/timeout.c +0 -1354
  253. package/deps/liburing/liburing/test/unlink.c +0 -111
  254. package/deps/liburing/liburing/test/wakeup-hang.c +0 -162
  255. package/deps/rocksdb/rocksdb/README.md +0 -32
  256. package/deps/rocksdb/rocksdb/microbench/README.md +0 -60
  257. package/deps/rocksdb/rocksdb/plugin/README.md +0 -43
  258. package/deps/rocksdb/rocksdb/port/README +0 -10
  259. package/deps/rocksdb/rocksdb/table/block_based/block_based_filter_block.cc +0 -358
  260. package/deps/rocksdb/rocksdb/table/block_based/block_based_filter_block.h +0 -127
  261. package/deps/rocksdb/rocksdb/table/block_based/block_based_filter_block_test.cc +0 -219
  262. package/deps/rocksdb/rocksdb/utilities/transactions/lock/range/range_tree/lib/README +0 -13
package/binding.cc CHANGED
@@ -6,10 +6,12 @@
6
6
 
7
7
  #include <rocksdb/cache.h>
8
8
  #include <rocksdb/comparator.h>
9
+ #include <rocksdb/convenience.h>
9
10
  #include <rocksdb/db.h>
10
11
  #include <rocksdb/env.h>
11
12
  #include <rocksdb/filter_policy.h>
12
13
  #include <rocksdb/options.h>
14
+ #include <rocksdb/slice_transform.h>
13
15
  #include <rocksdb/table.h>
14
16
  #include <rocksdb/write_batch.h>
15
17
 
@@ -34,32 +36,28 @@ struct Updates;
34
36
 
35
37
  #define NAPI_STATUS_RETURN(call) \
36
38
  { \
37
- const auto status = (call); \
38
- if (status != napi_ok) { \
39
- return status; \
39
+ auto _status = (call); \
40
+ if (_status != napi_ok) { \
41
+ return _status; \
40
42
  } \
41
43
  }
42
44
 
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
- } \
45
+ #define ROCKS_STATUS_RETURN(call) \
46
+ { \
47
+ auto _status = (call); \
48
+ if (!_status.ok()) { \
49
+ return _status; \
50
+ } \
50
51
  }
51
52
 
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
- }
53
+ #define ROCKS_STATUS_THROWS(call) \
54
+ { \
55
+ auto _status = (call); \
56
+ if (!_status.ok()) { \
57
+ napi_throw(env, ToError(env, _status)); \
58
+ return NULL; \
59
+ } \
60
+ }
63
61
 
64
62
  static napi_value CreateError(napi_env env, const std::optional<std::string_view>& code, const std::string_view& msg) {
65
63
  napi_value codeValue = nullptr;
@@ -109,20 +107,6 @@ static bool EncodingIsBuffer(napi_env env, napi_value obj, const std::string_vie
109
107
  return false;
110
108
  }
111
109
 
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
110
  static std::optional<uint32_t> Uint32Property(napi_env env, napi_value obj, const std::string_view& key) {
127
111
  if (HasProperty(env, obj, key.data())) {
128
112
  const auto value = GetProperty(env, obj, key.data());
@@ -157,27 +141,38 @@ static std::optional<int64_t> Int64Property(napi_env env, napi_value obj, const
157
141
  return {};
158
142
  }
159
143
 
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;
144
+ static napi_status ToString(napi_env env, napi_value from, std::string& to) {
145
+ napi_valuetype type;
146
+ NAPI_STATUS_RETURN(napi_typeof(env, from, &type));
147
+
148
+ if (type == napi_string) {
169
149
  size_t length = 0;
170
- napi_get_buffer_info(env, from, reinterpret_cast<void**>(&buf), &length);
171
- return std::string(buf, length);
150
+ NAPI_STATUS_RETURN(napi_get_value_string_utf8(env, from, nullptr, 0, &length));
151
+ to.resize(length, '\0');
152
+ NAPI_STATUS_RETURN(napi_get_value_string_utf8(env, from, &to[0], length + 1, &length));
153
+ } else {
154
+ bool isBuffer;
155
+ NAPI_STATUS_RETURN(napi_is_buffer(env, from, &isBuffer));
156
+
157
+ if (isBuffer) {
158
+ char* buf = nullptr;
159
+ size_t length = 0;
160
+ NAPI_STATUS_RETURN(napi_get_buffer_info(env, from, reinterpret_cast<void**>(&buf), &length));
161
+ to.assign(buf, length);
162
+ } else {
163
+ return napi_invalid_arg;
164
+ }
172
165
  }
173
166
 
174
- return defaultValue;
167
+ return napi_ok;
175
168
  }
176
169
 
177
170
  static std::optional<std::string> StringProperty(napi_env env, napi_value opts, const std::string_view& name) {
178
171
  if (HasProperty(env, opts, name)) {
179
- const auto value = GetProperty(env, opts, name);
180
- return ToString(env, value);
172
+ const auto property = GetProperty(env, opts, name);
173
+ std::string value;
174
+ ToString(env, property, value);
175
+ return value;
181
176
  }
182
177
  return {};
183
178
  }
@@ -224,54 +219,17 @@ static void Finalize(napi_env env, void* data, void* hint) {
224
219
  }
225
220
  }
226
221
 
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) {
222
+ template <typename T>
223
+ napi_status Convert(napi_env env, T&& s, bool asBuffer, napi_value& result) {
238
224
  if (!s) {
239
225
  return napi_get_null(env, &result);
240
226
  } 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);
227
+ return napi_create_buffer_copy(env, s->size(), s->data(), NULL, &result);
244
228
  } else {
245
229
  return napi_create_string_utf8(env, s->data(), s->size(), &result);
246
230
  }
247
231
  }
248
232
 
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
233
  /**
276
234
  * Base worker class. Handles the async work. Derived classes can override the
277
235
  * following virtual methods (listed in the order in which they're called):
@@ -322,9 +280,10 @@ struct Worker {
322
280
  virtual rocksdb::Status Execute(Database& database) = 0;
323
281
 
324
282
  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);
283
+ napi_value argv[1];
284
+ NAPI_STATUS_RETURN(napi_get_null(env, &argv[0]));
285
+
286
+ return CallFunction(env, callback, 1, &argv[0]);
328
287
  }
329
288
 
330
289
  virtual napi_status OnError(napi_env env, napi_value callback, napi_value err) {
@@ -466,22 +425,39 @@ struct BaseIterator {
466
425
  iterator_.reset();
467
426
  }
468
427
 
469
- bool Valid() const { return iterator_->Valid(); }
428
+ bool Valid() const {
429
+ assert(iterator_);
430
+ return iterator_->Valid();
431
+ }
470
432
 
471
- bool Increment() { return limit_ < 0 || ++count_ <= limit_; }
433
+ bool Increment() {
434
+ assert(iterator_);
435
+ return limit_ < 0 || ++count_ <= limit_;
436
+ }
472
437
 
473
438
  void Next() {
439
+ assert(iterator_);
440
+
474
441
  if (reverse_)
475
442
  iterator_->Prev();
476
443
  else
477
444
  iterator_->Next();
478
445
  }
479
446
 
480
- rocksdb::Slice CurrentKey() const { return iterator_->key(); }
447
+ rocksdb::Slice CurrentKey() const {
448
+ assert(iterator_);
449
+ return iterator_->key();
450
+ }
481
451
 
482
- rocksdb::Slice CurrentValue() const { return iterator_->value(); }
452
+ rocksdb::Slice CurrentValue() const {
453
+ assert(iterator_);
454
+ return iterator_->value();
455
+ }
483
456
 
484
- rocksdb::Status Status() const { return iterator_->status(); }
457
+ rocksdb::Status Status() const {
458
+ assert(iterator_);
459
+ return iterator_->status();
460
+ }
485
461
 
486
462
  Database* database_;
487
463
  rocksdb::ColumnFamilyHandle* column_;
@@ -489,26 +465,27 @@ struct BaseIterator {
489
465
 
490
466
  private:
491
467
  void Init() {
492
- rocksdb::ReadOptions options;
468
+ rocksdb::ReadOptions readOptions;
493
469
  if (upper_bound_) {
494
- options.iterate_upper_bound = &*upper_bound_;
470
+ readOptions.iterate_upper_bound = &*upper_bound_;
495
471
  }
496
472
  if (lower_bound_) {
497
- options.iterate_lower_bound = &*lower_bound_;
473
+ readOptions.iterate_lower_bound = &*lower_bound_;
498
474
  }
499
- options.fill_cache = fillCache_;
500
- options.snapshot = snapshot_.get();
501
- options.async_io = true;
475
+ readOptions.fill_cache = fillCache_;
476
+ readOptions.snapshot = snapshot_.get();
477
+ readOptions.async_io = true;
478
+ readOptions.adaptive_readahead = true;
502
479
 
503
- iterator_.reset(database_->db_->NewIterator(options, column_));
480
+ iterator_.reset(database_->db_->NewIterator(readOptions, column_));
504
481
  }
505
482
 
483
+ int count_ = 0;
506
484
  std::optional<rocksdb::PinnableSlice> lower_bound_;
507
485
  std::optional<rocksdb::PinnableSlice> upper_bound_;
508
486
  std::unique_ptr<rocksdb::Iterator> iterator_;
509
487
  const bool reverse_;
510
488
  const int limit_;
511
- int count_ = 0;
512
489
  const bool fillCache_;
513
490
  };
514
491
 
@@ -526,7 +503,7 @@ struct Iterator final : public BaseIterator {
526
503
  const bool fillCache,
527
504
  const bool keyAsBuffer,
528
505
  const bool valueAsBuffer,
529
- const int32_t highWaterMarkBytes,
506
+ const size_t highWaterMarkBytes,
530
507
  std::shared_ptr<const rocksdb::Snapshot> snapshot)
531
508
  : BaseIterator(database, column, reverse, lt, lte, gt, gte, limit, fillCache, snapshot),
532
509
  keys_(keys),
@@ -551,7 +528,7 @@ struct Iterator final : public BaseIterator {
551
528
  const bool values_;
552
529
  const bool keyAsBuffer_;
553
530
  const bool valueAsBuffer_;
554
- const int32_t highWaterMarkBytes_;
531
+ const size_t highWaterMarkBytes_;
555
532
  bool first_ = true;
556
533
 
557
534
  private:
@@ -559,8 +536,12 @@ struct Iterator final : public BaseIterator {
559
536
  };
560
537
 
561
538
  struct Updates {
562
- Updates(Database* database, const bool keyAsBuffer, const bool valueAsBuffer, int64_t seqNumber)
563
- : database_(database), keyAsBuffer_(keyAsBuffer), valueAsBuffer_(valueAsBuffer), seqNumber_(seqNumber) {}
539
+ Updates(Database* database, bool values, bool keyAsBuffer, bool valueAsBuffer, int64_t seqNumber)
540
+ : database_(database),
541
+ values_(values),
542
+ keyAsBuffer_(keyAsBuffer),
543
+ valueAsBuffer_(valueAsBuffer),
544
+ seqNumber_(seqNumber) {}
564
545
 
565
546
  void Close() { iterator_.reset(); }
566
547
 
@@ -577,6 +558,7 @@ struct Updates {
577
558
  }
578
559
 
579
560
  Database* database_;
561
+ const bool values_;
580
562
  const bool keyAsBuffer_;
581
563
  const bool valueAsBuffer_;
582
564
  int64_t seqNumber_;
@@ -586,9 +568,22 @@ struct Updates {
586
568
  napi_ref ref_ = nullptr;
587
569
  };
588
570
 
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();
571
+ static napi_status GetColumnFamily(Database* database,
572
+ napi_env env,
573
+ napi_value options,
574
+ rocksdb::ColumnFamilyHandle** column) {
575
+ bool hasColumn = false;
576
+ NAPI_STATUS_RETURN(napi_has_named_property(env, options, "column", &hasColumn));
577
+
578
+ if (hasColumn) {
579
+ napi_value value = nullptr;
580
+ NAPI_STATUS_RETURN(napi_get_named_property(env, options, "column", &value));
581
+ NAPI_STATUS_RETURN(napi_get_value_external(env, value, reinterpret_cast<void**>(column)));
582
+ } else {
583
+ *column = database->db_->DefaultColumnFamily();
584
+ }
585
+
586
+ return napi_ok;
592
587
  }
593
588
 
594
589
  /**
@@ -670,19 +665,18 @@ struct OpenWorker final : public Worker {
670
665
  }
671
666
 
672
667
  napi_status OnOk(napi_env env, napi_value callback) override {
668
+ napi_value argv[2];
669
+ NAPI_STATUS_RETURN(napi_get_null(env, &argv[0]));
670
+
673
671
  const auto size = database_->columns_.size();
674
- napi_value result;
675
- NAPI_STATUS_RETURN(napi_create_object(env, &result));
672
+ NAPI_STATUS_RETURN(napi_create_object(env, &argv[1]));
676
673
 
677
674
  for (size_t n = 0; n < size; ++n) {
678
675
  napi_value column;
679
676
  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));
677
+ NAPI_STATUS_RETURN(napi_set_named_property(env, argv[1], column_families_[n].name.c_str(), column));
681
678
  }
682
679
 
683
- napi_value argv[2];
684
- NAPI_STATUS_RETURN(napi_get_null(env, &argv[0]));
685
- argv[1] = result;
686
680
  return CallFunction(env, callback, 2, argv);
687
681
  }
688
682
 
@@ -692,7 +686,7 @@ struct OpenWorker final : public Worker {
692
686
  };
693
687
 
694
688
  template <typename T, typename U>
695
- napi_status InitOptions(napi_env env, T& columnOptions, const U& options) {
689
+ rocksdb::Status InitOptions(napi_env env, T& columnOptions, const U& options) {
696
690
  const auto memtable_memory_budget = Uint32Property(env, options, "memtableMemoryBudget").value_or(256 * 1024 * 1024);
697
691
 
698
692
  const auto compaction = StringProperty(env, options, "compaction").value_or("level");
@@ -733,7 +727,21 @@ napi_status InitOptions(napi_env env, T& columnOptions, const U& options) {
733
727
  if (columnOptions.compression == rocksdb::kZSTD) {
734
728
  columnOptions.compression_opts.max_dict_bytes = 16 * 1024;
735
729
  columnOptions.compression_opts.zstd_max_train_bytes = 16 * 1024 * 100;
736
- // columnOptions.compression_opts.parallel_threads
730
+ // TODO (perf): compression_opts.parallel_threads
731
+ }
732
+
733
+ const auto prefixExtractorOpt = StringProperty(env, options, "prefixExtractor");
734
+ if (prefixExtractorOpt) {
735
+ rocksdb::ConfigOptions configOptions;
736
+ ROCKS_STATUS_RETURN(
737
+ rocksdb::SliceTransform::CreateFromString(configOptions, *prefixExtractorOpt, &columnOptions.prefix_extractor));
738
+ }
739
+
740
+ const auto comparatorOpt = StringProperty(env, options, "comparator");
741
+ if (comparatorOpt) {
742
+ rocksdb::ConfigOptions configOptions;
743
+ ROCKS_STATUS_RETURN(
744
+ rocksdb::Comparator::CreateFromString(configOptions, *comparatorOpt, &columnOptions.comparator));
737
745
  }
738
746
 
739
747
  const auto cacheSize = Uint32Property(env, options, "cacheSize").value_or(8 << 20);
@@ -772,37 +780,43 @@ napi_status InitOptions(napi_env env, T& columnOptions, const U& options) {
772
780
 
773
781
  columnOptions.table_factory.reset(rocksdb::NewBlockBasedTableFactory(tableOptions));
774
782
 
775
- return napi_ok;
783
+ return rocksdb::Status::OK();
776
784
  }
777
785
 
778
786
  NAPI_METHOD(db_open) {
779
787
  NAPI_ARGV(4);
780
788
 
781
789
  Database* database;
782
- NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], (void**)&database));
790
+ NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&database)));
783
791
 
784
- const auto location = ToString(env, argv[1]);
785
- const auto options = argv[2];
786
- const auto callback = argv[3];
792
+ std::string location;
793
+ NAPI_STATUS_THROWS(ToString(env, argv[1], location));
787
794
 
788
795
  rocksdb::Options dbOptions;
789
796
 
790
- dbOptions.IncreaseParallelism(Uint32Property(env, options, "parallelism")
797
+ dbOptions.IncreaseParallelism(Uint32Property(env, argv[2], "parallelism")
791
798
  .value_or(std::max<uint32_t>(1, std::thread::hardware_concurrency() / 2)));
792
799
 
793
- dbOptions.create_if_missing = BooleanProperty(env, options, "createIfMissing").value_or(true);
794
- dbOptions.error_if_exists = BooleanProperty(env, options, "errorIfExists").value_or(false);
800
+ dbOptions.create_if_missing = BooleanProperty(env, argv[2], "createIfMissing").value_or(true);
801
+ dbOptions.error_if_exists = BooleanProperty(env, argv[2], "errorIfExists").value_or(false);
795
802
  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")
803
+ dbOptions.write_dbid_to_manifest = true;
804
+ dbOptions.use_adaptive_mutex = true; // We don't have soo many threads in the libuv thread pool...
805
+ dbOptions.enable_pipelined_write = false; // We only write in the main thread...
806
+ dbOptions.max_background_jobs = Uint32Property(env, argv[2], "maxBackgroundJobs")
799
807
  .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;
808
+ dbOptions.WAL_ttl_seconds = Uint32Property(env, argv[2], "walTTL").value_or(0) / 1e3;
809
+ dbOptions.WAL_size_limit_MB = Uint32Property(env, argv[2], "walSizeLimit").value_or(0) / 1e6;
802
810
  dbOptions.create_missing_column_families = true;
803
- dbOptions.unordered_write = BooleanProperty(env, options, "unorderedWrite").value_or(false);
811
+ dbOptions.unordered_write = BooleanProperty(env, argv[2], "unorderedWrite").value_or(false);
812
+ dbOptions.fail_if_options_file_error = true;
813
+ dbOptions.wal_compression = BooleanProperty(env, argv[2], "walCompression").value_or(false)
814
+ ? rocksdb::CompressionType::kZSTD
815
+ : rocksdb::CompressionType::kNoCompression;
804
816
 
805
- const auto infoLogLevel = StringProperty(env, options, "infoLogLevel").value_or("");
817
+ // TODO (feat): dbOptions.listeners
818
+
819
+ const auto infoLogLevel = StringProperty(env, argv[2], "infoLogLevel").value_or("");
806
820
  if (infoLogLevel.size() > 0) {
807
821
  rocksdb::InfoLogLevel lvl = {};
808
822
 
@@ -829,13 +843,16 @@ NAPI_METHOD(db_open) {
829
843
  dbOptions.info_log.reset(new NullLogger());
830
844
  }
831
845
 
832
- NAPI_STATUS_THROWS(InitOptions(env, dbOptions, options));
846
+ ROCKS_STATUS_THROWS(InitOptions(env, dbOptions, argv[2]));
847
+
848
+ std::vector<rocksdb::ColumnFamilyDescriptor> columnsFamilies;
833
849
 
834
- std::vector<rocksdb::ColumnFamilyDescriptor> column_families;
850
+ bool hasColumns;
851
+ NAPI_STATUS_THROWS(napi_has_named_property(env, argv[2], "columns", &hasColumns));
835
852
 
836
- if (HasProperty(env, options, "columns")) {
853
+ if (hasColumns) {
837
854
  napi_value columns;
838
- NAPI_STATUS_THROWS(napi_get_named_property(env, options, "columns", &columns));
855
+ NAPI_STATUS_THROWS(napi_get_named_property(env, argv[2], "columns", &columns));
839
856
 
840
857
  napi_value keys;
841
858
  NAPI_STATUS_THROWS(napi_get_property_names(env, columns, &keys));
@@ -843,6 +860,7 @@ NAPI_METHOD(db_open) {
843
860
  uint32_t len;
844
861
  NAPI_STATUS_THROWS(napi_get_array_length(env, keys, &len));
845
862
 
863
+ columnsFamilies.resize(len);
846
864
  for (uint32_t n = 0; n < len; ++n) {
847
865
  napi_value key;
848
866
  NAPI_STATUS_THROWS(napi_get_element(env, keys, n, &key));
@@ -850,14 +868,13 @@ NAPI_METHOD(db_open) {
850
868
  napi_value column;
851
869
  NAPI_STATUS_THROWS(napi_get_property(env, columns, key, &column));
852
870
 
853
- rocksdb::ColumnFamilyOptions columnOptions;
854
- NAPI_STATUS_THROWS(InitOptions(env, columnOptions, column));
871
+ ROCKS_STATUS_THROWS(InitOptions(env, columnsFamilies[n].options, column));
855
872
 
856
- column_families.emplace_back(ToString(env, key), columnOptions);
873
+ NAPI_STATUS_THROWS(ToString(env, key, columnsFamilies[n].name));
857
874
  }
858
875
  }
859
876
 
860
- auto worker = new OpenWorker(env, database, callback, location, dbOptions, column_families);
877
+ auto worker = new OpenWorker(env, database, argv[3], location, dbOptions, columnsFamilies);
861
878
  worker->Queue(env);
862
879
 
863
880
  return 0;
@@ -884,11 +901,9 @@ NAPI_METHOD(db_close) {
884
901
  NAPI_ARGV(2);
885
902
 
886
903
  Database* database;
887
- NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], (void**)&database));
904
+ NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&database)));
888
905
 
889
- const auto callback = argv[1];
890
-
891
- auto worker = new CloseWorker(env, database, callback);
906
+ auto worker = new CloseWorker(env, database, argv[1]);
892
907
 
893
908
  if (!database->HasPriorityWork()) {
894
909
  worker->Queue(env);
@@ -899,8 +914,8 @@ NAPI_METHOD(db_close) {
899
914
  return 0;
900
915
  }
901
916
 
902
- struct UpdateNextWorker final : public rocksdb::WriteBatch::Handler, public Worker {
903
- UpdateNextWorker(napi_env env, Updates* updates, napi_value callback)
917
+ struct UpdatesNextWorker final : public rocksdb::WriteBatch::Handler, public Worker {
918
+ UpdatesNextWorker(napi_env env, Updates* updates, napi_value callback)
904
919
  : Worker(env, updates->database_, callback, "rocks_level.db.get"), updates_(updates) {
905
920
  database_->IncrementPriorityWork(env);
906
921
  }
@@ -913,53 +928,45 @@ struct UpdateNextWorker final : public rocksdb::WriteBatch::Handler, public Work
913
928
  if (!status.ok()) {
914
929
  return status;
915
930
  }
931
+ } else {
932
+ updates_->iterator_->Next();
916
933
  }
917
934
 
918
935
  if (!updates_->iterator_->Valid()) {
919
- return rocksdb::Status::OK();
936
+ return updates_->iterator_->status();
920
937
  }
921
938
 
922
939
  auto batch = updates_->iterator_->GetBatch();
923
940
 
924
941
  updates_->seqNumber_ = batch.sequence;
925
942
 
926
- const auto status = batch.writeBatchPtr->Iterate(this);
927
- if (!status.ok()) {
928
- return status;
929
- }
930
-
931
- updates_->iterator_->Next();
943
+ cache_.reserve(batch.writeBatchPtr->Count() * 2);
932
944
 
933
- return rocksdb::Status::OK();
945
+ return batch.writeBatchPtr->Iterate(this);
934
946
  }
935
947
 
936
948
  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));
949
+ napi_value argv[3];
950
+ NAPI_STATUS_RETURN(napi_get_null(env, &argv[0]));
942
951
 
943
- for (size_t idx = 0; idx < cache_.size(); idx += 2) {
944
- napi_value key;
945
- napi_value val;
952
+ if (cache_.empty()) {
953
+ return CallFunction(env, callback, 1, argv);
954
+ }
946
955
 
947
- NAPI_STATUS_RETURN(Convert(env, cache_[idx + 0], updates_->keyAsBuffer_, key));
948
- NAPI_STATUS_RETURN(Convert(env, cache_[idx + 1], updates_->valueAsBuffer_, val));
956
+ NAPI_STATUS_RETURN(napi_create_array_with_length(env, cache_.size(), &argv[1]));
949
957
 
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
- }
958
+ for (size_t idx = 0; idx < cache_.size(); idx += 2) {
959
+ napi_value key;
960
+ NAPI_STATUS_RETURN(Convert(env, cache_[idx + 0], updates_->keyAsBuffer_, key));
961
+ NAPI_STATUS_RETURN(napi_set_element(env, argv[1], static_cast<int>(idx + 0), key));
953
962
 
954
- cache_.clear();
955
- } else {
956
- NAPI_STATUS_RETURN(napi_get_null(env, &result));
963
+ napi_value val;
964
+ NAPI_STATUS_RETURN(Convert(env, cache_[idx + 1], updates_->valueAsBuffer_, val));
965
+ NAPI_STATUS_RETURN(napi_set_element(env, argv[1], static_cast<int>(idx + 1), val));
957
966
  }
958
967
 
959
- napi_value argv[3];
960
- NAPI_STATUS_RETURN(napi_get_null(env, &argv[0]));
961
- argv[1] = result;
962
968
  NAPI_STATUS_RETURN(napi_create_bigint_int64(env, updates_->seqNumber_, &argv[2]));
969
+
963
970
  return CallFunction(env, callback, 3, argv);
964
971
  }
965
972
 
@@ -970,7 +977,11 @@ struct UpdateNextWorker final : public rocksdb::WriteBatch::Handler, public Work
970
977
 
971
978
  void Put(const rocksdb::Slice& key, const rocksdb::Slice& value) override {
972
979
  cache_.emplace_back(key.ToString());
973
- cache_.emplace_back(value.ToString());
980
+ if (updates_->values_) {
981
+ cache_.emplace_back(value.ToString());
982
+ } else {
983
+ cache_.emplace_back(std::nullopt);
984
+ }
974
985
  }
975
986
 
976
987
  void Delete(const rocksdb::Slice& key) override {
@@ -989,15 +1000,14 @@ NAPI_METHOD(updates_init) {
989
1000
  NAPI_ARGV(2);
990
1001
 
991
1002
  Database* database;
992
- NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], (void**)&database));
1003
+ NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&database)));
993
1004
 
994
- const auto options = argv[1];
995
-
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());
1005
+ const auto values = BooleanProperty(env, argv[1], "values").value_or(true);
1006
+ const bool keyAsBuffer = EncodingIsBuffer(env, argv[1], "keyEncoding");
1007
+ const bool valueAsBuffer = EncodingIsBuffer(env, argv[1], "valueEncoding");
1008
+ const auto seqNumber = Int64Property(env, argv[1], "since").value_or(database->db_->GetLatestSequenceNumber());
999
1009
 
1000
- auto updates = std::make_unique<Updates>(database, keyAsBuffer, valueAsBuffer, seqNumber);
1010
+ auto updates = std::make_unique<Updates>(database, values, keyAsBuffer, valueAsBuffer, seqNumber);
1001
1011
 
1002
1012
  napi_value result;
1003
1013
  NAPI_STATUS_THROWS(napi_create_external(env, updates.get(), Finalize<Updates>, updates.get(), &result));
@@ -1015,9 +1025,7 @@ NAPI_METHOD(updates_next) {
1015
1025
  Updates* updates;
1016
1026
  NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], (void**)&updates));
1017
1027
 
1018
- const auto callback = argv[1];
1019
-
1020
- auto worker = new UpdateNextWorker(env, updates, callback);
1028
+ auto worker = new UpdatesNextWorker(env, updates, argv[1]);
1021
1029
  worker->Queue(env);
1022
1030
 
1023
1031
  return 0;
@@ -1039,16 +1047,18 @@ NAPI_METHOD(db_put) {
1039
1047
  NAPI_ARGV(4);
1040
1048
 
1041
1049
  Database* database;
1042
- NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], (void**)&database));
1050
+ NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&database)));
1043
1051
 
1044
- NapiSlice key;
1045
- NAPI_STATUS_THROWS(ToNapiSlice(env, argv[1], key));
1052
+ std::string key;
1053
+ NAPI_STATUS_THROWS(ToString(env, argv[1], key));
1046
1054
 
1047
- NapiSlice val;
1048
- NAPI_STATUS_THROWS(ToNapiSlice(env, argv[2], val));
1055
+ std::string val;
1056
+ NAPI_STATUS_THROWS(ToString(env, argv[2], val));
1049
1057
 
1050
1058
  rocksdb::WriteOptions writeOptions;
1051
- return ToError(env, database->db_->Put(writeOptions, key, val));
1059
+ ROCKS_STATUS_THROWS(database->db_->Put(writeOptions, key, val));
1060
+
1061
+ return 0;
1052
1062
  }
1053
1063
 
1054
1064
  struct GetWorker final : public Worker {
@@ -1085,7 +1095,9 @@ struct GetWorker final : public Worker {
1085
1095
  napi_status OnOk(napi_env env, napi_value callback) override {
1086
1096
  napi_value argv[2];
1087
1097
  NAPI_STATUS_RETURN(napi_get_null(env, &argv[0]));
1088
- NAPI_STATUS_RETURN(Convert(env, value_, asBuffer_, argv[1]));
1098
+
1099
+ NAPI_STATUS_RETURN(Convert(env, &value_, asBuffer_, argv[1]));
1100
+
1089
1101
  return CallFunction(env, callback, 2, argv);
1090
1102
  }
1091
1103
 
@@ -1107,16 +1119,18 @@ NAPI_METHOD(db_get) {
1107
1119
  NAPI_ARGV(4);
1108
1120
 
1109
1121
  Database* database;
1110
- NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], (void**)&database));
1122
+ NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&database)));
1111
1123
 
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];
1124
+ std::string key;
1125
+ NAPI_STATUS_THROWS(ToString(env, argv[1], key));
1118
1126
 
1119
- auto worker = new GetWorker(env, database, column, callback, key, asBuffer, fillCache);
1127
+ const auto asBuffer = EncodingIsBuffer(env, argv[2], "valueEncoding");
1128
+ const auto fillCache = BooleanProperty(env, argv[2], "fillCache").value_or(true);
1129
+
1130
+ rocksdb::ColumnFamilyHandle* column;
1131
+ NAPI_STATUS_THROWS(GetColumnFamily(database, env, argv[2], &column));
1132
+
1133
+ auto worker = new GetWorker(env, database, column, argv[3], key, asBuffer, fillCache);
1120
1134
  worker->Queue(env);
1121
1135
 
1122
1136
  return 0;
@@ -1129,21 +1143,26 @@ struct GetManyWorker final : public Worker {
1129
1143
  std::vector<std::string> keys,
1130
1144
  napi_value callback,
1131
1145
  const bool valueAsBuffer,
1132
- const bool fillCache)
1146
+ const bool fillCache,
1147
+ const bool ignoreRangeDeletions)
1133
1148
  : Worker(env, database, callback, "leveldown.get.many"),
1134
1149
  column_(column),
1135
1150
  keys_(std::move(keys)),
1136
1151
  valueAsBuffer_(valueAsBuffer),
1137
1152
  fillCache_(fillCache),
1138
- snapshot_(database_->db_->GetSnapshot(), [=](const auto ptr) { database_->db_->ReleaseSnapshot(ptr); }) {
1153
+ ignoreRangeDeletions_(ignoreRangeDeletions),
1154
+ snapshot_(database_->db_->GetSnapshot()) {
1139
1155
  database_->IncrementPriorityWork(env);
1140
1156
  }
1141
1157
 
1158
+ ~GetManyWorker() { database_->db_->ReleaseSnapshot(snapshot_); }
1159
+
1142
1160
  rocksdb::Status Execute(Database& database) override {
1143
1161
  rocksdb::ReadOptions readOptions;
1144
1162
  readOptions.fill_cache = fillCache_;
1145
- readOptions.snapshot = snapshot_.get();
1163
+ readOptions.snapshot = snapshot_;
1146
1164
  readOptions.async_io = true;
1165
+ readOptions.ignore_range_deletions = ignoreRangeDeletions_;
1147
1166
 
1148
1167
  std::vector<rocksdb::Slice> keys;
1149
1168
  keys.reserve(keys_.size());
@@ -1154,12 +1173,7 @@ struct GetManyWorker final : public Worker {
1154
1173
  statuses_.resize(keys.size());
1155
1174
  values_.resize(keys.size());
1156
1175
 
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
- }
1176
+ database.db_->MultiGet(readOptions, column_, keys.size(), keys.data(), values_.data(), statuses_.data());
1163
1177
 
1164
1178
  for (const auto& status : statuses_) {
1165
1179
  if (!status.ok() && !status.IsNotFound()) {
@@ -1171,24 +1185,23 @@ struct GetManyWorker final : public Worker {
1171
1185
  }
1172
1186
 
1173
1187
  napi_status OnOk(napi_env env, napi_value callback) override {
1188
+ napi_value argv[2];
1189
+ NAPI_STATUS_RETURN(napi_get_null(env, &argv[0]));
1190
+
1174
1191
  const auto size = values_.size();
1175
1192
 
1176
- napi_value array;
1177
- NAPI_STATUS_RETURN(napi_create_array_with_length(env, size, &array));
1193
+ NAPI_STATUS_RETURN(napi_create_array_with_length(env, size, &argv[1]));
1178
1194
 
1179
1195
  for (size_t idx = 0; idx < size; idx++) {
1180
1196
  napi_value element;
1181
1197
  if (statuses_[idx].ok()) {
1182
- NAPI_STATUS_RETURN(Convert(env, values_[idx], valueAsBuffer_, element));
1198
+ NAPI_STATUS_RETURN(Convert(env, &values_[idx], valueAsBuffer_, element));
1183
1199
  } else {
1184
1200
  NAPI_STATUS_RETURN(napi_get_undefined(env, &element));
1185
1201
  }
1186
- NAPI_STATUS_RETURN(napi_set_element(env, array, static_cast<uint32_t>(idx), element));
1202
+ NAPI_STATUS_RETURN(napi_set_element(env, argv[1], static_cast<uint32_t>(idx), element));
1187
1203
  }
1188
1204
 
1189
- napi_value argv[2];
1190
- NAPI_STATUS_RETURN(napi_get_null(env, &argv[0]));
1191
- argv[1] = array;
1192
1205
  return CallFunction(env, callback, 2, argv);
1193
1206
  }
1194
1207
 
@@ -1204,37 +1217,38 @@ struct GetManyWorker final : public Worker {
1204
1217
  std::vector<rocksdb::Status> statuses_;
1205
1218
  const bool valueAsBuffer_;
1206
1219
  const bool fillCache_;
1207
- std::shared_ptr<const rocksdb::Snapshot> snapshot_;
1220
+ const bool ignoreRangeDeletions_;
1221
+ const rocksdb::Snapshot* snapshot_;
1208
1222
  };
1209
1223
 
1210
1224
  NAPI_METHOD(db_get_many) {
1211
1225
  NAPI_ARGV(4);
1212
1226
 
1213
1227
  Database* database;
1214
- NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], (void**)&database));
1228
+ NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&database)));
1215
1229
 
1216
1230
  std::vector<std::string> keys;
1217
1231
  {
1218
1232
  uint32_t length;
1219
1233
  NAPI_STATUS_THROWS(napi_get_array_length(env, argv[1], &length));
1220
1234
 
1221
- keys.reserve(length);
1222
-
1223
- for (uint32_t i = 0; i < length; i++) {
1235
+ keys.resize(length);
1236
+ for (uint32_t n = 0; n < length; n++) {
1224
1237
  napi_value element;
1225
-
1226
- NAPI_STATUS_THROWS(napi_get_element(env, argv[1], i, &element));
1227
- keys.push_back(ToString(env, element));
1238
+ NAPI_STATUS_THROWS(napi_get_element(env, argv[1], n, &element));
1239
+ NAPI_STATUS_THROWS(ToString(env, element, keys[n]));
1228
1240
  }
1229
1241
  }
1230
1242
 
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];
1243
+ const bool asBuffer = EncodingIsBuffer(env, argv[2], "valueEncoding");
1244
+ const bool fillCache = BooleanProperty(env, argv[2], "fillCache").value_or(true);
1245
+ const bool ignoreRangeDeletions = BooleanProperty(env, argv[2], "ignoreRangeDeletions").value_or(false);
1236
1246
 
1237
- auto worker = new GetManyWorker(env, database, column, std::move(keys), callback, asBuffer, fillCache);
1247
+ rocksdb::ColumnFamilyHandle* column;
1248
+ NAPI_STATUS_THROWS(GetColumnFamily(database, env, argv[2], &column));
1249
+
1250
+ auto worker =
1251
+ new GetManyWorker(env, database, column, std::move(keys), argv[3], asBuffer, fillCache, ignoreRangeDeletions);
1238
1252
  worker->Queue(env);
1239
1253
 
1240
1254
  return 0;
@@ -1244,60 +1258,67 @@ NAPI_METHOD(db_del) {
1244
1258
  NAPI_ARGV(3);
1245
1259
 
1246
1260
  Database* database;
1247
- NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], (void**)&database));
1261
+ NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&database)));
1248
1262
 
1249
- NapiSlice key;
1250
- NAPI_STATUS_THROWS(ToNapiSlice(env, argv[1], key));
1263
+ std::string key;
1264
+ NAPI_STATUS_THROWS(ToString(env, argv[1], key));
1251
1265
 
1252
- const auto options = argv[2];
1253
- const auto column = GetColumnFamily(database, env, options);
1266
+ rocksdb::ColumnFamilyHandle* column;
1267
+ NAPI_STATUS_THROWS(GetColumnFamily(database, env, argv[2], &column));
1254
1268
 
1255
1269
  rocksdb::WriteOptions writeOptions;
1256
- return ToError(env, database->db_->Delete(writeOptions, column, key));
1270
+ ROCKS_STATUS_THROWS(database->db_->Delete(writeOptions, column, key));
1271
+
1272
+ return 0;
1257
1273
  }
1258
1274
 
1259
1275
  NAPI_METHOD(db_clear) {
1260
1276
  NAPI_ARGV(2);
1261
1277
 
1262
1278
  Database* database;
1263
- NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], (void**)&database));
1279
+ NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&database)));
1264
1280
 
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);
1281
+ const auto reverse = BooleanProperty(env, argv[1], "reverse").value_or(false);
1282
+ const auto limit = Int32Property(env, argv[1], "limit").value_or(-1);
1268
1283
 
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);
1284
+ rocksdb::ColumnFamilyHandle* column;
1285
+ NAPI_STATUS_THROWS(GetColumnFamily(database, env, argv[1], &column));
1274
1286
 
1275
- if (!reverse && limit == -1 && (lte || lt)) {
1276
- rocksdb::Slice begin;
1287
+ auto lt = StringProperty(env, argv[1], "lt");
1288
+ auto lte = StringProperty(env, argv[1], "lte");
1289
+ auto gt = StringProperty(env, argv[1], "gt");
1290
+ auto gte = StringProperty(env, argv[1], "gte");
1291
+
1292
+ if (limit == -1) {
1293
+ rocksdb::PinnableSlice begin;
1277
1294
  if (gte) {
1278
- begin = *gte;
1295
+ *begin.GetSelf() = std::move(*gte);
1279
1296
  } else if (gt) {
1280
- begin = *gt + '\0';
1297
+ *begin.GetSelf() = std::move(*gt) + '\0';
1281
1298
  }
1299
+ begin.PinSelf();
1282
1300
 
1283
- rocksdb::Slice end;
1301
+ rocksdb::PinnableSlice end;
1284
1302
  if (lte) {
1285
- end = *lte + '\0';
1303
+ *end.GetSelf() = std::move(*lte) + '\0';
1286
1304
  } else if (lt) {
1287
- end = *lt;
1305
+ *end.GetSelf() = std::move(*lt);
1288
1306
  } else {
1289
- assert(false);
1307
+ // HACK: Assume no key that starts with 0xFF is larger than 1MiB.
1308
+ end.GetSelf()->resize(1e6);
1309
+ memset(end.GetSelf()->data(), 255, end.GetSelf()->size());
1290
1310
  }
1311
+ end.PinSelf();
1291
1312
 
1292
- if (begin.compare(end) > 0) {
1293
- return ToError(env, rocksdb::Status::OK());
1313
+ if (begin.compare(end) < 0) {
1314
+ rocksdb::WriteOptions writeOptions;
1315
+ ROCKS_STATUS_THROWS(database->db_->DeleteRange(writeOptions, column, begin, end));
1294
1316
  }
1295
1317
 
1296
- rocksdb::WriteOptions writeOptions;
1297
- const auto status = database->db_->DeleteRange(writeOptions, column, begin, end);
1298
- return ToError(env, status);
1318
+ return 0;
1299
1319
  } else {
1300
- // TODO (perf): Use DeleteRange.
1320
+ // TODO (fix): Error handling.
1321
+ // TODO (fix): This should be async...
1301
1322
 
1302
1323
  std::shared_ptr<const rocksdb::Snapshot> snapshot(database->db_->GetSnapshot(),
1303
1324
  [=](const auto ptr) { database->db_->ReleaseSnapshot(ptr); });
@@ -1305,9 +1326,6 @@ NAPI_METHOD(db_clear) {
1305
1326
 
1306
1327
  it.SeekToRange();
1307
1328
 
1308
- // TODO: add option
1309
- const uint32_t hwm = 16 * 1024;
1310
-
1311
1329
  rocksdb::WriteBatch batch;
1312
1330
  rocksdb::WriteOptions writeOptions;
1313
1331
  rocksdb::Status status;
@@ -1315,7 +1333,7 @@ NAPI_METHOD(db_clear) {
1315
1333
  while (true) {
1316
1334
  size_t bytesRead = 0;
1317
1335
 
1318
- while (bytesRead <= hwm && it.Valid() && it.Increment()) {
1336
+ while (bytesRead <= 16 * 1024 && it.Valid() && it.Increment()) {
1319
1337
  const auto key = it.CurrentKey();
1320
1338
  batch.Delete(column, key);
1321
1339
  bytesRead += key.size();
@@ -1337,7 +1355,11 @@ NAPI_METHOD(db_clear) {
1337
1355
 
1338
1356
  it.Close();
1339
1357
 
1340
- return ToError(env, status);
1358
+ if (!status.ok()) {
1359
+ ROCKS_STATUS_THROWS(status);
1360
+ }
1361
+
1362
+ return 0;
1341
1363
  }
1342
1364
  }
1343
1365
 
@@ -1345,10 +1367,10 @@ NAPI_METHOD(db_get_property) {
1345
1367
  NAPI_ARGV(2);
1346
1368
 
1347
1369
  Database* database;
1348
- NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], (void**)&database));
1370
+ NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&database)));
1349
1371
 
1350
- NapiSlice property;
1351
- NAPI_STATUS_THROWS(ToNapiSlice(env, argv[1], property));
1372
+ std::string property;
1373
+ NAPI_STATUS_THROWS(ToString(env, argv[1], property));
1352
1374
 
1353
1375
  std::string value;
1354
1376
  database->db_->GetProperty(property, &value);
@@ -1363,7 +1385,7 @@ NAPI_METHOD(iterator_init) {
1363
1385
  NAPI_ARGV(2);
1364
1386
 
1365
1387
  Database* database;
1366
- NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], (void**)&database));
1388
+ NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&database)));
1367
1389
 
1368
1390
  const auto options = argv[1];
1369
1391
  const auto reverse = BooleanProperty(env, options, "reverse").value_or(false);
@@ -1373,14 +1395,15 @@ NAPI_METHOD(iterator_init) {
1373
1395
  const bool keyAsBuffer = EncodingIsBuffer(env, options, "keyEncoding");
1374
1396
  const bool valueAsBuffer = EncodingIsBuffer(env, options, "valueEncoding");
1375
1397
  const auto limit = Int32Property(env, options, "limit").value_or(-1);
1376
- const auto highWaterMarkBytes = Int32Property(env, options, "highWaterMarkBytes").value_or(16 * 1024);
1398
+ const auto highWaterMarkBytes = Uint32Property(env, options, "highWaterMarkBytes").value_or(64 * 1024);
1377
1399
 
1378
1400
  const auto lt = StringProperty(env, options, "lt");
1379
1401
  const auto lte = StringProperty(env, options, "lte");
1380
1402
  const auto gt = StringProperty(env, options, "gt");
1381
1403
  const auto gte = StringProperty(env, options, "gte");
1382
1404
 
1383
- const auto column = GetColumnFamily(database, env, options);
1405
+ rocksdb::ColumnFamilyHandle* column;
1406
+ NAPI_STATUS_THROWS(GetColumnFamily(database, env, options, &column));
1384
1407
 
1385
1408
  std::shared_ptr<const rocksdb::Snapshot> snapshot(database->db_->GetSnapshot(),
1386
1409
  [=](const auto ptr) { database->db_->ReleaseSnapshot(ptr); });
@@ -1402,13 +1425,13 @@ NAPI_METHOD(iterator_seek) {
1402
1425
  NAPI_ARGV(2);
1403
1426
 
1404
1427
  Iterator* iterator;
1405
- NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], (void**)&iterator));
1428
+ NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&iterator)));
1406
1429
 
1407
- NapiSlice target;
1408
- NAPI_STATUS_THROWS(ToNapiSlice(env, argv[1], target));
1430
+ std::string target;
1431
+ NAPI_STATUS_THROWS(ToString(env, argv[1], target));
1409
1432
 
1410
1433
  iterator->first_ = true;
1411
- iterator->Seek(target);
1434
+ iterator->Seek(target); // TODO: Does seek causing blocking IO?
1412
1435
 
1413
1436
  return 0;
1414
1437
  }
@@ -1417,7 +1440,7 @@ NAPI_METHOD(iterator_close) {
1417
1440
  NAPI_ARGV(1);
1418
1441
 
1419
1442
  Iterator* iterator;
1420
- NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], (void**)&iterator));
1443
+ NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&iterator)));
1421
1444
 
1422
1445
  iterator->Detach(env);
1423
1446
  iterator->Close();
@@ -1429,7 +1452,7 @@ NAPI_METHOD(iterator_get_sequence) {
1429
1452
  NAPI_ARGV(1);
1430
1453
 
1431
1454
  Iterator* iterator;
1432
- NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], (void**)&iterator));
1455
+ NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&iterator)));
1433
1456
 
1434
1457
  const auto seq = iterator->snapshot_->GetSequenceNumber();
1435
1458
 
@@ -1478,8 +1501,7 @@ struct NextWorker final : public Worker {
1478
1501
  cache_.push_back(v.ToString());
1479
1502
  }
1480
1503
 
1481
- if ((iterator_->highWaterMarkBytes_ != -1 && bytesRead > static_cast<size_t>(iterator_->highWaterMarkBytes_)) ||
1482
- cache_.size() / 2 >= size_) {
1504
+ if (bytesRead > iterator_->highWaterMarkBytes_ || cache_.size() / 2 >= size_) {
1483
1505
  finished_ = false;
1484
1506
  return rocksdb::Status::OK();
1485
1507
  }
@@ -1491,27 +1513,24 @@ struct NextWorker final : public Worker {
1491
1513
  }
1492
1514
 
1493
1515
  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));
1516
+ napi_value argv[3];
1517
+ NAPI_STATUS_RETURN(napi_get_null(env, &argv[0]));
1518
+
1519
+ NAPI_STATUS_RETURN(napi_create_array_with_length(env, cache_.size(), &argv[1]));
1497
1520
 
1498
- for (size_t n = 0; n < size; n += 2) {
1521
+ for (size_t n = 0; n < cache_.size(); n += 2) {
1499
1522
  napi_value key;
1500
1523
  napi_value val;
1501
1524
 
1502
1525
  NAPI_STATUS_RETURN(Convert(env, cache_[n + 0], iterator_->keyAsBuffer_, key));
1503
1526
  NAPI_STATUS_RETURN(Convert(env, cache_[n + 1], iterator_->valueAsBuffer_, val));
1504
1527
 
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));
1528
+ NAPI_STATUS_RETURN(napi_set_element(env, argv[1], static_cast<int>(n + 0), key));
1529
+ NAPI_STATUS_RETURN(napi_set_element(env, argv[1], static_cast<int>(n + 1), val));
1507
1530
  }
1508
1531
 
1509
- cache_.clear();
1510
-
1511
- napi_value argv[3];
1512
- NAPI_STATUS_RETURN(napi_get_null(env, &argv[0]));
1513
- argv[1] = result;
1514
1532
  NAPI_STATUS_RETURN(napi_get_boolean(env, finished_, &argv[2]));
1533
+
1515
1534
  return CallFunction(env, callback, 3, argv);
1516
1535
  }
1517
1536
 
@@ -1526,14 +1545,12 @@ NAPI_METHOD(iterator_nextv) {
1526
1545
  NAPI_ARGV(3);
1527
1546
 
1528
1547
  Iterator* iterator;
1529
- NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], (void**)&iterator));
1548
+ NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&iterator)));
1530
1549
 
1531
1550
  uint32_t size;
1532
1551
  NAPI_STATUS_THROWS(napi_get_value_uint32(env, argv[1], &size));
1533
1552
 
1534
- const auto callback = argv[2];
1535
-
1536
- auto worker = new NextWorker(env, iterator, size, callback);
1553
+ auto worker = new NextWorker(env, iterator, size, argv[2]);
1537
1554
  worker->Queue(env);
1538
1555
 
1539
1556
  return 0;
@@ -1543,51 +1560,66 @@ NAPI_METHOD(batch_do) {
1543
1560
  NAPI_ARGV(3);
1544
1561
 
1545
1562
  Database* database;
1546
- NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], (void**)&database));
1547
-
1548
- const auto operations = argv[1];
1563
+ NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&database)));
1549
1564
 
1550
1565
  rocksdb::WriteBatch batch;
1551
1566
 
1567
+ std::string type;
1568
+ std::string key;
1569
+ std::string value;
1570
+
1552
1571
  uint32_t length;
1553
- NAPI_STATUS_THROWS(napi_get_array_length(env, operations, &length));
1572
+ NAPI_STATUS_THROWS(napi_get_array_length(env, argv[1], &length));
1554
1573
 
1555
1574
  for (uint32_t i = 0; i < length; i++) {
1556
1575
  napi_value element;
1557
- NAPI_STATUS_THROWS(napi_get_element(env, operations, i, &element));
1576
+ NAPI_STATUS_THROWS(napi_get_element(env, argv[1], i, &element));
1558
1577
 
1559
- NapiSlice type;
1560
- NAPI_STATUS_THROWS(ToNapiSlice(env, GetProperty(env, element, "type"), type));
1578
+ napi_value typeProperty;
1579
+ NAPI_STATUS_THROWS(napi_get_named_property(env, element, "type", &typeProperty));
1580
+ NAPI_STATUS_THROWS(ToString(env, typeProperty, type));
1561
1581
 
1562
- const auto column = GetColumnFamily(database, env, element);
1582
+ rocksdb::ColumnFamilyHandle* column;
1583
+ NAPI_STATUS_THROWS(GetColumnFamily(database, env, element, &column));
1563
1584
 
1564
1585
  if (type == "del") {
1565
- NapiSlice key;
1566
- NAPI_STATUS_THROWS(ToNapiSlice(env, GetProperty(env, element, "key"), key));
1567
- batch.Delete(column, key);
1586
+ napi_value keyProperty;
1587
+ NAPI_STATUS_THROWS(napi_get_named_property(env, element, "key", &keyProperty));
1588
+ NAPI_STATUS_THROWS(ToString(env, keyProperty, key));
1589
+
1590
+ ROCKS_STATUS_THROWS(batch.Delete(column, key));
1568
1591
  } 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);
1592
+ napi_value keyProperty;
1593
+ NAPI_STATUS_THROWS(napi_get_named_property(env, element, "key", &keyProperty));
1594
+ NAPI_STATUS_THROWS(ToString(env, keyProperty, key));
1595
+
1596
+ napi_value valueProperty;
1597
+ NAPI_STATUS_THROWS(napi_get_named_property(env, element, "value", &valueProperty));
1598
+ NAPI_STATUS_THROWS(ToString(env, valueProperty, value));
1599
+
1600
+ ROCKS_STATUS_THROWS(batch.Put(column, key, value));
1601
+ } else {
1602
+ ROCKS_STATUS_THROWS(rocksdb::Status::InvalidArgument());
1574
1603
  }
1575
1604
  }
1576
1605
 
1577
1606
  rocksdb::WriteOptions writeOptions;
1578
- return ToError(env, database->db_->Write(writeOptions, &batch));
1607
+ ROCKS_STATUS_THROWS(database->db_->Write(writeOptions, &batch));
1608
+
1609
+ return 0;
1579
1610
  }
1580
1611
 
1581
1612
  NAPI_METHOD(batch_init) {
1582
1613
  NAPI_ARGV(1);
1583
1614
 
1584
1615
  Database* database;
1585
- NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], (void**)&database));
1616
+ NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&database)));
1586
1617
 
1587
1618
  auto batch = new rocksdb::WriteBatch();
1588
1619
 
1589
1620
  napi_value result;
1590
1621
  NAPI_STATUS_THROWS(napi_create_external(env, batch, Finalize<rocksdb::WriteBatch>, batch, &result));
1622
+
1591
1623
  return result;
1592
1624
  }
1593
1625
 
@@ -1595,21 +1627,21 @@ NAPI_METHOD(batch_put) {
1595
1627
  NAPI_ARGV(5);
1596
1628
 
1597
1629
  Database* database;
1598
- NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], (void**)&database));
1630
+ NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&database)));
1599
1631
 
1600
1632
  rocksdb::WriteBatch* batch;
1601
1633
  NAPI_STATUS_THROWS(napi_get_value_external(env, argv[1], (void**)(&batch)));
1602
1634
 
1603
- NapiSlice key;
1604
- NAPI_STATUS_THROWS(ToNapiSlice(env, argv[2], key));
1635
+ std::string key;
1636
+ NAPI_STATUS_THROWS(ToString(env, argv[2], key));
1605
1637
 
1606
- NapiSlice val;
1607
- NAPI_STATUS_THROWS(ToNapiSlice(env, argv[3], val));
1638
+ std::string val;
1639
+ NAPI_STATUS_THROWS(ToString(env, argv[3], val));
1608
1640
 
1609
- const auto options = argv[4];
1610
- const auto column = GetColumnFamily(database, env, options);
1641
+ rocksdb::ColumnFamilyHandle* column;
1642
+ NAPI_STATUS_THROWS(GetColumnFamily(database, env, argv[4], &column));
1611
1643
 
1612
- batch->Put(column, key, val);
1644
+ ROCKS_STATUS_THROWS(batch->Put(column, key, val));
1613
1645
 
1614
1646
  return 0;
1615
1647
  }
@@ -1618,18 +1650,18 @@ NAPI_METHOD(batch_del) {
1618
1650
  NAPI_ARGV(4);
1619
1651
 
1620
1652
  Database* database;
1621
- NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], (void**)&database));
1653
+ NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&database)));
1622
1654
 
1623
1655
  rocksdb::WriteBatch* batch;
1624
1656
  NAPI_STATUS_THROWS(napi_get_value_external(env, argv[1], reinterpret_cast<void**>(&batch)));
1625
1657
 
1626
- NapiSlice key;
1627
- NAPI_STATUS_THROWS(ToNapiSlice(env, argv[2], key));
1658
+ std::string key;
1659
+ NAPI_STATUS_THROWS(ToString(env, argv[2], key));
1628
1660
 
1629
- const auto options = argv[3];
1630
- const auto column = GetColumnFamily(database, env, options);
1661
+ rocksdb::ColumnFamilyHandle* column;
1662
+ NAPI_STATUS_THROWS(GetColumnFamily(database, env, argv[3], &column));
1631
1663
 
1632
- batch->Delete(column, key);
1664
+ ROCKS_STATUS_THROWS(batch->Delete(column, key));
1633
1665
 
1634
1666
  return 0;
1635
1667
  }
@@ -1649,13 +1681,15 @@ NAPI_METHOD(batch_write) {
1649
1681
  NAPI_ARGV(3);
1650
1682
 
1651
1683
  Database* database;
1652
- NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], (void**)&database));
1684
+ NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&database)));
1653
1685
 
1654
1686
  rocksdb::WriteBatch* batch;
1655
1687
  NAPI_STATUS_THROWS(napi_get_value_external(env, argv[1], reinterpret_cast<void**>(&batch)));
1656
1688
 
1657
1689
  rocksdb::WriteOptions writeOptions;
1658
- return ToError(env, database->db_->Write(writeOptions, batch));
1690
+ ROCKS_STATUS_THROWS(database->db_->Write(writeOptions, batch));
1691
+
1692
+ return 0;
1659
1693
  }
1660
1694
 
1661
1695
  NAPI_INIT() {