@ohos-ports/lmdb 2.5.3 → 2.8.5-beta.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 (124) hide show
  1. package/LICENSE +20 -20
  2. package/README.md +72 -28
  3. package/SECURITY.md +12 -12
  4. package/bin/download-prebuilds.js +15 -0
  5. package/binding.gyp +115 -111
  6. package/build/Release/lmdb.node +0 -0
  7. package/caching.js +212 -156
  8. package/dependencies/lmdb/libraries/liblmdb/COPYRIGHT +20 -20
  9. package/dependencies/lmdb/libraries/liblmdb/Doxyfile +1631 -1631
  10. package/dependencies/lmdb/libraries/liblmdb/LICENSE +47 -47
  11. package/dependencies/lmdb/libraries/liblmdb/Makefile +136 -136
  12. package/dependencies/lmdb/libraries/liblmdb/chacha8.c +183 -183
  13. package/dependencies/lmdb/libraries/liblmdb/chacha8.h +14 -14
  14. package/dependencies/lmdb/libraries/liblmdb/crypto.c +121 -121
  15. package/dependencies/lmdb/libraries/liblmdb/intro.doc +192 -192
  16. package/dependencies/lmdb/libraries/liblmdb/lmdb.h +28 -3
  17. package/dependencies/lmdb/libraries/liblmdb/mdb.c +157 -31
  18. package/dependencies/lmdb/libraries/liblmdb/mdb_copy.1 +74 -74
  19. package/dependencies/lmdb/libraries/liblmdb/mdb_copy.c +106 -106
  20. package/dependencies/lmdb/libraries/liblmdb/mdb_drop.1 +53 -53
  21. package/dependencies/lmdb/libraries/liblmdb/mdb_drop.c +154 -154
  22. package/dependencies/lmdb/libraries/liblmdb/mdb_dump.1 +94 -94
  23. package/dependencies/lmdb/libraries/liblmdb/mdb_dump.c +333 -333
  24. package/dependencies/lmdb/libraries/liblmdb/mdb_load.1 +97 -97
  25. package/dependencies/lmdb/libraries/liblmdb/mdb_load.c +530 -530
  26. package/dependencies/lmdb/libraries/liblmdb/mdb_stat.1 +83 -83
  27. package/dependencies/lmdb/libraries/liblmdb/mdb_stat.c +276 -276
  28. package/dependencies/lmdb/libraries/liblmdb/midl-sparse.c +452 -0
  29. package/dependencies/lmdb/libraries/liblmdb/midl.c +452 -452
  30. package/dependencies/lmdb/libraries/liblmdb/midl.h +208 -208
  31. package/dependencies/lmdb/libraries/liblmdb/module.c +101 -101
  32. package/dependencies/lmdb/libraries/liblmdb/module.h +16 -16
  33. package/dependencies/lmdb/libraries/liblmdb/mtest.c +178 -178
  34. package/dependencies/lmdb/libraries/liblmdb/mtest2.c +124 -124
  35. package/dependencies/lmdb/libraries/liblmdb/mtest3.c +133 -133
  36. package/dependencies/lmdb/libraries/liblmdb/mtest4.c +168 -168
  37. package/dependencies/lmdb/libraries/liblmdb/mtest5.c +135 -135
  38. package/dependencies/lmdb/libraries/liblmdb/mtest6.c +141 -141
  39. package/dependencies/lmdb/libraries/liblmdb/mtest_enc.c +190 -190
  40. package/dependencies/lmdb/libraries/liblmdb/mtest_enc2.c +189 -189
  41. package/dependencies/lmdb/libraries/liblmdb/mtest_remap.c +177 -177
  42. package/dependencies/lmdb/libraries/liblmdb/sample-bdb.txt +73 -73
  43. package/dependencies/lmdb/libraries/liblmdb/sample-mdb.txt +62 -62
  44. package/dependencies/lmdb/libraries/liblmdb/tooltag +27 -27
  45. package/dependencies/lmdb-data-v1/libraries/liblmdb/CHANGES +266 -0
  46. package/dependencies/lmdb-data-v1/libraries/liblmdb/COPYRIGHT +20 -20
  47. package/dependencies/lmdb-data-v1/libraries/liblmdb/Doxyfile +1631 -1631
  48. package/dependencies/lmdb-data-v1/libraries/liblmdb/LICENSE +47 -47
  49. package/dependencies/lmdb-data-v1/libraries/liblmdb/intro.doc +192 -192
  50. package/dependencies/lmdb-data-v1/libraries/liblmdb/lmdb.h +1608 -1653
  51. package/dependencies/lmdb-data-v1/libraries/liblmdb/mdb.c +10320 -11359
  52. package/dependencies/lmdb-data-v1/libraries/liblmdb/mdb_copy.1 +55 -61
  53. package/dependencies/lmdb-data-v1/libraries/liblmdb/mdb_copy.c +82 -84
  54. package/dependencies/lmdb-data-v1/libraries/liblmdb/mdb_dump.1 +75 -81
  55. package/dependencies/lmdb-data-v1/libraries/liblmdb/mdb_dump.c +319 -319
  56. package/dependencies/lmdb-data-v1/libraries/liblmdb/mdb_load.1 +84 -84
  57. package/dependencies/lmdb-data-v1/libraries/liblmdb/mdb_load.c +496 -492
  58. package/dependencies/lmdb-data-v1/libraries/liblmdb/mdb_stat.1 +64 -70
  59. package/dependencies/lmdb-data-v1/libraries/liblmdb/mdb_stat.c +263 -264
  60. package/dependencies/lmdb-data-v1/libraries/liblmdb/midl.c +359 -421
  61. package/dependencies/lmdb-data-v1/libraries/liblmdb/midl.h +186 -200
  62. package/dependencies/lmdb-data-v1/libraries/liblmdb/mtest.c +177 -177
  63. package/dependencies/lmdb-data-v1/libraries/liblmdb/mtest2.c +124 -124
  64. package/dependencies/lmdb-data-v1/libraries/liblmdb/mtest3.c +133 -133
  65. package/dependencies/lmdb-data-v1/libraries/liblmdb/mtest4.c +168 -168
  66. package/dependencies/lmdb-data-v1/libraries/liblmdb/mtest5.c +135 -135
  67. package/dependencies/lmdb-data-v1/libraries/liblmdb/mtest6.c +141 -141
  68. package/dependencies/lmdb-data-v1/libraries/liblmdb/sample-bdb.txt +73 -73
  69. package/dependencies/lmdb-data-v1/libraries/liblmdb/sample-mdb.txt +62 -62
  70. package/dependencies/lmdb-data-v1/libraries/liblmdb/tooltag +22 -27
  71. package/dependencies/lz4/LICENSE +11 -11
  72. package/dependencies/lz4/lib/LICENSE +24 -24
  73. package/dependencies/lz4/lib/Makefile +225 -0
  74. package/dependencies/lz4/lib/README.md +169 -137
  75. package/dependencies/lz4/lib/dll/example/Makefile +63 -0
  76. package/dependencies/lz4/lib/dll/example/README.md +69 -69
  77. package/dependencies/lz4/lib/dll/liblz4.def +62 -62
  78. package/dependencies/lz4/lib/liblz4-dll.rc.in +35 -35
  79. package/dependencies/lz4/lib/liblz4.pc.in +14 -14
  80. package/dependencies/lz4/lib/lz4.c +2722 -2495
  81. package/dependencies/lz4/lib/lz4.h +842 -774
  82. package/dependencies/lz4/lib/lz4file.c +311 -0
  83. package/dependencies/lz4/lib/lz4file.h +93 -0
  84. package/dependencies/lz4/lib/lz4frame.c +2078 -1899
  85. package/dependencies/lz4/lib/lz4frame.h +692 -623
  86. package/dependencies/lz4/lib/lz4frame_static.h +47 -47
  87. package/dependencies/lz4/lib/lz4hc.c +1631 -1615
  88. package/dependencies/lz4/lib/lz4hc.h +413 -413
  89. package/dependencies/lz4/lib/xxhash.c +1030 -1030
  90. package/dependencies/lz4/lib/xxhash.h +328 -328
  91. package/dependencies/v8/v8-fast-api-calls-v16.h +790 -790
  92. package/dependencies/v8/v8-fast-api-calls.h +784 -888
  93. package/dist/index.cjs +1050 -584
  94. package/dist/index.cjs.map +1 -1
  95. package/index.d.cts +420 -0
  96. package/index.d.ts +450 -385
  97. package/index.js +38 -37
  98. package/keys.js +116 -102
  99. package/level.js +26 -26
  100. package/native.js +8 -5
  101. package/node-index.js +21 -17
  102. package/open.js +51 -17
  103. package/package.json +55 -21
  104. package/read.js +338 -95
  105. package/src/compression.cpp +12 -9
  106. package/src/cursor.cpp +82 -31
  107. package/src/dbi.cpp +78 -40
  108. package/src/env.cpp +336 -68
  109. package/src/lmdb-js.cpp +64 -64
  110. package/src/lmdb-js.h +83 -49
  111. package/src/misc.cpp +297 -28
  112. package/src/ordered-binary.cpp +46 -46
  113. package/src/txn.cpp +210 -257
  114. package/src/v8-functions.cpp +170 -166
  115. package/src/windows.c +34 -34
  116. package/src/writer.cpp +169 -84
  117. package/util/RangeIterable.js +112 -17
  118. package/util/set-optional-deps.cjs +14 -10
  119. package/util/when.js +8 -8
  120. package/write.js +145 -121
  121. package/dependencies/lmdb-data-v1/libraries/liblmdb/Makefile +0 -118
  122. package/dependencies/lmdb-data-v1/libraries/liblmdb/mdb_drop.1 +0 -40
  123. package/dependencies/lmdb-data-v1/libraries/liblmdb/mdb_drop.c +0 -135
  124. package/rollup.config.js +0 -12
