hyperbee2 2.2.0 → 2.4.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.
package/lib/write.js CHANGED
@@ -2,15 +2,7 @@ const b4a = require('b4a')
2
2
  const c = require('compact-encoding')
3
3
  const { OP_COHORT } = require('./compression.js')
4
4
  const { encodeBlock, TYPE_COMPAT, TYPE_LATEST } = require('./encoding.js')
5
- const {
6
- Pointer,
7
- KeyPointer,
8
- ValuePointer,
9
- TreeNode,
10
- TreeNodePointer,
11
- INSERTED,
12
- NEEDS_SPLIT
13
- } = require('./tree.js')
5
+ const { Pointer, KeyPointer, ValuePointer, TreeNode, INSERTED, NEEDS_SPLIT } = require('./tree.js')
14
6
 
15
7
  const PREFERRED_BLOCK_SIZE = 4096
16
8
  const INLINE_VALUE_SIZE = 4096
@@ -31,6 +23,7 @@ module.exports = class WriteBatch {
31
23
  } = opts
32
24
 
33
25
  this.tree = tree
26
+ this.config = tree.config.options(opts)
34
27
  this.deltaMax = deltaMax
35
28
  this.deltaMin = deltaMin
36
29
  this.inlineValueSize = inlineValueSize
@@ -76,7 +69,7 @@ module.exports = class WriteBatch {
76
69
  try {
77
70
  const ops = this.ops
78
71
 
79
- const root = await this.tree.bootstrap()
72
+ const root = await this.tree.bootstrap(this.config)
80
73
 
81
74
  const length = this._getLength(root)
82
75
  const context = this._getContext(root)
@@ -86,7 +79,7 @@ module.exports = class WriteBatch {
86
79
  const value = changed ? new TreeNode([], []) : null
87
80
 
88
81
  this.length = length
89
- this.root = new TreeNodePointer(context, 0, seq, 0, changed, value)
82
+ this.root = context.createTreeNode(0, seq, 0, changed, value)
90
83
 
91
84
  for (const op of ops) {
92
85
  if (op.put) op.applied = await this._put(op.key, op.value)
@@ -113,27 +106,29 @@ module.exports = class WriteBatch {
113
106
  async _put(key, value) {
114
107
  const stack = []
115
108
  const target = key
109
+ const snap = this.snapshot
110
+ const conf = this.config
116
111
 
117
112
  let ptr = this.root
118
113
 
119
114
  while (true) {
120
- const v = ptr.value ? this.snapshot.bump(ptr) : await this.snapshot.inflate(ptr)
121
- if (!v.children.length) break
115
+ const v = await retainAndInflate(ptr, snap, conf)
116
+ if (!v.children.ulength) break
122
117
 
123
118
  stack.push(ptr)
124
119
 
125
120
  let s = 0
126
- let e = v.keys.length
121
+ let e = v.keys.ulength
127
122
  let c = 0
128
123
 
129
124
  while (s < e) {
130
125
  const mid = (s + e) >> 1
131
- const m = v.keys.get(mid)
126
+ const m = v.keys.uget(mid)
132
127
 
133
128
  c = b4a.compare(target, m.key)
134
129
 
135
130
  if (c === 0) {
136
- const existing = await this.snapshot.inflateValue(m)
131
+ const existing = await snap.inflateValue(m, conf)
137
132
  if (b4a.equals(existing, value)) return false
138
133
  v.setValue(this.tree.context, mid, value)
139
134
  for (let i = 0; i < stack.length; i++) stack[i].changed = true
@@ -145,16 +140,16 @@ module.exports = class WriteBatch {
145
140
  }
146
141
 
147
142
  const i = c < 0 ? e : s
148
- ptr = v.children.get(i)
143
+ ptr = v.children.uget(i)
149
144
  }
150
145
 
151
- const v = ptr.value ? this.snapshot.bump(ptr) : await this.snapshot.inflate(ptr)
146
+ const v = await retainAndInflate(ptr, snap, conf)
152
147
  let status = v.insertLeaf(this.tree.context, target, value)
153
148
 
154
149
  if (status >= 0) {
155
150
  // already exists, upsert if changed
156
- const m = v.keys.get(status)
157
- const existing = await this.snapshot.inflateValue(m)
151
+ const m = v.keys.uget(status)
152
+ const existing = await snap.inflateValue(m, conf)
158
153
  if (b4a.equals(existing, value)) return false
159
154
  v.setValue(this.tree.context, status, value)
160
155
  }
@@ -163,20 +158,19 @@ module.exports = class WriteBatch {
163
158
  for (let i = 0; i < stack.length; i++) stack[i].changed = true
164
159
 
165
160
  while (status === NEEDS_SPLIT) {
166
- const v = ptr.value ? this.snapshot.bump(ptr) : await this.snapshot.inflate(ptr)
161
+ const v = await retainAndInflate(ptr, snap, conf)
167
162
  const parent = stack.pop()
168
163
  const { median, right } = v.split(this.tree.context)
169
164
 
170
165
  if (parent) {
171
- const p = parent.value ? this.snapshot.bump(parent) : await this.snapshot.inflate(parent)
166
+ const p = await retainAndInflate(parent, snap, conf)
172
167
  status = p.insertNode(this.tree.context, median, right)
173
168
  ptr = parent
174
169
  } else {
175
- this.root = new TreeNodePointer(this.tree.context, 0, 0, 0, true, new TreeNode([], []))
170
+ this.root = this.tree.context.createTreeNode(0, 0, 0, true, new TreeNode([], []))
176
171
  this.root.value.keys.push(median)
177
172
  this.root.value.children.push(ptr)
178
173
  this.root.value.children.push(right)
179
- this.snapshot.bump(this.root)
180
174
  status = INSERTED
181
175
  }
182
176
  }
@@ -190,19 +184,19 @@ module.exports = class WriteBatch {
190
184
  const stack = []
191
185
 
192
186
  while (true) {
193
- const v = ptr.value ? this.snapshot.bump(ptr) : await this.snapshot.inflate(ptr)
187
+ const v = await retainAndInflate(ptr, this.snapshot, this.config)
194
188
  stack.push(ptr)
195
189
 
196
190
  let s = 0
197
- let e = v.keys.length
191
+ let e = v.keys.ulength
198
192
  let c = 0
199
193
 
200
194
  while (s < e) {
201
195
  const mid = (s + e) >> 1
202
- c = b4a.compare(key, v.keys.get(mid).key)
196
+ c = b4a.compare(key, v.keys.uget(mid).key)
203
197
 
204
198
  if (c === 0) {
205
- if (v.children.length) await this._setKeyToNearestLeaf(v, mid, stack)
199
+ if (v.children.ulength) await this._setKeyToNearestLeaf(v, mid, stack)
206
200
  else v.removeKey(mid)
207
201
  // we mark these as changed late, so we don't rewrite them if it is a 404
208
202
  for (let i = 0; i < stack.length; i++) stack[i].changed = true
@@ -214,88 +208,95 @@ module.exports = class WriteBatch {
214
208
  else s = mid + 1
215
209
  }
216
210
 
217
- if (!v.children.length) return false
211
+ if (!v.children.ulength) return false
218
212
 
219
213
  const i = c < 0 ? e : s
220
- ptr = v.children.get(i)
214
+ ptr = v.children.uget(i)
221
215
  }
222
216
 
223
217
  return false
224
218
  }
225
219
 
226
220
  async _setKeyToNearestLeaf(v, index, stack) {
227
- let left = v.children.get(index)
228
- let right = v.children.get(index + 1)
221
+ const snap = this.snapshot
222
+ const conf = this.config
223
+
224
+ let left = v.children.uget(index)
225
+ let right = v.children.uget(index + 1)
229
226
 
230
227
  const [ls, rs] = await Promise.all([this._leafSize(left, false), this._leafSize(right, true)])
231
228
 
232
229
  if (ls < rs) {
233
230
  // if fewer leaves on the left
234
231
  stack.push(right)
235
- let r = right.value ? this.snapshot.bump(right) : await this.snapshot.inflate(right)
236
- while (r.children.length) {
237
- right = r.children.get(0)
232
+ let r = await retainAndInflate(right, snap, conf)
233
+ while (r.children.ulength) {
234
+ right = r.children.uget(0)
238
235
  stack.push(right)
239
- r = right.value ? this.snapshot.bump(right) : await this.snapshot.inflate(right)
236
+ r = await retainAndInflate(right, snap, conf)
240
237
  }
241
238
  v.keys.set(index, r.keys.shift())
242
239
  } else {
243
240
  // if fewer leaves on the right
244
241
  stack.push(left)
245
- let l = left.value ? this.snapshot.bump(left) : await this.snapshot.inflate(left)
246
- while (l.children.length) {
247
- left = l.children.get(l.children.length - 1)
242
+ let l = await retainAndInflate(left, snap, conf)
243
+ while (l.children.ulength) {
244
+ left = l.children.uget(l.children.ulength - 1)
248
245
  stack.push(left)
249
- l = left.value ? this.snapshot.bump(left) : await this.snapshot.inflate(left)
246
+ l = await retainAndInflate(left, snap, conf)
250
247
  }
251
248
  v.keys.set(index, l.keys.pop())
252
249
  }
253
250
  }
254
251
 
255
252
  async _leafSize(ptr, goLeft) {
256
- let v = ptr.value ? this.snapshot.bump(ptr) : await this.snapshot.inflate(ptr)
257
- while (v.children.length) {
258
- ptr = v.children.get(goLeft ? 0 : v.children.length - 1)
259
- v = ptr.value ? this.snapshot.bump(ptr) : await this.snapshot.inflate(ptr)
253
+ const snap = this.snapshot
254
+ const conf = this.config
255
+
256
+ let v = await retainAndInflate(ptr, snap, conf)
257
+ while (v.children.ulength) {
258
+ ptr = v.children.uget(goLeft ? 0 : v.children.ulength - 1)
259
+ v = await retainAndInflate(ptr, snap, conf)
260
260
  }
261
- return v.keys.length
261
+ return v.keys.ulength
262
262
  }
263
263
 
264
264
  async _rebalance(stack) {
265
265
  const root = stack[0]
266
266
  const minKeys = this.tree.context.minKeys
267
+ const snap = this.snapshot
268
+ const conf = this.config
267
269
 
268
270
  while (stack.length > 1) {
269
271
  const ptr = stack.pop()
270
272
  const parent = stack[stack.length - 1]
271
273
 
272
- const v = ptr.value ? this.snapshot.bump(ptr) : await this.snapshot.inflate(ptr)
274
+ const v = await retainAndInflate(ptr, snap, conf)
273
275
 
274
- if (v.keys.length >= minKeys) return root
276
+ if (v.keys.ulength >= minKeys) return root
275
277
 
276
- const p = parent.value ? this.snapshot.bump(parent) : await this.snapshot.inflate(parent)
278
+ const p = await retainAndInflate(parent, snap, conf)
277
279
 
278
280
  let { left, index, right } = v.siblings(p)
279
281
 
280
- let l = left && (left.value ? this.snapshot.bump(left) : await this.snapshot.inflate(left))
282
+ let l = left && (await retainAndInflate(left, snap, conf))
281
283
 
282
284
  // maybe borrow from left sibling?
283
- if (l && l.keys.length > minKeys) {
285
+ if (l && l.keys.ulength > minKeys) {
284
286
  left.changed = true
285
- v.keys.unshift(p.keys.get(index - 1))
286
- if (l.children.length) v.children.unshift(l.children.pop())
287
+ v.keys.unshift(p.keys.uget(index - 1))
288
+ if (l.children.ulength) v.children.unshift(l.children.pop())
287
289
  p.keys.set(index - 1, l.keys.pop())
288
290
  return root
289
291
  }
290
292
 
291
- let r =
292
- right && (right.value ? this.snapshot.bump(right) : await this.snapshot.inflate(right))
293
+ let r = right && (await retainAndInflate(right, snap, conf))
293
294
 
294
295
  // maybe borrow from right sibling?
295
- if (r && r.keys.length > minKeys) {
296
+ if (r && r.keys.ulength > minKeys) {
296
297
  right.changed = true
297
- v.keys.push(p.keys.get(index))
298
- if (r.children.length) v.children.push(r.children.shift())
298
+ v.keys.push(p.keys.uget(index))
299
+ if (r.children.ulength) v.children.push(r.children.shift())
299
300
  p.keys.set(index, r.keys.shift())
300
301
  return root
301
302
  }
@@ -311,15 +312,15 @@ module.exports = class WriteBatch {
311
312
  }
312
313
 
313
314
  left.changed = true
314
- l.merge(r, p.keys.get(index))
315
+ l.merge(r, p.keys.uget(index))
315
316
 
316
317
  parent.changed = true
317
318
  p.removeKey(index)
318
319
  }
319
320
 
320
- const r = root.value ? this.snapshot.bump(root) : await this.snapshot.inflate(root)
321
+ const r = await retainAndInflate(root, snap, conf)
321
322
  // check if the tree shrunk
322
- if (!r.keys.length && r.children.length) return r.children.get(0)
323
+ if (!r.keys.ulength && r.children.ulength) return r.children.uget(0)
323
324
  return root
324
325
  }
325
326
 
@@ -334,19 +335,21 @@ module.exports = class WriteBatch {
334
335
  return
335
336
  }
336
337
 
337
- if (!this.root.value) await this.snapshot.inflate(this.root)
338
+ if (!this.root.value) await this.snapshot.inflate(this.root, this.config)
338
339
 
339
340
  let update = { size: 0, nodes: [], keys: [], values: [] }
340
341
  let minValue = -1
341
342
 
343
+ this.root = this.root.commit()
344
+
342
345
  const batch = [update]
343
346
  const stack = [this.root]
344
347
  const values = []
345
348
 
346
349
  const context = this.tree.context.getLocalContext()
347
- const activeRequests = this.tree.activeRequests
350
+ const config = this.tree.config
348
351
 
349
- await context.update(activeRequests)
352
+ await context.update(config)
350
353
 
351
354
  while (stack.length > 0) {
352
355
  const node = stack.pop()
@@ -382,8 +385,9 @@ module.exports = class WriteBatch {
382
385
  for (let i = 0; i < children.entries.length; i++) {
383
386
  const c = children.entries[i]
384
387
  if (!c.value || !c.changed) continue
385
- children.touch(i)
386
- stack.push(c)
388
+ const node = c.commit()
389
+ children.touch(i, node)
390
+ stack.push(node)
387
391
  }
388
392
  }
389
393
 
@@ -486,7 +490,7 @@ module.exports = class WriteBatch {
486
490
  const buffers = new Array(blocks.length)
487
491
 
488
492
  if (blocks.length > 0 && this.length > 0) {
489
- const core = this.key ? await context.getCoreOffsetByKey(this.key, activeRequests) : 0
493
+ const core = this.key ? await context.getCoreOffsetByKey(this.key, config) : 0
490
494
  blocks[blocks.length - 1].previous = { core, seq: this.length - 1 }
491
495
  }
492
496
 
@@ -515,6 +519,9 @@ module.exports = class WriteBatch {
515
519
  this.snapshot.bump(node)
516
520
  }
517
521
  }
522
+
523
+ context.cache.retained++
524
+ context.cache.gc()
518
525
  }
519
526
  }
520
527
 
@@ -597,3 +604,12 @@ function prepareCohorts(context, block, seq, deltas, keys) {
597
604
  function supportsCompression(type) {
598
605
  return type !== TYPE_COMPAT && type !== 0
599
606
  }
607
+
608
+ async function retainAndInflate(ptr, snap, conf) {
609
+ if (ptr.value) {
610
+ ptr.retain()
611
+ return ptr.value
612
+ }
613
+ ptr.retain()
614
+ return await snap.inflate(ptr, conf)
615
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hyperbee2",
3
- "version": "2.2.0",
3
+ "version": "2.4.1",
4
4
  "description": "btree",
5
5
  "main": "index.js",
6
6
  "files": [
@@ -19,6 +19,7 @@
19
19
  "b4a": "^1.6.7",
20
20
  "compact-encoding": "^2.16.1",
21
21
  "hypercore": "^11.15.0",
22
+ "hypercore-errors": "^1.5.0",
22
23
  "hyperschema": "^1.14.0",
23
24
  "protocol-buffers-encodings": "^1.2.0",
24
25
  "scope-lock": "^1.2.4",