1
1
const flat = require ( 'flat-tree' )
2
2
const crypto = require ( 'hypercore-crypto' )
3
3
const c = require ( 'compact-encoding' )
4
+ const Xache = require ( 'xache' )
4
5
const b4a = require ( 'b4a' )
5
6
const caps = require ( './caps' )
6
7
7
8
const BLANK_HASH = b4a . alloc ( 32 )
8
9
const OLD_TREE = b4a . from ( [ 5 , 2 , 87 , 2 , 0 , 0 , 40 , 7 , 66 , 76 , 65 , 75 , 69 , 50 , 98 ] )
10
+ const TREE_CACHE = 128 // speeds up linear scans by A LOT
9
11
10
12
class NodeQueue {
11
13
constructor ( nodes , extra = null ) {
@@ -140,6 +142,7 @@ class MerkleTreeBatch {
140
142
: this . ancestors
141
143
142
144
this . tree . truncated = true
145
+ this . tree . cache = new Xache ( { maxSize : this . tree . cache . maxSize } )
143
146
truncateMap ( this . tree . unflushed , this . ancestors )
144
147
if ( this . tree . flushing !== null ) truncateMap ( this . tree . flushing , this . ancestors )
145
148
}
@@ -350,6 +353,7 @@ module.exports = class MerkleTree {
350
353
351
354
this . storage = storage
352
355
this . unflushed = new Map ( )
356
+ this . cache = new Xache ( { maxSize : TREE_CACHE } )
353
357
this . flushing = null
354
358
this . truncated = false
355
359
this . truncateTo = 0
@@ -403,6 +407,9 @@ module.exports = class MerkleTree {
403
407
}
404
408
405
409
get ( index , error = true ) {
410
+ const c = this . cache . get ( index )
411
+ if ( c ) return c
412
+
406
413
let node = this . unflushed . get ( index )
407
414
408
415
if ( this . flushing !== null && node === undefined ) {
@@ -422,7 +429,7 @@ module.exports = class MerkleTree {
422
429
return Promise . resolve ( node )
423
430
}
424
431
425
- return getStoredNode ( this . storage , index , error )
432
+ return getStoredNode ( this . storage , index , this . cache , error )
426
433
}
427
434
428
435
async flush ( ) {
@@ -495,6 +502,7 @@ module.exports = class MerkleTree {
495
502
}
496
503
497
504
clear ( ) {
505
+ this . cache = new Xache ( { maxSize : this . cache . maxSize } )
498
506
this . truncated = true
499
507
this . truncateTo = 0
500
508
this . roots = [ ]
@@ -754,7 +762,7 @@ module.exports = class MerkleTree {
754
762
755
763
const roots = [ ]
756
764
for ( const index of flat . fullRoots ( 2 * length ) ) {
757
- roots . push ( await getStoredNode ( storage , index , true ) )
765
+ roots . push ( await getStoredNode ( storage , index , null , true ) )
758
766
}
759
767
760
768
return new MerkleTree ( storage , roots , opts . fork || 0 , opts . signature || null )
@@ -1085,7 +1093,7 @@ function blankNode (index) {
1085
1093
1086
1094
// Storage methods
1087
1095
1088
- function getStoredNode ( storage , index , error ) {
1096
+ function getStoredNode ( storage , index , cache , error ) {
1089
1097
return new Promise ( ( resolve , reject ) => {
1090
1098
storage . read ( 40 * index , 40 , ( err , data ) => {
1091
1099
if ( err ) {
@@ -1103,7 +1111,9 @@ function getStoredNode (storage, index, error) {
1103
1111
return
1104
1112
}
1105
1113
1106
- resolve ( { index, size, hash } )
1114
+ const node = { index, size, hash }
1115
+ if ( cache !== null ) cache . set ( index , node )
1116
+ resolve ( node )
1107
1117
} )
1108
1118
} )
1109
1119
}
@@ -1122,7 +1132,7 @@ async function autoLength (storage) {
1122
1132
if ( ! nodes ) return 0
1123
1133
const ite = flat . iterator ( nodes - 1 )
1124
1134
let index = nodes - 1
1125
- while ( await getStoredNode ( storage , ite . parent ( ) , false ) ) index = ite . index
1135
+ while ( await getStoredNode ( storage , ite . parent ( ) , null , false ) ) index = ite . index
1126
1136
return flat . rightSpan ( index ) / 2 + 1
1127
1137
}
1128
1138
0 commit comments