@@ -16,7 +16,7 @@ Compression::Compression(const CallbackInfo& info) : ObjectWrap<Compression>(inf
16
16
  throwError(info.Env(), "Dictionary must be a buffer");
17
17
  return;
18
18
  }
19
- napi_get_typedarray_info(info.Env(), dictionaryOption, nullptr, &dictSize, (void**) &dictionary, nullptr, nullptr);
19
+ napi_get_buffer_info(info.Env(), dictionaryOption, (void**) &dictionary, &dictSize);
20
20
  dictSize = (dictSize >> 3) << 3; // make sure it is word-aligned
21
21
  }
22
22
  auto thresholdOption = info[0].As<Object>().Get("threshold");
@@ -34,10 +34,13 @@ Compression::Compression(const CallbackInfo& info) : ObjectWrap<Compression>(inf
34
34
  }
35
35
 
36
36
  Napi::Value Compression::setBuffer(const CallbackInfo& info) {
37
- napi_get_typedarray_info(info.Env(), info[0], nullptr, nullptr, (void**) &this->decompressTarget, nullptr, nullptr);
38
- this->decompressSize = info[1].As<Number>();
39
- napi_get_typedarray_info(info.Env(), info[2], nullptr, nullptr, (void**) &this->dictionary, nullptr, nullptr);
40
- this->dictionarySize = info[3].As<Number>();
37
+ size_t length;
38
+ napi_get_arraybuffer_info(info.Env(), info[0], (void**) &this->decompressTarget, &length);
39
+ unsigned int offset = info[1].As<Number>();
40
+ this->decompressTarget += offset;
41
+ this->decompressSize = info[2].As<Number>();
42
+ this->dictionarySize = info[4].As<Number>();
43
+ napi_get_buffer_info(info.Env(), info[3], (void**) &this->dictionary, &length);
41
44
  return info.Env().Undefined();
42
45
  }
