hypercore 11.0.20 → 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
@@ -122,6 +123,33 @@ module.exports = class SessionState {
122
123
  return MerkleTree.size(this.roots)
123
124
  }
124
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
+
125
153
  treeInfo () {
126
154
  return {
127
155
  fork: this.fork,
@@ -137,6 +165,7 @@ module.exports = class SessionState {
137
165
 
138
166
  this.active = 0
139
167
  this.mutex.destroy(new Error('Closed')).catch(noop)
168
+ if (this.parent && this.parent.atomized) this.parent.atomized = null
140
169
 
141
170
  const closing = this.storage.close()
142
171
 
@@ -153,14 +182,16 @@ module.exports = class SessionState {
153
182
  return closing
154
183
  }
155
184
 
156
- snapshot () {
185
+ async snapshot () {
186
+ const storage = this.storage.snapshot()
187
+
157
188
  const s = new SessionState(
158
189
  this.core,
159
190
  null,
160
- this.storage.snapshot(),
191
+ storage,
161
192
  this.blocks,
162
- this.tree.clone(),
163
- this.treeInfo(),
193
+ this.tree.clone(storage),
194
+ await this.getFlushedTreeInfo(storage),
164
195
  this.name
165
196
  )
166
197
 
@@ -214,46 +245,62 @@ module.exports = class SessionState {
214
245
  }
215
246
  }
216
247
 
217
- _commit () {
218
- const bitfield = this._pendingBitfield
219
- this._pendingBitfield = null
248
+ _precommit () {
249
+ this.commiting = true
250
+ }
251
+
252
+ async _commit () {
253
+ await this.mutex.lock()
220
254
 
221
- return this.parent._oncommit(this, bitfield)
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
+ }
222
263
  }
223
264
 
224
265
  async _oncommit (src, bitfield) {
225
- const currLength = this.length
266
+ await this.mutex.lock()
226
267
 
227
- this.fork = src.fork
228
- this.length = src.length
229
- this.roots = src.roots.slice()
230
- this.signature = src.signature
268
+ try {
269
+ const currLength = this.length
231
270
 
232
- const tree = {
233
- fork: this.fork,
234
- length: this.length,
235
- rootHash: this.hash(),
236
- signature: this.signature
237
- }
271
+ this.fork = src.fork
272
+ this.length = src.length
273
+ this.roots = src.roots.slice()
274
+ this.signature = src.signature
238
275
 
239
- const rx = src.storage.read()
240
- const dependencyPromise = rx.getDependency()
276
+ const tree = {
277
+ fork: this.fork,
278
+ length: this.length,
279
+ rootHash: this.hash(),
280
+ signature: this.signature
281
+ }
241
282
 
242
- rx.tryFlush()
283
+ const rx = src.storage.read()
284
+ const dependencyPromise = rx.getDependency()
243
285
 
244
- const dependency = await dependencyPromise
245
- if (dependency && dependency.length > this.flushedLength()) {
246
- this.storage.updateDependencyLength(dependency.length, false, true)
247
- }
286
+ rx.tryFlush()
248
287
 
249
- const truncated = bitfield ? bitfield.truncated : -1
288
+ const dependency = await dependencyPromise
289
+ if (dependency && dependency.length > this.flushedLength()) {
290
+ this.storage.updateDependencyLength(dependency.length, false, true)
291
+ }
250
292
 
251
- if (truncated !== -1 && truncated < currLength) {
252
- this.ontruncate(tree, truncated, currLength, true)
253
- if (!bitfield || bitfield.length === 0) return
254
- }
293
+ const truncated = bitfield ? bitfield.truncated : -1
255
294
 
256
- this.onappend(tree, bitfield, true)
295
+ if (truncated !== -1 && truncated < currLength) {
296
+ this.ontruncate(tree, truncated, currLength, true)
297
+ if (!bitfield || bitfield.length === 0) return
298
+ }
299
+
300
+ this.onappend(tree, bitfield, true)
301
+ } finally {
302
+ this.mutex.unlock()
303
+ }
257
304
  }
258
305
 
259
306
  flushed () {
@@ -968,6 +1015,10 @@ module.exports = class SessionState {
968
1015
  }
969
1016
  }
970
1017
 
1018
+ if (this.atomized && atom) {
1019
+ throw new Error('Session already atomized')
1020
+ }
1021
+
971
1022
  const tree = new MerkleTree(storage)
972
1023
 
973
1024
  const head = {
@@ -988,7 +1039,10 @@ module.exports = class SessionState {
988
1039
  atom ? this.name : name
989
1040
  )
990
1041
 
991
- if (atom) atom.onflush(state._commit.bind(state))
1042
+ if (atom) {
1043
+ this.atomized = atom
1044
+ atom.onflush(state._commit.bind(state))
1045
+ }
992
1046
 
993
1047
  return state
994
1048
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hypercore",
3
- "version": "11.0.20",
3
+ "version": "11.0.21",
4
4
  "description": "Hypercore is a secure, distributed append-only log",
5
5
  "main": "index.js",
6
6
  "scripts": {