hypercore-storage 0.0.22 → 0.0.24

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/index.js CHANGED
@@ -5,8 +5,10 @@ const RW = require('read-write-mutexify')
5
5
  const b4a = require('b4a')
6
6
  const flat = require('flat-tree')
7
7
  const assert = require('nanoassert')
8
+
8
9
  const m = require('./lib/messages')
9
10
  const DependencyStream = require('./lib/dependency-stream')
11
+ const MemoryOverlay = require('./lib/memory-overlay')
10
12
 
11
13
  const INF = b4a.from([0xff])
12
14
 
@@ -181,6 +183,10 @@ class ReadBatch {
181
183
  return this._get(encodeCoreIndex(this.storage.corePointer, CORE.ENCRYPTION_KEY), null)
182
184
  }
183
185
 
186
+ getDataDependency () {
187
+ return this._get(encodeDataIndex(this.storage.dataPointer, DATA.DEPENDENCY), m.DataDependency)
188
+ }
189
+
184
190
  getDataInfo (info) {
185
191
  return this._get(encodeDataIndex(this.storage.dataPointer, DATA.INFO), m.DataInfo)
186
192
  }
@@ -426,6 +432,12 @@ class HypercoreStorage {
426
432
  return this.dbSnapshot !== null
427
433
  }
428
434
 
435
+ dependencyLength () {
436
+ return this.dependencies.length
437
+ ? this.dependencies[this.dependencies.length - 1].length
438
+ : -1
439
+ }
440
+
429
441
  async openBatch (name) {
430
442
  const existing = await this.db.get(encodeBatch(this.corePointer, CORE.BATCHES, name))
431
443
  if (!existing) return null
@@ -469,6 +481,10 @@ class HypercoreStorage {
469
481
  }
470
482
  }
471
483
 
