hypercore 10.31.5 → 10.31.7
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 +1 -1
- package/lib/bitfield.js +11 -3
- package/lib/compat.js +2 -1
- package/lib/remote-bitfield.js +59 -5
- package/lib/replicator.js +127 -62
- package/package.json +2 -2
package/index.js
CHANGED
|
@@ -658,7 +658,7 @@ module.exports = class Hypercore extends EventEmitter {
|
|
|
658
658
|
const appended = (status & 0b0001) !== 0
|
|
659
659
|
|
|
660
660
|
if (truncated) {
|
|
661
|
-
this.replicator.ontruncate(bitfield.start)
|
|
661
|
+
this.replicator.ontruncate(bitfield.start, bitfield.length)
|
|
662
662
|
}
|
|
663
663
|
|
|
664
664
|
if ((status & 0b10011) !== 0) {
|
package/lib/bitfield.js
CHANGED
|
@@ -40,10 +40,10 @@ class BitfieldPage {
|
|
|
40
40
|
setRange (start, length, val) {
|
|
41
41
|
quickbit.fill(this.bitfield, val, start, start + length)
|
|
42
42
|
|
|
43
|
-
let i = Math.floor(start /
|
|
44
|
-
const n = i + Math.ceil(length /
|
|
43
|
+
let i = Math.floor(start / 128)
|
|
44
|
+
const n = i + Math.ceil(length / 128)
|
|
45
45
|
|
|
46
|
-
while (i
|
|
46
|
+
while (i <= n) this.tree.update(this.offset * 8 + i++ * 128)
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
findFirst (val, position) {
|
|
@@ -213,6 +213,14 @@ module.exports = class Bitfield {
|
|
|
213
213
|
}
|
|
214
214
|
}
|
|
215
215
|
|
|
216
|
+
getBitfield (index, length) {
|
|
217
|
+
const j = index & (BITS_PER_PAGE - 1)
|
|
218
|
+
const i = (index - j) / BITS_PER_PAGE
|
|
219
|
+
|
|
220
|
+
const p = this._pages.get(i)
|
|
221
|
+
return p || null
|
|
222
|
+
}
|
|
223
|
+
|
|
216
224
|
get (index) {
|
|
217
225
|
const j = index & (BITS_PER_PAGE - 1)
|
|
218
226
|
const i = (index - j) / BITS_PER_PAGE
|
package/lib/compat.js
CHANGED
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
let quickbit = require('quickbit-universal')
|
|
4
4
|
if (
|
|
5
5
|
typeof quickbit.findFirst !== 'function' ||
|
|
6
|
-
typeof quickbit.findLast !== 'function'
|
|
6
|
+
typeof quickbit.findLast !== 'function' ||
|
|
7
|
+
typeof quickbit.clear !== 'function'
|
|
7
8
|
) {
|
|
8
9
|
// This should always load the fallback from the locally installed version
|
|
9
10
|
quickbit = require('quickbit-universal/fallback')
|
package/lib/remote-bitfield.js
CHANGED
|
@@ -35,10 +35,10 @@ class RemoteBitfieldPage {
|
|
|
35
35
|
setRange (start, length, val) {
|
|
36
36
|
quickbit.fill(this.bitfield, val, start, start + length)
|
|
37
37
|
|
|
38
|
-
let i = Math.floor(start /
|
|
39
|
-
const n = i + Math.ceil(length /
|
|
38
|
+
let i = Math.floor(start / 128)
|
|
39
|
+
const n = i + Math.ceil(length / 128)
|
|
40
40
|
|
|
41
|
-
while (i
|
|
41
|
+
while (i <= n) this.tree.update(this.offset * 8 + i++ * 128)
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
findFirst (val, position) {
|
|
@@ -51,6 +51,11 @@ class RemoteBitfieldPage {
|
|
|
51
51
|
|
|
52
52
|
insert (start, bitfield) {
|
|
53
53
|
this.bitfield.set(bitfield, start / 32)
|
|
54
|
+
this.segment.refresh()
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
clear (start, bitfield) {
|
|
58
|
+
quickbit.clear(this.bitfield, { field: bitfield, offset: start })
|
|
54
59
|
}
|
|
55
60
|
}
|
|
56
61
|
|
|
@@ -60,14 +65,22 @@ class RemoteBitfieldSegment {
|
|
|
60
65
|
this.offset = index * BYTES_PER_SEGMENT
|
|
61
66
|
this.tree = quickbit.Index.from([], BYTES_PER_SEGMENT)
|
|
62
67
|
this.pages = new Array(PAGES_PER_SEGMENT)
|
|
68
|
+
this.pagesLength = 0
|
|
63
69
|
}
|
|
64
70
|
|
|
65
71
|
get chunks () {
|
|
66
72
|
return this.tree.chunks
|
|
67
73
|
}
|
|
68
74
|
|
|
75
|
+
refresh () {
|
|
76
|
+
this.tree = quickbit.Index.from(this.tree.chunks, BYTES_PER_SEGMENT)
|
|
77
|
+
}
|
|
78
|
+
|
|
69
79
|
add (page) {
|
|
70
|
-
|
|
80
|
+
const pageIndex = page.index - this.index * PAGES_PER_SEGMENT
|
|
81
|
+
if (pageIndex >= this.pagesLength) this.pagesLength = pageIndex + 1
|
|
82
|
+
|
|
83
|
+
this.pages[pageIndex] = page
|
|
71
84
|
|
|
72
85
|
const chunk = { field: page.bitfield, offset: page.offset }
|
|
73
86
|
|
|
@@ -89,7 +102,7 @@ class RemoteBitfieldSegment {
|
|
|
89
102
|
|
|
90
103
|
if (i >= PAGES_PER_SEGMENT) return -1
|
|
91
104
|
|
|
92
|
-
while (i < this.
|
|
105
|
+
while (i < this.pagesLength) {
|
|
93
106
|
const p = this.pages[i]
|
|
94
107
|
|
|
95
108
|
let index = -1
|
|
@@ -138,6 +151,14 @@ module.exports = class RemoteBitfield {
|
|
|
138
151
|
this._segments = new BigSparseArray()
|
|
139
152
|
}
|
|
140
153
|
|
|
154
|
+
getBitfield (index) {
|
|
155
|
+
const j = index & (BITS_PER_PAGE - 1)
|
|
156
|
+
const i = (index - j) / BITS_PER_PAGE
|
|
157
|
+
|
|
158
|
+
const p = this._pages.get(i)
|
|
159
|
+
return p || null
|
|
160
|
+
}
|
|
161
|
+
|
|
141
162
|
get (index) {
|
|
142
163
|
const j = index & (BITS_PER_PAGE - 1)
|
|
143
164
|
const i = (index - j) / BITS_PER_PAGE
|
|
@@ -278,4 +299,37 @@ module.exports = class RemoteBitfield {
|
|
|
278
299
|
|
|
279
300
|
return true
|
|
280
301
|
}
|
|
302
|
+
|
|
303
|
+
clear (start, bitfield) {
|
|
304
|
+
if (start % 32 !== 0) return false
|
|
305
|
+
|
|
306
|
+
let length = bitfield.byteLength * 8
|
|
307
|
+
|
|
308
|
+
let j = start & (BITS_PER_PAGE - 1)
|
|
309
|
+
let i = (start - j) / BITS_PER_PAGE
|
|
310
|
+
|
|
311
|
+
while (length > 0) {
|
|
312
|
+
let p = this._pages.get(i)
|
|
313
|
+
|
|
314
|
+
if (!p) {
|
|
315
|
+
const k = Math.floor(i / PAGES_PER_SEGMENT)
|
|
316
|
+
const s = this._segments.get(k) || this._segments.set(k, new RemoteBitfieldSegment(k))
|
|
317
|
+
|
|
318
|
+
p = this._pages.set(i, new RemoteBitfieldPage(i, new Uint32Array(WORDS_PER_PAGE), s))
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
const end = Math.min(j + length, BITS_PER_PAGE)
|
|
322
|
+
const range = end - j
|
|
323
|
+
|
|
324
|
+
p.clear(j, bitfield.subarray(0, range / 32))
|
|
325
|
+
|
|
326
|
+
bitfield = bitfield.subarray(range / 32)
|
|
327
|
+
|
|
328
|
+
j = 0
|
|
329
|
+
i++
|
|
330
|
+
length -= range
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
return true
|
|
334
|
+
}
|
|
281
335
|
}
|
package/lib/replicator.js
CHANGED
|
@@ -310,7 +310,7 @@ class Peer {
|
|
|
310
310
|
|
|
311
311
|
this.remoteOpened = false
|
|
312
312
|
this.remoteBitfield = new RemoteBitfield()
|
|
313
|
-
this.
|
|
313
|
+
this.missingBlocks = new RemoteBitfield()
|
|
314
314
|
|
|
315
315
|
this.remoteFork = 0
|
|
316
316
|
this.remoteLength = 0
|
|
@@ -350,7 +350,9 @@ class Peer {
|
|
|
350
350
|
}
|
|
351
351
|
|
|
352
352
|
broadcastRange (start, length, drop) {
|
|
353
|
-
if (drop) this.
|
|
353
|
+
if (drop) this._unclearLocalRange(start, length)
|
|
354
|
+
else this._clearLocalRange(start, length)
|
|
355
|
+
|
|
354
356
|
this.wireRange.send({
|
|
355
357
|
drop,
|
|
356
358
|
start,
|
|
@@ -699,6 +701,7 @@ class Peer {
|
|
|
699
701
|
// might be a fork, verify
|
|
700
702
|
this._checkIfConflict()
|
|
701
703
|
}
|
|
704
|
+
|
|
702
705
|
this.replicator._onnodata(this, req)
|
|
703
706
|
this.replicator.oninvalid(err, req, data, this)
|
|
704
707
|
return
|
|
@@ -732,25 +735,85 @@ class Peer {
|
|
|
732
735
|
}
|
|
733
736
|
|
|
734
737
|
onbitfield ({ start, bitfield }) {
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
+
this.remoteBitfield.insert(start, bitfield)
|
|
739
|
+
this.missingBlocks.insert(start, bitfield)
|
|
740
|
+
this._clearLocalRange(start, bitfield.byteLength * 8)
|
|
741
|
+
this._update()
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
_clearLocalRange (start, length) {
|
|
745
|
+
if (length === 1) {
|
|
746
|
+
this.missingBlocks.set(start, this.remoteBitfield.get(start) && !this.core.bitfield.get(start))
|
|
747
|
+
return
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
const contig = Math.min(this.core.tree.length, this.core.header.hints.contiguousLength)
|
|
751
|
+
|
|
752
|
+
if (start + length < contig) {
|
|
753
|
+
const delta = contig - start
|
|
754
|
+
this.missingBlocks.setRange(start, delta, false)
|
|
755
|
+
return
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
const rem = start & 32767
|
|
759
|
+
if (rem > 0) {
|
|
760
|
+
start -= rem
|
|
761
|
+
length += rem
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
const end = start + Math.min(length, this.core.tree.length)
|
|
765
|
+
while (start < end) {
|
|
766
|
+
const local = this.core.bitfield.getBitfield(start)
|
|
767
|
+
|
|
768
|
+
if (local && local.bitfield) {
|
|
769
|
+
this.missingBlocks.clear(start, local.bitfield)
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
start += 32768
|
|
738
773
|
}
|
|
739
774
|
}
|
|
740
775
|
|
|
776
|
+
_unclearLocalRange (start, length) {
|
|
777
|
+
if (length === 1) {
|
|
778
|
+
this.missingBlocks.set(start, this.remoteBitfield.get(start) && !this.core.bitfield.get(start))
|
|
779
|
+
return
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
const rem = start & 2097151
|
|
783
|
+
if (rem > 0) {
|
|
784
|
+
start -= rem
|
|
785
|
+
length += rem
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
const fixedStart = start
|
|
789
|
+
|
|
790
|
+
const end = start + Math.min(length, this.remoteLength)
|
|
791
|
+
while (start < end) {
|
|
792
|
+
const remote = this.remoteBitfield.getBitfield(start)
|
|
793
|
+
if (remote && remote.bitfield) {
|
|
794
|
+
this.missingBlocks.insert(start, remote.bitfield)
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
start += 2097152
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
this._clearLocalRange(fixedStart, length)
|
|
801
|
+
}
|
|
802
|
+
|
|
741
803
|
onrange ({ drop, start, length }) {
|
|
742
804
|
const has = drop === false
|
|
743
805
|
|
|
744
806
|
if (length === 1) {
|
|
745
|
-
this.remoteBitfield.
|
|
746
|
-
this.
|
|
807
|
+
this.remoteBitfield.set(start, has)
|
|
808
|
+
this.missingBlocks.set(start, has && !this.core.bitfield.get(start))
|
|
747
809
|
} else {
|
|
748
810
|
const rangeStart = this.remoteBitfield.findFirst(!has, start)
|
|
749
811
|
const rangeLength = length - (rangeStart - start)
|
|
750
812
|
|
|
751
813
|
if (rangeLength > 0) {
|
|
752
814
|
this.remoteBitfield.setRange(rangeStart, rangeLength, has)
|
|
753
|
-
this.
|
|
815
|
+
this.missingBlocks.setRange(rangeStart, rangeLength, has)
|
|
816
|
+
if (has) this._clearLocalRange(rangeStart, rangeLength)
|
|
754
817
|
}
|
|
755
818
|
}
|
|
756
819
|
|
|
@@ -942,74 +1005,74 @@ class Peer {
|
|
|
942
1005
|
return true
|
|
943
1006
|
}
|
|
944
1007
|
|
|
945
|
-
|
|
946
|
-
|
|
1008
|
+
_requestRangeBlock (index, length) {
|
|
1009
|
+
if (this.core.bitfield.get(index) === true || !this._hasTreeParent(index)) return false
|
|
947
1010
|
|
|
948
|
-
const
|
|
949
|
-
if (
|
|
1011
|
+
const b = this.replicator._blocks.add(index, PRIORITY.NORMAL)
|
|
1012
|
+
if (b.inflight.length > 0) return false
|
|
950
1013
|
|
|
951
|
-
const
|
|
952
|
-
const off = r.start + (r.linear ? 0 : Math.floor(Math.random() * len))
|
|
1014
|
+
const req = this._makeRequest(index >= length, b.priority)
|
|
953
1015
|
|
|
954
|
-
//
|
|
955
|
-
|
|
956
|
-
|
|
1016
|
+
// If the request cannot be satisfied, dealloc the block request if no one is subscribed to it
|
|
1017
|
+
if (req === null) {
|
|
1018
|
+
b.gc()
|
|
1019
|
+
return false
|
|
1020
|
+
}
|
|
957
1021
|
|
|
958
|
-
|
|
1022
|
+
req.block = { index, nodes: 0 }
|
|
959
1023
|
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
if (index >= end) index -= len
|
|
1024
|
+
b.inflight.push(req)
|
|
1025
|
+
this._send(req)
|
|
963
1026
|
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
wrapped++
|
|
970
|
-
index = this.skipList.findFirst(false, r.start)
|
|
971
|
-
if (index === -1 || index >= end) {
|
|
972
|
-
return false
|
|
973
|
-
}
|
|
974
|
-
}
|
|
975
|
-
}
|
|
1027
|
+
// Don't think this will ever happen, as the pending queue is drained before the range queue
|
|
1028
|
+
// but doesn't hurt to check this explicitly here also.
|
|
1029
|
+
if (b.queued) b.queued = false
|
|
1030
|
+
return true
|
|
1031
|
+
}
|
|
976
1032
|
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
continue
|
|
980
|
-
}
|
|
1033
|
+
_requestRange (r) {
|
|
1034
|
+
const { length, fork } = this.core.tree
|
|
981
1035
|
|
|
982
|
-
|
|
983
|
-
|
|
1036
|
+
if (r.blocks) {
|
|
1037
|
+
let min = -1
|
|
1038
|
+
let max = -1
|
|
1039
|
+
|
|
1040
|
+
for (let i = r.start; i < r.end; i++) {
|
|
1041
|
+
const index = r.blocks[i]
|
|
1042
|
+
if (min === -1 || index < min) min = index
|
|
1043
|
+
if (max === -1 || index > max) max = index
|
|
1044
|
+
if (this.missingBlocks.get(index) === true && this._requestRangeBlock(index, length)) return true
|
|
984
1045
|
}
|
|
985
1046
|
|
|
986
|
-
|
|
1047
|
+
if (min > -1) this._maybeWant(min, max - min)
|
|
1048
|
+
return false
|
|
1049
|
+
}
|
|
987
1050
|
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
continue
|
|
991
|
-
}
|
|
1051
|
+
const end = Math.min(r.end === -1 ? this.remoteLength : r.end, this.remoteLength)
|
|
1052
|
+
if (end < r.start || fork !== this.remoteFork) return false
|
|
992
1053
|
|
|
993
|
-
|
|
1054
|
+
const len = end - r.start
|
|
1055
|
+
const off = r.start + (r.linear ? 0 : Math.floor(Math.random() * len))
|
|
994
1056
|
|
|
995
|
-
|
|
996
|
-
if (req === null) {
|
|
997
|
-
b.gc()
|
|
998
|
-
return false
|
|
999
|
-
}
|
|
1057
|
+
let i = off
|
|
1000
1058
|
|
|
1001
|
-
|
|
1059
|
+
while (true) {
|
|
1060
|
+
i = this.missingBlocks.findFirst(true, i)
|
|
1061
|
+
if (i === -1 || i >= end) break
|
|
1062
|
+
|
|
1063
|
+
if (this._requestRangeBlock(i, length)) return true
|
|
1064
|
+
i++
|
|
1065
|
+
}
|
|
1002
1066
|
|
|
1003
|
-
|
|
1067
|
+
i = r.start
|
|
1004
1068
|
|
|
1005
|
-
|
|
1006
|
-
this.
|
|
1069
|
+
while (true) {
|
|
1070
|
+
i = this.missingBlocks.findFirst(true, i)
|
|
1007
1071
|
|
|
1008
|
-
|
|
1009
|
-
// but doesn't hurt to check this explicitly here also.
|
|
1010
|
-
if (b.queued) b.queued = false
|
|
1072
|
+
if (i === -1 || i >= off) break
|
|
1011
1073
|
|
|
1012
|
-
return true
|
|
1074
|
+
if (this._requestRangeBlock(i, length)) return true
|
|
1075
|
+
i++
|
|
1013
1076
|
}
|
|
1014
1077
|
|
|
1015
1078
|
this._maybeWant(r.start, len)
|
|
@@ -1197,7 +1260,7 @@ module.exports = class Replicator {
|
|
|
1197
1260
|
}
|
|
1198
1261
|
|
|
1199
1262
|
// Called externally when a truncation upgrade has been processed
|
|
1200
|
-
ontruncate (newLength) {
|
|
1263
|
+
ontruncate (newLength, truncated) {
|
|
1201
1264
|
const notify = []
|
|
1202
1265
|
|
|
1203
1266
|
for (const blk of this._blocks) {
|
|
@@ -1211,6 +1274,8 @@ module.exports = class Replicator {
|
|
|
1211
1274
|
blk.detach(r, SNAPSHOT_NOT_AVAILABLE())
|
|
1212
1275
|
}
|
|
1213
1276
|
}
|
|
1277
|
+
|
|
1278
|
+
for (const peer of this.peers) peer._unclearLocalRange(newLength, truncated)
|
|
1214
1279
|
}
|
|
1215
1280
|
|
|
1216
1281
|
// Called externally when a upgrade has been processed
|
|
@@ -1526,9 +1591,9 @@ module.exports = class Replicator {
|
|
|
1526
1591
|
|
|
1527
1592
|
if (b === null || removeInflight(b.inflight, req) === false) return
|
|
1528
1593
|
|
|
1529
|
-
if (isBlock && this.core.bitfield.get(index) === false) {
|
|
1530
|
-
|
|
1531
|
-
}
|
|
1594
|
+
// if (isBlock && this.core.bitfield.get(index) === false) {
|
|
1595
|
+
// for (const peer of this.peers) peer.skipList.set(index, false)
|
|
1596
|
+
// }
|
|
1532
1597
|
|
|
1533
1598
|
if (b.refs.length > 0 && isBlock === true) {
|
|
1534
1599
|
this._queueBlock(b)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hypercore",
|
|
3
|
-
"version": "10.31.
|
|
3
|
+
"version": "10.31.7",
|
|
4
4
|
"description": "Hypercore is a secure, distributed append-only log",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"hypercore-id-encoding": "^1.2.0",
|
|
49
49
|
"is-options": "^1.0.1",
|
|
50
50
|
"protomux": "^3.5.0",
|
|
51
|
-
"quickbit-universal": "^2.
|
|
51
|
+
"quickbit-universal": "^2.2.0",
|
|
52
52
|
"random-access-file": "^4.0.0",
|
|
53
53
|
"random-array-iterator": "^1.0.0",
|
|
54
54
|
"safety-catch": "^1.0.1",
|