@@ -24,10 +24,11 @@ const (
24
24
// Change represents a change to a DAG and contains a reference to the old and
25
25
// new CIDs.
26
26
type Change struct {
27
- Type ChangeType
28
- Key string
29
- Before * cbg.Deferred
30
- After * cbg.Deferred
27
+ Type ChangeType
28
+ Key string
29
+ Before * cbg.Deferred
30
+ After * cbg.Deferred
31
+ SelectorSuffix []int
31
32
}
32
33
33
34
func (ch Change ) String () string {
@@ -57,6 +58,29 @@ func Diff(ctx context.Context, prevBs, curBs cbor.IpldStore, prev, cur cid.Cid,
57
58
return diffNode (ctx , prevHamt , curHamt , 0 )
58
59
}
59
60
61
+ // DiffTrackedWithNodeSink returns a set of changes that transform node 'prev' into node 'cur'. opts are applied to both prev and cur.
62
+ // it associates selector suffixes with the emitted Change set and sinks all unique nodes encountered under the current CID to the provided CBORUnmarshaler
63
+ func DiffTrackedWithNodeSink (ctx context.Context , prevBs , curBs cbor.IpldStore , prev , cur cid.Cid , b * bytes.Buffer , sink cbg.CBORUnmarshaler , trail []int , opts ... Option ) ([]* Change , error ) {
64
+ if prev .Equals (cur ) {
65
+ return nil , nil
66
+ }
67
+
68
+ prevHamt , err := LoadNode (ctx , prevBs , prev , opts ... )
69
+ if err != nil {
70
+ return nil , err
71
+ }
72
+
73
+ curHamt , err := LoadNode (ctx , curBs , cur , opts ... )
74
+ if err != nil {
75
+ return nil , err
76
+ }
77
+
78
+ if curHamt .bitWidth != prevHamt .bitWidth {
79
+ return nil , xerrors .Errorf ("diffing HAMTs with differing bitWidths not supported (prev=%d, cur=%d)" , prevHamt .bitWidth , curHamt .bitWidth )
80
+ }
81
+ return diffNodeTrackedWithNodeSink (ctx , prevHamt , curHamt , 0 , b , sink , trail )
82
+ }
83
+
60
84
func diffNode (ctx context.Context , pre , cur * Node , depth int ) ([]* Change , error ) {
61
85
// which Bitfield contains the most bits. We will start a loop from this index, calling Bitfield.Bit(idx)
62
86
// on an out of range index will return zero.
@@ -176,6 +200,144 @@ func diffNode(ctx context.Context, pre, cur *Node, depth int) ([]*Change, error)
176
200
return changes , nil
177
201
}
178
202
203
+ func diffNodeTrackedWithNodeSink (ctx context.Context , pre , cur * Node , depth int , b * bytes.Buffer , sink cbg.CBORUnmarshaler , trail []int ) ([]* Change , error ) {
204
+ // which Bitfield contains the most bits. We will start a loop from this index, calling Bitfield.Bit(idx)
205
+ // on an out of range index will return zero.
206
+ bp := cur .Bitfield .BitLen ()
207
+ if pre .Bitfield .BitLen () > bp {
208
+ bp = pre .Bitfield .BitLen ()
209
+ }
210
+
211
+ if sink != nil {
212
+ if b == nil {
213
+ b = bytes .NewBuffer (nil )
214
+ }
215
+ b .Reset ()
216
+ if err := cur .MarshalCBOR (b ); err != nil {
217
+ return nil , err
218
+ }
219
+ if err := sink .UnmarshalCBOR (b ); err != nil {
220
+ return nil , err
221
+ }
222
+ }
223
+
224
+ // the changes between cur and prev
225
+ var changes []* Change
226
+ l := len (trail )
227
+ // loop over each bit in the bitfields
228
+ for idx := bp ; idx >= 0 ; idx -- {
229
+ preBit := pre .Bitfield .Bit (idx )
230
+ curBit := cur .Bitfield .Bit (idx )
231
+
232
+ subTrail := make ([]int , l , l + 1 )
233
+ copy (subTrail , trail )
234
+ subTrail = append (subTrail , idx )
235
+
236
+ if preBit == 1 && curBit == 1 {
237
+ // index for pre and cur will be unique to each, calculate it here.
238
+ prePointer := pre .getPointer (byte (pre .indexForBitPos (idx )))
239
+ curPointer := cur .getPointer (byte (cur .indexForBitPos (idx )))
240
+
241
+ // both pointers are shards, recurse down the tree.
242
+ if prePointer .isShard () && curPointer .isShard () {
243
+ if prePointer .Link == curPointer .Link {
244
+ continue
245
+ }
246
+ preChild , err := prePointer .loadChild (ctx , pre .store , pre .bitWidth , pre .hash )
247
+ if err != nil {
248
+ return nil , err
249
+ }
250
+ curChild , err := curPointer .loadChild (ctx , cur .store , cur .bitWidth , cur .hash )
251
+ if err != nil {
252
+ return nil , err
253
+ }
254
+
255
+ change , err := diffNodeTrackedWithNodeSink (ctx , preChild , curChild , depth + 1 , b , sink , subTrail )
256
+ if err != nil {
257
+ return nil , err
258
+ }
259
+ changes = append (changes , change ... )
260
+ }
261
+
262
+ // check if KV's from cur exists in any children of pre's child.
263
+ if prePointer .isShard () && ! curPointer .isShard () {
264
+ childKV , err := prePointer .loadChildKVs (ctx , pre .store , pre .bitWidth , pre .hash )
265
+ if err != nil {
266
+ return nil , err
267
+ }
268
+ changes = append (changes , diffKVsTracked (childKV , curPointer .KVs , idx , subTrail )... )
269
+
270
+ }
271
+
272
+ // check if KV's from pre exists in any children of cur's child.
273
+ if ! prePointer .isShard () && curPointer .isShard () {
274
+ childKV , err := curPointer .loadChildKVs (ctx , cur .store , cur .bitWidth , cur .hash )
275
+ if err != nil {
276
+ return nil , err
277
+ }
278
+ changes = append (changes , diffKVsTracked (prePointer .KVs , childKV , idx , subTrail )... )
279
+ }
280
+
281
+ // both contain KVs, compare.
282
+ if ! prePointer .isShard () && ! curPointer .isShard () {
283
+ changes = append (changes , diffKVsTracked (prePointer .KVs , curPointer .KVs , idx , subTrail )... )
284
+ }
285
+ } else if preBit == 1 && curBit == 0 {
286
+ // there exists a value in previous not found in current - it was removed
287
+ pointer := pre .getPointer (byte (pre .indexForBitPos (idx )))
288
+
289
+ if pointer .isShard () {
290
+ child , err := pointer .loadChild (ctx , pre .store , pre .bitWidth , pre .hash )
291
+ if err != nil {
292
+ return nil , err
293
+ }
294
+ rm , err := removeAllTracked (ctx , child , idx , subTrail )
295
+ if err != nil {
296
+ return nil , err
297
+ }
298
+ changes = append (changes , rm ... )
299
+ } else {
300
+ for _ , p := range pointer .KVs {
301
+ changes = append (changes , & Change {
302
+ Type : Remove ,
303
+ Key : string (p .Key ),
304
+ Before : p .Value ,
305
+ After : nil ,
306
+ SelectorSuffix : subTrail ,
307
+ })
308
+ }
309
+ }
310
+ } else if curBit == 1 && preBit == 0 {
311
+ // there exists a value in current not found in previous - it was added
312
+ pointer := cur .getPointer (byte (cur .indexForBitPos (idx )))
313
+
314
+ if pointer .isShard () {
315
+ child , err := pointer .loadChild (ctx , pre .store , pre .bitWidth , pre .hash )
316
+ if err != nil {
317
+ return nil , err
318
+ }
319
+ add , err := addAllTrackWithNodeSink (ctx , child , idx , b , sink , subTrail )
320
+ if err != nil {
321
+ return nil , err
322
+ }
323
+ changes = append (changes , add ... )
324
+ } else {
325
+ for _ , p := range pointer .KVs {
326
+ changes = append (changes , & Change {
327
+ Type : Add ,
328
+ Key : string (p .Key ),
329
+ Before : nil ,
330
+ After : p .Value ,
331
+ SelectorSuffix : subTrail ,
332
+ })
333
+ }
334
+ }
335
+ }
336
+ }
337
+
338
+ return changes , nil
339
+ }
340
+
179
341
func diffKVs (pre , cur []* KV , idx int ) []* Change {
180
342
preMap := make (map [string ]* cbg.Deferred , len (pre ))
181
343
curMap := make (map [string ]* cbg.Deferred , len (cur ))
@@ -222,6 +384,55 @@ func diffKVs(pre, cur []*KV, idx int) []*Change {
222
384
return changes
223
385
}
224
386
387
+ func diffKVsTracked (pre , cur []* KV , idx int , trail []int ) []* Change {
388
+ preMap := make (map [string ]* cbg.Deferred , len (pre ))
389
+ curMap := make (map [string ]* cbg.Deferred , len (cur ))
390
+ var changes []* Change
391
+
392
+ for _ , kv := range pre {
393
+ preMap [string (kv .Key )] = kv .Value
394
+ }
395
+ for _ , kv := range cur {
396
+ curMap [string (kv .Key )] = kv .Value
397
+ }
398
+ // find removed keys: keys in pre and not in cur
399
+ for key , value := range preMap {
400
+ if _ , ok := curMap [key ]; ! ok {
401
+ changes = append (changes , & Change {
402
+ Type : Remove ,
403
+ Key : key ,
404
+ Before : value ,
405
+ After : nil ,
406
+ SelectorSuffix : trail ,
407
+ })
408
+ }
409
+ }
410
+ // find added keys: keys in cur and not in pre
411
+ // find modified values: keys in cur and pre with different values
412
+ for key , curVal := range curMap {
413
+ if preVal , ok := preMap [key ]; ! ok {
414
+ changes = append (changes , & Change {
415
+ Type : Add ,
416
+ Key : key ,
417
+ Before : nil ,
418
+ After : curVal ,
419
+ SelectorSuffix : trail ,
420
+ })
421
+ } else {
422
+ if ! bytes .Equal (preVal .Raw , curVal .Raw ) {
423
+ changes = append (changes , & Change {
424
+ Type : Modify ,
425
+ Key : key ,
426
+ Before : preVal ,
427
+ After : curVal ,
428
+ SelectorSuffix : trail ,
429
+ })
430
+ }
431
+ }
432
+ }
433
+ return changes
434
+ }
435
+
225
436
func addAll (ctx context.Context , node * Node , idx int ) ([]* Change , error ) {
226
437
var changes []* Change
227
438
if err := node .ForEach (ctx , func (k string , val * cbg.Deferred ) error {
@@ -239,6 +450,24 @@ func addAll(ctx context.Context, node *Node, idx int) ([]*Change, error) {
239
450
return changes , nil
240
451
}
241
452
453
+ func addAllTrackWithNodeSink (ctx context.Context , node * Node , idx int , b * bytes.Buffer , sink cbg.CBORUnmarshaler , trail []int ) ([]* Change , error ) {
454
+ var changes []* Change
455
+ if err := node .ForEachTrackedWithNodeSink (ctx , trail , b , sink , func (k string , val * cbg.Deferred , selectorSuffix []int ) error {
456
+ changes = append (changes , & Change {
457
+ Type : Add ,
458
+ Key : k ,
459
+ Before : nil ,
460
+ After : val ,
461
+ SelectorSuffix : selectorSuffix ,
462
+ })
463
+
464
+ return nil
465
+ }); err != nil {
466
+ return nil , err
467
+ }
468
+ return changes , nil
469
+ }
470
+
242
471
func removeAll (ctx context.Context , node * Node , idx int ) ([]* Change , error ) {
243
472
var changes []* Change
244
473
if err := node .ForEach (ctx , func (k string , val * cbg.Deferred ) error {
@@ -255,3 +484,21 @@ func removeAll(ctx context.Context, node *Node, idx int) ([]*Change, error) {
255
484
}
256
485
return changes , nil
257
486
}
487
+
488
+ func removeAllTracked (ctx context.Context , node * Node , idx int , trail []int ) ([]* Change , error ) {
489
+ var changes []* Change
490
+ if err := node .ForEachTracked (ctx , trail , func (k string , val * cbg.Deferred , selectorSuffix []int ) error {
491
+ changes = append (changes , & Change {
492
+ Type : Remove ,
493
+ Key : k ,
494
+ Before : val ,
495
+ After : nil ,
496
+ SelectorSuffix : selectorSuffix ,
497
+ })
498
+
499
+ return nil
500
+ }); err != nil {
501
+ return nil , err
502
+ }
503
+ return changes , nil
504
+ }
0 commit comments