rocksdb-native 3.7.0 → 3.7.1

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 (2) hide show
  1. package/binding.cc +1556 -0
  2. package/package.json +2 -2
package/binding.cc ADDED
@@ -0,0 +1,1556 @@
1
+ #include <assert.h>
2
+ #include <bare.h>
3
+ #include <js.h>
4
+ #include <jstl.h>
5
+ #include <rocksdb.h>
6
+ #include <stdlib.h>
7
+ #include <string.h>
8
+ #include <utf.h>
9
+
10
+ namespace {
11
+ using cb_on_open_t = js_function_t<void, js_receiver_t, std::optional<js_string_t>>;
12
+ using cb_on_close_t = js_function_t<void, js_receiver_t>;
13
+ using cb_on_suspend_t = js_function_t<void, js_receiver_t, std::optional<js_string_t>>;
14
+ using cb_on_resume_t = js_function_t<void, js_receiver_t, std::optional<js_string_t>>;
15
+ using cb_on_flush_t = js_function_t<void, js_receiver_t, std::optional<js_string_t>>;
16
+ using cb_on_write_t = js_function_t<void, js_receiver_t, std::optional<js_string_t>>;
17
+ using cb_on_read_t = js_function_t<void, js_receiver_t, js_array_t, js_array_t>;
18
+ using cb_on_iterator_open_t = js_function_t<void, js_receiver_t, std::optional<js_string_t>>;
19
+ using cb_on_iterator_close_t = js_function_t<void, js_receiver_t, std::optional<js_string_t>>;
20
+ using cb_on_iterator_read_t = js_function_t<
21
+ void,
22
+ js_receiver_t,
23
+ std::optional<js_string_t>,
24
+ std::vector<js_arraybuffer_t>,
25
+ std::vector<js_arraybuffer_t>>;
26
+ }; // namespace
27
+
28
+ struct rocksdb_native_column_family_t {
29
+ rocksdb_column_family_t *handle;
30
+ rocksdb_column_family_descriptor_t descriptor;
31
+
32
+ rocksdb_t *db;
33
+
34
+ js_env_t *env;
35
+ js_persistent_t<js_receiver_t> ctx;
36
+ };
37
+
38
+ struct rocksdb_native_t {
39
+ rocksdb_t handle;
40
+ rocksdb_options_t options;
41
+
42
+ js_env_t *env;
43
+ js_persistent_t<js_receiver_t> ctx;
44
+
45
+ bool closing;
46
+ bool exiting;
47
+
48
+ js_deferred_teardown_t *teardown;
49
+ };
50
+
51
+ struct rocksdb_native_open_t {
52
+ rocksdb_open_t handle;
53
+
54
+ js_env_t *env;
55
+ js_persistent_t<js_receiver_t> ctx;
56
+ js_persistent_t<cb_on_open_t> on_open;
57
+
58
+ js_persistent_t<js_array_t> column_families;
59
+ };
60
+
61
+ struct rocksdb_native_close_t {
62
+ rocksdb_close_t handle;
63
+
64
+ js_env_t *env;
65
+ js_persistent_t<js_receiver_t> ctx;
66
+ js_persistent_t<cb_on_close_t> on_close;
67
+ };
68
+
69
+ struct rocksdb_native_suspend_t {
70
+ rocksdb_suspend_t handle;
71
+
72
+ js_env_t *env;
73
+ js_persistent_t<js_receiver_t> ctx;
74
+ js_persistent_t<cb_on_suspend_t> on_suspend;
75
+ };
76
+
77
+ struct rocksdb_native_resume_t {
78
+ rocksdb_resume_t handle;
79
+
80
+ js_env_t *env;
81
+ js_persistent_t<js_receiver_t> ctx;
82
+ js_persistent_t<cb_on_resume_t> on_resume;
83
+ };
84
+
85
+ struct rocksdb_native_iterator_t {
86
+ rocksdb_iterator_t handle;
87
+
88
+ rocksdb_slice_t *keys;
89
+ rocksdb_slice_t *values;
90
+
91
+ js_env_t *env;
92
+ js_persistent_t<js_receiver_t> ctx;
93
+ js_persistent_t<cb_on_iterator_open_t> on_open;
94
+ js_persistent_t<cb_on_iterator_close_t> on_close;
95
+ js_persistent_t<cb_on_iterator_read_t> on_read;
96
+
97
+ bool closing;
98
+ bool exiting;
99
+
100
+ js_deferred_teardown_t *teardown;
101
+ };
102
+
103
+ struct rocksdb_native_read_batch_t {
104
+ rocksdb_read_batch_t handle;
105
+
106
+ rocksdb_read_t *reads;
107
+
108
+ size_t capacity;
109
+
110
+ js_env_t *env;
111
+ js_persistent_t<js_receiver_t> ctx;
112
+ js_persistent_t<cb_on_read_t> on_read;
113
+ };
114
+
115
+ struct rocksdb_native_write_batch_t {
116
+ rocksdb_write_batch_t handle;
117
+
118
+ rocksdb_write_t *writes;
119
+
120
+ size_t capacity;
121
+
122
+ js_env_t *env;
123
+ js_persistent_t<js_receiver_t> ctx;
124
+ js_persistent_t<cb_on_write_t> on_write;
125
+ };
126
+
127
+ struct rocksdb_native_flush_t {
128
+ rocksdb_flush_t handle;
129
+
130
+ js_env_t *env;
131
+ js_persistent_t<js_receiver_t> ctx;
132
+ js_persistent_t<cb_on_flush_t> on_flush;
133
+
134
+ js_persistent_t<rocksdb_native_column_family_t> column_family;
135
+ };
136
+
137
+ struct rocksdb_native_snapshot_t {
138
+ rocksdb_snapshot_t handle;
139
+ };
140
+
141
+ static void
142
+ rocksdb_native__on_free(js_env_t *env, void *data, void *finalize_hint) {
143
+ free(data);
144
+ }
145
+
146
+ static void
147
+ rocksdb_native__on_column_family_teardown(void *data);
148
+
149
+ static void
150
+ rocksdb_native__on_open(rocksdb_open_t *handle, int status) {
151
+ int err;
152
+
153
+ assert(status == 0);
154
+
155
+ auto req = reinterpret_cast<rocksdb_native_open_t *>(handle->data);
156
+
157
+ auto db = reinterpret_cast<rocksdb_native_t *>(req->handle.req.db);
158
+
159
+ js_env_t *env = req->env;
160
+
161
+ const rocksdb_column_family_descriptor_t *descriptors = handle->column_families;
162
+
163
+ rocksdb_column_family_t **handles = handle->handles;
164
+
165
+ if (db->exiting) {
166
+ req->on_open.reset();
167
+ req->ctx.reset();
168
+ } else {
169
+ js_handle_scope_t *scope;
170
+ err = js_open_handle_scope(env, &scope);
171
+ assert(err == 0);
172
+
173
+ js_receiver_t ctx;
174
+ err = js_get_reference_value(env, req->ctx, ctx);
175
+ assert(err == 0);
176
+
177
+ cb_on_open_t cb;
178
+ err = js_get_reference_value(env, req->on_open, cb);
179
+ assert(err == 0);
180
+
181
+ js_array_t column_families;
182
+ err = js_get_reference_value(env, req->column_families, column_families);
183
+ assert(err == 0);
184
+
185
+ req->on_open.reset();
186
+ req->column_families.reset();
187
+ req->ctx.reset();
188
+
189
+ std::optional<js_string_t> error;
190
+
191
+ if (req->handle.error) {
192
+ err = js_create_string(env, req->handle.error, error.emplace());
193
+ assert(err == 0);
194
+ }
195
+
196
+ rocksdb_column_family_t **handles = handle->handles;
197
+
198
+ if (req->handle.error == NULL) {
199
+ std::vector<js_arraybuffer_t> elements;
200
+
201
+ err = js_get_array_elements(env, column_families, elements);
202
+ assert(err == 0);
203
+
204
+ const auto len = elements.size();
205
+
206
+ for (uint32_t i = 0; i < len; i++) {
207
+ js_arraybuffer_t handle = elements[i];
208
+
209
+ rocksdb_native_column_family_t *column_family;
210
+ err = js_get_arraybuffer_info(env, handle, column_family);
211
+ assert(err == 0);
212
+
213
+ column_family->handle = handles[i];
214
+
215
+ err = js_create_reference(env, ctx, column_family->ctx);
216
+ assert(err == 0);
217
+
218
+ err = js_add_teardown_callback(env, rocksdb_native__on_column_family_teardown, (void *) column_family);
219
+ assert(err == 0);
220
+ }
221
+ }
222
+
223
+ js_call_function_with_checkpoint(env, cb, ctx, error);
224
+
225
+ err = js_close_handle_scope(env, scope);
226
+ assert(err == 0);
227
+
228
+ delete[] descriptors;
229
+ delete[] handles;
230
+ }
231
+ }
232
+
233
+ static void
234
+ rocksdb_native__on_close(rocksdb_close_t *handle, int status) {
235
+ int err;
236
+
237
+ assert(status == 0);
238
+
239
+ rocksdb_native_close_t *req = (rocksdb_native_close_t *) handle->data;
240
+
241
+ rocksdb_native_t *db = (rocksdb_native_t *) req->handle.req.db;
242
+
243
+ js_env_t *env = req->env;
244
+
245
+ js_deferred_teardown_t *teardown = db->teardown;
246
+
247
+ if (db->exiting) {
248
+ db->ctx.reset();
249
+
250
+ if (db->closing) {
251
+ req->on_close.reset();
252
+ req->ctx.reset();
253
+ } else {
254
+ free(req);
255
+ }
256
+ } else {
257
+ js_handle_scope_t *scope;
258
+ err = js_open_handle_scope(env, &scope);
259
+ assert(err == 0);
260
+
261
+ js_receiver_t ctx;
262
+ err = js_get_reference_value(env, req->ctx, ctx);
263
+ assert(err == 0);
264
+
265
+ cb_on_close_t cb;
266
+ err = js_get_reference_value(env, req->on_close, cb);
267
+ assert(err == 0);
268
+
269
+ db->ctx.reset();
270
+ req->on_close.reset();
271
+ req->ctx.reset();
272
+
273
+ js_call_function_with_checkpoint(env, cb, ctx);
274
+
275
+ err = js_close_handle_scope(env, scope);
276
+ assert(err == 0);
277
+ }
278
+
279
+ err = js_finish_deferred_teardown_callback(teardown);
280
+ assert(err == 0);
281
+ }
282
+
283
+ static void
284
+ rocksdb_native__on_teardown(js_deferred_teardown_t *handle, void *data) {
285
+ int err;
286
+
287
+ rocksdb_native_t *db = (rocksdb_native_t *) data;
288
+
289
+ js_env_t *env = db->env;
290
+
291
+ db->exiting = true;
292
+
293
+ if (db->closing) return;
294
+
295
+ auto req = reinterpret_cast<rocksdb_native_close_t *>(malloc(sizeof(rocksdb_native_close_t)));
296
+
297
+ req->env = env;
298
+ req->handle.data = (void *) req;
299
+
300
+ err = rocksdb_close(&db->handle, &req->handle, rocksdb_native__on_close);
301
+ assert(err == 0);
302
+ }
303
+
304
+ static js_arraybuffer_t
305
+ rocksdb_native_init(
306
+ js_env_t *env,
307
+ bool read_only,
308
+ bool create_if_missing,
309
+ bool create_missing_column_families,
310
+ int32_t max_background_jobs,
311
+ uint64_t bytes_per_sync,
312
+ int32_t max_open_files,
313
+ bool use_direct_reads
314
+ ) {
315
+ int err;
316
+
317
+ uv_loop_t *loop;
318
+ err = js_get_env_loop(env, &loop);
319
+ assert(err == 0);
320
+
321
+ js_arraybuffer_t handle;
322
+
323
+ rocksdb_native_t *db;
324
+ err = js_create_arraybuffer(env, db, handle);
325
+ assert(err == 0);
326
+
327
+ db->env = env;
328
+ db->closing = false;
329
+ db->exiting = false;
330
+
331
+ db->options = (rocksdb_options_t) {
332
+ 1,
333
+ read_only,
334
+ create_if_missing,
335
+ create_missing_column_families,
336
+ max_background_jobs,
337
+ bytes_per_sync,
338
+ max_open_files,
339
+ use_direct_reads
340
+ };
341
+
342
+ err = rocksdb_init(loop, &db->handle);
343
+ assert(err == 0);
344
+
345
+ return handle;
346
+ }
347
+
348
+ static js_arraybuffer_t
349
+ rocksdb_native_open(
350
+ js_env_t *env,
351
+ js_arraybuffer_span_of_t<rocksdb_native_t, 1> db,
352
+ js_receiver_t self,
353
+ char *path,
354
+ js_array_t column_families_array,
355
+ js_receiver_t ctx,
356
+ cb_on_open_t on_open
357
+ ) {
358
+ int err;
359
+
360
+ std::vector<js_arraybuffer_t> elements;
361
+
362
+ err = js_get_array_elements(env, column_families_array, elements);
363
+ assert(err == 0);
364
+
365
+ const auto len = elements.size();
366
+
367
+ auto column_families = new rocksdb_column_family_descriptor_t[len];
368
+
369
+ for (uint32_t i = 0; i < len; i++) {
370
+ js_arraybuffer_t handle = elements[i];
371
+
372
+ rocksdb_native_column_family_t *column_family;
373
+ err = js_get_arraybuffer_info(env, handle, column_family);
374
+ assert(err == 0);
375
+
376
+ memcpy(&column_families[i], &column_family->descriptor, sizeof(rocksdb_column_family_descriptor_t));
377
+
378
+ column_family->db = &db->handle;
379
+ }
380
+
381
+ auto handles = new rocksdb_column_family_t *[len];
382
+
383
+ js_arraybuffer_t handle;
384
+
385
+ rocksdb_native_open_t *req;
386
+ err = js_create_arraybuffer(env, req, handle);
387
+ assert(err == 0);
388
+
389
+ req->env = env;
390
+ req->handle.data = req;
391
+
392
+ err = js_create_reference(env, self, db->ctx);
393
+ assert(err == 0);
394
+
395
+ err = js_create_reference(env, ctx, req->ctx);
396
+ assert(err == 0);
397
+
398
+ err = js_create_reference(env, on_open, req->on_open);
399
+ assert(err == 0);
400
+
401
+ err = js_create_reference(env, column_families_array, req->column_families);
402
+ assert(err == 0);
403
+
404
+ err = rocksdb_open(&db->handle, &req->handle, path, &db->options, column_families, handles, len, rocksdb_native__on_open);
405
+ assert(err == 0);
406
+
407
+ err = js_add_deferred_teardown_callback(env, rocksdb_native__on_teardown, (void *) db, &db->teardown);
408
+ assert(err == 0);
409
+
410
+ return handle;
411
+ }
412
+
413
+ static js_arraybuffer_t
414
+ rocksdb_native_close(
415
+ js_env_t *env,
416
+ js_arraybuffer_span_of_t<rocksdb_native_t, 1> db,
417
+ js_receiver_t ctx,
418
+ cb_on_close_t on_close
419
+ ) {
420
+ int err;
421
+
422
+ js_arraybuffer_t handle;
423
+
424
+ rocksdb_native_close_t *req;
425
+ err = js_create_arraybuffer(env, req, handle);
426
+ assert(err == 0);
427
+
428
+ req->env = env;
429
+ req->handle.data = (void *) req;
430
+
431
+ err = js_create_reference(env, ctx, req->ctx);
432
+ assert(err == 0);
433
+
434
+ err = js_create_reference(env, on_close, req->on_close);
435
+ assert(err == 0);
436
+
437
+ db->closing = true;
438
+
439
+ err = rocksdb_close(&db->handle, &req->handle, rocksdb_native__on_close);
440
+ assert(err == 0);
441
+
442
+ return handle;
443
+ }
444
+
445
+ static void
446
+ rocksdb_native__on_suspend(rocksdb_suspend_t *handle, int status) {
447
+ int err;
448
+
449
+ assert(status == 0);
450
+
451
+ rocksdb_native_suspend_t *req = (rocksdb_native_suspend_t *) handle->data;
452
+
453
+ rocksdb_native_t *db = (rocksdb_native_t *) req->handle.req.db;
454
+
455
+ js_env_t *env = req->env;
456
+
457
+ js_deferred_teardown_t *teardown = db->teardown;
458
+
459
+ if (db->exiting) {
460
+ req->on_suspend.reset();
461
+ req->ctx.reset();
462
+ } else {
463
+ js_handle_scope_t *scope;
464
+ err = js_open_handle_scope(env, &scope);
465
+ assert(err == 0);
466
+
467
+ js_receiver_t ctx;
468
+ err = js_get_reference_value(env, req->ctx, ctx);
469
+ assert(err == 0);
470
+
471
+ cb_on_suspend_t cb;
472
+ err = js_get_reference_value(env, req->on_suspend, cb);
473
+ assert(err == 0);
474
+
475
+ std::optional<js_string_t> error;
476
+
477
+ if (req->handle.error) {
478
+ err = js_create_string(env, req->handle.error, error.emplace());
479
+ assert(err == 0);
480
+ }
481
+
482
+ js_call_function_with_checkpoint(env, cb, ctx, error);
483
+
484
+ err = js_close_handle_scope(env, scope);
485
+ assert(err == 0);
486
+ }
487
+ }
488
+
489
+ static js_arraybuffer_t
490
+ rocksdb_native_suspend(
491
+ js_env_t *env,
492
+ js_arraybuffer_span_of_t<rocksdb_native_t, 1> db,
493
+ js_receiver_t ctx,
494
+ cb_on_suspend_t on_suspend
495
+ ) {
496
+ int err;
497
+
498
+ js_arraybuffer_t handle;
499
+
500
+ rocksdb_native_suspend_t *req;
501
+ err = js_create_arraybuffer(env, req, handle);
502
+ assert(err == 0);
503
+
504
+ req->env = env;
505
+ req->handle.data = (void *) req;
506
+
507
+ err = js_create_reference(env, ctx, req->ctx);
508
+ assert(err == 0);
509
+
510
+ err = js_create_reference(env, on_suspend, req->on_suspend);
511
+ assert(err == 0);
512
+
513
+ err = rocksdb_suspend(&db->handle, &req->handle, rocksdb_native__on_suspend);
514
+ assert(err == 0);
515
+
516
+ return handle;
517
+ }
518
+
519
+ static void
520
+ rocksdb_native__on_resume(rocksdb_resume_t *handle, int status) {
521
+ int err;
522
+
523
+ assert(status == 0);
524
+
525
+ rocksdb_native_resume_t *req = (rocksdb_native_resume_t *) handle->data;
526
+
527
+ rocksdb_native_t *db = (rocksdb_native_t *) req->handle.req.db;
528
+
529
+ js_env_t *env = req->env;
530
+
531
+ js_deferred_teardown_t *teardown = db->teardown;
532
+
533
+ if (db->exiting) {
534
+ req->on_resume.reset();
535
+ req->ctx.reset();
536
+ } else {
537
+ js_handle_scope_t *scope;
538
+ err = js_open_handle_scope(env, &scope);
539
+ assert(err == 0);
540
+
541
+ js_receiver_t ctx;
542
+ err = js_get_reference_value(env, req->ctx, ctx);
543
+ assert(err == 0);
544
+
545
+ cb_on_resume_t cb;
546
+ err = js_get_reference_value(env, req->on_resume, cb);
547
+ assert(err == 0);
548
+
549
+ req->on_resume.reset();
550
+ req->ctx.reset();
551
+
552
+ std::optional<js_string_t> error;
553
+
554
+ if (req->handle.error) {
555
+ err = js_create_string(env, req->handle.error, error.emplace());
556
+ assert(err == 0);
557
+ }
558
+
559
+ js_call_function_with_checkpoint(env, cb, ctx, error);
560
+
561
+ err = js_close_handle_scope(env, scope);
562
+ assert(err == 0);
563
+ }
564
+ }
565
+
566
+ static js_arraybuffer_t
567
+ rocksdb_native_resume(
568
+ js_env_t *env,
569
+ js_arraybuffer_span_of_t<rocksdb_native_t, 1> db,
570
+ js_receiver_t ctx,
571
+ cb_on_resume_t on_resume
572
+ ) {
573
+ int err;
574
+
575
+ js_arraybuffer_t handle;
576
+
577
+ rocksdb_native_resume_t *req;
578
+ err = js_create_arraybuffer(env, req, handle);
579
+ assert(err == 0);
580
+
581
+ req->env = env;
582
+ req->handle.data = (void *) req;
583
+
584
+ err = js_create_reference(env, ctx, req->ctx);
585
+ assert(err == 0);
586
+
587
+ err = js_create_reference(env, on_resume, req->on_resume);
588
+ assert(err == 0);
589
+
590
+ err = rocksdb_resume(&db->handle, &req->handle, rocksdb_native__on_resume);
591
+ assert(err == 0);
592
+
593
+ return handle;
594
+ }
595
+
596
+ static void
597
+ rocksdb_native__on_column_family_teardown(void *data) {
598
+ int err;
599
+
600
+ rocksdb_native_column_family_t *column_family = (rocksdb_native_column_family_t *) data;
601
+
602
+ js_env_t *env = column_family->env;
603
+
604
+ err = rocksdb_column_family_destroy(column_family->db, column_family->handle);
605
+ assert(err == 0);
606
+
607
+ column_family->ctx.reset();
608
+ }
609
+
610
+ static js_arraybuffer_t
611
+ rocksdb_native_column_family_init(
612
+ js_env_t *env,
613
+ char *name,
614
+ bool enable_blob_files,
615
+ uint64_t min_blob_size,
616
+ uint64_t blob_file_size,
617
+ bool enable_blob_garbage_collection,
618
+ uint64_t block_size,
619
+ bool cache_index_and_filter_blocks,
620
+ uint32_t format_version,
621
+ bool optimize_filters_for_memory,
622
+ bool no_block_cache,
623
+ uint32_t filter_policy_type,
624
+ double bits_per_key,
625
+ int32_t bloom_before_level,
626
+ uint32_t top_level_index_pinning_tier,
627
+ uint32_t partition_pinning_tier,
628
+ uint32_t unpartitioned_pinning_tier
629
+ ) {
630
+ int err;
631
+
632
+ rocksdb_filter_policy_t filter_policy = {rocksdb_filter_policy_type_t(filter_policy_type)};
633
+
634
+ switch (filter_policy_type) {
635
+ case rocksdb_bloom_filter_policy:
636
+ filter_policy.bloom = (rocksdb_bloom_filter_options_t) {
637
+ 0,
638
+ bits_per_key
639
+ };
640
+ break;
641
+
642
+ case rocksdb_ribbon_filter_policy:
643
+ filter_policy.ribbon = (rocksdb_ribbon_filter_options_t) {
644
+ 0,
645
+ bits_per_key,
646
+ bloom_before_level,
647
+ };
648
+ break;
649
+ }
650
+
651
+ uv_loop_t *loop;
652
+ err = js_get_env_loop(env, &loop);
653
+ assert(err == 0);
654
+
655
+ js_arraybuffer_t handle;
656
+
657
+ rocksdb_native_column_family_t *column_family;
658
+ err = js_create_arraybuffer(env, column_family, handle);
659
+ assert(err == 0);
660
+
661
+ column_family->env = env;
662
+ column_family->db = NULL;
663
+ column_family->handle = NULL;
664
+
665
+ column_family->descriptor = (rocksdb_column_family_descriptor_t) {
666
+ name,
667
+ {
668
+ 3,
669
+ rocksdb_level_compaction,
670
+ enable_blob_files,
671
+ min_blob_size,
672
+ blob_file_size,
673
+ enable_blob_garbage_collection,
674
+ block_size,
675
+ cache_index_and_filter_blocks,
676
+ format_version,
677
+ optimize_filters_for_memory,
678
+ no_block_cache,
679
+ filter_policy,
680
+ rocksdb_pinning_tier_t(top_level_index_pinning_tier),
681
+ rocksdb_pinning_tier_t(partition_pinning_tier),
682
+ rocksdb_pinning_tier_t(unpartitioned_pinning_tier),
683
+ }
684
+ };
685
+
686
+ return handle;
687
+ }
688
+
689
+ static void
690
+ rocksdb_native_column_family_destroy(
691
+ js_env_t *env,
692
+ js_arraybuffer_span_of_t<rocksdb_native_column_family_t, 1> column_family
693
+ ) {
694
+ int err;
695
+
696
+ if (column_family->handle == NULL) return;
697
+
698
+ err = rocksdb_column_family_destroy(column_family->db, column_family->handle);
699
+ assert(err == 0);
700
+
701
+ err = js_remove_teardown_callback(env, rocksdb_native__on_column_family_teardown, column_family);
702
+ assert(err == 0);
703
+
704
+ column_family->ctx.reset();
705
+
706
+ column_family->handle = NULL;
707
+ }
708
+
709
+ static js_arraybuffer_t
710
+ rocksdb_native_iterator_init(js_env_t *env) {
711
+ int err;
712
+
713
+ js_arraybuffer_t handle;
714
+
715
+ rocksdb_native_iterator_t *req;
716
+ err = js_create_arraybuffer(env, req, handle);
717
+ assert(err == 0);
718
+
719
+ req->env = env;
720
+ req->closing = false;
721
+ req->exiting = false;
722
+ req->handle.data = req;
723
+
724
+ return handle;
725
+ }
726
+
727
+ static js_arraybuffer_t
728
+ rocksdb_native_iterator_buffer(
729
+ js_env_t *env,
730
+ js_arraybuffer_span_of_t<rocksdb_native_iterator_t, 1> req,
731
+ uint32_t capacity
732
+ ) {
733
+ int err;
734
+
735
+ js_arraybuffer_t handle;
736
+
737
+ uint8_t *data;
738
+ err = js_create_arraybuffer(env, 2 * capacity * sizeof(rocksdb_slice_t), data, handle);
739
+ assert(err == 0);
740
+
741
+ size_t offset = 0;
742
+
743
+ req->keys = (rocksdb_slice_t *) &data[offset];
744
+
745
+ offset += capacity * sizeof(rocksdb_slice_t);
746
+
747
+ req->values = (rocksdb_slice_t *) &data[offset];
748
+
749
+ return handle;
750
+ }
751
+
752
+ static void
753
+ rocksdb_native__on_iterator_close(rocksdb_iterator_t *handle, int status) {
754
+ int err;
755
+
756
+ assert(status == 0);
757
+
758
+ rocksdb_native_iterator_t *req = (rocksdb_native_iterator_t *) handle->data;
759
+
760
+ js_env_t *env = req->env;
761
+
762
+ js_deferred_teardown_t *teardown = req->teardown;
763
+
764
+ if (req->exiting) {
765
+ req->on_open.reset();
766
+ req->on_close.reset();
767
+ req->on_read.reset();
768
+ req->ctx.reset();
769
+ } else {
770
+ js_handle_scope_t *scope;
771
+ err = js_open_handle_scope(env, &scope);
772
+ assert(err == 0);
773
+
774
+ js_receiver_t ctx;
775
+ err = js_get_reference_value(env, req->ctx, ctx);
776
+ assert(err == 0);
777
+
778
+ cb_on_iterator_close_t cb;
779
+ err = js_get_reference_value(env, req->on_close, cb);
780
+ assert(err == 0);
781
+
782
+ req->on_open.reset();
783
+ req->on_close.reset();
784
+ req->on_read.reset();
785
+ req->ctx.reset();
786
+
787
+ std::optional<js_string_t> error;
788
+
789
+ if (req->handle.error) {
790
+ err = js_create_string(env, req->handle.error, error.emplace());
791
+ assert(err == 0);
792
+ }
793
+
794
+ js_call_function_with_checkpoint(env, cb, ctx, error);
795
+
796
+ err = js_close_handle_scope(env, scope);
797
+ assert(err == 0);
798
+ }
799
+
800
+ err = js_finish_deferred_teardown_callback(teardown);
801
+ assert(err == 0);
802
+ }
803
+
804
+ static void
805
+ rocksdb_native__on_iterator_open(rocksdb_iterator_t *handle, int status) {
806
+ int err;
807
+
808
+ assert(status == 0);
809
+
810
+ rocksdb_native_iterator_t *req = (rocksdb_native_iterator_t *) handle->data;
811
+
812
+ if (req->exiting) return;
813
+
814
+ js_env_t *env = req->env;
815
+
816
+ js_handle_scope_t *scope;
817
+ err = js_open_handle_scope(env, &scope);
818
+ assert(err == 0);
819
+
820
+ js_receiver_t ctx;
821
+ err = js_get_reference_value(env, req->ctx, ctx);
822
+ assert(err == 0);
823
+
824
+ cb_on_iterator_open_t cb;
825
+ err = js_get_reference_value(env, req->on_open, cb);
826
+ assert(err == 0);
827
+
828
+ std::optional<js_string_t> error;
829
+
830
+ if (req->handle.error) {
831
+ err = js_create_string(env, req->handle.error, error.emplace());
832
+ assert(err == 0);
833
+ }
834
+
835
+ js_call_function_with_checkpoint(env, cb, ctx, error);
836
+
837
+ err = js_close_handle_scope(env, scope);
838
+ assert(err == 0);
839
+ }
840
+
841
+ static void
842
+ rocksdb_native__on_iterator_teardown(js_deferred_teardown_t *handle, void *data) {
843
+ int err;
844
+
845
+ rocksdb_native_iterator_t *req = (rocksdb_native_iterator_t *) data;
846
+
847
+ req->exiting = true;
848
+
849
+ if (req->closing) return;
850
+
851
+ err = rocksdb_iterator_close(&req->handle, rocksdb_native__on_iterator_close);
852
+ assert(err == 0);
853
+ }
854
+
855
+ static void
856
+ rocksdb_native_iterator_open(
857
+ js_env_t *env,
858
+ js_arraybuffer_span_of_t<rocksdb_native_t, 1> db,
859
+ js_arraybuffer_span_of_t<rocksdb_native_iterator_t, 1> req,
860
+ js_arraybuffer_span_of_t<rocksdb_native_column_family_t, 1> column_family,
861
+ js_typedarray_t<> gt,
862
+ js_typedarray_t<> gte,
863
+ js_typedarray_t<> lt,
864
+ js_typedarray_t<> lte,
865
+ bool reverse,
866
+ bool keys_only,
867
+ std::optional<js_arraybuffer_t> snapshot,
868
+ js_receiver_t ctx,
869
+ cb_on_iterator_open_t on_open,
870
+ cb_on_iterator_close_t on_close,
871
+ cb_on_iterator_read_t on_read
872
+ ) {
873
+ int err;
874
+
875
+ rocksdb_range_t range;
876
+
877
+ err = js_get_typedarray_info(env, gt, range.gt.data, range.gt.len);
878
+ assert(err == 0);
879
+
880
+ err = js_get_typedarray_info(env, gte, range.gte.data, range.gte.len);
881
+ assert(err == 0);
882
+
883
+ err = js_get_typedarray_info(env, lt, range.lt.data, range.lt.len);
884
+ assert(err == 0);
885
+
886
+ err = js_get_typedarray_info(env, lte, range.lte.data, range.lte.len);
887
+ assert(err == 0);
888
+
889
+ rocksdb_iterator_options_t options = {
890
+ .version = 0,
891
+ .reverse = reverse,
892
+ .keys_only = keys_only
893
+ };
894
+
895
+ if (snapshot) {
896
+ err = js_get_arraybuffer_info(env, snapshot.value(), options.snapshot);
897
+ assert(err == 0);
898
+ }
899
+
900
+ err = js_create_reference(env, ctx, req->ctx);
901
+ assert(err == 0);
902
+
903
+ err = js_create_reference(env, on_open, req->on_open);
904
+ assert(err == 0);
905
+
906
+ err = js_create_reference(env, on_close, req->on_close);
907
+ assert(err == 0);
908
+
909
+ err = js_create_reference(env, on_read, req->on_read);
910
+ assert(err == 0);
911
+
912
+ err = rocksdb_iterator_open(&db->handle, &req->handle, column_family->handle, range, &options, rocksdb_native__on_iterator_open);
913
+ assert(err == 0);
914
+
915
+ err = js_add_deferred_teardown_callback(env, rocksdb_native__on_iterator_teardown, (void *) req, &req->teardown);
916
+ assert(err == 0);
917
+ }
918
+
919
+ static void
920
+ rocksdb_native_iterator_close(js_env_t *env, js_arraybuffer_span_of_t<rocksdb_native_iterator_t, 1> req) {
921
+ int err;
922
+
923
+ req->closing = true;
924
+
925
+ err = rocksdb_iterator_close(&req->handle, rocksdb_native__on_iterator_close);
926
+ assert(err == 0);
927
+ }
928
+
929
+ static int
930
+ rocksdb_native_try_create_external_arraybuffer(js_env_t *env, char *data, size_t len, js_arraybuffer_t &result) {
931
+ // the external arraybuffer api is optional per (https://nodejs.org/api/n-api.html#napi_create_external_arraybuffer)
932
+ // so provide a fallback that does a std::copy
933
+ int err = js_create_external_arraybuffer(env, data, len, result);
934
+ if (err == 0) return 0;
935
+
936
+ return js_create_arraybuffer(env, data, len, result);
937
+ }
938
+
939
+ static void
940
+ rocksdb_native__on_iterator_read(rocksdb_iterator_t *handle, int status) {
941
+ int err;
942
+
943
+ assert(status == 0);
944
+
945
+ rocksdb_native_iterator_t *req = (rocksdb_native_iterator_t *) handle->data;
946
+
947
+ rocksdb_native_t *db = (rocksdb_native_t *) req->handle.req.db;
948
+
949
+ size_t len = req->handle.len;
950
+
951
+ if (db->exiting) {
952
+ if (status == 0 && req->handle.error == NULL) {
953
+ for (size_t i = 0; i < len; i++) {
954
+ js_value_t *result;
955
+
956
+ rocksdb_slice_destroy(&req->keys[i]);
957
+
958
+ rocksdb_slice_destroy(&req->values[i]);
959
+ }
960
+ }
961
+ } else {
962
+ js_env_t *env = req->env;
963
+
964
+ js_handle_scope_t *scope;
965
+ err = js_open_handle_scope(env, &scope);
966
+ assert(err == 0);
967
+
968
+ js_receiver_t ctx;
969
+ err = js_get_reference_value(env, req->ctx, ctx);
970
+ assert(err == 0);
971
+
972
+ cb_on_iterator_read_t cb;
973
+ err = js_get_reference_value(env, req->on_read, cb);
974
+ assert(err == 0);
975
+
976
+ std::optional<js_string_t> error;
977
+
978
+ std::vector<js_arraybuffer_t> keys;
979
+ keys.reserve(len);
980
+
981
+ std::vector<js_arraybuffer_t> values;
982
+ values.reserve(len);
983
+
984
+ if (req->handle.error) {
985
+ err = js_create_string(env, req->handle.error, error.emplace());
986
+ assert(err == 0);
987
+ } else {
988
+ for (size_t i = 0; i < len; i++) {
989
+ js_arraybuffer_t result;
990
+
991
+ rocksdb_slice_t *key = &req->keys[i];
992
+
993
+ err = rocksdb_native_try_create_external_arraybuffer(env, const_cast<char *>(key->data), key->len, result);
994
+ assert(err == 0);
995
+
996
+ keys.push_back(result);
997
+
998
+ rocksdb_slice_t *value = &req->values[i];
999
+
1000
+ err = rocksdb_native_try_create_external_arraybuffer(env, const_cast<char *>(value->data), value->len, result);
1001
+ assert(err == 0);
1002
+
1003
+ values.push_back(result);
1004
+ }
1005
+ }
1006
+
1007
+ js_call_function_with_checkpoint(env, cb, ctx, error, keys, values);
1008
+
1009
+ err = js_close_handle_scope(env, scope);
1010
+ assert(err == 0);
1011
+ }
1012
+ }
1013
+
1014
+ static void
1015
+ rocksdb_native_iterator_read(
1016
+ js_env_t *env,
1017
+ js_arraybuffer_span_of_t<rocksdb_native_iterator_t, 1> req,
1018
+ uint32_t capacity
1019
+ ) {
1020
+ int err;
1021
+
1022
+ err = rocksdb_iterator_read(&req->handle, req->keys, req->values, capacity, rocksdb_native__on_iterator_read);
1023
+ assert(err == 0);
1024
+ }
1025
+
1026
+ static js_arraybuffer_t
1027
+ rocksdb_native_read_init(js_env_t *env) {
1028
+ int err;
1029
+
1030
+ js_arraybuffer_t handle;
1031
+
1032
+ rocksdb_native_read_batch_t *req;
1033
+ err = js_create_arraybuffer(env, req, handle);
1034
+ assert(err == 0);
1035
+
1036
+ req->env = env;
1037
+ req->handle.data = req;
1038
+
1039
+ return handle;
1040
+ }
1041
+
1042
+ static js_arraybuffer_t
1043
+ rocksdb_native_read_buffer(
1044
+ js_env_t *env,
1045
+ js_arraybuffer_span_of_t<rocksdb_native_read_batch_t, 1> req,
1046
+ uint32_t capacity
1047
+ ) {
1048
+ int err;
1049
+
1050
+ js_arraybuffer_t handle;
1051
+
1052
+ rocksdb_read_t *reads;
1053
+ err = js_create_arraybuffer(env, capacity, reads, handle);
1054
+ assert(err == 0);
1055
+
1056
+ req->capacity = capacity;
1057
+ req->reads = reads;
1058
+
1059
+ return handle;
1060
+ }
1061
+
1062
+ static void
1063
+ rocksdb_native__on_read(rocksdb_read_batch_t *handle, int status) {
1064
+ int err;
1065
+
1066
+ assert(status == 0);
1067
+
1068
+ rocksdb_native_read_batch_t *req = (rocksdb_native_read_batch_t *) handle->data;
1069
+
1070
+ rocksdb_native_t *db = (rocksdb_native_t *) req->handle.req.db;
1071
+
1072
+ js_env_t *env = req->env;
1073
+
1074
+ size_t len = req->handle.len;
1075
+
1076
+ if (db->exiting) {
1077
+ if (status == 0) {
1078
+ for (size_t i = 0; i < len; i++) {
1079
+ char *error = req->handle.errors[i];
1080
+
1081
+ if (error) continue;
1082
+
1083
+ rocksdb_slice_destroy(&req->reads[i].value);
1084
+ }
1085
+ }
1086
+
1087
+ req->on_read.reset();
1088
+ req->ctx.reset();
1089
+ } else {
1090
+ js_handle_scope_t *scope;
1091
+ err = js_open_handle_scope(env, &scope);
1092
+ assert(err == 0);
1093
+
1094
+ js_array_t errors;
1095
+ err = js_create_array(env, len, errors);
1096
+ assert(err == 0);
1097
+
1098
+ js_array_t values;
1099
+ err = js_create_array(env, len, values);
1100
+ assert(err == 0);
1101
+
1102
+ for (size_t i = 0; i < len; i++) {
1103
+ char *error = req->handle.errors[i];
1104
+
1105
+ if (error) {
1106
+ js_string_t result;
1107
+
1108
+ err = js_create_string(env, error, result);
1109
+ assert(err == 0);
1110
+
1111
+ err = js_set_element(env, errors, i, result);
1112
+ assert(err == 0);
1113
+ } else {
1114
+ js_arraybuffer_t result;
1115
+
1116
+ rocksdb_slice_t *slice = &req->reads[i].value;
1117
+
1118
+ if (slice->data == NULL && slice->len == (size_t) -1) {
1119
+ err = js_get_null(env, (js_value_t **) result);
1120
+ assert(err == 0);
1121
+ } else {
1122
+ err = rocksdb_native_try_create_external_arraybuffer(env, const_cast<char *>(slice->data), slice->len, result);
1123
+ assert(err == 0);
1124
+ }
1125
+
1126
+ err = js_set_element(env, values, i, result);
1127
+ assert(err == 0);
1128
+ }
1129
+ }
1130
+
1131
+ js_receiver_t ctx;
1132
+ err = js_get_reference_value(env, req->ctx, ctx);
1133
+ assert(err == 0);
1134
+
1135
+ cb_on_read_t cb;
1136
+ err = js_get_reference_value(env, req->on_read, cb);
1137
+ assert(err == 0);
1138
+
1139
+ req->on_read.reset();
1140
+ req->ctx.reset();
1141
+
1142
+ js_call_function_with_checkpoint(env, cb, ctx, errors, values);
1143
+
1144
+ err = js_close_handle_scope(env, scope);
1145
+ assert(err == 0);
1146
+ }
1147
+ }
1148
+
1149
+ static void
1150
+ rocksdb_native_read(
1151
+ js_env_t *env,
1152
+ js_arraybuffer_span_of_t<rocksdb_native_t, 1> db,
1153
+ js_arraybuffer_span_of_t<rocksdb_native_read_batch_t, 1> req,
1154
+ js_array_t operations,
1155
+ std::optional<js_arraybuffer_t> snapshot,
1156
+ js_receiver_t ctx,
1157
+ cb_on_read_t on_read
1158
+ ) {
1159
+ int err;
1160
+
1161
+ err = js_create_reference(env, ctx, req->ctx);
1162
+ assert(err == 0);
1163
+
1164
+ err = js_create_reference(env, on_read, req->on_read);
1165
+ assert(err == 0);
1166
+
1167
+ std::vector<js_object_t> elements;
1168
+
1169
+ err = js_get_array_elements(env, operations, elements);
1170
+ assert(err == 0);
1171
+
1172
+ const auto len = elements.size();
1173
+
1174
+ for (uint32_t i = 0; i < len; i++) {
1175
+ js_object_t read = elements[i];
1176
+
1177
+ rocksdb_read_type_t type;
1178
+ err = js_get_property(env, read, "type", reinterpret_cast<uint32_t &>(type));
1179
+ assert(err == 0);
1180
+
1181
+ req->reads[i].type = type;
1182
+
1183
+ js_arraybuffer_t column_family_property;
1184
+ err = js_get_property(env, read, "columnFamily", column_family_property);
1185
+ assert(err == 0);
1186
+
1187
+ rocksdb_native_column_family_t *column_family;
1188
+ err = js_get_arraybuffer_info(env, column_family_property, column_family);
1189
+ assert(err == 0);
1190
+
1191
+ req->reads[i].column_family = column_family->handle;
1192
+
1193
+ switch (type) {
1194
+ case rocksdb_get: {
1195
+ js_typedarray_t property;
1196
+
1197
+ rocksdb_slice_t *key = &req->reads[i].key;
1198
+
1199
+ err = js_get_property(env, read, "key", property);
1200
+ assert(err == 0);
1201
+
1202
+ err = js_get_typedarray_info(env, property, key->data, key->len);
1203
+ assert(err == 0);
1204
+ break;
1205
+ }
1206
+ }
1207
+ }
1208
+
1209
+ rocksdb_read_options_t options = {
1210
+ .version = 0,
1211
+ };
1212
+
1213
+ if (snapshot) {
1214
+ err = js_get_arraybuffer_info(env, snapshot.value(), options.snapshot);
1215
+ assert(err == 0);
1216
+ }
1217
+
1218
+ err = rocksdb_read(&db->handle, &req->handle, req->reads, len, &options, rocksdb_native__on_read);
1219
+ assert(err == 0);
1220
+ }
1221
+
1222
+ static js_arraybuffer_t
1223
+ rocksdb_native_write_init(js_env_t *env) {
1224
+ int err;
1225
+
1226
+ js_arraybuffer_t handle;
1227
+
1228
+ rocksdb_native_write_batch_t *req;
1229
+ err = js_create_arraybuffer(env, req, handle);
1230
+ assert(err == 0);
1231
+
1232
+ req->env = env;
1233
+ req->handle.data = req;
1234
+
1235
+ return handle;
1236
+ }
1237
+
1238
+ static js_arraybuffer_t
1239
+ rocksdb_native_write_buffer(
1240
+ js_env_t *env,
1241
+ js_arraybuffer_span_of_t<rocksdb_native_write_batch_t, 1> req,
1242
+ uint32_t capacity
1243
+ ) {
1244
+ int err;
1245
+
1246
+ js_arraybuffer_t handle;
1247
+
1248
+ rocksdb_write_t *writes;
1249
+ err = js_create_arraybuffer(env, capacity, writes, handle);
1250
+ assert(err == 0);
1251
+
1252
+ req->capacity = capacity;
1253
+ req->writes = writes;
1254
+
1255
+ return handle;
1256
+ }
1257
+
1258
+ static void
1259
+ rocksdb_native__on_write(rocksdb_write_batch_t *handle, int status) {
1260
+ int err;
1261
+
1262
+ assert(status == 0);
1263
+
1264
+ rocksdb_native_write_batch_t *req = (rocksdb_native_write_batch_t *) handle->data;
1265
+
1266
+ rocksdb_native_t *db = (rocksdb_native_t *) req->handle.req.db;
1267
+
1268
+ js_env_t *env = req->env;
1269
+
1270
+ if (db->exiting) {
1271
+ req->on_write.reset();
1272
+ req->ctx.reset();
1273
+ } else {
1274
+ js_handle_scope_t *scope;
1275
+ err = js_open_handle_scope(env, &scope);
1276
+ assert(err == 0);
1277
+
1278
+ std::optional<js_string_t> error;
1279
+
1280
+ if (req->handle.error) {
1281
+ err = js_create_string(env, req->handle.error, error.emplace());
1282
+ assert(err == 0);
1283
+ }
1284
+
1285
+ js_receiver_t ctx;
1286
+ err = js_get_reference_value(env, req->ctx, ctx);
1287
+ assert(err == 0);
1288
+
1289
+ cb_on_write_t cb;
1290
+ err = js_get_reference_value(env, req->on_write, cb);
1291
+ assert(err == 0);
1292
+
1293
+ req->on_write.reset();
1294
+ req->ctx.reset();
1295
+
1296
+ js_call_function_with_checkpoint(env, cb, ctx, error);
1297
+
1298
+ err = js_close_handle_scope(env, scope);
1299
+ assert(err == 0);
1300
+ }
1301
+ }
1302
+
1303
+ static void
1304
+ rocksdb_native_write(
1305
+ js_env_t *env,
1306
+ js_arraybuffer_span_of_t<rocksdb_native_t, 1> db,
1307
+ js_arraybuffer_span_of_t<rocksdb_native_write_batch_t, 1> req,
1308
+ js_array_t operations,
1309
+ js_receiver_t ctx,
1310
+ cb_on_write_t on_write
1311
+ ) {
1312
+ int err;
1313
+
1314
+ err = js_create_reference(env, ctx, req->ctx);
1315
+ assert(err == 0);
1316
+
1317
+ err = js_create_reference(env, on_write, req->on_write);
1318
+ assert(err == 0);
1319
+
1320
+ std::vector<js_object_t> elements;
1321
+
1322
+ err = js_get_array_elements(env, operations, elements);
1323
+ assert(err == 0);
1324
+
1325
+ const auto len = elements.size();
1326
+
1327
+ for (uint32_t i = 0; i < len; i++) {
1328
+ js_object_t write = elements[i];
1329
+
1330
+ rocksdb_write_type_t type;
1331
+ err = js_get_property(env, write, "type", reinterpret_cast<uint32_t &>(type));
1332
+ assert(err == 0);
1333
+
1334
+ req->writes[i].type = type;
1335
+
1336
+ js_arraybuffer_t column_family_property;
1337
+ err = js_get_property(env, write, "columnFamily", column_family_property);
1338
+ assert(err == 0);
1339
+
1340
+ rocksdb_native_column_family_t *column_family;
1341
+ err = js_get_arraybuffer_info(env, column_family_property, column_family);
1342
+ assert(err == 0);
1343
+
1344
+ req->writes[i].column_family = column_family->handle;
1345
+
1346
+ js_typedarray_t property;
1347
+
1348
+ switch (type) {
1349
+ case rocksdb_put: {
1350
+ rocksdb_slice_t *key = &req->writes[i].key;
1351
+
1352
+ err = js_get_property(env, write, "key", property);
1353
+ assert(err == 0);
1354
+
1355
+ err = js_get_typedarray_info(env, property, key->data, key->len);
1356
+ assert(err == 0);
1357
+
1358
+ rocksdb_slice_t *value = &req->writes[i].value;
1359
+
1360
+ err = js_get_property(env, write, "value", property);
1361
+ assert(err == 0);
1362
+
1363
+ err = js_get_typedarray_info(env, property, value->data, value->len);
1364
+ assert(err == 0);
1365
+ break;
1366
+ }
1367
+
1368
+ case rocksdb_delete: {
1369
+ rocksdb_slice_t *key = &req->writes[i].key;
1370
+
1371
+ err = js_get_property(env, write, "key", property);
1372
+ assert(err == 0);
1373
+
1374
+ err = js_get_typedarray_info(env, property, key->data, key->len);
1375
+ assert(err == 0);
1376
+ break;
1377
+ }
1378
+
1379
+ case rocksdb_delete_range: {
1380
+ rocksdb_slice_t *start = &req->writes[i].start;
1381
+
1382
+ err = js_get_property(env, write, "start", property);
1383
+ assert(err == 0);
1384
+
1385
+ err = js_get_typedarray_info(env, property, start->data, start->len);
1386
+ assert(err == 0);
1387
+
1388
+ rocksdb_slice_t *end = &req->writes[i].end;
1389
+
1390
+ err = js_get_property(env, write, "end", property);
1391
+ assert(err == 0);
1392
+
1393
+ err = js_get_typedarray_info(env, property, end->data, end->len);
1394
+ assert(err == 0);
1395
+ break;
1396
+ }
1397
+ }
1398
+ }
1399
+
1400
+ err = rocksdb_write(&db->handle, &req->handle, req->writes, len, NULL, rocksdb_native__on_write);
1401
+ assert(err == 0);
1402
+ }
1403
+
1404
+ static void
1405
+ rocksdb_native__on_flush(rocksdb_flush_t *handle, int status) {
1406
+ int err;
1407
+
1408
+ assert(status == 0);
1409
+
1410
+ rocksdb_native_flush_t *req = (rocksdb_native_flush_t *) handle->data;
1411
+
1412
+ rocksdb_native_t *db = (rocksdb_native_t *) req->handle.req.db;
1413
+
1414
+ js_env_t *env = req->env;
1415
+
1416
+ if (db->exiting) {
1417
+ req->on_flush.reset();
1418
+ req->ctx.reset();
1419
+ } else {
1420
+ js_handle_scope_t *scope;
1421
+ err = js_open_handle_scope(env, &scope);
1422
+ assert(err == 0);
1423
+
1424
+ std::optional<js_string_t> error;
1425
+
1426
+ if (req->handle.error) {
1427
+ err = js_create_string(env, req->handle.error, error.emplace());
1428
+ assert(err == 0);
1429
+ }
1430
+
1431
+ js_receiver_t ctx;
1432
+ err = js_get_reference_value(env, req->ctx, ctx);
1433
+ assert(err == 0);
1434
+
1435
+ cb_on_flush_t cb;
1436
+ err = js_get_reference_value(env, req->on_flush, cb);
1437
+ assert(err == 0);
1438
+
1439
+ req->on_flush.reset();
1440
+ req->ctx.reset();
1441
+
1442
+ js_call_function_with_checkpoint(env, cb, ctx, error);
1443
+
1444
+ err = js_close_handle_scope(env, scope);
1445
+ assert(err == 0);
1446
+ }
1447
+ }
1448
+
1449
+ static js_arraybuffer_t
1450
+ rocksdb_native_flush(
1451
+ js_env_t *env,
1452
+ js_arraybuffer_span_of_t<rocksdb_native_t, 1> db,
1453
+ js_arraybuffer_span_of_t<rocksdb_native_column_family_t, 1> column_family,
1454
+ js_receiver_t ctx,
1455
+ cb_on_flush_t on_flush
1456
+ ) {
1457
+ int err;
1458
+
1459
+ js_arraybuffer_t handle;
1460
+
1461
+ rocksdb_native_flush_t *req;
1462
+ err = js_create_arraybuffer(env, req, handle);
1463
+ assert(err == 0);
1464
+
1465
+ req->env = env;
1466
+ req->handle.data = (void *) req;
1467
+
1468
+ err = js_create_reference(env, ctx, req->ctx);
1469
+ assert(err == 0);
1470
+
1471
+ err = js_create_reference(env, on_flush, req->on_flush);
1472
+ assert(err == 0);
1473
+
1474
+ err = rocksdb_flush(&db->handle, &req->handle, column_family->handle, NULL, rocksdb_native__on_flush);
1475
+ assert(err == 0);
1476
+
1477
+ return handle;
1478
+ }
1479
+
1480
+ static js_arraybuffer_t
1481
+ rocksdb_native_snapshot_create(js_env_t *env, js_arraybuffer_span_of_t<rocksdb_native_t, 1> db) {
1482
+ int err;
1483
+
1484
+ js_arraybuffer_t handle;
1485
+
1486
+ rocksdb_native_snapshot_t *snapshot;
1487
+ err = js_create_arraybuffer(env, snapshot, handle);
1488
+ assert(err == 0);
1489
+
1490
+ err = rocksdb_snapshot_create(&db->handle, &snapshot->handle);
1491
+ assert(err == 0);
1492
+
1493
+ return handle;
1494
+ }
1495
+
1496
+ static void
1497
+ rocksdb_native_snapshot_destroy(js_env_t *env, js_arraybuffer_span_of_t<rocksdb_native_snapshot_t, 1> snapshot) {
1498
+ rocksdb_snapshot_destroy(&snapshot->handle);
1499
+ }
1500
+
1501
+ static js_value_t *
1502
+ rocksdb_native_exports(js_env_t *env, js_value_t *exports) {
1503
+ int err;
1504
+
1505
+ #define V(name, fn) \
1506
+ err = js_set_property<fn>(env, exports, name); \
1507
+ assert(err == 0);
1508
+
1509
+ V("init", rocksdb_native_init)
1510
+ V("open", rocksdb_native_open)
1511
+ V("close", rocksdb_native_close)
1512
+ V("suspend", rocksdb_native_suspend)
1513
+ V("resume", rocksdb_native_resume)
1514
+
1515
+ V("columnFamilyInit", rocksdb_native_column_family_init)
1516
+ V("columnFamilyDestroy", rocksdb_native_column_family_destroy)
1517
+
1518
+ V("readInit", rocksdb_native_read_init)
1519
+ V("readBuffer", rocksdb_native_read_buffer)
1520
+ V("read", rocksdb_native_read)
1521
+
1522
+ V("writeInit", rocksdb_native_write_init)
1523
+ V("writeBuffer", rocksdb_native_write_buffer)
1524
+ V("write", rocksdb_native_write)
1525
+
1526
+ V("iteratorInit", rocksdb_native_iterator_init)
1527
+ V("iteratorBuffer", rocksdb_native_iterator_buffer)
1528
+ V("iteratorOpen", rocksdb_native_iterator_open)
1529
+ V("iteratorClose", rocksdb_native_iterator_close)
1530
+ V("iteratorRead", rocksdb_native_iterator_read)
1531
+
1532
+ V("flush", rocksdb_native_flush)
1533
+
1534
+ V("snapshotCreate", rocksdb_native_snapshot_create)
1535
+ V("snapshotDestroy", rocksdb_native_snapshot_destroy)
1536
+ #undef V
1537
+
1538
+ #define V(name, n) \
1539
+ { \
1540
+ js_value_t *val; \
1541
+ err = js_create_uint32(env, n, &val); \
1542
+ assert(err == 0); \
1543
+ err = js_set_named_property(env, exports, name, val); \
1544
+ assert(err == 0); \
1545
+ }
1546
+
1547
+ V("GET", rocksdb_get)
1548
+ V("PUT", rocksdb_put)
1549
+ V("DELETE", rocksdb_delete)
1550
+ V("DELETE_RANGE", rocksdb_delete_range)
1551
+ #undef V
1552
+
1553
+ return exports;
1554
+ }
1555
+
1556
+ BARE_MODULE(rocksdb_native, rocksdb_native_exports)