rocksdb-native 3.11.1 → 3.11.3

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.
package/binding.cc CHANGED
@@ -1,3 +1,5 @@
1
+ #include <set>
2
+
1
3
  #include <assert.h>
2
4
  #include <bare.h>
3
5
  #include <js.h>
@@ -21,14 +23,23 @@ using rocksdb_native_on_iterator_read_t = js_function_t<void, js_receiver_t, std
21
23
  using rocksdb_native_on_compact_range_t = js_function_t<void, js_receiver_t, std::optional<js_string_t>>;
22
24
  using rocksdb_native_on_approximate_size_t = js_function_t<void, js_receiver_t, std::optional<js_string_t>, uint64_t>;
23
25
 
26
+ struct rocksdb_native_t;
27
+
24
28
  struct rocksdb_native_column_family_t {
25
29
  rocksdb_column_family_t *handle;
26
30
  rocksdb_column_family_descriptor_t descriptor;
27
31
 
28
- rocksdb_t *db;
32
+ rocksdb_native_t *db;
29
33
 
30
- js_env_t *env;
31
- js_persistent_t<js_receiver_t> ctx;
34
+ js_persistent_t<js_arraybuffer_t> ctx;
35
+ };
36
+
37
+ struct rocksdb_native_snapshot_t {
38
+ rocksdb_snapshot_t handle;
39
+
40
+ rocksdb_native_t *db;
41
+
42
+ js_persistent_t<js_arraybuffer_t> ctx;
32
43
  };
33
44
 
