hypercore 11.0.19 → 11.0.21

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
@@ -247,19 +247,6 @@ class Hypercore extends EventEmitter {
247
247
  this.core.replicator.updateActivity(this._active ? 1 : -1)
248
248
  }
249
249
 
250
- _setupSession (parent) {
251
- if (!this.keyPair) this.keyPair = parent.keyPair
252
-
253
- const s = parent.state
254
-
255
- if (s) {
256
- const shouldSnapshot = this.snapshotted && !s.isSnapshot()
257
- this.state = shouldSnapshot ? s.snapshot() : s.ref()
258
- }
259
-
260
- if (this.snapshotted && this.core && !this._snapshot) this._updateSnapshot()
261
- }
262
-
263
250
  async _open (storage, key, opts) {
264
251
  const preload = opts.preload || (opts.parent && opts.parent.preload)
265
252
 
@@ -339,7 +326,18 @@ class Hypercore extends EventEmitter {
339
326
 
340
327
  if (parent) {
341
328
  if (parent._stateIndex === -1) await parent.ready()
342
- this._setupSession(parent)
329
+ if (!this.keyPair) this.keyPair = parent.keyPair
330
+
331
+ const ps = parent.state
332
+
333
+ if (ps) {
334
+ const shouldSnapshot = this.snapshotted && !ps.isSnapshot()
335
+ this.state = shouldSnapshot ? await ps.snapshot() : ps.ref()
336
+ }
337
+
338
+ if (this.snapshotted && this.core && !this._snapshot) {
339
+ this._updateSnapshot()
340
+ }
343
341
  }
344
342
 
345
343
  if (opts.exclusive && opts.writable !== false) {
@@ -24,6 +24,7 @@ module.exports = class SessionState {
24
24
  this.lingers = null
25
25
 
26
26
  this.parent = parent
27
+ this.atomized = null
27
28
  this.mutex = new Mutex()
28
29
 
29
30
  this.blocks = blocks
@@ -40,7 +41,7 @@ module.exports = class SessionState {
40
41
 
41
42
  if (treeInfo.roots.length) this.setRoots(treeInfo.roots)
42
43
 
43
- this.snapshotCompatLength = this.isSnapshot() ? this.length : -1
44
+ this.snapshotCompatLength = this.isSnapshot() ? Math.min(this.length, this.core.state.length) : -1
44
45
 
45
46
  this.active = 0
46
47
 
@@ -91,7 +92,8 @@ module.exports = class SessionState {
91
92
  }
92
93
 
93
94
  signedLength () {
94
- return Math.min(this.flushedLength(), this.core.state.length)
95
+ const l = Math.min(this.flushedLength(), this.core.state.length)
96
+ return this.isSnapshot() && l > this.snapshotCompatLength ? this.snapshotCompatLength : l
95
97
  }
96
98
 
97
99
  unref () {
@@ -121,6 +123,33 @@ module.exports = class SessionState {
121
123
  return MerkleTree.size(this.roots)
122
124
  }
123
125
 
126
+ async getFlushedTreeInfo (storage) {
127
+ if (!this.atomized || !this.atomized.flushing) return this.treeInfo()
128
+ await this.atomized.flushed()
129
+
130
+ let rx = storage.read()
131
+ const headPromise = rx.getHead()
132
+ const authPromise = rx.getAuth()
133
+
134
+ rx.tryFlush()
135
+ const [head, auth] = await Promise.all([headPromise, authPromise])
136
+
137
+ rx = storage.read()
138
+ const rootPromises = []
139
+ for (const r of flat.fullRoots(head.length * 2)) {
140
+ rootPromises.push(rx.getTreeNode(r))
141
+ }
142
+
143
+ rx.tryFlush()
144
+ return {
145
+ fork: head.fork,
146
+ roots: await Promise.all(rootPromises),
147
+ length: head.length,
148
+ prologue: auth.manifest && auth.manifest.prologue,
149
+ signature: head.signature
150
+ }
151
+ }
152
+
124
153
  treeInfo () {
125
154
  return {
126
155
  fork: this.fork,
@@ -136,6 +165,7 @@ module.exports = class SessionState {
136
165
 
137
166
  this.active = 0
138
167
  this.mutex.destroy(new Error('Closed')).catch(noop)
168
+ if (this.parent && this.parent.atomized) this.parent.atomized = null
139
169
 
140
170
  const closing = this.storage.close()
141
171
 
@@ -152,14 +182,16 @@ module.exports = class SessionState {
152
182
  return closing
153
183
  }
154
184
 
155
- snapshot () {
185
+ async snapshot () {
186
+ const storage = this.storage.snapshot()
187
+
156
188
  const s = new SessionState(
157
189
  this.core,
158
190
  null,
159
- this.storage.snapshot(),
191
+ storage,
160
192
  this.blocks,
161
- this.tree.clone(),
162
- this.treeInfo(),
193
+ this.tree.clone(storage),
194
+ await this.getFlushedTreeInfo(storage),
163
195
  this.name
164
196
  )
165
197
 
@@ -213,46 +245,62 @@ module.exports = class SessionState {
213
245
  }
214
246
  }
215
247
 
216
- _commit () {
217
- const bitfield = this._pendingBitfield
218
- this._pendingBitfield = null
248
+ _precommit () {
249
+ this.commiting = true
250
+ }
219
251
 
220
- return this.parent._oncommit(this, bitfield)
252
+ async _commit () {
253
+ await this.mutex.lock()
254
+
255
+ try {
256
+ const bitfield = this._pendingBitfield
257
+ this._pendingBitfield = null
258
+ await this.parent._oncommit(this, bitfield)
259
+ } finally {
260
+ this.commiting = false
261
+ this.mutex.unlock()
262
+ }
221
263
  }
222
264
 
223
265
  async _oncommit (src, bitfield) {
224
- const currLength = this.length
266
+ await this.mutex.lock()
225
267
 
226
- this.fork = src.fork
227
- this.length = src.length
228
- this.roots = src.roots.slice()
229
- this.signature = src.signature
268
+ try {
269
+ const currLength = this.length
230
270
 
231
- const tree = {
232
- fork: this.fork,
233
- length: this.length,
234
- rootHash: this.hash(),
235
- signature: this.signature
236
- }
271
+ this.fork = src.fork
272
+ this.length = src.length
273
+ this.roots = src.roots.slice()
274
+ this.signature = src.signature
237
275
 
238
- const rx = src.storage.read()
239
- const dependencyPromise = rx.getDependency()
276
+ const tree = {
277
+ fork: this.fork,
278
+ length: this.length,
279
+ rootHash: this.hash(),
280
+ signature: this.signature
281
+ }
240
282
 
241
- rx.tryFlush()
283
+ const rx = src.storage.read()
284
+ const dependencyPromise = rx.getDependency()
242
285
 
243
- const dependency = await dependencyPromise
244
- if (dependency && dependency.length > this.flushedLength()) {
245
- this.storage.updateDependencyLength(dependency.length, false, true)
246
- }
286
+ rx.tryFlush()
287
+
288
+ const dependency = await dependencyPromise
289
+ if (dependency && dependency.length > this.flushedLength()) {
290
+ this.storage.updateDependencyLength(dependency.length, false, true)
291
+ }
247
292
 
248
- const truncated = bitfield ? bitfield.truncated : -1
293
+ const truncated = bitfield ? bitfield.truncated : -1
249
294
 
250
- if (truncated !== -1 && truncated < currLength) {
251
- this.ontruncate(tree, truncated, currLength, true)
252
- if (!bitfield || bitfield.length === 0) return
253
- }
295
+ if (truncated !== -1 && truncated < currLength) {
296
+ this.ontruncate(tree, truncated, currLength, true)
297
+ if (!bitfield || bitfield.length === 0) return
298
+ }
254
299
 
255
- this.onappend(tree, bitfield, true)
300
+ this.onappend(tree, bitfield, true)
301
+ } finally {
302
+ this.mutex.unlock()
303
+ }
256
304
  }
257
305
 
258
306
  flushed () {
@@ -350,6 +398,12 @@ module.exports = class SessionState {
350
398
 
351
399
  const { dependency, tree, roots } = await this._truncate(tx, batch)
352
400
 
401
+ for (const sessionState of this.core.sessionStates) {
402
+ if (sessionState.isSnapshot() && sessionState.name === this.name && length < sessionState.snapshotCompatLength) {
403
+ sessionState.snapshotCompatLength = length
404
+ }
405
+ }
406
+
353
407
  const flushed = await this.flush()
354
408
 
355
409
  this.fork = tree.fork
@@ -524,6 +578,12 @@ module.exports = class SessionState {
524
578
  if (!flushed) this._updateBitfield(bitfield)
525
579
  else if (this.isDefault()) this.core.ontruncate(tree, bitfield)
526
580
 
581
+ for (const sessionState of this.core.sessionStates) {
582
+ if (sessionState.isSnapshot() && sessionState.name === this.name && to < sessionState.snapshotCompatLength) {
583
+ sessionState.snapshotCompatLength = to
584
+ }
585
+ }
586
+
527
587
  for (let i = this.sessions.length - 1; i >= 0; i--) {
528
588
  this.sessions[i].emit('truncate', to, tree.fork)
529
589
  }
@@ -955,6 +1015,10 @@ module.exports = class SessionState {
955
1015
  }
956
1016
  }
957
1017
 
1018
+ if (this.atomized && atom) {
1019
+ throw new Error('Session already atomized')
1020
+ }
1021
+
958
1022
  const tree = new MerkleTree(storage)
959
1023
 
960
1024
  const head = {
@@ -975,7 +1039,10 @@ module.exports = class SessionState {
975
1039
  atom ? this.name : name
976
1040
  )
977
1041
 
978
- if (atom) atom.onflush(state._commit.bind(state))
1042
+ if (atom) {
1043
+ this.atomized = atom
1044
+ atom.onflush(state._commit.bind(state))
1045
+ }
979
1046
 
980
1047
  return state
981
1048
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hypercore",
3
- "version": "11.0.19",
3
+ "version": "11.0.21",
4
4
  "description": "Hypercore is a secure, distributed append-only log",
5
5
  "main": "index.js",
6
6
  "scripts": {