@nxtedition/rocksdb 13.0.2 → 13.1.0

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
@@ -18,6 +18,8 @@
18
18
  #include <rocksdb/table.h>
19
19
  #include <rocksdb/write_batch.h>
20
20
 
21
+ #include <re2/re2.h>
22
+
21
23
  #include <iostream>
22
24
  #include <memory>
23
25
  #include <optional>
@@ -410,6 +412,7 @@ class Iterator final : public BaseIterator {
410
412
  bool first_ = true;
411
413
  const Encoding keyEncoding_;
412
414
  const Encoding valueEncoding_;
415
+ std::unique_ptr<re2::RE2> expr_;
413
416
 
414
417
  public:
415
418
  Iterator(Database* database,
@@ -425,13 +428,19 @@ class Iterator final : public BaseIterator {
425
428
  const size_t highWaterMarkBytes,
426
429
  Encoding keyEncoding = Encoding::Invalid,
427
430
  Encoding valueEncoding = Encoding::Invalid,
428
- rocksdb::ReadOptions readOptions = {})
431
+ rocksdb::ReadOptions readOptions = {},
432
+ const std::string& selector = "")
429
433
  : BaseIterator(database, column, reverse, lt, lte, gt, gte, limit, readOptions),
430
434
  keys_(keys),
431
435
  values_(values),
432
436
  highWaterMarkBytes_(highWaterMarkBytes),
433
437
  keyEncoding_(keyEncoding),
434
- valueEncoding_(valueEncoding) {}
438
+ valueEncoding_(valueEncoding) {
439
+ if (selector != "") {
440
+ // TODO (fix): Pool selectors?
441
+ expr_.reset(new re2::RE2(selector));
442
+ }
443
+ }
435
444
 
436
445
  void Seek(const rocksdb::Slice& target) override {
437
446
  first_ = true;
@@ -504,18 +513,21 @@ class Iterator final : public BaseIterator {
504
513
  readOptions.ignore_range_deletions = false;
505
514
  NAPI_STATUS_THROWS(GetProperty(env, options, "ignoreRangeDeletions", readOptions.ignore_range_deletions));
506
515
 
507
- uint32_t timeout = 0;
508
- NAPI_STATUS_THROWS(GetProperty(env, options, "timeout", timeout));
516
+ std::string selector;
517
+ NAPI_STATUS_THROWS(GetProperty(env, options, "selector", selector));
518
+
519
+ // uint32_t timeout = 0;
520
+ // NAPI_STATUS_THROWS(GetProperty(env, options, "timeout", timeout));
509
521
 
510
- readOptions.deadline = timeout
511
- ? std::chrono::microseconds(database->db->GetEnv()->NowMicros() + timeout * 1000)
512
- : std::chrono::microseconds::zero();
522
+ // readOptions.deadline = timeout
523
+ // ? std::chrono::microseconds(database->db->GetEnv()->NowMicros() + timeout * 1000)
524
+ // : std::chrono::microseconds::zero();
513
525
 
514
526
  return std::make_unique<Iterator>(database, column, reverse, keys, values, limit, lt, lte, gt, gte,
515
- highWaterMarkBytes, keyEncoding, valueEncoding, readOptions);
527
+ highWaterMarkBytes, keyEncoding, valueEncoding, readOptions, selector);
516
528
  }
517
529
 
518
- napi_value nextv(napi_env env, uint32_t count, napi_value callback) {
530
+ napi_value nextv(napi_env env, uint32_t count, uint32_t timeout, napi_value callback) {
519
531
  struct State {
520
532
  std::vector<rocksdb::PinnableSlice> keys;
521
533
  std::vector<rocksdb::PinnableSlice> values;
@@ -528,18 +540,18 @@ class Iterator final : public BaseIterator {
528
540
  state.keys.reserve(count);
529
541
  state.values.reserve(count);
530
542
 
543
+ const auto deadline = timeout
544
+ ? database_->db->GetEnv()->NowMicros() + timeout * 1000
545
+ : 0;
546
+
531
547
  size_t bytesRead = 0;
532
- while (true) {
548
+ for (int n = 0; n < count; n++) {
533
549
  if (!first_) {
534
550
  Next();
535
551
  } else {
536
552
  first_ = false;
537
553
  }
538
554
 
539
- if (Status().IsTimedOut()) {
540
- break;
541
- }
542
-
543
555
  ROCKS_STATUS_RETURN(Status());
544
556
 
545
557
  if (!Valid() || !Increment()) {
@@ -547,33 +559,35 @@ class Iterator final : public BaseIterator {
547
559
  break;
548
560
  }
549
561
 
550
- if (keys_ && values_) {
551
- rocksdb::PinnableSlice k;
552
- k.PinSelf(CurrentKey());
553
- bytesRead += k.size();
554
- state.keys.push_back(std::move(k));
555
-
556
- rocksdb::PinnableSlice v;
557
- v.PinSelf(CurrentValue());
558
- bytesRead += v.size();
559
- state.values.push_back(std::move(v));
560
- } else if (keys_) {
561
- rocksdb::PinnableSlice k;
562
- k.PinSelf(CurrentKey());
563
- bytesRead += k.size();
564
- state.keys.push_back(std::move(k));
565
- } else if (values_) {
566
- rocksdb::PinnableSlice v;
567
- v.PinSelf(CurrentValue());
568
- bytesRead += v.size();
569
- state.values.push_back(std::move(v));
570
- } else {
571
- assert(false);
562
+ if (!expr_ || re2::RE2::PartialMatch(CurrentKey().ToStringView(), *expr_)) {
563
+ if (keys_ && values_) {
564
+ rocksdb::PinnableSlice k;
565
+ k.PinSelf(CurrentKey());
566
+ state.keys.push_back(std::move(k));
567
+
568
+ rocksdb::PinnableSlice v;
569
+ v.PinSelf(CurrentValue());
570
+ state.values.push_back(std::move(v));
571
+ } else if (keys_) {
572
+ rocksdb::PinnableSlice k;
573
+ k.PinSelf(CurrentKey());
574
+ state.keys.push_back(std::move(k));
575
+ } else if (values_) {
576
+ rocksdb::PinnableSlice v;
577
+ v.PinSelf(CurrentValue());
578
+ state.values.push_back(std::move(v));
579
+ } else {
580
+ assert(false);
581
+ }
582
+ state.count += 1;
572
583
  }
573
584
 
574
- state.count += 1;
585
+ bytesRead += CurrentKey().size() + CurrentValue().size();
586
+ if (bytesRead > highWaterMarkBytes_) {
587
+ break;
588
+ }
575
589
 
576
- if (bytesRead > highWaterMarkBytes_ || state.count >= count) {
590
+ if (deadline > 0 && database_->db->GetEnv()->NowMicros() > deadline) {
577
591
  break;
578
592
  }
579
593
  }
@@ -620,26 +634,26 @@ class Iterator final : public BaseIterator {
620
634
  return 0;
621
635
  }
622
636
 
623
- napi_value nextv(napi_env env, uint32_t count) {
637
+ napi_value nextv(napi_env env, uint32_t count, uint32_t timeout = 0) {
624
638
  napi_value finished;
625
639
  NAPI_STATUS_THROWS(napi_get_boolean(env, false, &finished));
626
640
 
627
641
  napi_value rows;
628
642
  NAPI_STATUS_THROWS(napi_create_array(env, &rows));
629
643
 
644
+ const auto deadline = timeout
645
+ ? database_->db->GetEnv()->NowMicros() + timeout * 1000
646
+ : 0;
647
+
630
648
  size_t idx = 0;
631
649
  size_t bytesRead = 0;
632
- while (true) {
650
+ for (int n = 0; n < count; n++) {
633
651
  if (!first_) {
634
652
  Next();
635
653
  } else {
636
654
  first_ = false;
637
655
  }
638
656
 
639
- if (Status().IsTimedOut()) {
640
- break;
641
- }
642
-
643
657
  ROCKS_STATUS_THROWS_NAPI(Status());
644
658
 
645
659
  if (!Valid() || !Increment()) {
@@ -647,33 +661,37 @@ class Iterator final : public BaseIterator {
647
661
  break;
648
662
  }
649
663
 
650
- napi_value key;
651
- napi_value val;
664
+ if (!expr_ || re2::RE2::PartialMatch(CurrentKey().ToStringView(), *expr_)) {
665
+ napi_value key;
666
+ napi_value val;
667
+
668
+ if (keys_ && values_) {
669
+ const auto k = CurrentKey();
670
+ const auto v = CurrentValue();
671
+ NAPI_STATUS_THROWS(Convert(env, &k, keyEncoding_, key));
672
+ NAPI_STATUS_THROWS(Convert(env, &v, valueEncoding_, val));
673
+ } else if (keys_) {
674
+ const auto k = CurrentKey();
675
+ NAPI_STATUS_THROWS(Convert(env, &k, keyEncoding_, key));
676
+ NAPI_STATUS_THROWS(napi_get_undefined(env, &val));
677
+ } else if (values_) {
678
+ const auto v = CurrentValue();
679
+ NAPI_STATUS_THROWS(napi_get_undefined(env, &key));
680
+ NAPI_STATUS_THROWS(Convert(env, &v, valueEncoding_, val));
681
+ } else {
682
+ assert(false);
683
+ }
652
684
 
653
- if (keys_ && values_) {
654
- const auto k = CurrentKey();
655
- const auto v = CurrentValue();
656
- NAPI_STATUS_THROWS(Convert(env, &k, keyEncoding_, key));
657
- NAPI_STATUS_THROWS(Convert(env, &v, valueEncoding_, val));
658
- bytesRead += k.size() + v.size();
659
- } else if (keys_) {
660
- const auto k = CurrentKey();
661
- NAPI_STATUS_THROWS(Convert(env, &k, keyEncoding_, key));
662
- NAPI_STATUS_THROWS(napi_get_undefined(env, &val));
663
- bytesRead += k.size();
664
- } else if (values_) {
665
- const auto v = CurrentValue();
666
- NAPI_STATUS_THROWS(napi_get_undefined(env, &key));
667
- NAPI_STATUS_THROWS(Convert(env, &v, valueEncoding_, val));
668
- bytesRead += v.size();
669
- } else {
670
- assert(false);
685
+ NAPI_STATUS_THROWS(napi_set_element(env, rows, idx++, key));
686
+ NAPI_STATUS_THROWS(napi_set_element(env, rows, idx++, val));
671
687
  }
672
688
 
673
- NAPI_STATUS_THROWS(napi_set_element(env, rows, idx++, key));
674
- NAPI_STATUS_THROWS(napi_set_element(env, rows, idx++, val));
689
+ bytesRead += CurrentKey().size() + CurrentValue().size();
690
+ if (bytesRead > highWaterMarkBytes_) {
691
+ break;
692
+ }
675
693
 
676
- if (bytesRead > highWaterMarkBytes_ || idx / 2 >= count) {
694
+ if (deadline > 0 && database_->db->GetEnv()->NowMicros() > deadline) {
677
695
  break;
678
696
  }
679
697
  }
@@ -776,7 +794,12 @@ NAPI_METHOD(db_get_location) {
776
794
  NAPI_METHOD(db_query) {
777
795
  NAPI_ARGV(2);
778
796
 
779
- return Iterator::create(env, argv[0], argv[1])->nextv(env, std::numeric_limits<uint32_t>::max());
797
+ try {
798
+ return Iterator::create(env, argv[0], argv[1])->nextv(env, std::numeric_limits<uint32_t>::max());
799
+ } catch (const std::exception& e) {
800
+ napi_throw_error(env, nullptr, e.what());
801
+ return nullptr;
802
+ }
780
803
  }
781
804
 
782
805
  template <typename T, typename U>
@@ -786,50 +809,50 @@ napi_status InitOptions(napi_env env, T& columnOptions, const U& options) {
786
809
  uint64_t memtable_memory_budget = 256 * 1024 * 1024;
787
810
  NAPI_STATUS_RETURN(GetProperty(env, options, "memtableMemoryBudget", memtable_memory_budget));
788
811
 
789
- std::optional<std::string> compactionOpt;
790
- NAPI_STATUS_RETURN(GetProperty(env, options, "compaction", compactionOpt));
791
- if (compactionOpt) {
792
- if (*compactionOpt == "universal") {
793
- columnOptions.write_buffer_size = memtable_memory_budget / 4;
794
- // merge two memtables when flushing to L0
795
- columnOptions.min_write_buffer_number_to_merge = 2;
796
- // this means we'll use 50% extra memory in the worst case, but will reduce
797
- // write stalls.
798
- columnOptions.max_write_buffer_number = 6;
799
- // universal style compaction
800
- columnOptions.compaction_style = rocksdb::kCompactionStyleUniversal;
801
- columnOptions.compaction_options_universal.compression_size_percent = 80;
802
- } else if (*compactionOpt == "level") {
803
- columnOptions.write_buffer_size = static_cast<size_t>(memtable_memory_budget / 4);
804
- // merge two memtables when flushing to L0
805
- columnOptions.min_write_buffer_number_to_merge = 2;
806
- // this means we'll use 50% extra memory in the worst case, but will reduce
807
- // write stalls.
808
- columnOptions.max_write_buffer_number = 6;
809
- // start flushing L0->L1 as soon as possible. each file on level0 is
810
- // (memtable_memory_budget / 2). This will flush level 0 when it's bigger than
811
- // memtable_memory_budget.
812
- columnOptions.level0_file_num_compaction_trigger = 2;
813
- // doesn't really matter much, but we don't want to create too many files
814
- columnOptions.target_file_size_base = memtable_memory_budget / 8;
815
- // make Level1 size equal to Level0 size, so that L0->L1 compactions are fast
816
- columnOptions.max_bytes_for_level_base = memtable_memory_budget;
817
-
818
- // level style compaction
819
- columnOptions.compaction_style = rocksdb::kCompactionStyleLevel;
820
-
821
- // only compress levels >= 2
822
- columnOptions.compression_per_level.resize(columnOptions.num_levels);
823
- for (int i = 0; i < columnOptions.num_levels; ++i) {
824
- if (i < 2) {
825
- columnOptions.compression_per_level[i] = rocksdb::kNoCompression;
826
- } else {
827
- columnOptions.compression_per_level[i] = rocksdb::kZSTD;
828
- }
812
+ std::string compaction;
813
+ NAPI_STATUS_RETURN(GetProperty(env, options, "compaction", compaction));
814
+ if (compaction == "") {
815
+ // Do nothing...
816
+ } else if (compaction == "universal") {
817
+ columnOptions.write_buffer_size = memtable_memory_budget / 4;
818
+ // merge two memtables when flushing to L0
819
+ columnOptions.min_write_buffer_number_to_merge = 2;
820
+ // this means we'll use 50% extra memory in the worst case, but will reduce
821
+ // write stalls.
822
+ columnOptions.max_write_buffer_number = 6;
823
+ // universal style compaction
824
+ columnOptions.compaction_style = rocksdb::kCompactionStyleUniversal;
825
+ columnOptions.compaction_options_universal.compression_size_percent = 80;
826
+ } else if (compaction == "level") {
827
+ columnOptions.write_buffer_size = static_cast<size_t>(memtable_memory_budget / 4);
828
+ // merge two memtables when flushing to L0
829
+ columnOptions.min_write_buffer_number_to_merge = 2;
830
+ // this means we'll use 50% extra memory in the worst case, but will reduce
831
+ // write stalls.
832
+ columnOptions.max_write_buffer_number = 6;
833
+ // start flushing L0->L1 as soon as possible. each file on level0 is
834
+ // (memtable_memory_budget / 2). This will flush level 0 when it's bigger than
835
+ // memtable_memory_budget.
836
+ columnOptions.level0_file_num_compaction_trigger = 2;
837
+ // doesn't really matter much, but we don't want to create too many files
838
+ columnOptions.target_file_size_base = memtable_memory_budget / 8;
839
+ // make Level1 size equal to Level0 size, so that L0->L1 compactions are fast
840
+ columnOptions.max_bytes_for_level_base = memtable_memory_budget;
841
+
842
+ // level style compaction
843
+ columnOptions.compaction_style = rocksdb::kCompactionStyleLevel;
844
+
845
+ // only compress levels >= 2
846
+ columnOptions.compression_per_level.resize(columnOptions.num_levels);
847
+ for (int i = 0; i < columnOptions.num_levels; ++i) {
848
+ if (i < 2) {
849
+ columnOptions.compression_per_level[i] = rocksdb::kNoCompression;
850
+ } else {
851
+ columnOptions.compression_per_level[i] = rocksdb::kZSTD;
829
852
  }
830
- } else {
831
- return napi_invalid_arg;
832
853
  }
854
+ } else {
855
+ return napi_invalid_arg;
833
856
  }
834
857
 
835
858
  bool compression = true;
@@ -888,15 +911,17 @@ napi_status InitOptions(napi_env env, T& columnOptions, const U& options) {
888
911
  columnOptions.optimize_filters_for_hits = false;
889
912
  NAPI_STATUS_RETURN(GetProperty(env, options, "optimizeFiltersForHits", columnOptions.optimize_filters_for_hits));
890
913
 
891
- uint32_t cacheSize = 8 << 20;
892
- NAPI_STATUS_RETURN(GetProperty(env, options, "cacheSize", cacheSize));
893
-
894
914
  rocksdb::BlockBasedTableOptions tableOptions;
895
915
 
896
- if (cacheSize) {
897
- tableOptions.block_cache = rocksdb::HyperClockCacheOptions(cacheSize, 0).MakeSharedCache();
898
- } else {
899
- tableOptions.no_block_cache = true;
916
+ {
917
+ uint32_t cacheSize = 8 << 20;
918
+ NAPI_STATUS_RETURN(GetProperty(env, options, "cacheSize", cacheSize));
919
+
920
+ if (cacheSize) {
921
+ tableOptions.block_cache = rocksdb::HyperClockCacheOptions(cacheSize, 0).MakeSharedCache();
922
+ } else {
923
+ tableOptions.no_block_cache = true;
924
+ }
900
925
  }
901
926
 
902
927
  std::string optimize = "";
@@ -915,11 +940,11 @@ napi_status InitOptions(napi_env env, T& columnOptions, const U& options) {
915
940
  tableOptions.filter_policy.reset(rocksdb::NewBloomFilterPolicy(10));
916
941
  }
917
942
 
918
- std::optional<std::string> filterPolicyOpt;
919
- NAPI_STATUS_RETURN(GetProperty(env, options, "filterPolicy", filterPolicyOpt));
920
- if (filterPolicyOpt) {
943
+ std::string filterPolicy;
944
+ NAPI_STATUS_RETURN(GetProperty(env, options, "filterPolicy", filterPolicy));
945
+ if (filterPolicy != "") {
921
946
  ROCKS_STATUS_RETURN_NAPI(
922
- rocksdb::FilterPolicy::CreateFromString(configOptions, *filterPolicyOpt, &tableOptions.filter_policy));
947
+ rocksdb::FilterPolicy::CreateFromString(configOptions, filterPolicy, &tableOptions.filter_policy));
923
948
  }
924
949
 
925
950
  tableOptions.block_size = 4 * 1024;
@@ -931,7 +956,7 @@ napi_status InitOptions(napi_env env, T& columnOptions, const U& options) {
931
956
  tableOptions.block_align = false;
932
957
  NAPI_STATUS_RETURN(GetProperty(env, options, "blockAlign", tableOptions.block_align));
933
958
 
934
- tableOptions.cache_index_and_filter_blocks = true; // false
959
+ tableOptions.cache_index_and_filter_blocks = false;
935
960
  NAPI_STATUS_RETURN(GetProperty(env, options, "cacheIndexAndFilterBlocks", tableOptions.cache_index_and_filter_blocks));
936
961
 
937
962
  tableOptions.cache_index_and_filter_blocks_with_high_priority = true;
@@ -1469,11 +1494,16 @@ NAPI_METHOD(db_get_latest_sequence) {
1469
1494
  NAPI_METHOD(iterator_init) {
1470
1495
  NAPI_ARGV(2);
1471
1496
 
1472
- auto iterator = Iterator::create(env, argv[0], argv[1]);
1473
-
1474
1497
  napi_value result;
1475
- NAPI_STATUS_THROWS(napi_create_external(env, iterator.get(), Finalize<Iterator>, iterator.get(), &result));
1476
- iterator.release();
1498
+ try {
1499
+ auto iterator = Iterator::create(env, argv[0], argv[1]);
1500
+
1501
+ NAPI_STATUS_THROWS(napi_create_external(env, iterator.get(), Finalize<Iterator>, iterator.get(), &result));
1502
+ iterator.release();
1503
+ } catch (const std::exception& e) {
1504
+ napi_throw_error(env, nullptr, e.what());
1505
+ return nullptr;
1506
+ }
1477
1507
 
1478
1508
  return result;
1479
1509
  }
@@ -1481,13 +1511,18 @@ NAPI_METHOD(iterator_init) {
1481
1511
  NAPI_METHOD(iterator_seek) {
1482
1512
  NAPI_ARGV(2);
1483
1513
 
1484
- Iterator* iterator;
1485
- NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&iterator)));
1514
+ try {
1515
+ Iterator* iterator;
1516
+ NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&iterator)));
1486
1517
 
1487
- rocksdb::PinnableSlice target;
1488
- NAPI_STATUS_THROWS(GetValue(env, argv[1], target));
1518
+ rocksdb::PinnableSlice target;
1519
+ NAPI_STATUS_THROWS(GetValue(env, argv[1], target));
1489
1520
 
1490
- iterator->Seek(target);
1521
+ iterator->Seek(target);
1522
+ } catch (const std::exception& e) {
1523
+ napi_throw_error(env, nullptr, e.what());
1524
+ return nullptr;
1525
+ }
1491
1526
 
1492
1527
  return 0;
1493
1528
  }
@@ -1495,36 +1530,57 @@ NAPI_METHOD(iterator_seek) {
1495
1530
  NAPI_METHOD(iterator_close) {
1496
1531
  NAPI_ARGV(1);
1497
1532
 
1498
- Iterator* iterator;
1499
- NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&iterator)));
1533
+ try {
1534
+ Iterator* iterator;
1535
+ NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&iterator)));
1500
1536
 
1501
- ROCKS_STATUS_THROWS_NAPI(iterator->Close());
1537
+ ROCKS_STATUS_THROWS_NAPI(iterator->Close());
1538
+ } catch (const std::exception& e) {
1539
+ napi_throw_error(env, nullptr, e.what());
1540
+ return nullptr;
1541
+ }
1502
1542
 
1503
1543
  return 0;
1504
1544
  }
1505
1545
 
1506
1546
  NAPI_METHOD(iterator_nextv) {
1507
- NAPI_ARGV(3);
1547
+ NAPI_ARGV(4);
1508
1548
 
1509
- Iterator* iterator;
1510
- NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&iterator)));
1549
+ try {
1550
+ Iterator* iterator;
1551
+ NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&iterator)));
1511
1552
 
1512
- uint32_t count;
1513
- NAPI_STATUS_THROWS(napi_get_value_uint32(env, argv[1], &count));
1553
+ uint32_t count = 1024;
1554
+ NAPI_STATUS_THROWS(GetValue(env, argv[1], count));
1555
+
1556
+ uint32_t timeout = 0;
1557
+ NAPI_STATUS_THROWS(GetProperty(env, argv[2], "timeout", timeout));
1514
1558
 
1515
- return iterator->nextv(env, count, argv[2]);
1559
+ return iterator->nextv(env, count, timeout, argv[3]);
1560
+ } catch (const std::exception& e) {
1561
+ napi_throw_error(env, nullptr, e.what());
1562
+ return nullptr;
1563
+ }
1516
1564
  }
1517
1565
 
1518
1566
  NAPI_METHOD(iterator_nextv_sync) {
1519
- NAPI_ARGV(2);
1567
+ NAPI_ARGV(3);
1520
1568
 
1521
- Iterator* iterator;
1522
- NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&iterator)));
1569
+ try {
1570
+ Iterator* iterator;
1571
+ NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&iterator)));
1523
1572
 
1524
- uint32_t count;
1525
- NAPI_STATUS_THROWS(napi_get_value_uint32(env, argv[1], &count));
1573
+ uint32_t count = 1024;
1574
+ NAPI_STATUS_THROWS(GetValue(env, argv[1], count));
1526
1575
 
1527
- return iterator->nextv(env, count);
1576
+ uint32_t timeout = 0;
1577
+ NAPI_STATUS_THROWS(GetProperty(env, argv[2], "timeout", timeout));
1578
+
1579
+ return iterator->nextv(env, count, timeout);
1580
+ } catch (const std::exception& e) {
1581
+ napi_throw_error(env, nullptr, e.what());
1582
+ return nullptr;
1583
+ }
1528
1584
  }
1529
1585
 
1530
1586
  NAPI_METHOD(batch_init) {
package/binding.gyp CHANGED
@@ -8,9 +8,14 @@
8
8
  [
9
9
  "OS == 'linux'",
10
10
  {
11
+ "direct_dependent_settings": {
12
+ "libraries": [
13
+ "/usr/lib/x86_64-linux-gnu/libre2.a",
14
+ ],
15
+ },
11
16
  "include_dirs": [
12
- "/usr/lib/x86_64-linux-gnu/include",
13
- "/usr/lib/include",
17
+ "/usr/lib/x86_64-linux-gnu/include",
18
+ "/usr/lib/include",
14
19
  ],
15
20
  "cflags": ["-march=znver1"],
16
21
  "ccflags": ["-flto", '-march=znver1'],
@@ -22,6 +27,15 @@
22
27
  [
23
28
  "OS == 'mac'",
24
29
  {
30
+ "direct_dependent_settings": {
31
+ "libraries": [
32
+ "/opt/homebrew/Cellar/re2/20240702_1/lib/re2.a"
33
+ ],
34
+ },
35
+ "include_dirs": [
36
+ "/opt/homebrew/Cellar/re2/20240702_1/include",
37
+ "/opt/homebrew/Cellar/abseil/20240722.0/include"
38
+ ],
25
39
  "xcode_settings": {
26
40
  "WARNING_CFLAGS": [
27
41
  "-Wno-sign-compare",
package/iterator.js CHANGED
@@ -96,7 +96,7 @@ class Iterator extends AbstractIterator {
96
96
  this[kFirst] = false
97
97
 
98
98
  try {
99
- const { rows, finished } = binding.iterator_nextv_sync(this[kContext], size)
99
+ const { rows, finished } = binding.iterator_nextv_sync(this[kContext], size, null)
100
100
  this[kCache] = rows
101
101
  this[kFinished] = finished
102
102
  this[kPosition] = 0
@@ -162,7 +162,7 @@ class Iterator extends AbstractIterator {
162
162
  }
163
163
 
164
164
  this[kFirst] = false
165
- const result = binding.iterator_nextv_sync(this[kContext], size)
165
+ const result = binding.iterator_nextv_sync(this[kContext], size, options)
166
166
  this[kFinished] = result.finished
167
167
 
168
168
  return result
@@ -182,7 +182,7 @@ class Iterator extends AbstractIterator {
182
182
  this[kFirst] = false
183
183
  this[kBusy] = true
184
184
  this[kDB][kRef]()
185
- binding.iterator_nextv(this[kContext], size, (err, result) => {
185
+ binding.iterator_nextv(this[kContext], size, options, (err, result) => {
186
186
  this[kBusy] = false
187
187
  this[kDB][kUnref]()
188
188
  if (err) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nxtedition/rocksdb",
3
- "version": "13.0.2",
3
+ "version": "13.1.0",
4
4
  "description": "A low-level Node.js RocksDB binding",
5
5
  "license": "MIT",
6
6
  "main": "index.js",
package/util.h CHANGED
@@ -260,6 +260,10 @@ static napi_status GetValue(napi_env env, napi_value value, rocksdb::ColumnFamil
260
260
  return napi_get_value_external(env, value, reinterpret_cast<void**>(&result));
261
261
  }
262
262
 
263
+ static napi_status GetValue(napi_env env, napi_value value, std::shared_ptr<rocksdb::Cache>*& result) {
264
+ return napi_get_value_external(env, value, reinterpret_cast<void**>(&result));
265
+ }
266
+
263
267
  static napi_status GetValue(napi_env env, napi_value value, Encoding& result) {
264
268
  size_t size;
265
269
  NAPI_STATUS_RETURN(napi_get_value_string_utf8(env, value, nullptr, 0, &size));