hypercore 10.0.0-alpha.44 → 10.0.0-alpha.47

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
@@ -113,6 +113,7 @@ module.exports = class Hypercore extends EventEmitter {
113
113
  indent + ' opened: ' + opts.stylize(this.opened, 'boolean') + '\n' +
114
114
  indent + ' closed: ' + opts.stylize(this.closed, 'boolean') + '\n' +
115
115
  indent + ' snapshotted: ' + opts.stylize(this.snapshotted, 'boolean') + '\n' +
116
+ indent + ' sparse: ' + opts.stylize(this.sparse, 'boolean') + '\n' +
116
117
  indent + ' writable: ' + opts.stylize(this.writable, 'boolean') + '\n' +
117
118
  indent + ' length: ' + opts.stylize(this.length, 'number') + '\n' +
118
119
  indent + ' byteLength: ' + opts.stylize(this.byteLength, 'number') + '\n' +
@@ -182,9 +183,11 @@ module.exports = class Hypercore extends EventEmitter {
182
183
  throw SESSION_CLOSED('Cannot make sessions on a closing core')
183
184
  }
184
185
 
186
+ const sparse = opts.sparse === false ? false : this.sparse
185
187
  const Clz = opts.class || Hypercore
186
188
  const s = new Clz(this.storage, this.key, {
187
189
  ...opts,
190
+ sparse,
188
191
  _opening: this.opening,
189
192
  _sessions: this.sessions
190
193
  })
@@ -297,7 +300,8 @@ module.exports = class Hypercore extends EventEmitter {
297
300
  crypto: this.crypto,
298
301
  legacy: opts.legacy,
299
302
  auth: opts.auth,
300
- onupdate: this._oncoreupdate.bind(this)
303
+ onupdate: this._oncoreupdate.bind(this),
304
+ oncontigupdate: this._oncorecontigupdate.bind(this)
301
305
  })
302
306
 
303
307
  if (opts.userData) {
@@ -323,14 +327,27 @@ module.exports = class Hypercore extends EventEmitter {
323
327
  }
324
328
  }
325
329
 
