fix: curio seal: Fix partial Finalize retry
This commit is contained in:
parent
8ec74fdb05
commit
e86d81b26a
@ -374,12 +374,62 @@ func (sb *SealCalls) FinalizeSector(ctx context.Context, sector storiface.Sector
|
|||||||
// * we truncate the temp file to the sector size
|
// * we truncate the temp file to the sector size
|
||||||
// * we move the temp file to the unsealed location
|
// * we move the temp file to the unsealed location
|
||||||
|
|
||||||
// move tree-d to temp file
|
// temp path in cache where we'll move tree-d before truncating
|
||||||
|
// it is in the cache directory so that we can use os.Rename to move it
|
||||||
|
// to unsealed (which may be on a different filesystem)
|
||||||
tempUnsealed := filepath.Join(sectorPaths.Cache, storiface.SectorName(sector.ID))
|
tempUnsealed := filepath.Join(sectorPaths.Cache, storiface.SectorName(sector.ID))
|
||||||
|
|
||||||
|
_, terr := os.Stat(tempUnsealed)
|
||||||
|
tempUnsealedExists := terr == nil
|
||||||
|
|
||||||
|
// First handle an edge case where we have already gone through this step,
|
||||||
|
// but ClearCache or later steps failed. In that case we'll see tree-d missing and unsealed present
|
||||||
|
|
||||||
|
if _, err := os.Stat(filepath.Join(sectorPaths.Cache, proofpaths.TreeDName)); err != nil {
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
// check that unsealed exists and is the right size
|
||||||
|
st, err := os.Stat(sectorPaths.Unsealed)
|
||||||
|
if err != nil {
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
if tempUnsealedExists {
|
||||||
|
// unsealed file does not exist, but temp unsealed file does
|
||||||
|
// so we can just resume where the previous attempt left off
|
||||||
|
goto retryUnsealedMove
|
||||||
|
}
|
||||||
|
return xerrors.Errorf("neither unsealed file nor temp-unsealed file exists")
|
||||||
|
}
|
||||||
|
return xerrors.Errorf("stat unsealed file: %w", err)
|
||||||
|
}
|
||||||
|
if st.Size() != int64(ssize) {
|
||||||
|
if tempUnsealedExists {
|
||||||
|
// unsealed file exists but is the wrong size, and temp unsealed file exists
|
||||||
|
// so we can just resume where the previous attempt left off with some cleanup
|
||||||
|
|
||||||
|
if err := os.Remove(sectorPaths.Unsealed); err != nil {
|
||||||
|
return xerrors.Errorf("removing unsealed file from last attempt: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
goto retryUnsealedMove
|
||||||
|
}
|
||||||
|
return xerrors.Errorf("unsealed file is not the right size: %d != %d and temp unsealed is missing", st.Size(), ssize)
|
||||||
|
}
|
||||||
|
|
||||||
|
// all good, just log that this edge case happened
|
||||||
|
log.Warnw("unsealed file exists but tree-d is missing, skipping move", "sector", sector.ID, "unsealed", sectorPaths.Unsealed, "cache", sectorPaths.Cache)
|
||||||
|
goto afterUnsealedMove
|
||||||
|
}
|
||||||
|
return xerrors.Errorf("stat tree-d file: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the state in clean do the move
|
||||||
|
|
||||||
|
// move tree-d to temp file
|
||||||
if err := os.Rename(filepath.Join(sectorPaths.Cache, proofpaths.TreeDName), tempUnsealed); err != nil {
|
if err := os.Rename(filepath.Join(sectorPaths.Cache, proofpaths.TreeDName), tempUnsealed); err != nil {
|
||||||
return xerrors.Errorf("moving tree-d to temp file: %w", err)
|
return xerrors.Errorf("moving tree-d to temp file: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
retryUnsealedMove:
|
||||||
|
|
||||||
// truncate sealed file to sector size
|
// truncate sealed file to sector size
|
||||||
if err := os.Truncate(tempUnsealed, int64(ssize)); err != nil {
|
if err := os.Truncate(tempUnsealed, int64(ssize)); err != nil {
|
||||||
return xerrors.Errorf("truncating unsealed file to sector size: %w", err)
|
return xerrors.Errorf("truncating unsealed file to sector size: %w", err)
|
||||||
@ -391,6 +441,7 @@ func (sb *SealCalls) FinalizeSector(ctx context.Context, sector storiface.Sector
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
afterUnsealedMove:
|
||||||
if err := ffi.ClearCache(uint64(ssize), sectorPaths.Cache); err != nil {
|
if err := ffi.ClearCache(uint64(ssize), sectorPaths.Cache); err != nil {
|
||||||
return xerrors.Errorf("clearing cache: %w", err)
|
return xerrors.Errorf("clearing cache: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,7 @@ func TestSectorImportAfterPC2(t *testing.T) {
|
|||||||
// We use two miners so that in case the actively tested miner misses PoSt, we still have a blockchain
|
// We use two miners so that in case the actively tested miner misses PoSt, we still have a blockchain
|
||||||
client, miner, _, ens := kit.EnsembleOneTwo(t, kit.ThroughRPC())
|
client, miner, _, ens := kit.EnsembleOneTwo(t, kit.ThroughRPC())
|
||||||
|
|
||||||
ens.InterconnectAll().BeginMiningMustPost(blockTime)
|
ens.InterconnectAll().BeginMining(blockTime)
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
|
@ -476,14 +476,18 @@ func (st *Local) AcquireSector(ctx context.Context, sid storiface.SectorRef, exi
|
|||||||
var out storiface.SectorPaths
|
var out storiface.SectorPaths
|
||||||
var storageIDs storiface.SectorPaths
|
var storageIDs storiface.SectorPaths
|
||||||
|
|
||||||
|
// First find existing files
|
||||||
for _, fileType := range storiface.PathTypes {
|
for _, fileType := range storiface.PathTypes {
|
||||||
if fileType&existing == 0 {
|
// also try to find existing sectors if we're allocating
|
||||||
|
if fileType&(existing|allocate) == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
si, err := st.index.StorageFindSector(ctx, sid.ID, fileType, ssize, false)
|
si, err := st.index.StorageFindSector(ctx, sid.ID, fileType, ssize, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warnf("finding existing sector %d(t:%d) failed: %+v", sid, fileType, err)
|
if fileType&existing != 0 {
|
||||||
|
log.Warnf("finding existing sector %d(t:%d) failed: %+v", sid, fileType, err)
|
||||||
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -501,11 +505,13 @@ func (st *Local) AcquireSector(ctx context.Context, sid storiface.SectorRef, exi
|
|||||||
storiface.SetPathByType(&out, fileType, spath)
|
storiface.SetPathByType(&out, fileType, spath)
|
||||||
storiface.SetPathByType(&storageIDs, fileType, string(info.ID))
|
storiface.SetPathByType(&storageIDs, fileType, string(info.ID))
|
||||||
|
|
||||||
existing ^= fileType
|
existing = existing.Unset(fileType)
|
||||||
|
allocate = allocate.Unset(fileType)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Then allocate for allocation requests
|
||||||
for _, fileType := range storiface.PathTypes {
|
for _, fileType := range storiface.PathTypes {
|
||||||
if fileType&allocate == 0 {
|
if fileType&allocate == 0 {
|
||||||
continue
|
continue
|
||||||
|
@ -174,6 +174,10 @@ func (t SectorFileType) SubAllowed(allowTypes []string, denyTypes []string) Sect
|
|||||||
return t & denyMask
|
return t & denyMask
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t SectorFileType) Unset(toUnset SectorFileType) SectorFileType {
|
||||||
|
return t &^ toUnset
|
||||||
|
}
|
||||||
|
|
||||||
func (t SectorFileType) AnyAllowed(allowTypes []string, denyTypes []string) bool {
|
func (t SectorFileType) AnyAllowed(allowTypes []string, denyTypes []string) bool {
|
||||||
return t.SubAllowed(allowTypes, denyTypes) != t
|
return t.SubAllowed(allowTypes, denyTypes) != t
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user