package stores import ( "context" "github.com/filecoin-project/lotus/extern/sector-storage/storiface" "testing" "time" "github.com/stretchr/testify/require" "github.com/filecoin-project/go-state-types/abi" ) var aSector = abi.SectorID{ Miner: 2, Number: 9000, } func TestCanLock(t *testing.T) { lk := sectorLock{ r: [storiface.FileTypes]uint{}, w: storiface.FTNone, } require.Equal(t, true, lk.canLock(storiface.FTUnsealed, storiface.FTNone)) require.Equal(t, true, lk.canLock(storiface.FTNone, storiface.FTUnsealed)) ftAll := storiface.FTUnsealed | storiface.FTSealed | storiface.FTCache require.Equal(t, true, lk.canLock(ftAll, storiface.FTNone)) require.Equal(t, true, lk.canLock(storiface.FTNone, ftAll)) lk.r[0] = 1 // unsealed read taken require.Equal(t, true, lk.canLock(storiface.FTUnsealed, storiface.FTNone)) require.Equal(t, false, lk.canLock(storiface.FTNone, storiface.FTUnsealed)) require.Equal(t, true, lk.canLock(ftAll, storiface.FTNone)) require.Equal(t, false, lk.canLock(storiface.FTNone, ftAll)) require.Equal(t, true, lk.canLock(storiface.FTNone, storiface.FTSealed|storiface.FTCache)) require.Equal(t, true, lk.canLock(storiface.FTUnsealed, storiface.FTSealed|storiface.FTCache)) lk.r[0] = 0 lk.w = storiface.FTSealed require.Equal(t, true, lk.canLock(storiface.FTUnsealed, storiface.FTNone)) require.Equal(t, true, lk.canLock(storiface.FTNone, storiface.FTUnsealed)) require.Equal(t, false, lk.canLock(storiface.FTSealed, storiface.FTNone)) require.Equal(t, false, lk.canLock(storiface.FTNone, storiface.FTSealed)) require.Equal(t, false, lk.canLock(ftAll, storiface.FTNone)) require.Equal(t, false, lk.canLock(storiface.FTNone, ftAll)) } func TestIndexLocksSeq(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), time.Second) ilk := &indexLocks{ locks: map[abi.SectorID]*sectorLock{}, } require.NoError(t, ilk.StorageLock(ctx, aSector, storiface.FTNone, storiface.FTUnsealed)) cancel() ctx, cancel = context.WithTimeout(context.Background(), time.Second) require.NoError(t, ilk.StorageLock(ctx, aSector, storiface.FTNone, storiface.FTUnsealed)) cancel() ctx, cancel = context.WithTimeout(context.Background(), time.Second) require.NoError(t, ilk.StorageLock(ctx, aSector, storiface.FTNone, storiface.FTUnsealed)) cancel() ctx, cancel = context.WithTimeout(context.Background(), time.Second) require.NoError(t, ilk.StorageLock(ctx, aSector, storiface.FTUnsealed, storiface.FTNone)) cancel() ctx, cancel = context.WithTimeout(context.Background(), time.Second) require.NoError(t, ilk.StorageLock(ctx, aSector, storiface.FTNone, storiface.FTUnsealed)) cancel() ctx, cancel = context.WithTimeout(context.Background(), time.Second) require.NoError(t, ilk.StorageLock(ctx, aSector, storiface.FTNone, storiface.FTUnsealed)) cancel() } func TestIndexLocksBlockOn(t *testing.T) { test := func(r1 storiface.SectorFileType, w1 storiface.SectorFileType, r2 storiface.SectorFileType, w2 storiface.SectorFileType) func(t *testing.T) { return func(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) ilk := &indexLocks{ locks: map[abi.SectorID]*sectorLock{}, } require.NoError(t, ilk.StorageLock(ctx, aSector, r1, w1)) sch := make(chan struct{}) go func() { ctx, cancel := context.WithCancel(context.Background()) sch <- struct{}{} require.NoError(t, ilk.StorageLock(ctx, aSector, r2, w2)) cancel() sch <- struct{}{} }() <-sch select { case <-sch: t.Fatal("that shouldn't happen") case <-time.After(40 * time.Millisecond): } cancel() select { case <-sch: case <-time.After(time.Second): t.Fatal("timed out") } } } t.Run("readBlocksWrite", test(storiface.FTUnsealed, storiface.FTNone, storiface.FTNone, storiface.FTUnsealed)) t.Run("writeBlocksRead", test(storiface.FTNone, storiface.FTUnsealed, storiface.FTUnsealed, storiface.FTNone)) t.Run("writeBlocksWrite", test(storiface.FTNone, storiface.FTUnsealed, storiface.FTNone, storiface.FTUnsealed)) } func TestIndexLocksBlockWonR(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) ilk := &indexLocks{ locks: map[abi.SectorID]*sectorLock{}, } require.NoError(t, ilk.StorageLock(ctx, aSector, storiface.FTUnsealed, storiface.FTNone)) sch := make(chan struct{}) go func() { ctx, cancel := context.WithCancel(context.Background()) sch <- struct{}{} require.NoError(t, ilk.StorageLock(ctx, aSector, storiface.FTNone, storiface.FTUnsealed)) cancel() sch <- struct{}{} }() <-sch select { case <-sch: t.Fatal("that shouldn't happen") case <-time.After(40 * time.Millisecond): } cancel() select { case <-sch: case <-time.After(time.Second): t.Fatal("timed out") } }