326
- _updateSnapshot () {
327
- const prev = this._snapshot
328
- const next = this._snapshot = {
329
- length: this.core.tree.length,
330
- byteLength: this.core.tree.byteLength,
330
+ _getSnapshot () {
331
+ if (this.sparse) {
332
+ return {
333
+ length: this.core.tree.length,
334
+ byteLength: this.core.tree.byteLength,
335
+ fork: this.core.tree.fork,
336
+ compatLength: this.core.tree.length
337
+ }
338
+ }
339
+
340
+ return {
341
+ length: this.core.header.contiguousLength,
342
+ byteLength: 0,
331
343
  fork: this.core.tree.fork,
332
- compatLength: this.core.tree.length
344
+ compatLength: this.core.header.contiguousLength
333
345
  }
346
+ }
347
+
348
+ _updateSnapshot () {
349
+ const prev = this._snapshot
350
+ const next = this._snapshot = this._getSnapshot()
334
351
 
335
352
  if (!prev) return true
336
353
  return prev.length !== next.length || prev.fork !== next.fork
@@ -484,9 +501,10 @@ module.exports = class Hypercore extends EventEmitter {
484
501
  if (s._snapshot && bitfield.start < s._snapshot.compatLength) s._snapshot.compatLength = bitfield.start
485
502
  }
486
503
 
487
- if (appended) {
488
- s.emit('append')
489
- }
504
+ // For sparse sessions, immediately emit appends. Non-sparse sessions
505
+ // are handled separately and only emit appends when their contiguous
506
+ // length is updated.
507
+ if (appended && s.sparse) s.emit('append')
490
508
  }
491
509
 
492
510
  this.replicator.onupgrade()
@@ -505,6 +523,16 @@ module.exports = class Hypercore extends EventEmitter {
505
523
  }
506
524
  }
507
525
 
526
+ _oncorecontigupdate () {
527
+ // For non-sparse sessions, emit appends only when the contiguous length is
528
+ // updated.
529
+ for (let i = 0; i < this.sessions.length; i++) {
530
+ const s = this.sessions[i]
531
+
532
+ if (!s.sparse) s.emit('append')
533
+ }
534
+ }
535
+
508
536
  _onpeerupdate (added, peer) {
509
537
  const name = added ? 'peer-add' : 'peer-remove'
510
538
 
@@ -561,10 +589,19 @@ module.exports = class Hypercore extends EventEmitter {
561
589
  const activeRequests = (opts && opts.activeRequests) || this.activeRequests
562
590
  const req = this.replicator.addUpgrade(activeRequests)
563
591
 
564
- if (!this.snapshotted) return req.promise
565
- if (!(await req.promise)) return false
592
+ const upgraded = await req.promise
593
+
594
+ if (!this.sparse) {
595
+ // Download all available blocks in non-sparse mode
596
+ const start = this.length
597
+ const end = this.core.tree.length
598
+
599
+ await this.download({ start, end, ifAvailable: true }).downloaded()
600
+ }
566
601
 
567
- return this._updateSnapshot()
602
+ if (!upgraded) return false
603
+ if (this.snapshotted) return this._updateSnapshot()
604
+ return true
568
605
  }
569
606
 
570
607
  async seek (bytes, opts) {
package/lib/caps.js CHANGED
@@ -4,9 +4,7 @@ const b4a = require('b4a')
4
4
  const c = require('compact-encoding')
5
5
 
6
6
  // TODO: rename this to "crypto" and move everything hashing related etc in here
7
- // Also lets move the tree stuff from hypercore-crypto here, and loose the types
8
- // from the hashes there - they are not needed since we lock the indexes in the tree
9
- // hash and just makes alignment etc harder in other languages
7
+ // Also lets move the tree stuff from hypercore-crypto here
10
8
 
11
9
  const [TREE, REPLICATE_INITIATOR, REPLICATE_RESPONDER] = crypto.namespace('hypercore', 3)
12
10
 
package/lib/core.js CHANGED
@@ -9,8 +9,9 @@ const { BAD_ARGUMENT, STORAGE_EMPTY, STORAGE_CONFLICT, INVALID_SIGNATURE } = req
9
9
  const m = require('./messages')
10
10
 
11
11
  module.exports = class Core {
12
- constructor (header, crypto, oplog, tree, blocks, bitfield, auth, legacy, onupdate) {
12
+ constructor (header, crypto, oplog, tree, blocks, bitfield, auth, legacy, onupdate, oncontigupdate) {
13
13
  this.onupdate = onupdate
14
+ this.oncontigupdate = oncontigupdate
14
15
  this.header = header
15
16
  this.crypto = crypto
16
17
  this.oplog = oplog
@@ -164,7 +165,7 @@ module.exports = class Core {
164
165
  }
165
166
  }
166
167
 
167
- return new this(header, crypto, oplog, tree, blocks, bitfield, auth, !!opts.legacy, opts.onupdate || noop)
168
+ return new this(header, crypto, oplog, tree, blocks, bitfield, auth, !!opts.legacy, opts.onupdate || noop, opts.oncontigupdate || noop)
168
169
  }
169
170
 
170
171
  _shouldFlush () {
@@ -202,6 +203,7 @@ module.exports = class Core {
202
203
  while (this.bitfield.get(i)) i++
203
204
 
204
205
  this.header.contiguousLength = i
206
+ this.oncontigupdate()
205
207
  }
206
208
  }
207
209
 
@@ -285,6 +287,7 @@ module.exports = class Core {
285
287
  batch.commit()
286
288
 
287
289
  this.header.contiguousLength = batch.length
290
+ this.oncontigupdate()
288
291
  this.header.tree.length = batch.length
289
292
  this.header.tree.rootHash = hash
290
293
  this.header.tree.signature = batch.signature
@@ -472,6 +475,7 @@ module.exports = class Core {
472
475
  const appended = batch.length > batch.ancestors
473
476
 
474
477
  this.header.contiguousLength = Math.min(batch.ancestors, this.header.contiguousLength)
478
+ this.oncontigupdate()
475
479
  this.header.tree.fork = batch.fork
476
480
  this.header.tree.length = batch.length
477
481
  this.header.tree.rootHash = batch.hash()
package/lib/replicator.js CHANGED
@@ -102,12 +102,13 @@ class BlockRequest extends Attachable {
102
102
  }
103
103
 
104
104
  class RangeRequest extends Attachable {
105
- constructor (ranges, start, end, linear, blocks) {
105
+ constructor (ranges, start, end, linear, ifAvailable, blocks) {
106
106
  super()
107
107
 
108
108
  this.start = start
109
109
  this.end = end
110
110
  this.linear = linear
111
+ this.ifAvailable = ifAvailable
111
112
  this.blocks = blocks
112
113
  this.ranges = ranges
113
114
 
@@ -172,6 +173,10 @@ class InflightTracker {
172
173
  this._free = []
173
174
  }
174
175
 
176
+ get idle () {
177
+ return this._requests.length === this._free.length
178
+ }
179
+
175
180
  * [Symbol.iterator] () {
176
181
  for (const req of this._requests) {
177
182
  if (req !== null) yield req
@@ -260,6 +265,7 @@ class Peer {
260
265
 
261
266
  this.inflight = 0
262
267
  this.maxInflight = DEFAULT_MAX_INFLIGHT
268
+ this.dataProcessing = 0
263
269
 
264
270
  this.canUpgrade = true
265
271
 
@@ -515,6 +521,8 @@ class Peer {
515
521
 
516
522
  if (reorg === true) return this.replicator._onreorgdata(this, req, data)
517
523
 
524
+ this.dataProcessing++
525
+
518
526
  try {
519
527
  if (!matchingRequest(req, data) || !(await this.core.verify(data, this))) {
520
528
  this.replicator._onnodata(this, req)
@@ -523,6 +531,8 @@ class Peer {
523
531
  } catch (err) {
524
532
  this.replicator._onnodata(this, req)
525
533
  throw err
534
+ } finally {
535
+ this.dataProcessing--
526
536
  }
527
537
 
528
538
  this.replicator._ondata(this, req, data)
@@ -909,13 +919,21 @@ module.exports = class Replicator {
909
919
  return ref
910
920
  }
911
921
 
912
- addRange (session, { start = 0, end = -1, length = toLength(start, end), blocks = null, linear = false } = {}) {
922
+ addRange (session, { start = 0, end = -1, length = toLength(start, end), blocks = null, linear = false, ifAvailable = false } = {}) {
913
923
  if (blocks !== null) { // if using blocks, start, end just acts as frames around the blocks array
914
924
  start = 0
915
925
  end = length = blocks.length
916
926
  }
917
927
 
918
- const r = new RangeRequest(this._ranges, start, length === -1 ? -1 : start + length, linear, blocks)
928
+ const r = new RangeRequest(
929
+ this._ranges,
930
+ start,
931
+ length === -1 ? -1 : start + length,
932
+ linear,
933
+ ifAvailable,
934
+ blocks
935
+ )
936
+
919
937
  const ref = r.attach(session)
920
938
 
921
939
  this._ranges.push(r)
@@ -1115,6 +1133,14 @@ module.exports = class Replicator {
1115
1133
  return true
1116
1134
  }
1117
1135
 
1136
+ _resolveRangeRequest (req, index) {
1137
+ const head = this._ranges.pop()
1138
+
1139
+ if (index < this._ranges.length) this._ranges[index] = head
1140
+
1141
+ req.resolve(true)
1142
+ }
1143
+
1118
1144
  _clearInflightBlock (tracker, req) {
1119
1145
  const isBlock = tracker === this._blocks
1120
1146
  const index = isBlock === true ? req.block.index : req.hash.index / 2
@@ -1168,14 +1194,9 @@ module.exports = class Replicator {
1168
1194
  while (r.start < r.end && this.core.bitfield.get(mapIndex(r.blocks, r.start)) === true) r.start++
1169
1195
  while (r.start < r.end && this.core.bitfield.get(mapIndex(r.blocks, r.end - 1)) === true) r.end--
1170
1196
 
1171
- if (r.end === -1 || r.start < r.end) continue
1172
-
1173
- if (i < this._ranges.length - 1) this._ranges[i] = this._ranges.pop()
1174
- else this._ranges.pop()
1175
-
1176
- i--
1177
-
1178
- r.resolve(true)
1197
+ if (r.end !== -1 && r.start >= r.end) {
1198
+ this._resolveRangeRequest(r, i--)
1199
+ }
1179
1200
  }
1180
1201
 
1181
1202
  for (let i = 0; i < this._seeks.length; i++) {
@@ -1201,7 +1222,7 @@ module.exports = class Replicator {
1201
1222
  else s.resolve(res)
1202
1223
  }
1203
1224
 
1204
- this.updateAll()
1225
+ if (this._inflight.idle) this.updateAll()
1205
1226
 
1206
1227
  // No additional updates scheduled - return
1207
1228
  if (--this._updatesPending === 0) return
@@ -1210,6 +1231,22 @@ module.exports = class Replicator {
1210
1231
  }
1211
1232
  }
1212
1233
 
1234
+ _maybeResolveIfAvailableRanges () {
1235
+ if (this._ifAvailable > 0 || !this._inflight.idle || !this._ranges.length) return
1236
+
1237
+ for (let i = 0; i < this.peers.length; i++) {
1238
+ if (this.peers[i].dataProcessing > 0) return
1239
+ }
1240
+
1241
+ for (let i = 0; i < this._ranges.length; i++) {
1242
+ const r = this._ranges[i]
1243
+
1244
+ if (r.ifAvailable) {
1245
+ this._resolveRangeRequest(r, i--)
1246
+ }
1247
+ }
1248
+ }
1249
+
1213
1250
  _clearRequest (peer, req) {
1214
1251
  if (req.block !== null) {
1215
1252
  this._clearInflightBlock(this._blocks, req)
@@ -1407,6 +1444,7 @@ module.exports = class Replicator {
1407
1444
  while (this._updatePeerNonPrimary(peer) === true);
1408
1445
 
1409
1446
  this._checkUpgradeIfAvailable()
1447
+ this._maybeResolveIfAvailableRanges()
1410
1448
  }
1411
1449
 
1412
1450
  updateAll () {
@@ -1434,6 +1472,7 @@ module.exports = class Replicator {
1434
1472
  }
1435
1473
 
1436
1474
  this._checkUpgradeIfAvailable()
1475
+ this._maybeResolveIfAvailableRanges()
1437
1476
  }
1438
1477
 
1439
1478
  attachTo (protomux) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hypercore",
3
- "version": "10.0.0-alpha.44",
3
+ "version": "10.0.0-alpha.47",
4
4
  "description": "Hypercore 10",
5
5
  "main": "index.js",
6
6
  "scripts": {