34
45
  struct rocksdb_native_t {
@@ -41,6 +52,9 @@ struct rocksdb_native_t {
41
52
  bool closing;
42
53
  bool exiting;
43
54
 
55
+ std::set<rocksdb_native_column_family_t *> column_families;
56
+ std::set<rocksdb_native_snapshot_t *> snapshots;
57
+
44
58
  js_deferred_teardown_t *teardown;
45
59
  };
46
60
 
@@ -59,6 +73,7 @@ struct rocksdb_native_close_t {
59
73
 
60
74
  js_env_t *env;
61
75
  js_persistent_t<js_receiver_t> ctx;
76
+ js_persistent_t<js_arraybuffer_t> self;
62
77
  js_persistent_t<rocksdb_native_on_close_t> on_close;
63
78
  };
64
79
 
@@ -90,7 +105,7 @@ struct rocksdb_native_iterator_t {
90
105
  js_persistent_t<rocksdb_native_on_iterator_close_t> on_close;
91
106
  js_persistent_t<rocksdb_native_on_iterator_read_t> on_read;
92
107
 
93
- bool active;
108
+ bool closing;
94
109
  bool exiting;
95
110
 
96
111
  js_deferred_teardown_t *teardown;
@@ -130,10 +145,6 @@ struct rocksdb_native_flush_t {
130
145
  js_persistent_t<rocksdb_native_column_family_t> column_family;
131
146
  };
132
147
 
133
- struct rocksdb_native_snapshot_t {
134
- rocksdb_snapshot_t handle;
135
- };
136
-
137
148
  struct rocksdb_native_compact_range_t {
138
149
  rocksdb_compact_range_t handle;
139
150
 
@@ -170,9 +181,6 @@ rocksdb_native__try_create_external_arraybuffer(js_env_t *env, char *data, size_
170
181
  return 0;
171
182
  }
172
183
 
173
- static void
174
- rocksdb_native__on_column_family_teardown(void *data);
175
-
176
184
  static void
177
185
  rocksdb_native__on_open(rocksdb_open_t *handle, int status) {
178
186
  int err;
@@ -186,50 +194,43 @@ rocksdb_native__on_open(rocksdb_open_t *handle, int status) {
186
194
  auto env = req->env;
187
195
 
188
196
  auto descriptors = handle->column_families;
189
-
190
197
  auto handles = handle->handles;
191
198
 
192
- if (db->exiting) {
193
- req->on_open.reset();
194
- req->ctx.reset();
195
- } else {
196
- js_handle_scope_t *scope;
197
- err = js_open_handle_scope(env, &scope);
198
- assert(err == 0);
199
-
200
- js_receiver_t ctx;
201
- err = js_get_reference_value(env, req->ctx, ctx);
202
- assert(err == 0);
203
-
204
- rocksdb_native_on_open_t cb;
205
- err = js_get_reference_value(env, req->on_open, cb);
206
- assert(err == 0);
199
+ js_handle_scope_t *scope;
200
+ err = js_open_handle_scope(env, &scope);
201
+ assert(err == 0);
207
202
 
208
- js_array_t column_families;
209
- err = js_get_reference_value(env, req->column_families, column_families);
210
- assert(err == 0);
203
+ js_receiver_t ctx;
204
+ err = js_get_reference_value(env, req->ctx, ctx);
205
+ assert(err == 0);
211
206
 
212
- req->on_open.reset();
213
- req->column_families.reset();
214
- req->ctx.reset();
207
+ rocksdb_native_on_open_t cb;
208
+ err = js_get_reference_value(env, req->on_open, cb);
209
+ assert(err == 0);
215
210
 
216
- std::optional<js_string_t> error;
211
+ js_array_t column_families;
212
+ err = js_get_reference_value(env, req->column_families, column_families);
213
+ assert(err == 0);
217
214
 
218
- if (req->handle.error) {
219
- err = js_create_string(env, req->handle.error, error.emplace());
220
- assert(err == 0);
221
- }
215
+ req->on_open.reset();
216
+ req->column_families.reset();
217
+ req->ctx.reset();
222
218
 
223
- rocksdb_column_family_t **handles = handle->handles;
219
+ std::optional<js_string_t> error;
224
220
 
225
- if (req->handle.error == nullptr) {
226
- std::vector<js_arraybuffer_t> elements;
227
- err = js_get_array_elements(env, column_families, elements);
228
- assert(err == 0);
221
+ if (req->handle.error) {
222
+ err = js_create_string(env, req->handle.error, error.emplace());
223
+ assert(err == 0);
224
+ } else {
225
+ std::vector<js_arraybuffer_t> elements;
226
+ err = js_get_array_elements(env, column_families, elements);
227
+ assert(err == 0);
229
228
 
230
- const auto len = elements.size();
229
+ const auto len = elements.size();
231
230
 
232
- for (uint32_t i = 0; i < len; i++) {
231
+ for (uint32_t i = 0; i < len; i++) {
232
+ if (db->exiting) rocksdb_column_family_destroy(&db->handle, handles[i]);
233
+ else {
233
234
  js_arraybuffer_t handle = elements[i];
234
235
 
235
236
  rocksdb_native_column_family_t *column_family;
@@ -238,22 +239,49 @@ rocksdb_native__on_open(rocksdb_open_t *handle, int status) {
238
239
 
239
240
  column_family->handle = handles[i];
240
241
 
241
- err = js_create_reference(env, ctx, column_family->ctx);
242
+ err = js_create_reference(env, handle, column_family->ctx);
242
243
  assert(err == 0);
243
244
 
244
- err = js_add_teardown_callback(env, rocksdb_native__on_column_family_teardown, column_family);
245
- assert(err == 0);
245
+ db->column_families.insert(column_family);
246
246
  }
247
247
  }
248
+ }
249
+
250
+ if (!db->exiting) {
251
+ err = js_call_function_with_checkpoint(env, cb, ctx, error);
252
+ (void) err;
253
+ }
254
+
255
+ err = js_close_handle_scope(env, scope);
256
+ assert(err == 0);
248
257
 
249
- js_call_function_with_checkpoint(env, cb, ctx, error);
258
+ delete[] descriptors;
259
+ delete[] handles;
260
+ }
250
261
 
251
- err = js_close_handle_scope(env, scope);
262
+ static void
263
+ rocksdb_native__on_idle(rocksdb_t *handle) {
264
+ int err;
265
+
266
+ auto db = reinterpret_cast<rocksdb_native_t *>(handle);
267
+
268
+ for (auto &column_family : db->column_families) {
269
+ err = rocksdb_column_family_destroy(&column_family->db->handle, column_family->handle);
252
270
  assert(err == 0);
253
271
 
254
- delete[] descriptors;
255
- delete[] handles;
272
+ column_family->handle = nullptr;
273
+
274
+ column_family->ctx.reset();
256
275
  }
276
+
277
+ for (auto &snapshot : db->snapshots) {
278
+ rocksdb_snapshot_destroy(&snapshot->handle);
279
+
280
+ snapshot->ctx.reset();
281
+ }
282
+
283
+ db->column_families.~set();
284
+ db->snapshots.~set();
257
285
  }
258
286
 
259
287
  static void
@@ -270,61 +298,82 @@ rocksdb_native__on_close(rocksdb_close_t *handle, int status) {
270
298
 
271
299
  auto teardown = db->teardown;
272
300
 
273
- if (db->exiting) {
274
- if (db->closing) {
275
- req->on_close.reset();
276
- req->ctx.reset();
277
- } else {
278
- free(req);
279
- }
280
-
281
- db->ctx.reset();
282
- } else {
283
- js_handle_scope_t *scope;
284
- err = js_open_handle_scope(env, &scope);
285
- assert(err == 0);
286
-
287
- js_receiver_t ctx;
288
- err = js_get_reference_value(env, req->ctx, ctx);
289
- assert(err == 0);
301
+ js_handle_scope_t *scope;
302
+ err = js_open_handle_scope(env, &scope);
303
+ assert(err == 0);
290
304
 
291
- rocksdb_native_on_close_t cb;
292
- err = js_get_reference_value(env, req->on_close, cb);
293
- assert(err == 0);
305
+ js_receiver_t ctx;
306
+ err = js_get_reference_value(env, req->ctx, ctx);
307
+ assert(err == 0);
294
308
 
295
- req->on_close.reset();
296
- req->ctx.reset();
309
+ rocksdb_native_on_close_t cb;
310
+ err = js_get_reference_value(env, req->on_close, cb);
311
+ assert(err == 0);
297
312
 
298
- db->ctx.reset();
313
+ req->on_close.reset();
314
+ req->self.reset();
315
+ req->ctx.reset();
299
316
 
300
- js_call_function_with_checkpoint(env, cb, ctx);
317
+ db->ctx.reset();
301
318
 
302
- err = js_close_handle_scope(env, scope);
303
- assert(err == 0);
319
+ if (!db->exiting) {
320
+ err = js_call_function_with_checkpoint(env, cb, ctx);
321
+ (void) err;
304
322
  }
305
323
 
324
+ err = js_close_handle_scope(env, scope);
325
+ assert(err == 0);
326
+
306
327
  err = js_finish_deferred_teardown_callback(teardown);
307
328
  assert(err == 0);
308
329
  }
309
330
 
310
331
  static void
311
- rocksdb_native__on_teardown(js_deferred_teardown_t *handle, void *data) {
332
+ rocksdb_native__on_teardown(js_deferred_teardown_t *teardown, void *data) {
312
333
  int err;
313
334
 
314
335
  auto db = reinterpret_cast<rocksdb_native_t *>(data);
315
336
 
316
- auto env = db->env;
317
-
318
337
  db->exiting = true;
319
338
 
320
339
  if (db->closing) return;
321
340
 
322
- auto req = reinterpret_cast<rocksdb_native_close_t *>(malloc(sizeof(rocksdb_native_close_t)));
341
+ auto env = db->env;
342
+
343
+ js_handle_scope_t *scope;
344
+ err = js_open_handle_scope(env, &scope);
345
+ assert(err == 0);
346
+
347
+ js_arraybuffer_t handle;
348
+
349
+ rocksdb_native_close_t *req;
350
+ err = js_create_arraybuffer(env, req, handle);
351
+ assert(err == 0);
323
352
 
324
353
  req->env = env;
325
354
  req->handle.data = req;
326
355
 
327
- err = rocksdb_close(&db->handle, &req->handle, rocksdb_native__on_close);
356
+ err = rocksdb_close(&db->handle, &req->handle, rocksdb_native__on_idle, rocksdb_native__on_close);
357
+ assert(err == 0);
358
+
359
+ js_receiver_t ctx;
360
+ err = js_get_null(env, static_cast<js_value_t **>(ctx));
361
+ assert(err == 0);
362
+
363
+ rocksdb_native_on_close_t on_close;
364
+ err = js_get_null(env, static_cast<js_value_t **>(on_close));
365
+ assert(err == 0);
366
+
367
+ err = js_create_reference(env, ctx, req->ctx);
368
+ assert(err == 0);
369
+
370
+ err = js_create_reference(env, handle, req->self);
371
+ assert(err == 0);
372
+
373
+ err = js_create_reference(env, on_close, req->on_close);
374
+ assert(err == 0);
375
+
376
+ err = js_close_handle_scope(env, scope);
328
377
  assert(err == 0);
329
378
  }
330
379
 
@@ -345,10 +394,6 @@ rocksdb_native_init(
345
394
  ) {
346
395
  int err;
347
396
 
348
- uv_loop_t *loop;
349
- err = js_get_env_loop(env, &loop);
350
- assert(err == 0);
351
-
352
397
  js_arraybuffer_t handle;
353
398
 
354
399
  rocksdb_native_t *db;
@@ -359,6 +404,9 @@ rocksdb_native_init(
359
404
  db->closing = false;
360
405
  db->exiting = false;
361
406
 
407
+ new (&db->column_families) std::set<rocksdb_native_column_family_t *>();
408
+ new (&db->snapshots) std::set<rocksdb_native_snapshot_t *>();
409
+
362
410
  db->options = (rocksdb_options_t) {
363
411
  3,
364
412
  read_only,
@@ -375,15 +423,6 @@ rocksdb_native_init(
375
423
  -1,
376
424
  };
377
425
 
378
- err = rocksdb_init(loop, &db->handle);
379
-
380
- if (err < 0) {
381
- err = js_throw_error(env, uv_err_name(err), uv_strerror(err));
382
- assert(err == 0);
383
-
384
- throw js_pending_exception;
385
- }
386
-
387
426
  return handle;
388
427
  }
389
428
 
@@ -417,11 +456,15 @@ rocksdb_native_open(
417
456
 
418
457
  memcpy(&column_families[i], &column_family->descriptor, sizeof(rocksdb_column_family_descriptor_t));
419
458
 
420
- column_family->db = &db->handle;
459
+ column_family->db = db;
421
460
  }
422
461
 
423
462
  auto handles = new rocksdb_column_family_t *[len];
424
463
 
464
+ uv_loop_t *loop;
465
+ err = js_get_env_loop(env, &loop);
466
+ assert(err == 0);
467
+
425
468
  js_arraybuffer_t handle;
426
469
 
427
470
  rocksdb_native_open_t *req;
@@ -433,7 +476,7 @@ rocksdb_native_open(
433
476
 
434
477
  db->options.lock = lock;
435
478
 
436
- err = rocksdb_open(&db->handle, &req->handle, path, &db->options, column_families, handles, len, rocksdb_native__on_open);
479
+ err = rocksdb_open(loop, &db->handle, &req->handle, path, &db->options, column_families, handles, len, nullptr, rocksdb_native__on_open);
437
480
 
438
481
  if (err < 0) {
439
482
  err = js_throw_error(env, uv_err_name(err), uv_strerror(err));
@@ -484,7 +527,7 @@ rocksdb_native_close(
484
527
  req->env = env;
485
528
  req->handle.data = req;
486
529
 
487
- err = rocksdb_close(&db->handle, &req->handle, rocksdb_native__on_close);
530
+ err = rocksdb_close(&db->handle, &req->handle, rocksdb_native__on_idle, rocksdb_native__on_close);
488
531
 
489
532
  if (err < 0) {
490
533
  err = js_throw_error(env, uv_err_name(err), uv_strerror(err));
@@ -496,6 +539,9 @@ rocksdb_native_close(
496
539
  err = js_create_reference(env, ctx, req->ctx);
497
540
  assert(err == 0);
498
541
 
542
+ err = js_create_reference(env, handle, req->self);
543
+ assert(err == 0);
544
+
499
545
  err = js_create_reference(env, on_close, req->on_close);
500
546
  assert(err == 0);
501
547
 
@@ -516,36 +562,35 @@ rocksdb_native__on_suspend(rocksdb_suspend_t *handle, int status) {
516
562
 
517
563
  auto env = req->env;
518
564
 
519
- auto teardown = db->teardown;
520
-
521
- if (db->exiting) {
522
- req->on_suspend.reset();
523
- req->ctx.reset();
524
- } else {
525
- js_handle_scope_t *scope;
526
- err = js_open_handle_scope(env, &scope);
527
- assert(err == 0);
565
+ js_handle_scope_t *scope;
566
+ err = js_open_handle_scope(env, &scope);
567
+ assert(err == 0);
528
568
 
529
- js_receiver_t ctx;
530
- err = js_get_reference_value(env, req->ctx, ctx);
531
- assert(err == 0);
569
+ js_receiver_t ctx;
570
+ err = js_get_reference_value(env, req->ctx, ctx);
571
+ assert(err == 0);
532
572
 
533
- rocksdb_native_on_suspend_t cb;
534
- err = js_get_reference_value(env, req->on_suspend, cb);
535
- assert(err == 0);
573
+ rocksdb_native_on_suspend_t cb;
574
+ err = js_get_reference_value(env, req->on_suspend, cb);
575
+ assert(err == 0);
536
576
 
537
- std::optional<js_string_t> error;
577
+ req->on_suspend.reset();
578
+ req->ctx.reset();
538
579
 
539
- if (req->handle.error) {
540
- err = js_create_string(env, req->handle.error, error.emplace());
541
- assert(err == 0);
542
- }
580
+ std::optional<js_string_t> error;
543
581
 
544
- js_call_function_with_checkpoint(env, cb, ctx, error);
545
-
546
- err = js_close_handle_scope(env, scope);
582
+ if (req->handle.error) {
583
+ err = js_create_string(env, req->handle.error, error.emplace());
547
584
  assert(err == 0);
548
585
  }
586
+
587
+ if (!db->exiting) {
588
+ err = js_call_function_with_checkpoint(env, cb, ctx, error);
589
+ (void) err;
590
+ }
591
+
592
+ err = js_close_handle_scope(env, scope);
593
+ assert(err == 0);
549
594
  }
550
595
 
551
596
  static js_arraybuffer_t
@@ -596,39 +641,35 @@ rocksdb_native__on_resume(rocksdb_resume_t *handle, int status) {
596
641
 
597
642
  auto env = req->env;
598
643
 
599
- auto teardown = db->teardown;
600
-
601
- if (db->exiting) {
602
- req->on_resume.reset();
603
- req->ctx.reset();
604
- } else {
605
- js_handle_scope_t *scope;
606
- err = js_open_handle_scope(env, &scope);
607
- assert(err == 0);
608
-
609
- js_receiver_t ctx;
610
- err = js_get_reference_value(env, req->ctx, ctx);
611
- assert(err == 0);
612
-
613
- rocksdb_native_on_resume_t cb;
614
- err = js_get_reference_value(env, req->on_resume, cb);
615
- assert(err == 0);
644
+ js_handle_scope_t *scope;
645
+ err = js_open_handle_scope(env, &scope);
646
+ assert(err == 0);
616
647
 
617
- req->on_resume.reset();
618
- req->ctx.reset();
648
+ js_receiver_t ctx;
649
+ err = js_get_reference_value(env, req->ctx, ctx);
650
+ assert(err == 0);
619
651
 
620
- std::optional<js_string_t> error;
652
+ rocksdb_native_on_resume_t cb;
653
+ err = js_get_reference_value(env, req->on_resume, cb);
654
+ assert(err == 0);
621
655
 
622
- if (req->handle.error) {
623
- err = js_create_string(env, req->handle.error, error.emplace());
624
- assert(err == 0);
625
- }
656
+ req->on_resume.reset();
657
+ req->ctx.reset();
626
658
 
627
- js_call_function_with_checkpoint(env, cb, ctx, error);
659
+ std::optional<js_string_t> error;
628
660
 
629
- err = js_close_handle_scope(env, scope);
661
+ if (req->handle.error) {
662
+ err = js_create_string(env, req->handle.error, error.emplace());
630
663
  assert(err == 0);
631
664
  }
665
+
666
+ if (!db->exiting) {
667
+ err = js_call_function_with_checkpoint(env, cb, ctx, error);
668
+ (void) err;
669
+ }
670
+
671
+ err = js_close_handle_scope(env, scope);
672
+ assert(err == 0);
632
673
  }
633
674
 
634
675
  static js_arraybuffer_t
@@ -667,20 +708,6 @@ rocksdb_native_resume(
667
708
  return handle;
668
709
  }
669
710
 
670
- static void
671
- rocksdb_native__on_column_family_teardown(void *data) {
672
- int err;
673
-
674
- auto column_family = reinterpret_cast<rocksdb_native_column_family_t *>(data);
675
-
676
- auto env = column_family->env;
677
-
678
- err = rocksdb_column_family_destroy(column_family->db, column_family->handle);
679
- assert(err == 0);
680
-
681
- column_family->ctx.reset();
682
- }
683
-
684
711
  static js_arraybuffer_t
685
712
  rocksdb_native_column_family_init(
686
713
  js_env_t *env,
@@ -735,7 +762,6 @@ rocksdb_native_column_family_init(
735
762
  err = js_create_arraybuffer(env, column_family, handle);
736
763
  assert(err == 0);
737
764
 
738
- column_family->env = env;
739
765
  column_family->db = nullptr;
740
766
  column_family->handle = nullptr;
741
767
 
@@ -775,15 +801,14 @@ rocksdb_native_column_family_destroy(
775
801
 
776
802
  if (column_family->handle == nullptr) return;
777
803
 
778
- err = rocksdb_column_family_destroy(column_family->db, column_family->handle);
804
+ err = rocksdb_column_family_destroy(&column_family->db->handle, column_family->handle);
779
805
  assert(err == 0);
780
806
 
781
- err = js_remove_teardown_callback(env, rocksdb_native__on_column_family_teardown, column_family);
782
- assert(err == 0);
807
+ column_family->handle = nullptr;
783
808
 
784
- column_family->ctx.reset();
809
+ column_family->db->column_families.erase(column_family);
785
810
 
786
- column_family->handle = nullptr;
811
+ column_family->ctx.reset();
787
812
  }
788
813
 
789
814
  static js_arraybuffer_t
@@ -797,7 +822,7 @@ rocksdb_native_iterator_init(js_env_t *env) {
797
822
  assert(err == 0);
798
823
 
799
824
  req->env = env;
800
- req->active = false;
825
+ req->closing = false;
801
826
  req->exiting = false;
802
827
  req->handle.data = req;
803
828
 
@@ -837,48 +862,42 @@ rocksdb_native__on_iterator_close(rocksdb_iterator_t *handle, int status) {
837
862
 
838
863
  auto req = reinterpret_cast<rocksdb_native_iterator_t *>(handle->data);
839
864
 
840
- req->active = false;
841
-
842
865
  auto env = req->env;
843
866
 
844
867
  auto teardown = req->teardown;
845
868
 
846
- if (req->exiting) {
847
- req->on_open.reset();
848
- req->on_close.reset();
849
- req->on_read.reset();
850
- req->ctx.reset();
851
- } else {
852
- js_handle_scope_t *scope;
853
- err = js_open_handle_scope(env, &scope);
854
- assert(err == 0);
855
-
856
- js_receiver_t ctx;
857
- err = js_get_reference_value(env, req->ctx, ctx);
858
- assert(err == 0);
859
-
860
- rocksdb_native_on_iterator_close_t cb;
861
- err = js_get_reference_value(env, req->on_close, cb);
862
- assert(err == 0);
869
+ js_handle_scope_t *scope;
870
+ err = js_open_handle_scope(env, &scope);
871
+ assert(err == 0);
863
872
 
864
- req->on_open.reset();
865
- req->on_close.reset();
866
- req->on_read.reset();
867
- req->ctx.reset();
873
+ js_receiver_t ctx;
874
+ err = js_get_reference_value(env, req->ctx, ctx);
875
+ assert(err == 0);
868
876
 
869
- std::optional<js_string_t> error;
877
+ rocksdb_native_on_iterator_close_t cb;
878
+ err = js_get_reference_value(env, req->on_close, cb);
879
+ assert(err == 0);
870
880
 
871
- if (req->handle.error) {
872
- err = js_create_string(env, req->handle.error, error.emplace());
873
- assert(err == 0);
874
- }
881
+ req->on_open.reset();
882
+ req->on_close.reset();
883
+ req->on_read.reset();
884
+ req->ctx.reset();
875
885
 
876
- js_call_function_with_checkpoint(env, cb, ctx, error);
886
+ std::optional<js_string_t> error;
877
887
 
878
- err = js_close_handle_scope(env, scope);
888
+ if (req->handle.error) {
889
+ err = js_create_string(env, req->handle.error, error.emplace());
879
890
  assert(err == 0);
880
891
  }
881
892
 
893
+ if (!req->exiting) {
894
+ err = js_call_function_with_checkpoint(env, cb, ctx, error);
895
+ (void) err;
896
+ }
897
+
898
+ err = js_close_handle_scope(env, scope);
899
+ assert(err == 0);
900
+
882
901
  err = js_finish_deferred_teardown_callback(teardown);
883
902
  assert(err == 0);
884
903
  }
@@ -891,49 +910,45 @@ rocksdb_native__on_iterator_open(rocksdb_iterator_t *handle, int status) {
891
910
 
892
911
  auto req = reinterpret_cast<rocksdb_native_iterator_t *>(handle->data);
893
912
 
894
- req->active = false;
895
-
896
- if (req->exiting) {
897
- err = rocksdb_iterator_close(&req->handle, rocksdb_native__on_iterator_close);
898
- assert(err == 0);
899
- } else {
900
- auto env = req->env;
901
-
902
- js_handle_scope_t *scope;
903
- err = js_open_handle_scope(env, &scope);
904
- assert(err == 0);
905
-
906
- js_receiver_t ctx;
907
- err = js_get_reference_value(env, req->ctx, ctx);
908
- assert(err == 0);
913
+ auto env = req->env;
909
914
 
910
- rocksdb_native_on_iterator_open_t cb;
911
- err = js_get_reference_value(env, req->on_open, cb);
912
- assert(err == 0);
915
+ js_handle_scope_t *scope;
916
+ err = js_open_handle_scope(env, &scope);
917
+ assert(err == 0);
913
918
 
914
- std::optional<js_string_t> error;
919
+ js_receiver_t ctx;
920
+ err = js_get_reference_value(env, req->ctx, ctx);
921
+ assert(err == 0);
915
922
 
916
- if (req->handle.error) {
917
- err = js_create_string(env, req->handle.error, error.emplace());
918
- assert(err == 0);
919
- }
923
+ rocksdb_native_on_iterator_open_t cb;
924
+ err = js_get_reference_value(env, req->on_open, cb);
925
+ assert(err == 0);
920
926
 
921
- js_call_function_with_checkpoint(env, cb, ctx, error);
927
+ std::optional<js_string_t> error;
922
928
 
923
- err = js_close_handle_scope(env, scope);
929
+ if (req->handle.error) {
930
+ err = js_create_string(env, req->handle.error, error.emplace());
924
931
  assert(err == 0);
925
932
  }
933
+
934
+ if (!req->exiting) {
935
+ err = js_call_function_with_checkpoint(env, cb, ctx, error);
936
+ (void) err;
937
+ }
938
+
939
+ err = js_close_handle_scope(env, scope);
940
+ assert(err == 0);
926
941
  }
927
942
 
928
943
  static void
929
- rocksdb_native__on_iterator_teardown(js_deferred_teardown_t *handle, void *data) {
944
+ rocksdb_native__on_iterator_teardown(js_deferred_teardown_t *teardown, void *data) {
930
945
  int err;
931
946
 
932
947
  auto req = reinterpret_cast<rocksdb_native_iterator_t *>(data);
933
948
 
934
949
  req->exiting = true;
935
950
 
936
- if (req->active) return;
951
+ if (req->closing) return;
937
952
 
938
953
  err = rocksdb_iterator_close(&req->handle, rocksdb_native__on_iterator_close);
939
954
  assert(err == 0);
@@ -951,7 +966,7 @@ rocksdb_native_iterator_open(
951
966
  js_typedarray_t<> lte,
952
967
  bool reverse,
953
968
  bool keys_only,
954
- std::optional<js_arraybuffer_t> snapshot,
969
+ std::optional<js_arraybuffer_span_of_t<rocksdb_native_snapshot_t, 1>> snapshot,
955
970
  js_receiver_t ctx,
956
971
  rocksdb_native_on_iterator_open_t on_open,
957
972
  rocksdb_native_on_iterator_close_t on_close,
@@ -979,10 +994,7 @@ rocksdb_native_iterator_open(
979
994
  .keys_only = keys_only
980
995
  };
981
996
 
982
- if (snapshot) {
983
- err = js_get_arraybuffer_info(env, snapshot.value(), options.snapshot);
984
- assert(err == 0);
985
- }
997
+ if (snapshot) options.snapshot = &snapshot.value()->handle;
986
998
 
987
999
  err = rocksdb_iterator_open(&db->handle, &req->handle, column_family->handle, range, &options, rocksdb_native__on_iterator_open);
988
1000
 
@@ -993,8 +1005,6 @@ rocksdb_native_iterator_open(
993
1005
  throw js_pending_exception;
994
1006
  }
995
1007
 
996
- req->active = true;
997
-
998
1008
  err = js_create_reference(env, ctx, req->ctx);
999
1009
  assert(err == 0);
1000
1010
 
@@ -1024,7 +1034,7 @@ rocksdb_native_iterator_close(js_env_t *env, js_arraybuffer_span_of_t<rocksdb_na
1024
1034
  throw js_pending_exception;
1025
1035
  }
1026
1036
 
1027
- req->active = true;
1037
+ req->closing = true;
1028
1038
  }
1029
1039
 
1030
1040
  static void
@@ -1035,76 +1045,66 @@ rocksdb_native__on_iterator_read(rocksdb_iterator_t *handle, int status) {
1035
1045
 
1036
1046
  auto req = reinterpret_cast<rocksdb_native_iterator_t *>(handle->data);
1037
1047
 
1038
- req->active = false;
1039
-
1040
1048
  auto db = reinterpret_cast<rocksdb_native_t *>(req->handle.req.db);
1041
1049
 
1042
- size_t len = req->handle.len;
1043
-
1044
- if (db->exiting) {
1045
- if (status == 0 && req->handle.error == nullptr) {
1046
- for (size_t i = 0; i < len; i++) {
1047
- js_value_t *result;
1050
+ auto len = req->handle.len;
1048
1051
 
1049
- rocksdb_slice_destroy(&req->keys[i]);
1050
-
1051
- rocksdb_slice_destroy(&req->values[i]);
1052
- }
1053
- }
1052
+ auto env = req->env;
1054
1053
 
1055
- err = rocksdb_iterator_close(&req->handle, rocksdb_native__on_iterator_close);
1056
- assert(err == 0);
1057
- } else {
1058
- auto env = req->env;
1054
+ js_handle_scope_t *scope;
1055
+ err = js_open_handle_scope(env, &scope);
1056
+ assert(err == 0);
1059
1057
 
1060
- js_handle_scope_t *scope;
1061
- err = js_open_handle_scope(env, &scope);
1062
- assert(err == 0);
1058
+ js_receiver_t ctx;
1059
+ err = js_get_reference_value(env, req->ctx, ctx);
1060
+ assert(err == 0);
1063
1061
 
1064
- js_receiver_t ctx;
1065
- err = js_get_reference_value(env, req->ctx, ctx);
1066
- assert(err == 0);
1062
+ rocksdb_native_on_iterator_read_t cb;
1063
+ err = js_get_reference_value(env, req->on_read, cb);
1064
+ assert(err == 0);
1067
1065
 
1068
- rocksdb_native_on_iterator_read_t cb;
1069
- err = js_get_reference_value(env, req->on_read, cb);
1070
- assert(err == 0);
1066
+ std::optional<js_string_t> error;
1071
1067
 
1072
- std::optional<js_string_t> error;
1068
+ std::vector<js_arraybuffer_t> keys;
1069
+ keys.reserve(len);
1073
1070
 
1074
- std::vector<js_arraybuffer_t> keys;
1075
- keys.reserve(len);
1071
+ std::vector<js_arraybuffer_t> values;
1072
+ values.reserve(len);
1076
1073
 
1077
- std::vector<js_arraybuffer_t> values;
1078
- values.reserve(len);
1074
+ if (req->handle.error) {
1075
+ err = js_create_string(env, req->handle.error, error.emplace());
1076
+ assert(err == 0);
1077
+ } else {
1078
+ for (size_t i = 0; i < len; i++) {
1079
+ rocksdb_slice_t *key = &req->keys[i];
1080
+ rocksdb_slice_t *value = &req->values[i];
1079
1081
 
1080
- if (req->handle.error) {
1081
- err = js_create_string(env, req->handle.error, error.emplace());
1082
- assert(err == 0);
1083
- } else {
1084
- for (size_t i = 0; i < len; i++) {
1082
+ if (req->exiting) {
1083
+ rocksdb_slice_destroy(key);
1084
+ rocksdb_slice_destroy(value);
1085
+ } else {
1085
1086
  js_arraybuffer_t result;
1086
1087
 
1087
- rocksdb_slice_t *key = &req->keys[i];
1088
-
1089
1088
  err = rocksdb_native__try_create_external_arraybuffer(env, const_cast<char *>(key->data), key->len, result);
1090
1089
  assert(err == 0);
1091
1090
 
1092
1091
  keys.push_back(result);
1093
1092
 
1094
- rocksdb_slice_t *value = &req->values[i];
1095
-
1096
1093
  err = rocksdb_native__try_create_external_arraybuffer(env, const_cast<char *>(value->data), value->len, result);
1097
1094
  assert(err == 0);
1098
1095
 
1099
1096
  values.push_back(result);
1100
1097
  }
1101
1098
  }
1099
+ }
1102
1100
 
1103
- js_call_function_with_checkpoint(env, cb, ctx, error, keys, values);
1104
-
1105
- err = js_close_handle_scope(env, scope);
1106
- assert(err == 0);
1101
+ if (!req->exiting) {
1102
+ err = js_call_function_with_checkpoint(env, cb, ctx, error, keys, values);
1103
+ (void) err;
1107
1104
  }
1105
+
1106
+ err = js_close_handle_scope(env, scope);
1107
+ assert(err == 0);
1108
1108
  }
1109
1109
 
1110
1110
  static void
@@ -1123,8 +1123,6 @@ rocksdb_native_iterator_read(
1123
1123
 
1124
1124
  throw js_pending_exception;
1125
1125
  }
1126
-
1127
- req->active = true;
1128
1126
  }
1129
1127
 
1130
1128
  static js_arraybuffer_t
@@ -1173,57 +1171,56 @@ rocksdb_native__on_read(rocksdb_read_batch_t *handle, int status) {
1173
1171
 
1174
1172
  auto db = reinterpret_cast<rocksdb_native_t *>(req->handle.req.db);
1175
1173
 
1174
+ auto len = req->handle.len;
1175
+
1176
1176
  auto env = req->env;
1177
1177
 
1178
- size_t len = req->handle.len;
1178
+ js_handle_scope_t *scope;
1179
+ err = js_open_handle_scope(env, &scope);
1180
+ assert(err == 0);
1179
1181
 
1180
- if (db->exiting) {
1181
- if (status == 0) {
1182
- for (size_t i = 0; i < len; i++) {
1183
- char *error = req->handle.errors[i];
1182
+ js_receiver_t ctx;
1183
+ err = js_get_reference_value(env, req->ctx, ctx);
1184
+ assert(err == 0);
1184
1185
 
1185
- if (error) continue;
1186
+ rocksdb_native_on_read_t cb;
1187
+ err = js_get_reference_value(env, req->on_read, cb);
1188
+ assert(err == 0);
1186
1189
 
1187
- rocksdb_slice_destroy(&req->reads[i].value);
1188
- }
1189
- }
1190
+ req->on_read.reset();
1191
+ req->ctx.reset();
1190
1192
 
1191
- req->on_read.reset();
1192
- req->ctx.reset();
1193
- } else {
1194
- js_handle_scope_t *scope;
1195
- err = js_open_handle_scope(env, &scope);
1196
- assert(err == 0);
1193
+ js_array_t errors;
1194
+ err = js_create_array(env, len, errors);
1195
+ assert(err == 0);
1197
1196
 
1198
- js_array_t errors;
1199
- err = js_create_array(env, len, errors);
1200
- assert(err == 0);
1197
+ js_array_t values;
1198
+ err = js_create_array(env, len, values);
1199
+ assert(err == 0);
1201
1200
 
1202
- js_array_t values;
1203
- err = js_create_array(env, len, values);
1204
- assert(err == 0);
1201
+ for (size_t i = 0; i < len; i++) {
1202
+ char *error = req->handle.errors[i];
1205
1203
 
1206
- for (size_t i = 0; i < len; i++) {
1207
- char *error = req->handle.errors[i];
1204
+ if (error) {
1205
+ js_string_t result;
1208
1206
 
1209
- if (error) {
1210
- js_string_t result;
1207
+ err = js_create_string(env, error, result);
1208
+ assert(err == 0);
1211
1209
 
1212
- err = js_create_string(env, error, result);
1213
- assert(err == 0);
1210
+ err = js_set_element(env, errors, i, result);
1211
+ assert(err == 0);
1212
+ } else {
1213
+ rocksdb_slice_t *value = &req->reads[i].value;
1214
1214
 
1215
- err = js_set_element(env, errors, i, result);
1216
- assert(err == 0);
1217
- } else {
1215
+ if (db->exiting) rocksdb_slice_destroy(value);
1216
+ else {
1218
1217
  js_arraybuffer_t result;
1219
1218
 
1220
- rocksdb_slice_t *slice = &req->reads[i].value;
1221
-
1222
- if (slice->data == nullptr && slice->len == size_t(-1)) {
1219
+ if (value->data == nullptr && value->len == size_t(-1)) {
1223
1220
  err = js_get_null(env, static_cast<js_value_t **>(result));
1224
1221
  assert(err == 0);
1225
1222
  } else {
1226
- err = rocksdb_native__try_create_external_arraybuffer(env, const_cast<char *>(slice->data), slice->len, result);
1223
+ err = rocksdb_native__try_create_external_arraybuffer(env, const_cast<char *>(value->data), value->len, result);
1227
1224
  assert(err == 0);
1228
1225
  }
1229
1226
 
@@ -1231,23 +1228,15 @@ rocksdb_native__on_read(rocksdb_read_batch_t *handle, int status) {
1231
1228
  assert(err == 0);
1232
1229
  }
1233
1230
  }
1231
+ }
1234
1232
 
1235
- js_receiver_t ctx;
1236
- err = js_get_reference_value(env, req->ctx, ctx);
1237
- assert(err == 0);
1238
-
1239
- rocksdb_native_on_read_t cb;
1240
- err = js_get_reference_value(env, req->on_read, cb);
1241
- assert(err == 0);
1242
-
1243
- req->on_read.reset();
1244
- req->ctx.reset();
1245
-
1246
- js_call_function_with_checkpoint(env, cb, ctx, errors, values);
1247
-
1248
- err = js_close_handle_scope(env, scope);
1249
- assert(err == 0);
1233
+ if (!db->exiting) {
1234
+ err = js_call_function_with_checkpoint(env, cb, ctx, errors, values);
1235
+ (void) err;
1250
1236
  }
1237
+
1238
+ err = js_close_handle_scope(env, scope);
1239
+ assert(err == 0);
1251
1240
  }
1252
1241
 
1253
1242
  static void
@@ -1256,7 +1245,7 @@ rocksdb_native_read(
1256
1245
  js_arraybuffer_span_of_t<rocksdb_native_t, 1> db,
1257
1246
  js_arraybuffer_span_of_t<rocksdb_native_read_batch_t, 1> req,
1258
1247
  js_array_t operations,
1259
- std::optional<js_arraybuffer_t> snapshot,
1248
+ std::optional<js_arraybuffer_span_of_t<rocksdb_native_snapshot_t, 1>> snapshot,
1260
1249
  bool async_io,
1261
1250
  bool fill_cache,
1262
1251
  js_receiver_t ctx,
@@ -1311,10 +1300,7 @@ rocksdb_native_read(
1311
1300
  .fill_cache = fill_cache
1312
1301
  };
1313
1302
 
1314
- if (snapshot) {
1315
- err = js_get_arraybuffer_info(env, snapshot.value(), options.snapshot);
1316
- assert(err == 0);
1317
- }
1303
+ if (snapshot) options.snapshot = &snapshot.value()->handle;
1318
1304
 
1319
1305
  err = rocksdb_read(&db->handle, &req->handle, req->reads, len, &options, rocksdb_native__on_read);
1320
1306
 
@@ -1380,37 +1366,35 @@ rocksdb_native__on_write(rocksdb_write_batch_t *handle, int status) {
1380
1366
 
1381
1367
  auto env = req->env;
1382
1368
 
1383
- if (db->exiting) {
1384
- req->on_write.reset();
1385
- req->ctx.reset();
1386
- } else {
1387
- js_handle_scope_t *scope;
1388
- err = js_open_handle_scope(env, &scope);
1389
- assert(err == 0);
1390
-
1391
- std::optional<js_string_t> error;
1392
-
1393
- if (req->handle.error) {
1394
- err = js_create_string(env, req->handle.error, error.emplace());
1395
- assert(err == 0);
1396
- }
1369
+ js_handle_scope_t *scope;
1370
+ err = js_open_handle_scope(env, &scope);
1371
+ assert(err == 0);
1397
1372
 
1398
- js_receiver_t ctx;
1399
- err = js_get_reference_value(env, req->ctx, ctx);
1400
- assert(err == 0);
1373
+ js_receiver_t ctx;
1374
+ err = js_get_reference_value(env, req->ctx, ctx);
1375
+ assert(err == 0);
1401
1376
 
1402
- rocksdb_native_on_write_t cb;
1403
- err = js_get_reference_value(env, req->on_write, cb);
1404
- assert(err == 0);
1377
+ rocksdb_native_on_write_t cb;
1378
+ err = js_get_reference_value(env, req->on_write, cb);
1379
+ assert(err == 0);
1405
1380
 
1406
- req->on_write.reset();
1407
- req->ctx.reset();
1381
+ req->on_write.reset();
1382
+ req->ctx.reset();
1408
1383
 
1409
- js_call_function_with_checkpoint(env, cb, ctx, error);
1384
+ std::optional<js_string_t> error;
1410
1385
 
1411
- err = js_close_handle_scope(env, scope);
1386
+ if (req->handle.error) {
1387
+ err = js_create_string(env, req->handle.error, error.emplace());
1412
1388
  assert(err == 0);
1413
1389
  }
1390
+
1391
+ if (!db->exiting) {
1392
+ err = js_call_function_with_checkpoint(env, cb, ctx, error);
1393
+ (void) err;
1394
+ }
1395
+
1396
+ err = js_close_handle_scope(env, scope);
1397
+ assert(err == 0);
1414
1398
  }
1415
1399
 
1416
1400
  static void
@@ -1531,37 +1515,35 @@ rocksdb_native__on_flush(rocksdb_flush_t *handle, int status) {
1531
1515
 
1532
1516
  auto env = req->env;
1533
1517
 
1534
- if (db->exiting) {
1535
- req->on_flush.reset();
1536
- req->ctx.reset();
1537
- } else {
1538
- js_handle_scope_t *scope;
1539
- err = js_open_handle_scope(env, &scope);
1540
- assert(err == 0);
1541
-
1542
- std::optional<js_string_t> error;
1543
-
1544
- if (req->handle.error) {
1545
- err = js_create_string(env, req->handle.error, error.emplace());
1546
- assert(err == 0);
1547
- }
1518
+ js_handle_scope_t *scope;
1519
+ err = js_open_handle_scope(env, &scope);
1520
+ assert(err == 0);
1548
1521
 
1549
- js_receiver_t ctx;
1550
- err = js_get_reference_value(env, req->ctx, ctx);
1551
- assert(err == 0);
1522
+ js_receiver_t ctx;
1523
+ err = js_get_reference_value(env, req->ctx, ctx);
1524
+ assert(err == 0);
1552
1525
 
1553
- rocksdb_native_on_flush_t cb;
1554
- err = js_get_reference_value(env, req->on_flush, cb);
1555
- assert(err == 0);
1526
+ rocksdb_native_on_flush_t cb;
1527
+ err = js_get_reference_value(env, req->on_flush, cb);
1528
+ assert(err == 0);
1556
1529
 
1557
- req->on_flush.reset();
1558
- req->ctx.reset();
1530
+ req->on_flush.reset();
1531
+ req->ctx.reset();
1559
1532
 
1560
- js_call_function_with_checkpoint(env, cb, ctx, error);
1533
+ std::optional<js_string_t> error;
1561
1534
 
1562
- err = js_close_handle_scope(env, scope);
1535
+ if (req->handle.error) {
1536
+ err = js_create_string(env, req->handle.error, error.emplace());
1563
1537
  assert(err == 0);
1564
1538
  }
1539
+
1540
+ if (!db->exiting) {
1541
+ err = js_call_function_with_checkpoint(env, cb, ctx, error);
1542
+ (void) err;
1543
+ }
1544
+
1545
+ err = js_close_handle_scope(env, scope);
1546
+ assert(err == 0);
1565
1547
  }
1566
1548
 
1567
1549
  static js_arraybuffer_t
@@ -1613,37 +1595,35 @@ rocksdb_native__on_compact_range(rocksdb_compact_range_t *handle, int status) {
1613
1595
 
1614
1596
  auto env = req->env;
1615
1597
 
1616
- if (db->exiting) {
1617
- req->on_compact_range.reset();
1618
- req->ctx.reset();
1619
- } else {
1620
- js_handle_scope_t *scope;
1621
- err = js_open_handle_scope(env, &scope);
1622
- assert(err == 0);
1623
-
1624
- std::optional<js_string_t> error;
1625
-
1626
- if (req->handle.error) {
1627
- err = js_create_string(env, req->handle.error, error.emplace());
1628
- assert(err == 0);
1629
- }
1598
+ js_handle_scope_t *scope;
1599
+ err = js_open_handle_scope(env, &scope);
1600
+ assert(err == 0);
1630
1601
 
1631
- js_receiver_t ctx;
1632
- err = js_get_reference_value(env, req->ctx, ctx);
1633
- assert(err == 0);
1602
+ js_receiver_t ctx;
1603
+ err = js_get_reference_value(env, req->ctx, ctx);
1604
+ assert(err == 0);
1634
1605
 
1635
- rocksdb_native_on_compact_range_t cb;
1636
- err = js_get_reference_value(env, req->on_compact_range, cb);
1637
- assert(err == 0);
1606
+ rocksdb_native_on_compact_range_t cb;
1607
+ err = js_get_reference_value(env, req->on_compact_range, cb);
1608
+ assert(err == 0);
1638
1609
 
1639
- req->on_compact_range.reset();
1640
- req->ctx.reset();
1610
+ req->on_compact_range.reset();
1611
+ req->ctx.reset();
1641
1612
 
1642
- js_call_function_with_checkpoint(env, cb, ctx, error);
1613
+ std::optional<js_string_t> error;
1643
1614
 
1644
- err = js_close_handle_scope(env, scope);
1615
+ if (req->handle.error) {
1616
+ err = js_create_string(env, req->handle.error, error.emplace());
1645
1617
  assert(err == 0);
1646
1618
  }
1619
+
1620
+ if (!db->exiting) {
1621
+ err = js_call_function_with_checkpoint(env, cb, ctx, error);
1622
+ (void) err;
1623
+ }
1624
+
1625
+ err = js_close_handle_scope(env, scope);
1626
+ assert(err == 0);
1647
1627
  }
1648
1628
 
1649
1629
  static js_arraybuffer_t
@@ -1711,37 +1691,35 @@ rocksdb_native__on_approximate_size(rocksdb_approximate_size_t *handle, int stat
1711
1691
 
1712
1692
  auto env = req->env;
1713
1693
 
1714
- if (db->exiting) {
1715
- req->on_approximate_size.reset();
1716
- req->ctx.reset();
1717
- } else {
1718
- js_handle_scope_t *scope;
1719
- err = js_open_handle_scope(env, &scope);
1720
- assert(err == 0);
1721
-
1722
- std::optional<js_string_t> error;
1723
-
1724
- if (req->handle.error) {
1725
- err = js_create_string(env, req->handle.error, error.emplace());
1726
- assert(err == 0);
1727
- }
1694
+ js_handle_scope_t *scope;
1695
+ err = js_open_handle_scope(env, &scope);
1696
+ assert(err == 0);
1728
1697
 
1729
- js_receiver_t ctx;
1730
- err = js_get_reference_value(env, req->ctx, ctx);
1731
- assert(err == 0);
1698
+ js_receiver_t ctx;
1699
+ err = js_get_reference_value(env, req->ctx, ctx);
1700
+ assert(err == 0);
1732
1701
 
1733
- rocksdb_native_on_approximate_size_t cb;
1734
- err = js_get_reference_value(env, req->on_approximate_size, cb);
1735
- assert(err == 0);
1702
+ rocksdb_native_on_approximate_size_t cb;
1703
+ err = js_get_reference_value(env, req->on_approximate_size, cb);
1704
+ assert(err == 0);
1736
1705
 
1737
- req->on_approximate_size.reset();
1738
- req->ctx.reset();
1706
+ req->on_approximate_size.reset();
1707
+ req->ctx.reset();
1739
1708
 
1740
- js_call_function_with_checkpoint(env, cb, ctx, error, req->handle.result);
1709
+ std::optional<js_string_t> error;
1741
1710
 
1742
- err = js_close_handle_scope(env, scope);
1711
+ if (req->handle.error) {
1712
+ err = js_create_string(env, req->handle.error, error.emplace());
1743
1713
  assert(err == 0);
1744
1714
  }
1715
+
1716
+ if (!db->exiting) {
1717
+ err = js_call_function_with_checkpoint(env, cb, ctx, error, req->handle.result);
1718
+ (void) err;
1719
+ }
1720
+
1721
+ err = js_close_handle_scope(env, scope);
1722
+ assert(err == 0);
1745
1723
  }
1746
1724
 
1747
1725
  static js_arraybuffer_t
@@ -1801,13 +1779,6 @@ rocksdb_native_approximate_size(
1801
1779
  return handle;
1802
1780
  }
1803
1781
 
1804
- static void
1805
- rocksdb_native__on_snapshot_teardown(void *data) {
1806
- auto snapshot = reinterpret_cast<rocksdb_native_snapshot_t *>(data);
1807
-
1808
- rocksdb_snapshot_destroy(&snapshot->handle);
1809
- }
1810
-
1811
1782
  static js_arraybuffer_t
1812
1783
  rocksdb_native_snapshot_create(js_env_t *env, js_arraybuffer_span_of_t<rocksdb_native_t, 1> db) {
1813
1784
  int err;
@@ -1818,6 +1789,8 @@ rocksdb_native_snapshot_create(js_env_t *env, js_arraybuffer_span_of_t<rocksdb_n
1818
1789
  err = js_create_arraybuffer(env, snapshot, handle);
1819
1790
  assert(err == 0);
1820
1791
 
1792
+ snapshot->db = db;
1793
+
1821
1794
  err = rocksdb_snapshot_create(&db->handle, &snapshot->handle);
1822
1795
 
1823
1796
  if (err < 0) {
@@ -1827,9 +1800,11 @@ rocksdb_native_snapshot_create(js_env_t *env, js_arraybuffer_span_of_t<rocksdb_n
1827
1800
  throw js_pending_exception;
1828
1801
  }
1829
1802
 
1830
- err = js_add_teardown_callback(env, rocksdb_native__on_snapshot_teardown, snapshot);
1803
+ err = js_create_reference(env, handle, snapshot->ctx);
1831
1804
  assert(err == 0);
1832
1805
 
1806
+ db->snapshots.insert(snapshot);
1807
+
1833
1808
  return handle;
1834
1809
  }
1835
1810
 
@@ -1839,8 +1814,9 @@ rocksdb_native_snapshot_destroy(js_env_t *env, js_arraybuffer_span_of_t<rocksdb_
1839
1814
 
1840
1815
  rocksdb_snapshot_destroy(&snapshot->handle);
1841
1816
 
1842
- err = js_remove_teardown_callback(env, rocksdb_native__on_snapshot_teardown, snapshot);
1843
- assert(err == 0);
1817
+ snapshot->db->snapshots.erase(snapshot);
1818
+
1819
+ snapshot->ctx.reset();
1844
1820
  }
1845
1821
 
1846
1822
  static js_value_t *