484
+ createMemoryOverlay () {
485
+ return new MemoryOverlay(this)
486
+ }
487
+
472
488
  snapshot () {
473
489
  assert(this.closed === false)
474
490
  return new HypercoreStorage(this.root, this.discoveryKey, this.corePointer, this.dataPointer, this.db.snapshot())
@@ -519,7 +535,7 @@ class HypercoreStorage {
519
535
  return s
520
536
  }
521
537
 
522
- async peakLastTreeNode () {
538
+ async peekLastTreeNode () {
523
539
  assert(this.closed === false)
524
540
 
525
541
  const last = await this.db.peek(encodeIndexRange(this.dataPointer, DATA.TREE, this.dbSnapshot, { reverse: true }))
@@ -527,7 +543,7 @@ class HypercoreStorage {
527
543
  return c.decode(m.TreeNode, last.value)
528
544
  }
529
545
 
530
- async peakLastBitfieldPage () {
546
+ async peekLastBitfieldPage () {
531
547
  assert(this.closed === false)
532
548
 
533
549
  const last = await this.db.peek(encodeIndexRange(this.dataPointer, DATA.BITFIELD, this.dbSnapshot, { reverse: true }))
@@ -535,6 +551,11 @@ class HypercoreStorage {
535
551
  return mapStreamBitfieldPage(last)
536
552
  }
537
553
 
554
+ destroy () {
555
+ if (this.dbSnapshot === null) return
556
+ this.dbSnapshot.destroy()
557
+ }
558
+
538
559
  close () {
539
560
  if (this.closed) return Promise.resolve()
540
561
  this.closed = true
@@ -0,0 +1,285 @@
1
+ const { ASSERTION } = require('hypercore-errors')
2
+
3
+ const TipList = require('./tip-list')
4
+
5
+ class MemoryOverlay {
6
+ constructor (storage) {
7
+ this.storage = storage
8
+ this.head = null
9
+ this.auth = null
10
+ this.localKeyPair = null
11
+ this.encryptionKey = null
12
+ this.dataDependency = null
13
+ this.dataInfo = null
14
+ this.userData = null
15
+ this.blocks = null
16
+ this.treeNodes = null
17
+ this.bitfields = null
18
+
19
+ this.snapshotted = false
20
+ }
21
+
22
+ async registerBatch (name, length, overwrite) {
23
+ todo()
24
+ }
25
+
26
+ snapshot () {
27
+ todo()
28
+ }
29
+
30
+ get dependencies () {
31
+ return this.storage.dependencies
32
+ }
33
+
34
+ dependencyLength () {
35
+ if (this.dataDependency) return this.dataDependency.length
36
+ return this.storage.dependencyLength()
37
+ }
38
+
39
+ createReadBatch () {
40
+ return new MemoryOverlayReadBatch(this, this.storage.createReadBatch())
41
+ }
42
+
43
+ createWriteBatch () {
44
+ return new MemoryOverlayWriteBatch(this)
45
+ }
46
+
47
+ createBlockStream () {
48
+ todo()
49
+ }
50
+
51
+ createUserDataStream () {
52
+ todo()
53
+ }
54
+
55
+ createTreeNodeStream () {
56
+ todo()
57
+ }
58
+
59
+ createBitfieldPageStream () {
60
+ todo()
61
+ }
62
+
63
+ async peekLastTreeNode () {
64
+ todo()
65
+ }
66
+
67
+ async peekLastBitfieldPage () {
68
+ const mem = this.bitfields !== null ? this.bitfields.get(this.bitfields.length() - 1) : { valid: false }
69
+
70
+ const page = mem.valid ? mem.value : null
71
+ const index = page ? this.bitfields.length() - 1 : -1
72
+
73
+ const disk = await this.storage.peekLastBitfieldPage()
74
+
75
+ return (page && (!disk || index > disk.index)) ? { index, page } : disk
76
+ }
77
+
78
+ close () {
79
+ return Promise.resolve()
80
+ }
81
+
82
+ merge (overlay) {
83
+ if (overlay.head !== null) this.head = overlay.head
84
+ if (overlay.auth !== null) this.auth = overlay.auth
85
+ if (overlay.localKeyPair !== null) this.localKeyPair = overlay.localKeyPair
86
+ if (overlay.encryptionKey !== null) this.encryptionKey = overlay.encryptionKey
87
+ if (overlay.dataDependency !== null) this.dataDependency = overlay.dataDependency
88
+ if (overlay.dataInfo !== null) this.dataInfo = overlay.dataInfo
89
+ if (overlay.userData !== null) this.userData = mergeMap(this.userData, overlay.userData)
90
+ if (overlay.blocks !== null) this.blocks = mergeTip(this.blocks, overlay.blocks)
91
+ if (overlay.treeNodes !== null) this.treeNodes = mergeMap(this.treeNodes, overlay.treeNodes)
92
+ if (overlay.bitfields !== null) this.bitfields = mergeTip(this.bitfields, overlay.bitfields)
93
+ }
94
+ }
95
+
96
+ module.exports = MemoryOverlay
97
+
98
+ class MemoryOverlayReadBatch {
99
+ constructor (overlay, read) {
100
+ this.read = read
101
+ this.overlay = overlay
102
+ }
103
+
104
+ async getCoreHead () {
105
+ return this.overlay.head !== null ? this.overlay.head : this.read.getCoreHead()
106
+ }
107
+
108
+ async getCoreAuth () {
109
+ return this.overlay.auth !== null ? this.overlay.auth : this.read.getCoreAuth()
110
+ }
111
+
112
+ async getDataDependency () {
113
+ return this.overlay.dataDependency !== null ? this.overlay.dataDependency : this.read.getDataDependency()
114
+ }
115
+
116
+ async getLocalKeyPair () {
117
+ return this.overlay.localKeyPair !== null ? this.overlay.localKeyPair : this.read.getLocalKeyPair()
118
+ }
119
+
120
+ async getEncryptionKey () {
121
+ return this.overlay.encryptionKey !== null ? this.overlay.encryptionKey : this.read.getEncryptionKey()
122
+ }
123
+
124
+ async getDataInfo () {
125
+ return this.overlay.dataInfo !== null ? this.overlay.dataInfo : this.read.getDataInfo()
126
+ }
127
+
128
+ async getUserData (key) {
129
+ return this.overlay.userData !== null && this.overlay.userData.has(key)
130
+ ? this.overlay.userData.get(key)
131
+ : this.read.getUserData(key)
132
+ }
133
+
134
+ async hasBlock (index) {
135
+ if (this.overlay.blocks !== null && index >= this.overlay.blocks.offset) {
136
+ const blk = this.overlay.blocks.get(index)
137
+ if (blk.valid) return true
138
+ }
139
+ return this.read.hasBlock(index)
140
+ }
141
+
142
+ async getBlock (index, error) {
143
+ if (this.overlay.blocks !== null && index >= this.overlay.blocks.offset) {
144
+ const blk = this.overlay.blocks.get(index)
145
+ if (blk.valid) return blk.value
146
+ }
147
+ return this.read.getBlock(index, error)
148
+ }
149
+
150
+ async hasTreeNode (index) {
151
+ return this.overlay.treeNodes !== null
152
+ ? this.overlay.treeNodes.has(index)
153
+ : this.read.hasTreeNode(index)
154
+ }
155
+
156
+ async getTreeNode (index, error) {
157
+ return this.overlay.treeNodes !== null && this.overlay.treeNodes.has(index)
158
+ ? this.overlay.treeNodes.get(index)
159
+ : this.read.getTreeNode(index, error)
160
+ }
161
+
162
+ async getBitfieldPage (index) {
163
+ if (this.overlay.bitfields !== null && index >= this.overlay.bitfields.offset) {
164
+ const page = this.overlay.bitfields.get(index)
165
+ if (page.valid) return page.value
166
+ }
167
+ return this.read.getBitfieldPage(index)
168
+ }
169
+
170
+ destroy () {
171
+ this.read.destroy()
172
+ }
173
+
174
+ flush () {
175
+ return this.read.flush()
176
+ }
177
+
178
+ tryFlush () {
179
+ this.read.tryFlush()
180
+ }
181
+ }
182
+
183
+ class MemoryOverlayWriteBatch {
184
+ constructor (storage) {
185
+ this.storage = storage
186
+ this.overlay = new MemoryOverlay()
187
+ }
188
+
189
+ setCoreHead (head) {
190
+ this.overlay.head = head
191
+ }
192
+
193
+ setCoreAuth (auth) {
194
+ this.overlay.auth = auth
195
+ }
196
+
197
+ setBatchPointer (name, pointer) {
198
+ todo()
199
+ }
200
+
201
+ setDataDependency (dependency) {
202
+ this.overlay.dataDependency = dependency
203
+ }
204
+
205
+ setLocalKeyPair (keyPair) {
206
+ this.overlay.localKeyPair = keyPair
207
+ }
208
+
209
+ setEncryptionKey (encryptionKey) {
210
+ this.overlay.encryptionKey = encryptionKey
211
+ }
212
+
213
+ setDataInfo (info) {
214
+ this.overlay.dataInfo = info
215
+ }
216
+
217
+ setUserData (key, value) {
218
+ if (this.overlay.userData === null) this.overlay.userData = new Map()
219
+ this.overlay.userData.set(key, value)
220
+ }
221
+
222
+ putBlock (index, data) {
223
+ if (this.overlay.blocks === null) this.overlay.blocks = new TipList()
224
+ this.overlay.blocks.put(index, data)
225
+ }
226
+
227
+ deleteBlock (index) {
228
+ todo()
229
+ }
230
+
231
+ deleteBlockRange (start, end) {
232
+ if (this.overlay.blocks === null) this.overlay.blocks = new TipList()
233
+ this.overlay.blocks.delete(start, end)
234
+ }
235
+
236
+ putTreeNode (node) {
237
+ if (this.overlay.treeNodes === null) this.overlay.treeNodes = new Map()
238
+ this.overlay.treeNodes.set(node.index, node)
239
+ }
240
+
241
+ deleteTreeNode (index) {
242
+ todo()
243
+ }
244
+
245
+ deleteTreeNodeRange (start, end) {
246
+ todo()
247
+ }
248
+
249
+ putBitfieldPage (index, page) {
250
+ if (this.overlay.bitfields === null) this.overlay.bitfields = new TipList()
251
+ this.overlay.bitfields.put(index, page)
252
+ }
253
+
254
+ deleteBitfieldPage (index) {
255
+ todo()
256
+ }
257
+
258
+ deleteBitfieldPageRange (start, end) {
259
+ if (this.overlay.bitfields === null) this.overlay.bitfields = new TipList()
260
+ this.overlay.bitfields.delete(start, end)
261
+ }
262
+
263
+ destroy () {}
264
+
265
+ flush () {
266
+ this.storage.merge(this.overlay)
267
+ return Promise.resolve()
268
+ }
269
+ }
270
+
271
+ function mergeMap (a, b) {
272
+ if (a === null) return b
273
+ for (const [key, value] of b) a.set(key, value)
274
+ return a
275
+ }
276
+
277
+ function mergeTip (a, b) {
278
+ if (a === null) return b
279
+ a.merge(b)
280
+ return a
281
+ }
282
+
283
+ function todo () {
284
+ throw ASSERTION('Not supported yet, but will be')
285
+ }
@@ -0,0 +1,93 @@
1
+ const { ASSERTION } = require('hypercore-errors')
2
+
3
+ module.exports = class TipList {
4
+ constructor () {
5
+ this.offset = 0
6
+ this.removed = 0
7
+ this.data = []
8
+ }
9
+
10
+ length () {
11
+ return this.offset + this.data.length
12
+ }
13
+
14
+ end () {
15
+ if (this.removed) return this.removed
16
+ return this.offset + this.data.length
17
+ }
18
+
19
+ delete (start, end) {
20
+ if (end !== -1) {
21
+ if (end < this.length() || (this.length() < start && this.length() !== 0)) {
22
+ throw ASSERTION('Invalid delete on tip list')
23
+ }
24
+ }
25
+
26
+ if (this.end() === 0) this.offset = start
27
+ if (this.removed < end || end === -1) this.removed = end
28
+
29
+ if (start < this.offset) {
30
+ this.offset = start
31
+ this.data = [] // clear everything
32
+ return
33
+ }
34
+
35
+ while (this.length() > start) this.data.pop()
36
+ }
37
+
38
+ put (index, value) {
39
+ if (this.end() === 0) {
40
+ this.offset = index
41
+ this.data.push(value)
42
+ return
43
+ }
44
+
45
+ if (!this.removed && this.end() === index) {
46
+ this.data.push(value)
47
+ return
48
+ }
49
+
50
+ throw ASSERTION('Invalid put on tip list')
51
+ }
52
+
53
+ get (index) {
54
+ if (index < this.offset) {
55
+ return {
56
+ valid: false,
57
+ value: null
58
+ }
59
+ }
60
+
61
+ if (index - this.offset < this.data.length) {
62
+ return {
63
+ valid: true,
64
+ value: this.data[index - this.offset]
65
+ }
66
+ }
67
+
68
+ return {
69
+ valid: index < this.end(),
70
+ value: null
71
+ }
72
+ }
73
+
74
+ * [Symbol.iterator] () {
75
+ for (let i = 0; i < this.data.length; i++) {
76
+ yield [i + this.offset, this.data[i]]
77
+ }
78
+ }
79
+
80
+ merge (tip) {
81
+ const invalidDeletion = tip.removed && tip.end() !== -1 && tip.end() < this.end()
82
+ const invalidTip = (tip.removed !== -1 && tip.end() < this.offset) || this.end() < tip.offset
83
+
84
+ if (invalidTip || invalidDeletion) throw ASSERTION('Cannot merge tip list')
85
+
86
+ while (this.end() !== tip.offset && tip.offset >= this.offset && tip.end() >= this.end()) this.data.pop()
87
+ while (tip.removed && this.end() > tip.length() && this.data.length) this.data.pop()
88
+
89
+ for (const data of tip.data) this.data.push(data)
90
+
91
+ return this
92
+ }
93
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hypercore-storage",
3
- "version": "0.0.22",
3
+ "version": "0.0.24",
4
4
  "main": "index.js",
5
5
  "files": [
6
6
  "index.js",
@@ -16,6 +16,7 @@
16
16
  "b4a": "^1.6.6",
17
17
  "compact-encoding": "^2.15.0",
18
18
  "flat-tree": "^1.10.0",
19
+ "hypercore-errors": "^1.3.0",
19
20
  "index-encoder": "^3.0.1",
20
21
  "nanoassert": "^2.0.0",
21
22
  "read-write-mutexify": "^2.1.0",