hypercore 10.4.0 → 10.4.1
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/lib/bitfield.js +172 -50
- package/lib/core.js +1 -1
- package/package.json +1 -1
package/lib/bitfield.js
CHANGED
|
@@ -2,16 +2,28 @@ const BigSparseArray = require('big-sparse-array')
|
|
|
2
2
|
const b4a = require('b4a')
|
|
3
3
|
const quickbit = require('./compat').quickbit
|
|
4
4
|
|
|
5
|
-
const BITS_PER_PAGE =
|
|
5
|
+
const BITS_PER_PAGE = 32768
|
|
6
6
|
const BYTES_PER_PAGE = BITS_PER_PAGE / 8
|
|
7
7
|
const WORDS_PER_PAGE = BYTES_PER_PAGE / 4
|
|
8
|
+
const BITS_PER_SEGMENT = 2097152
|
|
9
|
+
const BYTES_PER_SEGMENT = BITS_PER_SEGMENT / 8
|
|
10
|
+
const WORDS_PER_SEGMENT = BYTES_PER_SEGMENT / 4
|
|
11
|
+
const INITIAL_WORDS_PER_SEGMENT = 1024
|
|
12
|
+
const PAGES_PER_SEGMENT = BITS_PER_SEGMENT / BITS_PER_PAGE
|
|
13
|
+
const SEGMENT_GROWTH_FACTOR = 4
|
|
8
14
|
|
|
9
15
|
class BitfieldPage {
|
|
10
|
-
constructor (index,
|
|
16
|
+
constructor (index, segment) {
|
|
11
17
|
this.dirty = false
|
|
12
18
|
this.index = index
|
|
13
|
-
this.bitfield =
|
|
14
|
-
this.
|
|
19
|
+
this.bitfield = null
|
|
20
|
+
this.segment = segment
|
|
21
|
+
|
|
22
|
+
segment.add(this)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
get tree () {
|
|
26
|
+
return this.segment.tree
|
|
15
27
|
}
|
|
16
28
|
|
|
17
29
|
get (index) {
|
|
@@ -20,7 +32,7 @@ class BitfieldPage {
|
|
|
20
32
|
|
|
21
33
|
set (index, val) {
|
|
22
34
|
if (quickbit.set(this.bitfield, index, val)) {
|
|
23
|
-
this.tree.update(index)
|
|
35
|
+
this.tree.update(this.offset * 8 + index)
|
|
24
36
|
}
|
|
25
37
|
}
|
|
26
38
|
|
|
@@ -30,34 +42,144 @@ class BitfieldPage {
|
|
|
30
42
|
let i = Math.floor(start / 32)
|
|
31
43
|
const n = i + Math.ceil(length / 32)
|
|
32
44
|
|
|
33
|
-
while (i < n) this.tree.update(i++ * 32)
|
|
45
|
+
while (i < n) this.tree.update(this.offset * 8 + i++ * 32)
|
|
34
46
|
}
|
|
35
47
|
|
|
36
48
|
findFirst (val, position) {
|
|
37
|
-
return quickbit.findFirst(this.bitfield, val,
|
|
49
|
+
return quickbit.findFirst(this.bitfield, val, position)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
findLast (val, position) {
|
|
53
|
+
return quickbit.findLast(this.bitfield, val, position)
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
class BitfieldSegment {
|
|
58
|
+
constructor (index, bitfield) {
|
|
59
|
+
this.index = index
|
|
60
|
+
this.offset = index * BYTES_PER_SEGMENT
|
|
61
|
+
this.tree = quickbit.Index.from(bitfield)
|
|
62
|
+
this.pages = new Array(PAGES_PER_SEGMENT)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
get bitfield () {
|
|
66
|
+
return this.tree.field
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
add (page) {
|
|
70
|
+
const i = page.index - this.index * PAGES_PER_SEGMENT
|
|
71
|
+
this.pages[i] = page
|
|
72
|
+
|
|
73
|
+
const start = i * WORDS_PER_PAGE
|
|
74
|
+
const end = start + WORDS_PER_PAGE
|
|
75
|
+
|
|
76
|
+
if (end >= this.bitfield.length) this.reallocate(end)
|
|
77
|
+
|
|
78
|
+
page.bitfield = this.bitfield.subarray(start, end)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
reallocate (length) {
|
|
82
|
+
let target = this.bitfield.length
|
|
83
|
+
while (target < length) target *= SEGMENT_GROWTH_FACTOR
|
|
84
|
+
|
|
85
|
+
const bitfield = new Uint32Array(target)
|
|
86
|
+
bitfield.set(this.bitfield)
|
|
87
|
+
|
|
88
|
+
this.tree = quickbit.Index.from(bitfield)
|
|
89
|
+
|
|
90
|
+
for (let i = 0; i < this.pages.length; i++) {
|
|
91
|
+
const page = this.pages[i]
|
|
92
|
+
if (!page) continue
|
|
93
|
+
|
|
94
|
+
const start = i * WORDS_PER_PAGE
|
|
95
|
+
const end = start + WORDS_PER_PAGE
|
|
96
|
+
|
|
97
|
+
page.bitfield = bitfield.subarray(start, end)
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
findFirst (val, position) {
|
|
102
|
+
position = this.tree.skipFirst(!val, position)
|
|
103
|
+
|
|
104
|
+
const j = position & (BITS_PER_PAGE - 1)
|
|
105
|
+
const i = (position - j) / BITS_PER_PAGE
|
|
106
|
+
|
|
107
|
+
if (i >= PAGES_PER_SEGMENT) return -1
|
|
108
|
+
|
|
109
|
+
const p = this.pages[i]
|
|
110
|
+
|
|
111
|
+
if (p) {
|
|
112
|
+
const index = p.findFirst(val, j)
|
|
113
|
+
|
|
114
|
+
if (index !== -1) {
|
|
115
|
+
return i * BITS_PER_PAGE + index
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return -1
|
|
38
120
|
}
|
|
39
121
|
|
|
40
122
|
findLast (val, position) {
|
|
41
|
-
|
|
123
|
+
position = this.tree.skipLast(!val, position)
|
|
124
|
+
|
|
125
|
+
const j = position & (BITS_PER_PAGE - 1)
|
|
126
|
+
const i = (position - j) / BITS_PER_PAGE
|
|
127
|
+
|
|
128
|
+
if (i >= PAGES_PER_SEGMENT) return -1
|
|
129
|
+
|
|
130
|
+
const p = this.pages[i]
|
|
131
|
+
|
|
132
|
+
if (p) {
|
|
133
|
+
const index = p.findLast(val, j)
|
|
134
|
+
|
|
135
|
+
if (index !== -1) {
|
|
136
|
+
return i * BITS_PER_PAGE + index
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return -1
|
|
42
141
|
}
|
|
43
142
|
}
|
|
44
143
|
|
|
45
144
|
module.exports = class Bitfield {
|
|
46
|
-
constructor (storage,
|
|
145
|
+
constructor (storage, buffer) {
|
|
47
146
|
this.unflushed = []
|
|
48
147
|
this.storage = storage
|
|
49
|
-
this.resumed = !!(
|
|
148
|
+
this.resumed = !!(buffer && buffer.byteLength >= 4)
|
|
50
149
|
|
|
51
150
|
this._pages = new BigSparseArray()
|
|
151
|
+
this._segments = new BigSparseArray()
|
|
152
|
+
|
|
153
|
+
const view = this.resumed
|
|
154
|
+
? new Uint32Array(
|
|
155
|
+
buffer.buffer,
|
|
156
|
+
buffer.byteOffset,
|
|
157
|
+
Math.floor(buffer.byteLength / 4)
|
|
158
|
+
)
|
|
159
|
+
: new Uint32Array(INITIAL_WORDS_PER_SEGMENT)
|
|
160
|
+
|
|
161
|
+
for (let i = 0; i < view.length; i += WORDS_PER_SEGMENT) {
|
|
162
|
+
let bitfield = view.subarray(i, i + (WORDS_PER_SEGMENT))
|
|
163
|
+
let length = WORDS_PER_SEGMENT
|
|
164
|
+
|
|
165
|
+
if (i === 0) {
|
|
166
|
+
length = INITIAL_WORDS_PER_SEGMENT
|
|
167
|
+
while (length < bitfield.length) length *= SEGMENT_GROWTH_FACTOR
|
|
168
|
+
}
|
|
52
169
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
170
|
+
if (bitfield.length !== length) {
|
|
171
|
+
const copy = new Uint32Array(length)
|
|
172
|
+
copy.set(bitfield, 0)
|
|
173
|
+
bitfield = copy
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const segment = new BitfieldSegment(i / (WORDS_PER_SEGMENT), bitfield)
|
|
177
|
+
this._segments.set(segment.index, segment)
|
|
56
178
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
179
|
+
for (let j = 0; j < bitfield.length; j += WORDS_PER_PAGE) {
|
|
180
|
+
const page = new BitfieldPage((i + j) / WORDS_PER_PAGE, segment)
|
|
181
|
+
this._pages.set(page.index, page)
|
|
182
|
+
}
|
|
61
183
|
}
|
|
62
184
|
}
|
|
63
185
|
|
|
@@ -77,7 +199,10 @@ module.exports = class Bitfield {
|
|
|
77
199
|
let p = this._pages.get(i)
|
|
78
200
|
|
|
79
201
|
if (!p && val) {
|
|
80
|
-
|
|
202
|
+
const k = Math.floor(i / PAGES_PER_SEGMENT)
|
|
203
|
+
const s = this._segments.get(k) || this._segments.set(k, new BitfieldSegment(k, new Uint32Array(k === 0 ? INITIAL_WORDS_PER_SEGMENT : WORDS_PER_SEGMENT)))
|
|
204
|
+
|
|
205
|
+
p = this._pages.set(i, new BitfieldPage(i, s))
|
|
81
206
|
}
|
|
82
207
|
|
|
83
208
|
if (p) {
|
|
@@ -98,7 +223,10 @@ module.exports = class Bitfield {
|
|
|
98
223
|
let p = this._pages.get(i)
|
|
99
224
|
|
|
100
225
|
if (!p && val) {
|
|
101
|
-
|
|
226
|
+
const k = Math.floor(i / PAGES_PER_SEGMENT)
|
|
227
|
+
const s = this._segments.get(k) || this._segments.set(k, new BitfieldSegment(k, new Uint32Array(k === 0 ? INITIAL_WORDS_PER_SEGMENT : WORDS_PER_SEGMENT)))
|
|
228
|
+
|
|
229
|
+
p = this._pages.set(i, new BitfieldPage(i, s))
|
|
102
230
|
}
|
|
103
231
|
|
|
104
232
|
const end = Math.min(j + length, BITS_PER_PAGE)
|
|
@@ -120,17 +248,17 @@ module.exports = class Bitfield {
|
|
|
120
248
|
}
|
|
121
249
|
|
|
122
250
|
findFirst (val, position) {
|
|
123
|
-
let j = position & (
|
|
124
|
-
let i = (position - j) /
|
|
251
|
+
let j = position & (BITS_PER_SEGMENT - 1)
|
|
252
|
+
let i = (position - j) / BITS_PER_SEGMENT
|
|
125
253
|
|
|
126
|
-
while (i < this.
|
|
127
|
-
const
|
|
254
|
+
while (i < this._segments.maxLength) {
|
|
255
|
+
const s = this._segments.get(i)
|
|
128
256
|
|
|
129
|
-
if (
|
|
130
|
-
const index =
|
|
257
|
+
if (s) {
|
|
258
|
+
const index = s.findFirst(val, j)
|
|
131
259
|
|
|
132
260
|
if (index !== -1) {
|
|
133
|
-
return i *
|
|
261
|
+
return i * BITS_PER_SEGMENT + index
|
|
134
262
|
}
|
|
135
263
|
}
|
|
136
264
|
|
|
@@ -150,21 +278,21 @@ module.exports = class Bitfield {
|
|
|
150
278
|
}
|
|
151
279
|
|
|
152
280
|
findLast (val, position) {
|
|
153
|
-
let j = position & (
|
|
154
|
-
let i = (position - j) /
|
|
281
|
+
let j = position & (BITS_PER_SEGMENT - 1)
|
|
282
|
+
let i = (position - j) / BITS_PER_SEGMENT
|
|
155
283
|
|
|
156
284
|
while (i >= 0) {
|
|
157
|
-
const
|
|
285
|
+
const s = this._segments.get(i)
|
|
158
286
|
|
|
159
|
-
if (
|
|
160
|
-
const index =
|
|
287
|
+
if (s) {
|
|
288
|
+
const index = s.findLast(val, j)
|
|
161
289
|
|
|
162
290
|
if (index !== -1) {
|
|
163
|
-
return i *
|
|
291
|
+
return i * BITS_PER_SEGMENT + index
|
|
164
292
|
}
|
|
165
293
|
}
|
|
166
294
|
|
|
167
|
-
j =
|
|
295
|
+
j = BITS_PER_SEGMENT - 1
|
|
168
296
|
i--
|
|
169
297
|
}
|
|
170
298
|
|
|
@@ -180,25 +308,25 @@ module.exports = class Bitfield {
|
|
|
180
308
|
}
|
|
181
309
|
|
|
182
310
|
* want (start, length) {
|
|
183
|
-
const j = start & (
|
|
184
|
-
let i = (start - j) /
|
|
311
|
+
const j = start & (BITS_PER_SEGMENT - 1)
|
|
312
|
+
let i = (start - j) / BITS_PER_SEGMENT
|
|
185
313
|
|
|
186
314
|
while (length > 0) {
|
|
187
|
-
const
|
|
315
|
+
const s = this._segments.get(i)
|
|
188
316
|
|
|
189
|
-
if (
|
|
317
|
+
if (s) {
|
|
190
318
|
// We always send at least 4 KiB worth of bitfield in a want, rounding
|
|
191
319
|
// to the nearest 4 KiB.
|
|
192
|
-
const end = ceilTo(clamp(length / 8, 4096,
|
|
320
|
+
const end = ceilTo(clamp(length / 8, 4096, BYTES_PER_SEGMENT), 4096)
|
|
193
321
|
|
|
194
322
|
yield {
|
|
195
|
-
start: i *
|
|
196
|
-
bitfield:
|
|
323
|
+
start: i * BITS_PER_SEGMENT,
|
|
324
|
+
bitfield: s.bitfield.subarray(0, end / 4)
|
|
197
325
|
}
|
|
198
326
|
}
|
|
199
327
|
|
|
200
328
|
i++
|
|
201
|
-
length -=
|
|
329
|
+
length -= BITS_PER_SEGMENT
|
|
202
330
|
}
|
|
203
331
|
}
|
|
204
332
|
|
|
@@ -251,12 +379,13 @@ module.exports = class Bitfield {
|
|
|
251
379
|
})
|
|
252
380
|
}
|
|
253
381
|
|
|
254
|
-
static open (storage) {
|
|
382
|
+
static open (storage, tree = null) {
|
|
255
383
|
return new Promise((resolve, reject) => {
|
|
256
384
|
storage.stat((err, st) => {
|
|
257
385
|
if (err) return resolve(new Bitfield(storage, null))
|
|
258
|
-
|
|
386
|
+
let size = st.size - (st.size & 3)
|
|
259
387
|
if (!size) return resolve(new Bitfield(storage, null))
|
|
388
|
+
if (tree) size = Math.min(size, ceilTo(tree.length / 8, 4096))
|
|
260
389
|
storage.read(0, size, (err, data) => {
|
|
261
390
|
if (err) return reject(err)
|
|
262
391
|
resolve(new Bitfield(storage, data))
|
|
@@ -266,13 +395,6 @@ module.exports = class Bitfield {
|
|
|
266
395
|
}
|
|
267
396
|
}
|
|
268
397
|
|
|
269
|
-
function ensureSize (buffer, size) {
|
|
270
|
-
if (buffer.byteLength === size) return buffer
|
|
271
|
-
const copy = new Uint32Array(size)
|
|
272
|
-
copy.set(buffer, 0)
|
|
273
|
-
return copy
|
|
274
|
-
}
|
|
275
|
-
|
|
276
398
|
function clamp (n, min, max) {
|
|
277
399
|
return Math.min(Math.max(n, min), max)
|
|
278
400
|
}
|
package/lib/core.js
CHANGED
|
@@ -108,7 +108,7 @@ module.exports = class Core {
|
|
|
108
108
|
}
|
|
109
109
|
|
|
110
110
|
const tree = await MerkleTree.open(treeFile, { crypto, ...header.tree })
|
|
111
|
-
const bitfield = await Bitfield.open(bitfieldFile)
|
|
111
|
+
const bitfield = await Bitfield.open(bitfieldFile, tree)
|
|
112
112
|
const blocks = new BlockStore(dataFile, tree)
|
|
113
113
|
|
|
114
114
|
if (overwrite) {
|