@@ -236,27 +236,22 @@ func (db *merkleDB) rebuild(ctx context.Context) error {
236
236
it := db .nodeDB .NewIterator ()
237
237
defer it .Release ()
238
238
239
- currentViewSize := 0
240
239
viewSizeLimit := math .Max (
241
240
db .nodeCache .maxSize / rebuildViewSizeFractionOfCacheSize ,
242
241
minRebuildViewSizePerCommit ,
243
242
)
244
-
245
- currentView , err := db .newUntrackedView (viewSizeLimit )
246
- if err != nil {
247
- return err
248
- }
243
+ currentOps := make ([]database.BatchOp , 0 , viewSizeLimit )
249
244
250
245
for it .Next () {
251
- if currentViewSize >= viewSizeLimit {
252
- if err := currentView .commitToDB (ctx ); err != nil {
246
+ if len (currentOps ) >= viewSizeLimit {
247
+ view , err := db .newUntrackedView (currentOps )
248
+ if err != nil {
253
249
return err
254
250
}
255
- currentView , err = db .newUntrackedView (viewSizeLimit )
256
- if err != nil {
251
+ if err := view .commitToDB (ctx ); err != nil {
257
252
return err
258
253
}
259
- currentViewSize = 0
254
+ currentOps = make ([]database. BatchOp , 0 , viewSizeLimit )
260
255
}
261
256
262
257
key := it .Key ()
@@ -266,20 +261,21 @@ func (db *merkleDB) rebuild(ctx context.Context) error {
266
261
if err != nil {
267
262
return err
268
263
}
269
- if n .hasValue () {
270
- serializedPath := path .Serialize ()
271
- if err := currentView .Insert (ctx , serializedPath .Value , n .value .Value ()); err != nil {
272
- return err
273
- }
274
- currentViewSize ++
275
- } else if err := db .nodeDB .Delete (key ); err != nil {
276
- return err
277
- }
264
+
265
+ currentOps = append (currentOps , database.BatchOp {
266
+ Key : path .Serialize ().Value ,
267
+ Value : n .value .Value (),
268
+ Delete : ! n .hasValue (),
269
+ })
278
270
}
279
271
if err := it .Error (); err != nil {
280
272
return err
281
273
}
282
- if err := currentView .commitToDB (ctx ); err != nil {
274
+ view , err := db .newUntrackedView (currentOps )
275
+ if err != nil {
276
+ return err
277
+ }
278
+ if err := view .commitToDB (ctx ); err != nil {
283
279
return err
284
280
}
285
281
return db .nodeDB .Compact (nil , nil )
@@ -301,8 +297,16 @@ func (db *merkleDB) CommitChangeProof(ctx context.Context, proof *ChangeProof) e
301
297
if db .closed {
302
298
return database .ErrClosed
303
299
}
300
+ ops := make ([]database.BatchOp , len (proof .KeyChanges ))
301
+ for i , kv := range proof .KeyChanges {
302
+ ops [i ] = database.BatchOp {
303
+ Key : kv .Key ,
304
+ Value : kv .Value .Value (),
305
+ Delete : kv .Value .IsNothing (),
306
+ }
307
+ }
304
308
305
- view , err := db .prepareChangeProofView ( proof )
309
+ view , err := db .newUntrackedView ( ops )
306
310
if err != nil {
307
311
return err
308
312
}
@@ -317,10 +321,37 @@ func (db *merkleDB) CommitRangeProof(ctx context.Context, start []byte, proof *R
317
321
return database .ErrClosed
318
322
}
319
323
320
- view , err := db .prepareRangeProofView (start , proof )
324
+ ops := make ([]database.BatchOp , len (proof .KeyValues ))
325
+ keys := set.NewSet [string ](len (proof .KeyValues ))
326
+ for i , kv := range proof .KeyValues {
327
+ keys .Add (string (kv .Key ))
328
+ ops [i ] = database.BatchOp {
329
+ Key : kv .Key ,
330
+ Value : kv .Value ,
331
+ }
332
+ }
333
+
334
+ var largestKey []byte
335
+ if len (proof .KeyValues ) > 0 {
336
+ largestKey = proof .KeyValues [len (proof .KeyValues )- 1 ].Key
337
+ }
338
+ keysToDelete , err := db .getKeysNotInSet (start , largestKey , keys )
339
+ if err != nil {
340
+ return err
341
+ }
342
+ for _ , keyToDelete := range keysToDelete {
343
+ ops = append (ops , database.BatchOp {
344
+ Key : keyToDelete ,
345
+ Delete : true ,
346
+ })
347
+ }
348
+
349
+ // Don't need to lock [view] because nobody else has a reference to it.
350
+ view , err := db .newUntrackedView (ops )
321
351
if err != nil {
322
352
return err
323
353
}
354
+
324
355
return view .commitToDB (ctx )
325
356
}
326
357
@@ -469,7 +500,7 @@ func (db *merkleDB) getProof(ctx context.Context, key []byte) (*Proof, error) {
469
500
return nil , database .ErrClosed
470
501
}
471
502
472
- view , err := db .newUntrackedView (defaultPreallocationSize )
503
+ view , err := db .newUntrackedView (nil )
473
504
if err != nil {
474
505
return nil , err
475
506
}
@@ -633,35 +664,37 @@ func (db *merkleDB) GetChangeProof(
633
664
634
665
// NewView returns a new view on top of this trie.
635
666
// Changes made to the view will only be reflected in the original trie if Commit is called.
636
- // Assumes [db.lock] isn't held.
637
- func (db * merkleDB ) NewView () (TrieView , error ) {
638
- return db .NewPreallocatedView (defaultPreallocationSize )
639
- }
667
+ // Assumes [db.commitLock] and [db.lock] aren't held.
668
+ func (db * merkleDB ) NewView (batchOps []database.BatchOp ) (TrieView , error ) {
669
+ // ensure the db doesn't change while creating the new view
670
+ db .commitLock .RLock ()
671
+ defer db .commitLock .RUnlock ()
640
672
641
- // Returns a new view that isn't tracked in [db.childViews].
642
- // For internal use only, namely in methods that create short-lived views.
643
- // Assumes [db.lock] and/or [db.commitLock] is read locked.
644
- func (db * merkleDB ) newUntrackedView (estimatedSize int ) (* trieView , error ) {
645
- return newTrieView (db , db , db .root .clone (), estimatedSize )
646
- }
673
+ newView , err := db .newUntrackedView (batchOps )
674
+ if err != nil {
675
+ return nil , err
676
+ }
647
677
648
- // NewPreallocatedView returns a new view with memory allocated to hold at least [estimatedSize] value changes at a time.
649
- // If more changes are made, additional memory will be allocated.
650
- // The returned view is added to [db.childViews].
651
- // Assumes [db.lock] isn't held.
652
- func (db * merkleDB ) NewPreallocatedView (estimatedSize int ) (TrieView , error ) {
678
+ // ensure access to childViews is protected
653
679
db .lock .Lock ()
654
680
defer db .lock .Unlock ()
655
681
682
+ db .childViews = append (db .childViews , newView )
683
+ return newView , nil
684
+ }
685
+
686
+ // Returns a new view that isn't tracked in [db.childViews].
687
+ // For internal use only, namely in methods that create short-lived views.
688
+ // Assumes [db.lock] isn't held and [db.commitLock] is read locked.
689
+ func (db * merkleDB ) newUntrackedView (batchOps []database.BatchOp ) (* trieView , error ) {
656
690
if db .closed {
657
691
return nil , database .ErrClosed
658
692
}
659
693
660
- newView , err := newTrieView (db , db , db .root .clone (), estimatedSize )
694
+ newView , err := newTrieView (db , db , db .root .clone (), batchOps )
661
695
if err != nil {
662
696
return nil , err
663
697
}
664
- db .childViews = append (db .childViews , newView )
665
698
return newView , nil
666
699
}
667
700
@@ -698,14 +731,15 @@ func (db *merkleDB) Insert(ctx context.Context, k, v []byte) error {
698
731
return database .ErrClosed
699
732
}
700
733
701
- view , err := db .newUntrackedView (defaultPreallocationSize )
734
+ view , err := db .newUntrackedView ([]database.BatchOp {
735
+ {
736
+ Key : k ,
737
+ Value : v ,
738
+ },
739
+ })
702
740
if err != nil {
703
741
return err
704
742
}
705
- // Don't need to lock [view] because nobody else has a reference to it.
706
- if err := view .insert (k , v ); err != nil {
707
- return err
708
- }
709
743
return view .commitToDB (ctx )
710
744
}
711
745
@@ -817,14 +851,15 @@ func (db *merkleDB) Remove(ctx context.Context, key []byte) error {
817
851
return database .ErrClosed
818
852
}
819
853
820
- view , err := db .newUntrackedView (defaultPreallocationSize )
854
+ view , err := db .newUntrackedView ([]database.BatchOp {
855
+ {
856
+ Key : key ,
857
+ Delete : true ,
858
+ },
859
+ })
821
860
if err != nil {
822
861
return err
823
862
}
824
- // Don't need to lock [view] because nobody else has a reference to it.
825
- if err = view .remove (key ); err != nil {
826
- return err
827
- }
828
863
return view .commitToDB (ctx )
829
864
}
830
865
@@ -836,7 +871,7 @@ func (db *merkleDB) commitBatch(ops []database.BatchOp) error {
836
871
return database .ErrClosed
837
872
}
838
873
839
- view , err := db .prepareBatchView (ops )
874
+ view , err := db .newUntrackedView (ops )
840
875
if err != nil {
841
876
return err
842
877
}
@@ -1049,23 +1084,22 @@ func (db *merkleDB) VerifyChangeProof(
1049
1084
return err
1050
1085
}
1051
1086
1087
+ // Insert the key-value pairs into the trie.
1088
+ ops := make ([]database.BatchOp , len (proof .KeyChanges ))
1089
+ for i , kv := range proof .KeyChanges {
1090
+ ops [i ] = database.BatchOp {
1091
+ Key : kv .Key ,
1092
+ Value : kv .Value .Value (),
1093
+ Delete : kv .Value .IsNothing (),
1094
+ }
1095
+ }
1096
+
1052
1097
// Don't need to lock [view] because nobody else has a reference to it.
1053
- view , err := db .newUntrackedView (len ( proof . KeyChanges ) )
1098
+ view , err := db .newUntrackedView (ops )
1054
1099
if err != nil {
1055
1100
return err
1056
1101
}
1057
1102
1058
- // Insert the key-value pairs into the trie.
1059
- for _ , kv := range proof .KeyChanges {
1060
- if kv .Value .IsNothing () {
1061
- if err := view .removeFromTrie (newPath (kv .Key )); err != nil {
1062
- return err
1063
- }
1064
- } else if _ , err := view .insertIntoTrie (newPath (kv .Key ), kv .Value ); err != nil {
1065
- return err
1066
- }
1067
- }
1068
-
1069
1103
// For all the nodes along the edges of the proof, insert the children whose
1070
1104
// keys are less than [insertChildrenLessThan] or whose keys are greater
1071
1105
// than [insertChildrenGreaterThan] into the trie so that we get the
@@ -1172,14 +1206,14 @@ func (db *merkleDB) getHistoricalViewForRange(
1172
1206
1173
1207
// looking for the trie's current root id, so return the trie unmodified
1174
1208
if currentRootID == rootID {
1175
- return newTrieView (db , db , db .root .clone (), 100 )
1209
+ return newTrieView (db , db , db .root .clone (), nil )
1176
1210
}
1177
1211
1178
1212
changeHistory , err := db .history .getChangesToGetToRoot (rootID , start , end )
1179
1213
if err != nil {
1180
1214
return nil , err
1181
1215
}
1182
- return newTrieViewWithChanges (db , db , changeHistory , len ( changeHistory . nodes ) )
1216
+ return newTrieViewWithChanges (db , db , changeHistory )
1183
1217
}
1184
1218
1185
1219
// Returns all keys in range [start, end] that aren't in [keySet].
@@ -1261,81 +1295,3 @@ func (db *merkleDB) getNode(key path) (*node, error) {
1261
1295
err = db .nodeCache .Put (key , node )
1262
1296
return node , err
1263
1297
}
1264
-
1265
- // Returns a new view atop [db] with the changes in [ops] applied to it.
1266
- // Assumes [db.commitLock] is read locked.
1267
- func (db * merkleDB ) prepareBatchView (ops []database.BatchOp ) (* trieView , error ) {
1268
- view , err := db .newUntrackedView (len (ops ))
1269
- if err != nil {
1270
- return nil , err
1271
- }
1272
- // Don't need to lock [view] because nobody else has a reference to it.
1273
-
1274
- // write into the trie
1275
- for _ , op := range ops {
1276
- if op .Delete {
1277
- if err := view .remove (op .Key ); err != nil {
1278
- return nil , err
1279
- }
1280
- } else if err := view .insert (op .Key , op .Value ); err != nil {
1281
- return nil , err
1282
- }
1283
- }
1284
-
1285
- return view , nil
1286
- }
1287
-
1288
- // Returns a new view atop [db] with the key/value pairs in [proof.KeyValues]
1289
- // inserted and the key/value pairs in [proof.DeletedKeys] removed.
1290
- // Assumes [db.commitLock] is locked.
1291
- func (db * merkleDB ) prepareChangeProofView (proof * ChangeProof ) (* trieView , error ) {
1292
- view , err := db .newUntrackedView (len (proof .KeyChanges ))
1293
- if err != nil {
1294
- return nil , err
1295
- }
1296
- // Don't need to lock [view] because nobody else has a reference to it.
1297
-
1298
- for _ , kv := range proof .KeyChanges {
1299
- if kv .Value .IsNothing () {
1300
- if err := view .remove (kv .Key ); err != nil {
1301
- return nil , err
1302
- }
1303
- } else if err := view .insert (kv .Key , kv .Value .Value ()); err != nil {
1304
- return nil , err
1305
- }
1306
- }
1307
- return view , nil
1308
- }
1309
-
1310
- // Returns a new view atop [db] with the key/value pairs in [proof.KeyValues] added and
1311
- // any existing key-value pairs in the proof's range but not in the proof removed.
1312
- // Assumes [db.commitLock] is locked.
1313
- func (db * merkleDB ) prepareRangeProofView (start []byte , proof * RangeProof ) (* trieView , error ) {
1314
- // Don't need to lock [view] because nobody else has a reference to it.
1315
- view , err := db .newUntrackedView (len (proof .KeyValues ))
1316
- if err != nil {
1317
- return nil , err
1318
- }
1319
- keys := set.NewSet [string ](len (proof .KeyValues ))
1320
- for _ , kv := range proof .KeyValues {
1321
- keys .Add (string (kv .Key ))
1322
- if err := view .insert (kv .Key , kv .Value ); err != nil {
1323
- return nil , err
1324
- }
1325
- }
1326
-
1327
- var largestKey []byte
1328
- if len (proof .KeyValues ) > 0 {
1329
- largestKey = proof .KeyValues [len (proof .KeyValues )- 1 ].Key
1330
- }
1331
- keysToDelete , err := db .getKeysNotInSet (start , largestKey , keys )
1332
- if err != nil {
1333
- return nil , err
1334
- }
1335
- for _ , keyToDelete := range keysToDelete {
1336
- if err := view .remove (keyToDelete ); err != nil {
1337
- return nil , err
1338
- }
1339
- }
1340
- return view , nil
1341
- }
0 commit comments