github.com/filecoin-project/specs-actors/v4@v4.0.2/actors/migration/nv10/util.go (about)

     1  package nv10
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"sync"
     7  	"testing"
     8  
     9  	amt2 "github.com/filecoin-project/go-amt-ipld/v2"
    10  	amt3 "github.com/filecoin-project/go-amt-ipld/v3"
    11  	hamt2 "github.com/filecoin-project/go-hamt-ipld/v2"
    12  	hamt3 "github.com/filecoin-project/go-hamt-ipld/v3"
    13  	"github.com/filecoin-project/go-state-types/rt"
    14  	adt2 "github.com/filecoin-project/specs-actors/v2/actors/util/adt"
    15  	cid "github.com/ipfs/go-cid"
    16  	cbor "github.com/ipfs/go-ipld-cbor"
    17  	cbg "github.com/whyrusleeping/cbor-gen"
    18  	"golang.org/x/xerrors"
    19  
    20  	adt3 "github.com/filecoin-project/specs-actors/v4/actors/util/adt"
    21  )
    22  
    23  // Migrates a HAMT from v2 to v3 without re-encoding keys or values.
    24  func migrateHAMTRaw(ctx context.Context, store cbor.IpldStore, root cid.Cid, newBitwidth int) (cid.Cid, error) {
    25  	inRootNode, err := hamt2.LoadNode(ctx, store, root, adt2.HamtOptions...)
    26  	if err != nil {
    27  		return cid.Undef, err
    28  	}
    29  
    30  	newOpts := append(adt3.DefaultHamtOptions, hamt3.UseTreeBitWidth(newBitwidth))
    31  	outRootNode, err := hamt3.NewNode(store, newOpts...)
    32  	if err != nil {
    33  		return cid.Undef, err
    34  	}
    35  
    36  	if err = inRootNode.ForEach(ctx, func(k string, val interface{}) error {
    37  		return outRootNode.SetRaw(ctx, k, val.(*cbg.Deferred).Raw)
    38  	}); err != nil {
    39  		return cid.Undef, err
    40  	}
    41  
    42  	err = outRootNode.Flush(ctx)
    43  	if err != nil {
    44  		return cid.Undef, err
    45  	}
    46  	return store.Put(ctx, outRootNode)
    47  }
    48  
    49  // Migrates an AMT from v2 to v3 without re-encoding values.
    50  func migrateAMTRaw(ctx context.Context, store cbor.IpldStore, root cid.Cid, newBitwidth int) (cid.Cid, error) {
    51  	inRootNode, err := amt2.LoadAMT(ctx, store, root)
    52  	if err != nil {
    53  		return cid.Undef, err
    54  	}
    55  
    56  	newOpts := append(adt3.DefaultAmtOptions, amt3.UseTreeBitWidth(uint(newBitwidth)))
    57  	outRootNode, err := amt3.NewAMT(store, newOpts...)
    58  	if err != nil {
    59  		return cid.Undef, err
    60  	}
    61  
    62  	if err = inRootNode.ForEach(ctx, func(k uint64, d *cbg.Deferred) error {
    63  		return outRootNode.Set(ctx, k, d)
    64  	}); err != nil {
    65  		return cid.Undef, err
    66  	}
    67  
    68  	return outRootNode.Flush(ctx)
    69  }
    70  
    71  // Migrates a HAMT of HAMTs from v2 to v3 without re-encoding leaf keys or values.
    72  func migrateHAMTHAMTRaw(ctx context.Context, store cbor.IpldStore, root cid.Cid, newOuterBitwidth, newInnerBitwidth int) (cid.Cid, error) {
    73  	inRootNodeOuter, err := hamt2.LoadNode(ctx, store, root)
    74  	if err != nil {
    75  		return cid.Undef, err
    76  	}
    77  
    78  	newOptsOuter := append(adt3.DefaultHamtOptions, hamt3.UseTreeBitWidth(newOuterBitwidth))
    79  	outRootNodeOuter, err := hamt3.NewNode(store, newOptsOuter...)
    80  	if err != nil {
    81  		return cid.Undef, err
    82  	}
    83  
    84  	if err = inRootNodeOuter.ForEach(ctx, func(k string, val interface{}) error {
    85  		var inInner cbg.CborCid
    86  		if err := inInner.UnmarshalCBOR(bytes.NewReader(val.(*cbg.Deferred).Raw)); err != nil {
    87  			return err
    88  		}
    89  		outInner, err := migrateHAMTRaw(ctx, store, cid.Cid(inInner), newInnerBitwidth)
    90  		if err != nil {
    91  			return err
    92  		}
    93  		c := cbg.CborCid(outInner)
    94  		return outRootNodeOuter.Set(ctx, k, &c)
    95  	}); err != nil {
    96  		return cid.Undef, err
    97  	}
    98  
    99  	if err := outRootNodeOuter.Flush(ctx); err != nil {
   100  		return cid.Undef, err
   101  	}
   102  	return store.Put(ctx, outRootNodeOuter)
   103  }
   104  
   105  // Migrates a HAMT of AMTs from v2 to v3 without re-encoding values.
   106  func migrateHAMTAMTRaw(ctx context.Context, store cbor.IpldStore, root cid.Cid, newOuterBitwidth, newInnerBitwidth int) (cid.Cid, error) {
   107  	inRootNodeOuter, err := hamt2.LoadNode(ctx, store, root)
   108  	if err != nil {
   109  		return cid.Undef, err
   110  	}
   111  	newOptsOuter := append(adt3.DefaultHamtOptions, hamt3.UseTreeBitWidth(newOuterBitwidth))
   112  	outRootNodeOuter, err := hamt3.NewNode(store, newOptsOuter...)
   113  	if err != nil {
   114  		return cid.Undef, err
   115  	}
   116  
   117  	if err = inRootNodeOuter.ForEach(ctx, func(k string, val interface{}) error {
   118  		var inInner cbg.CborCid
   119  		if err := inInner.UnmarshalCBOR(bytes.NewReader(val.(*cbg.Deferred).Raw)); err != nil {
   120  			return err
   121  		}
   122  		outInner, err := migrateAMTRaw(ctx, store, cid.Cid(inInner), newInnerBitwidth)
   123  		if err != nil {
   124  			return err
   125  		}
   126  		c := cbg.CborCid(outInner)
   127  		return outRootNodeOuter.Set(ctx, k, &c)
   128  	}); err != nil {
   129  		return cid.Undef, err
   130  	}
   131  
   132  	if err := outRootNodeOuter.Flush(ctx); err != nil {
   133  		return cid.Undef, err
   134  	}
   135  	return store.Put(ctx, outRootNodeOuter)
   136  }
   137  
   138  type MemMigrationCache struct {
   139  	MigrationMap sync.Map
   140  }
   141  
   142  func NewMemMigrationCache() *MemMigrationCache {
   143  	return new(MemMigrationCache)
   144  }
   145  
   146  func (m *MemMigrationCache) Write(key string, c cid.Cid) error {
   147  	m.MigrationMap.Store(key, c)
   148  	return nil
   149  }
   150  
   151  func (m *MemMigrationCache) Read(key string) (bool, cid.Cid, error) {
   152  	val, found := m.MigrationMap.Load(key)
   153  	if !found {
   154  		return false, cid.Undef, nil
   155  	}
   156  	c, ok := val.(cid.Cid)
   157  	if !ok {
   158  		return false, cid.Undef, xerrors.Errorf("non cid value in cache")
   159  	}
   160  
   161  	return true, c, nil
   162  }
   163  
   164  func (m *MemMigrationCache) Load(key string, loadFunc func() (cid.Cid, error)) (cid.Cid, error) {
   165  	found, c, err := m.Read(key)
   166  	if err != nil {
   167  		return cid.Undef, err
   168  	}
   169  	if found {
   170  		return c, nil
   171  	}
   172  	c, err = loadFunc()
   173  	if err != nil {
   174  		return cid.Undef, err
   175  	}
   176  	m.MigrationMap.Store(key, c)
   177  	return c, nil
   178  }
   179  
   180  func (m *MemMigrationCache) Clone() *MemMigrationCache {
   181  	newCache := NewMemMigrationCache()
   182  	newCache.Update(m)
   183  	return newCache
   184  }
   185  
   186  func (m *MemMigrationCache) Update(other *MemMigrationCache) {
   187  	other.MigrationMap.Range(func(key, value interface{}) bool {
   188  		m.MigrationMap.Store(key, value)
   189  		return true
   190  	})
   191  }
   192  
   193  type TestLogger struct {
   194  	TB testing.TB
   195  }
   196  
   197  func (t TestLogger) Log(_ rt.LogLevel, msg string, args ...interface{}) {
   198  	t.TB.Logf(msg, args...)
   199  }