43
46
  void Compression::decompress(MDB_val& data, bool &isValid, bool canAllocate) {
@@ -180,10 +183,10 @@ class CompressionWorker : public AsyncWorker {
180
183
 
181
184
  NAPI_FUNCTION(EnvWrap::compress) {
182
185
  ARGS(3)
183
- GET_INT64_ARG(0);
184
- EnvWrap* ew = (EnvWrap*) i64;
185
- napi_get_value_int64(env, args[1], &i64);
186
- double* compressionAddress = (double*) i64;
186
+ GET_INT64_ARG(0);
187
+ EnvWrap* ew = (EnvWrap*) i64;
188
+ napi_get_value_int64(env, args[1], &i64);
189
+ double* compressionAddress = (double*) i64;
187
190
  CompressionWorker* worker = new CompressionWorker(ew, (double*) compressionAddress, Function(env, args[2]));
188
191
  worker->Queue();
189
192
  RETURN_UNDEFINED;
package/src/cursor.cpp CHANGED
@@ -3,6 +3,15 @@
3
3
 
4
4
  using namespace Napi;
5
5
 
6
+ const int INCLUDE_VALUES = 0x100;
7
+ const int REVERSE = 0x400;
8
+ const int VALUES_FOR_KEY = 0x800;
9
+ const int ONLY_COUNT = 0x1000;
10
+ const int RENEW_CURSOR = 0x2000;
11
+ const int EXACT_MATCH = 0x4000;
12
+ const int INCLUSIVE_END = 0x8000;
13
+ const int EXCLUSIVE_START = 0x10000;
14
+
6
15
  CursorWrap::CursorWrap(const CallbackInfo& info) : Napi::ObjectWrap<CursorWrap>(info) {
7
16
  this->keyType = LmdbKeyType::StringKey;
8
17
  this->freeKey = nullptr;
@@ -14,10 +23,11 @@ CursorWrap::CursorWrap(const CallbackInfo& info) : Napi::ObjectWrap<CursorWrap>(
14
23
 
15
24
  DbiWrap *dw;
16
25
  napi_unwrap(info.Env(), info[0], (void**)&dw);
17
-
26
+ int64_t tw_address = 0;
27
+ napi_get_value_int64(info.Env(), info[1], &tw_address);
18
28
  // Open the cursor
19
29
  MDB_cursor *cursor;
20
- MDB_txn *txn = dw->ew->getReadTxn();
30
+ MDB_txn *txn = dw->ew->getReadTxn(tw_address);
21
31
  int rc = mdb_cursor_open(txn, dw->dbi, &cursor);
22
32
  if (rc != 0) {
23
33
  throwLmdbError(info.Env(), rc);
@@ -77,22 +87,30 @@ int CursorWrap::returnEntry(int lastRC, MDB_val &key, MDB_val &data) {
77
87
  }
78
88
  if (endKey.mv_size > 0) {
79
89
  int comparison;
80
- if (flags & 0x800)
90
+ if (flags & VALUES_FOR_KEY)
81
91
  comparison = mdb_dcmp(txn, dw->dbi, &endKey, &data);
82
92
  else
83
93
  comparison = mdb_cmp(txn, dw->dbi, &endKey, &key);
84
- if ((flags & 0x400) ? comparison >= 0 : (comparison <= 0)) {
85
- return 0;
94
+ if ((flags & REVERSE) ? comparison >= 0 : (comparison <= 0)) {
95
+ if (!((flags & INCLUSIVE_END) && comparison == 0))
96
+ return 0;
86
97
  }
87
98
  }
88
99
  char* keyBuffer = dw->ew->keyBuffer;
89
- if (flags & 0x100) {
90
- bool result = getVersionAndUncompress(data, dw);
91
- if (result)
92
- result = valToBinaryFast(data, dw);
93
- *((size_t*)keyBuffer) = data.mv_size;
100
+ if (flags & INCLUDE_VALUES) {
101
+ int result = getVersionAndUncompress(data, dw);
102
+ bool fits = true;
103
+ if (result) {
104
+ fits = valToBinaryFast(data, dw); // it fit in the global/compression-target buffer
105
+ }
106
+ if (fits || result == 2 || data.mv_size < SHARED_BUFFER_THRESHOLD) {// if it was decompressed
107
+ *((uint32_t*)keyBuffer) = data.mv_size;
108
+ *((uint32_t*)(keyBuffer + 4)) = 0; // buffer id of 0
109
+ } else {
110
+ EnvWrap::toSharedBuffer(dw->ew->env, (uint32_t*) dw->ew->keyBuffer, data);
111
+ }
94
112
  }
95
- if (!(flags & 0x800)) {
113
+ if (!(flags & VALUES_FOR_KEY)) {
96
114
  memcpy(keyBuffer + 32, key.mv_data, key.mv_size);
97
115
  *(keyBuffer + 32 + key.mv_size) = 0; // make sure it is null terminated for the sake of better ordered-binary performance
98
116
  }
@@ -105,7 +123,10 @@ int32_t CursorWrap::doPosition(uint32_t offset, uint32_t keySize, uint64_t endKe
105
123
  //char* keyBuffer = dw->ew->keyBuffer;
106
124
  MDB_val key, data;
107
125
  int rc;
108
- if (flags & 0x2000) { // TODO: check the txn_id to determine if we need to renew
126
+ if (dw->ew->env == nullptr) {
127
+ return MDB_BAD_TXN;
128
+ }
129
+ if (flags & RENEW_CURSOR) { // TODO: check the txn_id to determine if we need to renew
109
130
  rc = mdb_cursor_renew(txn = dw->ew->getReadTxn(), cursor);
110
131
  if (rc) {
111
132
  if (rc > 0)
@@ -119,25 +140,28 @@ int32_t CursorWrap::doPosition(uint32_t offset, uint32_t keySize, uint64_t endKe
119
140
  endKey.mv_data = (char*)(keyBuffer + 1);
120
141
  } else
121
142
  endKey.mv_size = 0;
122
- iteratingOp = (flags & 0x400) ?
123
- (flags & 0x100) ?
124
- (flags & 0x800) ? MDB_PREV_DUP : MDB_PREV :
143
+ iteratingOp = (flags & REVERSE) ?
144
+ (flags & INCLUDE_VALUES) ?
145
+ (flags & VALUES_FOR_KEY) ? MDB_PREV_DUP : MDB_PREV :
125
146
  MDB_PREV_NODUP :
126
- (flags & 0x100) ?
127
- (flags & 0x800) ? MDB_NEXT_DUP : MDB_NEXT :
147
+ (flags & INCLUDE_VALUES) ?
148
+ (flags & VALUES_FOR_KEY) ? MDB_NEXT_DUP : MDB_NEXT :
128
149
  MDB_NEXT_NODUP;
129
150
  key.mv_size = keySize;
130
151
  key.mv_data = dw->ew->keyBuffer;
131
152
  if (keySize == 0) {
132
- rc = mdb_cursor_get(cursor, &key, &data, flags & 0x400 ? MDB_LAST : MDB_FIRST);
153
+ rc = mdb_cursor_get(cursor, &key, &data, flags & REVERSE ? MDB_LAST : MDB_FIRST);
133
154
  } else {
134
- if (flags & 0x800) { // only values for this key
155
+ if (flags & VALUES_FOR_KEY) { // only values for this key
135
156
  // take the next part of the key buffer as a pointer to starting data
136
157
  uint32_t* startValueBuffer = (uint32_t*)(size_t)(*(double*)(dw->ew->keyBuffer + START_ADDRESS_POSITION));
137
158
  data.mv_size = endKeyAddress ? *((uint32_t*)startValueBuffer) : 0;
138
159
  data.mv_data = startValueBuffer + 1;
139
- if (flags & 0x400) {// reverse through values
140
- MDB_val startValue = data; // save it for comparison
160
+ MDB_val startValue;
161
+ if (flags & EXCLUSIVE_START)
162
+ startValue = data; // save it for comparison
163
+ if (flags & REVERSE) {// reverse through values
164
+ startValue = data; // save it for comparison
141
165
  rc = mdb_cursor_get(cursor, &key, &data, data.mv_size ? MDB_GET_BOTH_RANGE : MDB_SET_KEY);
142
166
  if (rc) {
143
167
  if (startValue.mv_size) {
@@ -154,33 +178,54 @@ int32_t CursorWrap::doPosition(uint32_t offset, uint32_t keySize, uint64_t endKe
154
178
  }
155
179
  } else // forward, just do a get by range
156
180
  rc = mdb_cursor_get(cursor, &key, &data, data.mv_size ?
157
- (flags & 0x4000) ? MDB_GET_BOTH : MDB_GET_BOTH_RANGE : MDB_SET_KEY);
181
+ (flags & EXACT_MATCH) ? MDB_GET_BOTH : MDB_GET_BOTH_RANGE : MDB_SET_KEY);
158
182
 
159
183
  if (rc == MDB_NOTFOUND)
160
184
  return 0;
161
- if (flags & 0x1000 && (!endKeyAddress || (flags & 0x4000))) {
185
+ if (flags & ONLY_COUNT && (!endKeyAddress || (flags & EXACT_MATCH))) {
162
186
  size_t count;
163
187
  rc = mdb_cursor_count(cursor, &count);
164
188
  if (rc)
165
189
  return rc > 0 ? -rc : rc;
166
190
  return count;
167
191
  }
192
+ if (flags & EXCLUSIVE_START) {
193
+ while(!rc) {
194
+ if (mdb_dcmp(txn, dw->dbi, &startValue, &data))
195
+ break;
196
+ rc = mdb_cursor_get(cursor, &key, &data, iteratingOp);
197
+ }
198
+ }
168
199
  } else {
169
- if (flags & 0x400) {// reverse
170
- MDB_val firstKey = key; // save it for comparison
200
+ MDB_val firstKey;
201
+ if (flags & EXCLUSIVE_START)
202
+ firstKey = key; // save it for comparison
203
+ if (flags & REVERSE) {// reverse
204
+ firstKey = key; // save it for comparison
171
205
  rc = mdb_cursor_get(cursor, &key, &data, MDB_SET_RANGE);
172
206
  if (rc)
173
207
  rc = mdb_cursor_get(cursor, &key, &data, MDB_LAST);
174
208
  else if (mdb_cmp(txn, dw->dbi, &firstKey, &key)) // the range found the next entry *after* the start
175
209
  rc = mdb_cursor_get(cursor, &key, &data, MDB_PREV);
210
+ else if (dw->flags & MDB_DUPSORT)
211
+ // we need to go to the last value of this key
212
+ rc = mdb_cursor_get(cursor, &key, &data, MDB_LAST_DUP);
176
213
  } else // forward, just do a get by range
177
- rc = mdb_cursor_get(cursor, &key, &data, (flags & 0x4000) ? MDB_SET_KEY : MDB_SET_RANGE);
214
+ rc = mdb_cursor_get(cursor, &key, &data, (flags & EXACT_MATCH) ? MDB_SET_KEY : MDB_SET_RANGE);
215
+ if (flags & EXCLUSIVE_START) {
216
+ while(!rc) {
217
+ if (mdb_cmp(txn, dw->dbi, &firstKey, &key))
218
+ break;
219
+ rc = mdb_cursor_get(cursor, &key, &data, iteratingOp);
220
+ }
221
+ }
178
222
  }
179
223
  }
224
+
180
225
  while (offset-- > 0 && !rc) {
181
226
  rc = mdb_cursor_get(cursor, &key, &data, iteratingOp);
182
227
  }
183
- if (flags & 0x1000) {
228
+ if (flags & ONLY_COUNT) {
184
229
  uint32_t count = 0;
185
230
  bool useCursorCount = false;
186
231
  // if we are in a dupsort database, and we are iterating over all entries, we can just count all the values for each key
@@ -198,12 +243,13 @@ int32_t CursorWrap::doPosition(uint32_t offset, uint32_t keySize, uint64_t endKe
198
243
  while (!rc) {
199
244
  if (endKey.mv_size > 0) {
200
245
  int comparison;
201
- if (flags & 0x800)
246
+ if (flags & VALUES_FOR_KEY)
202
247
  comparison = mdb_dcmp(txn, dw->dbi, &endKey, &data);
203
248
  else
204
249
  comparison = mdb_cmp(txn, dw->dbi, &endKey, &key);
205
- if ((flags & 0x400) ? comparison >= 0 : (comparison <=0)) {
206
- return count;
250
+ if ((flags & REVERSE) ? comparison >= 0 : (comparison <=0)) {
251
+ if (!((flags & INCLUSIVE_END) && comparison == 0))
252
+ return count;
207
253
  }
208
254
  }
209
255
  if (useCursorCount) {
@@ -251,7 +297,10 @@ NAPI_FUNCTION(iterate) {
251
297
  GET_INT64_ARG(0);
252
298
  CursorWrap* cw = (CursorWrap*) i64;
253
299
  MDB_val key, data;
254
- int rc = mdb_cursor_get(cw->cursor, &key, &data, cw->iteratingOp);
300
+ int rc;
301
+ if (cw->dw->ew->env == nullptr) rc = MDB_BAD_TXN;
302
+ else
303
+ rc = mdb_cursor_get(cw->cursor, &key, &data, cw->iteratingOp);
255
304
  RETURN_INT32(cw->returnEntry(rc, key, data));
256
305
  }
257
306
 
@@ -260,6 +309,8 @@ int32_t iterateFFI(double cwPointer) {
260
309
  DbiWrap* dw = cw->dw;
261
310
  dw->getFast = true;
262
311
  MDB_val key, data;
312
+ if (cw->dw->ew->env == nullptr)
313
+ return MDB_BAD_TXN;
263
314
  int rc = mdb_cursor_get(cw->cursor, &key, &data, cw->iteratingOp);
264
315
  return cw->returnEntry(rc, key, data);
265
316
  }
package/src/dbi.cpp CHANGED
@@ -30,7 +30,7 @@ DbiWrap::DbiWrap(const Napi::CallbackInfo& info) : ObjectWrap<DbiWrap>(info) {
30
30
  napi_unwrap(info.Env(), info[4], (void**) &compression);
31
31
  else
32
32
  compression = nullptr;
33
- int rc = this->open(flags & ~HAS_VERSIONS, nameBytes, flags & HAS_VERSIONS,
33
+ int rc = this->open(flags, nameBytes, flags & HAS_VERSIONS,
34
34
  keyType, compression);
35
35
  //if (nameBytes)
36
36
  //delete nameBytes;
@@ -69,8 +69,10 @@ int DbiWrap::open(int flags, char* name, bool hasVersions, LmdbKeyType keyType,
69
69
  this->hasVersions = hasVersions;
70
70
  this->compression = compression;
71
71
  this->keyType = keyType;
72
+ #ifndef MDB_RPAGE_CACHE
73
+ flags &= ~0x100; // remove use versions flag for older lmdb
74
+ #endif
72
75
  this->flags = flags;
73
- flags &= ~HAS_VERSIONS;
74
76
  int rc = txn ? mdb_dbi_open(txn, name, flags, &this->dbi) : EINVAL;
75
77
  if (rc)
76
78
  return rc;
@@ -136,46 +138,58 @@ Value DbiWrap::stat(const Napi::CallbackInfo& info) {
136
138
  return stats;
137
139
  }
138
140
 
139
-
140
- int32_t DbiWrap::doGetByBinary(uint32_t keySize) {
141
+ int32_t DbiWrap::doGetByBinary(uint32_t keySize, uint32_t ifNotTxnId, int64_t txnWrapAddress) {
141
142
  char* keyBuffer = ew->keyBuffer;
142
- MDB_txn* txn = ew->getReadTxn();
143
+ MDB_txn* txn = ew->getReadTxn(txnWrapAddress);
143
144
  MDB_val key, data;
144
145
  key.mv_size = keySize;
145
146
  key.mv_data = (void*) keyBuffer;
146
-
147
+ uint32_t* currentTxnId = (uint32_t*) (keyBuffer + 32);
148
+ #ifdef MDB_RPAGE_CACHE
149
+ int result = mdb_get_with_txn(txn, dbi, &key, &data, (mdb_size_t*) currentTxnId);
150
+ #else
147
151
  int result = mdb_get(txn, dbi, &key, &data);
152
+ #endif
148
153
  if (result) {
149
- if (result > 0)
150
- return -result;
154
+ if (result > 0)
155
+ return -result;
151
156
  return result;
152
157
  }
158
+ #ifdef MDB_RPAGE_CACHE
159
+ if (ifNotTxnId && ifNotTxnId == *currentTxnId)
160
+ return -30004;
161
+ #endif
153
162
  result = getVersionAndUncompress(data, this);
154
- if (result)
155
- valToBinaryFast(data, this);
156
- if (data.mv_size < 0x80000000)
157
- return data.mv_size;
158
- *((uint32_t*)keyBuffer) = data.mv_size;
159
- return -30000;
160
- /*
161
- alternately, if we want to send over the address, which can be used for direct access to the LMDB shared memory, but all benchmarking shows it is slower
162
- *((size_t*) keyBuffer) = data.mv_size;
163
- *((uint64_t*) (keyBuffer + 8)) = (uint64_t) data.mv_data;
164
- return 0;*/
163
+ bool fits = true;
164
+ if (result) {
165
+ fits = valToBinaryFast(data, this); // it fits in the global/compression-target buffer
166
+ }
167
+ if (fits || result == 2 || data.mv_size < SHARED_BUFFER_THRESHOLD) {// result = 2 if it was decompressed
168
+ if (data.mv_size < 0x80000000)
169
+ return data.mv_size;
170
+ *((uint32_t*)keyBuffer) = data.mv_size;
171
+ return -30000;
172
+ } else {
173
+ return EnvWrap::toSharedBuffer(ew->env, (uint32_t*) ew->keyBuffer, data);
174
+ }
165
175
  }
166
176
 
167
177
  NAPI_FUNCTION(getByBinary) {
168
- ARGS(2)
169
- GET_INT64_ARG(0);
170
- DbiWrap* dw = (DbiWrap*) i64;
178
+ ARGS(4)
179
+ GET_INT64_ARG(0);
180
+ DbiWrap* dw = (DbiWrap*) i64;
171
181
  uint32_t keySize;
172
182
  GET_UINT32_ARG(keySize, 1);
173
- RETURN_INT32(dw->doGetByBinary(keySize));
183
+ uint32_t ifNotTxnId;
184
+ GET_UINT32_ARG(ifNotTxnId, 2);
185
+ int64_t txnAddress = 0;
186
+ napi_status status = napi_get_value_int64(env, args[3], &txnAddress);
187
+ RETURN_INT32(dw->doGetByBinary(keySize, ifNotTxnId, txnAddress));
174
188
  }
175
189
 
176
- uint32_t getByBinaryFFI(double dwPointer, uint32_t keySize) {
177
- DbiWrap* dw = (DbiWrap*) (size_t) dwPointer;
178
- return dw->doGetByBinary(keySize);
190
+ uint32_t getByBinaryFFI(double dwPointer, uint32_t keySize, uint32_t ifNotTxnId, uint64_t txnAddress) {
191
+ DbiWrap* dw = (DbiWrap*) (size_t) dwPointer;
192
+ return dw->doGetByBinary(keySize, ifNotTxnId, txnAddress);
179
193
  }
180
194
 
181
195
  napi_finalize noopDbi = [](napi_env, void *, void *) {
@@ -183,8 +197,8 @@ napi_finalize noopDbi = [](napi_env, void *, void *) {
183
197
  };
184
198
  NAPI_FUNCTION(getSharedByBinary) {
185
199
  ARGS(2)
186
- GET_INT64_ARG(0);
187
- DbiWrap* dw = (DbiWrap*) i64;
200
+ GET_INT64_ARG(0);
201
+ DbiWrap* dw = (DbiWrap*) i64;
188
202
  uint32_t keySize;
189
203
  GET_UINT32_ARG(keySize, 1);
190
204
  MDB_val key;
@@ -205,16 +219,18 @@ NAPI_FUNCTION(getSharedByBinary) {
205
219
  return returnValue;
206
220
  }
207
221
  NAPI_FUNCTION(getStringByBinary) {
208
- ARGS(2)
209
- GET_INT64_ARG(0);
210
- DbiWrap* dw = (DbiWrap*) i64;
222
+ ARGS(3)
223
+ GET_INT64_ARG(0);
224
+ DbiWrap* dw = (DbiWrap*) i64;
211
225
  uint32_t keySize;
212
226
  GET_UINT32_ARG(keySize, 1);
227
+ int64_t txnAddress = 0;
228
+ napi_status status = napi_get_value_int64(env, args[2], &txnAddress);
213
229
  MDB_val key;
214
230
  MDB_val data;
215
231
  key.mv_size = keySize;
216
232
  key.mv_data = (void*) dw->ew->keyBuffer;
217
- MDB_txn* txn = dw->ew->getReadTxn();
233
+ MDB_txn* txn = dw->ew->getReadTxn(txnAddress);
218
234
  int rc = mdb_get(txn, dw->dbi, &key, &data);
219
235
  if (rc) {
220
236
  if (rc == MDB_NOTFOUND) {
@@ -237,12 +253,14 @@ int DbiWrap::prefetch(uint32_t* keys) {
237
253
  MDB_val data;
238
254
  unsigned int flags;
239
255
  mdb_dbi_flags(txn, dbi, &flags);
240
- bool dupSort = flags & MDB_DUPSORT;
256
+ bool findAllValues = flags & MDB_DUPSORT;
241
257
  int effected = 0;
258
+ bool findDataValue = false;
242
259
  MDB_cursor *cursor;
243
260
  int rc = mdb_cursor_open(txn, dbi, &cursor);
244
261
  if (rc)
245
262
  return rc;
263
+
246
264
  while((key.mv_size = *keys++) > 0) {
247
265
  if (key.mv_size == 0xffffffff) {
248
266
  // it is a pointer to a new buffer
@@ -251,9 +269,20 @@ int DbiWrap::prefetch(uint32_t* keys) {
251
269
  if (key.mv_size == 0)
252
270
  break;
253
271
  }
254
- key.mv_data = (void*) keys;
272
+ if (key.mv_size & 0x80000000) {
273
+ // indicator of using a data value combination (with dupSort), to be followed by the corresponding key
274
+ data.mv_size = key.mv_size & 0x7fffffff;
275
+ data.mv_data = (void *) keys;
276
+ keys += (data.mv_size + 12) >> 2;
277
+ findDataValue = true;
278
+ findAllValues = false;
279
+ continue;
280
+ }
281
+ // else standard key
282
+ key.mv_data = (void *) keys;
255
283
  keys += (key.mv_size + 12) >> 2;
256
- int rc = mdb_cursor_get(cursor, &key, &data, MDB_SET_KEY);
284
+ int rc = mdb_cursor_get(cursor, &key, &data, findDataValue ? MDB_GET_BOTH : MDB_SET_KEY);
285
+ findDataValue = false;
257
286
  while (!rc) {
258
287
  // access one byte from each of the pages to ensure they are in the OS cache,
259
288
  // potentially triggering the hard page fault in this thread
@@ -262,7 +291,7 @@ int DbiWrap::prefetch(uint32_t* keys) {
262
291
  for (int i = 0; i < pages; i++) {
263
292
  effected += *(((uint8_t*)data.mv_data) + (i << 12));
264
293
  }
265
- if (dupSort) // in dupsort databases, access the rest of the values
294
+ if (findAllValues) // in dupsort databases, access the rest of the values
266
295
  rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT_DUP);
267
296
  else
268
297
  rc = 1; // done
@@ -283,7 +312,13 @@ class PrefetchWorker : public AsyncWorker {
283
312
  }
284
313
 
285
314
  void OnOK() {
286
- Callback().Call({Env().Null()});
315
+ napi_value result; // we use direct napi call here because node-addon-api interface with throw a fatal error if a worker thread is terminating
316
+ napi_call_function(Env(), Env().Undefined(), Callback().Value(), 0, {}, &result);
317
+ }
318
+ void OnError(const Error& e) {
319
+ napi_value result; // we use direct napi call here because node-addon-api interface with throw a fatal error if a worker thread is terminating
320
+ napi_value arg = e.Value();
321
+ napi_call_function(Env(), Env().Undefined(), Callback().Value(), 1, &arg, &result);
287
322
  }
288
323
 
289
324
  private:
@@ -293,9 +328,9 @@ class PrefetchWorker : public AsyncWorker {
293
328
 
294
329
  NAPI_FUNCTION(prefetchNapi) {
295
330
  ARGS(3)
296
- GET_INT64_ARG(0);
297
- DbiWrap* dw = (DbiWrap*) i64;
298
- napi_get_value_int64(env, args[1], &i64);
331
+ GET_INT64_ARG(0);
332
+ DbiWrap* dw = (DbiWrap*) i64;
333
+ napi_get_value_int64(env, args[1], &i64);
299
334
  uint32_t* keys = (uint32_t*) i64;
300
335
  PrefetchWorker* worker = new PrefetchWorker(dw, keys, Function(env, args[2]));
301
336
  worker->Queue();
@@ -319,6 +354,9 @@ void DbiWrap::setupExports(Napi::Env env, Object exports) {
319
354
  // TODO: wrap mdb_stat too
320
355
  }
321
356
 
357
+
358
+
359
+
322
360
  // This file contains code from the node-lmdb project
323
361
  // Copyright (c) 2013-2017 Timur Kristóf
324
362
  // Copyright (c) 2021 Kristopher Tate