@@ -3,6 +3,7 @@ package main
33import (
44 "context"
55 "database/sql"
6+ "encoding/json"
67 "fmt"
78 "os"
89 "path/filepath"
@@ -17,9 +18,11 @@ import (
1718 "github.com/filecoin-project/go-padreader"
1819 "github.com/filecoin-project/go-state-types/abi"
1920
21+ "github.com/filecoin-project/curio/alertmanager/curioalerting"
2022 "github.com/filecoin-project/curio/deps"
2123 "github.com/filecoin-project/curio/harmony/harmonydb"
2224 "github.com/filecoin-project/curio/lib/parkpiece"
25+ "github.com/filecoin-project/curio/lib/paths"
2326 "github.com/filecoin-project/curio/lib/storiface"
2427 "github.com/filecoin-project/curio/market/mk20"
2528)
@@ -61,7 +64,7 @@ var importPiecesCmd = &cli.Command{
6164 },
6265 & cli.StringFlag {
6366 Name : "target" ,
64- Usage : "path to piece storage directory in Curio's attached permanent storage" ,
67+ Usage : "path to storage directory in Curio's attached permanent storage" ,
6568 },
6669 & cli.IntFlag {
6770 Name : "batch-size" ,
@@ -77,9 +80,9 @@ var importPiecesCmd = &cli.Command{
7780
7881 The source directory has Storacha CAR files named by piece CID v2. Curio's
7982 piece park stores the same bytes under a parked_pieces id, so the final
80- filename becomes s-t00-<parked_piece_id>. That means the migration must
81- first learn or create the parked_pieces row before it knows the final
82- filename.
83+ file under the target storage root becomes piece/ s-t00-<parked_piece_id>.
84+ That means the migration must first learn or create the parked_pieces
85+ row before it knows the final filename.
8386
8487 Every fresh source file is moved to target/storacha-staging first. That
8588 staging move is the first retry boundary: once the file leaves source, a
@@ -93,12 +96,13 @@ var importPiecesCmd = &cli.Command{
9396 file alone because that task owns the normal download/write path.
9497 4. Otherwise, ensure exactly one storacha-migration parked_piece_refs row
9598 and exactly one pdp_piecerefs row for that parked ref.
96- 5. After the transaction commits, move the staged file to s-t00-<id>,
97- declare it in sector_location, then mark parked_pieces.complete=true.
99+ 5. After the transaction commits, move the staged file to
100+ target/piece/s-t00-<id>, declare it in sector_location, then mark
101+ parked_pieces.complete=true.
98102
99103 recoverFinalStorachaPieces exists for the one point where staging can no
100- longer help: if a previous run already renamed the file to s-t00-<id> and
101- then crashed before declaring the file or marking the parked piece
104+ longer help: if a previous run already renamed the file into target/piece
105+ and then crashed before declaring the file or marking the parked piece
102106 complete. At that point there is no staged filename left to process, so
103107 recovery starts from the DB row/ref and checks whether the final file is
104108 already present.
@@ -122,12 +126,14 @@ var importPiecesCmd = &cli.Command{
122126 return xerrors .Errorf ("resolving target path: %w" , err )
123127 }
124128
125- dep , err := deps .GetDepsCLI ( ctx , cctx )
129+ db , err := deps .MakeDB ( cctx )
126130 if err != nil {
127131 return err
128132 }
129133
130- out , err := runImportPieces (ctx , dep , sourcePath , targetPath , cctx .Int ("batch-size" ))
134+ si := paths .NewDBIndex (curioalerting .NewAlertingSystem (), db )
135+
136+ out , err := runImportPieces (ctx , db , si , sourcePath , targetPath , cctx .Int ("batch-size" ))
131137 if err != nil {
132138 return err
133139 }
@@ -141,15 +147,10 @@ var importPiecesCmd = &cli.Command{
141147 },
142148}
143149
144- func runImportPieces (ctx context.Context , dep * deps. Deps , sourcePath , targetPath string , batchSize int ) (importPiecesOutput , error ) {
150+ func runImportPieces (ctx context.Context , db * harmonydb. DB , si paths. SectorIndex , sourcePath , targetPath string , batchSize int ) (importPiecesOutput , error ) {
145151 var out importPiecesOutput
146152
147- targetPath , err := filepath .Abs (filepath .Clean (targetPath ))
148- if err != nil {
149- return out , xerrors .Errorf ("resolving target path: %w" , err )
150- }
151-
152- storageID , err := pieceStorageID (ctx , dep , targetPath )
153+ storageID , err := pieceStorageID (targetPath )
153154 if err != nil {
154155 return out , err
155156 }
@@ -178,7 +179,7 @@ func runImportPieces(ctx context.Context, dep *deps.Deps, sourcePath, targetPath
178179 continue
179180 }
180181
181- result , err := importStagedStorachaPiece (ctx , dep , storageID , targetPath , filepath .Join (staging , entry .Name ()))
182+ result , err := importStagedStorachaPiece (ctx , db , si , storageID , targetPath , filepath .Join (staging , entry .Name ()))
182183 if err != nil {
183184 return out , err
184185 }
@@ -191,7 +192,7 @@ func runImportPieces(ctx context.Context, dep *deps.Deps, sourcePath, targetPath
191192
192193 // This covers the crash point after staging was renamed to the final
193194 // piece path, but before sector_location/parked_pieces was finalized.
194- err = recoverFinalStorachaPieces (ctx , dep , storageID , targetPath , & out , batchSize )
195+ err = recoverFinalStorachaPieces (ctx , db , si , storageID , targetPath , & out , batchSize )
195196 if err != nil {
196197 return out , err
197198 }
@@ -237,7 +238,7 @@ func runImportPieces(ctx context.Context, dep *deps.Deps, sourcePath, targetPath
237238 return out , xerrors .Errorf ("renaming old path: %w" , err )
238239 }
239240
240- result , err := importStagedStorachaPiece (ctx , dep , storageID , targetPath , stagingPath )
241+ result , err := importStagedStorachaPiece (ctx , db , si , storageID , targetPath , stagingPath )
241242 if err != nil {
242243 return out , err
243244 }
@@ -251,27 +252,24 @@ func runImportPieces(ctx context.Context, dep *deps.Deps, sourcePath, targetPath
251252}
252253
253254// pieceStorageID maps the user-provided target directory back to Curio's
254- // storage id. The target flag is expected to point at an attached storage
255- // path's "piece" directory, because StorageDeclareSector needs the parent
256- // storage id when it writes sector_location.
257- func pieceStorageID (ctx context.Context , dep * deps.Deps , targetPath string ) (storiface.ID , error ) {
258- localPaths , err := dep .LocalStore .Local (ctx )
255+ // storage id. The target flag is expected to point at the storage root that
256+ // contains sectorstore.json; final piece files are stored under target/piece.
257+ func pieceStorageID (targetPath string ) (storiface.ID , error ) {
258+ mb , err := os .ReadFile (filepath .Join (targetPath , paths .MetaFile ))
259259 if err != nil {
260- return "" , xerrors .Errorf ("listing local storage paths : %w" , err )
260+ return "" , xerrors .Errorf ("reading storage metadata for %s : %w" , targetPath , err )
261261 }
262262
263- for _ , localPath := range localPaths {
264- piecePath := filepath .Join (localPath .LocalPath , storiface .FTPiece .String ())
265- piecePath , err = filepath .Abs (filepath .Clean (piecePath ))
266- if err != nil {
267- return "" , xerrors .Errorf ("resolving piece path %s: %w" , piecePath , err )
268- }
269- if piecePath == targetPath {
270- return localPath .ID , nil
271- }
263+ var meta storiface.LocalStorageMeta
264+ if err := json .Unmarshal (mb , & meta ); err != nil {
265+ return "" , xerrors .Errorf ("unmarshalling storage metadata for %s: %w" , targetPath , err )
266+ }
267+
268+ if meta .ID != ("" ) {
269+ return meta .ID , nil
272270 }
273271
274- return "" , xerrors .Errorf ("target %s is not the piece directory of an attached local storage path " , targetPath )
272+ return "" , xerrors .Errorf ("no storage ID found for %s " , targetPath )
275273}
276274
277275// storachaPieceInfoFromFileName accepts only Storacha migration inputs named
@@ -300,10 +298,11 @@ func storachaPieceInfoFromFileName(name string) (*mk20.PieceInfo, bool, error) {
300298// It first creates or reuses parked_pieces/refs in a committed DB transaction.
301299// If an existing incomplete parked_piece still has a live task, it returns
302300// Imported=false and leaves the staged file untouched for a later retry.
303- // Otherwise it consumes the staged file: remove it if the final s-t00-<id>
304- // already exists, or rename it to that final path. It then declares the piece
305- // location and marks parked_pieces.complete unless the row was already complete.
306- func importStagedStorachaPiece (ctx context.Context , dep * deps.Deps , storageID storiface.ID , targetPath , stagingPath string ) (storachaImportResult , error ) {
301+ // Otherwise it consumes the staged file: remove it if the final
302+ // target/piece/s-t00-<id> already exists, or rename it to that final path. It
303+ // then declares the piece location and marks parked_pieces.complete unless the
304+ // row was already complete.
305+ func importStagedStorachaPiece (ctx context.Context , db * harmonydb.DB , si paths.SectorIndex , storageID storiface.ID , targetPath , stagingPath string ) (storachaImportResult , error ) {
307306 info , err := os .Stat (stagingPath )
308307 if err != nil {
309308 return storachaImportResult {}, xerrors .Errorf ("checking staging file: %w" , err )
@@ -324,7 +323,7 @@ func importStagedStorachaPiece(ctx context.Context, dep *deps.Deps, storageID st
324323 // The transaction only decides ownership and DB references. It deliberately
325324 // does not move the file to s-t00-<id>; the id must be committed before the
326325 // filename depends on it.
327- comm , err := dep . DB .BeginTransaction (ctx , func (tx * harmonydb.Tx ) (commit bool , err error ) {
326+ comm , err := db .BeginTransaction (ctx , func (tx * harmonydb.Tx ) (commit bool , err error ) {
328327 parkedPieceID , createdParkedPiece , err := parkpiece .UpsertSkipWithInserted (tx , pi .PieceCIDV1 .String (), int64 (pi .Size ), int64 (pi .RawSize ), true , true )
329328 if err != nil {
330329 return false , xerrors .Errorf ("upsert parked piece: %w" , err )
@@ -386,14 +385,14 @@ func importStagedStorachaPiece(ctx context.Context, dep *deps.Deps, storageID st
386385 return storachaImportResult {}, xerrors .Errorf ("checking final piece file: %w" , err )
387386 }
388387
389- if err := declareStorachaPiece (ctx , dep , storageID , state .ID ); err != nil {
388+ if err := declareStorachaPiece (ctx , si , storageID , state .ID ); err != nil {
390389 return storachaImportResult {}, err
391390 }
392391
393392 if ! state .AlreadyComplete {
394393 // complete is last. If we crash before this, final-file recovery will see
395394 // s-t00-<id>, declare it again idempotently, and mark the row complete.
396- if err := markParkedPieceComplete (ctx , dep . DB , state .ID ); err != nil {
395+ if err := markParkedPieceComplete (ctx , db , state .ID ); err != nil {
397396 return storachaImportResult {}, err
398397 }
399398 }
@@ -403,16 +402,17 @@ func importStagedStorachaPiece(ctx context.Context, dep *deps.Deps, storageID st
403402
404403// recoverFinalStorachaPieces scans incomplete storacha-migration rows where the
405404// DB/ref side already exists. For each row it checks whether the file has
406- // already reached its final s-t00-<id> path. If yes, it finishes declaration and
407- // complete=true. If no final file exists, it leaves the row alone; there is
408- // nothing safe to do without either the staged file or the final file.
409- func recoverFinalStorachaPieces (ctx context.Context , dep * deps.Deps , storageID storiface.ID , targetPath string , out * importPiecesOutput , batchSize int ) error {
405+ // already reached its final target/piece/s-t00-<id> path. If yes, it finishes
406+ // declaration and complete=true. If no final file exists, it leaves the row
407+ // alone; there is nothing safe to do without either the staged file or the final
408+ // file.
409+ func recoverFinalStorachaPieces (ctx context.Context , db * harmonydb.DB , si paths.SectorIndex , storageID storiface.ID , targetPath string , out * importPiecesOutput , batchSize int ) error {
410410 if out .Count >= batchSize {
411411 return nil
412412 }
413413
414414 var rows []storachaFinalRecoveryRow
415- err := dep . DB .Select (ctx , & rows , `
415+ err := db .Select (ctx , & rows , `
416416 SELECT pp.id, pp.piece_cid, pp.piece_padded_size, pp.piece_raw_size
417417 FROM parked_pieces pp
418418 WHERE pp.complete = FALSE
@@ -436,7 +436,7 @@ func recoverFinalStorachaPieces(ctx context.Context, dep *deps.Deps, storageID s
436436 break
437437 }
438438
439- imported , err := recoverFinalStorachaPiece (ctx , dep , storageID , targetPath , row )
439+ imported , err := recoverFinalStorachaPiece (ctx , db , si , storageID , targetPath , row )
440440 if err != nil {
441441 return err
442442 }
@@ -468,11 +468,11 @@ func storachaPieceCIDV2FromRow(row storachaFinalRecoveryRow) (string, error) {
468468}
469469
470470// recoverFinalStorachaPiece handles the post-rename crash window for one DB row.
471- // It requires target/s-t00-<id> to exist, rebuilds the piece info from the DB
472- // row, reuses the same claim/ref checks as staged import, then declares the
471+ // It requires target/piece/ s-t00-<id> to exist, rebuilds the piece info from the
472+ // DB row, reuses the same claim/ref checks as staged import, then declares the
473473// final file and marks the parked piece complete. It returns false when the
474474// final file is missing or a live task still owns the parked_piece.
475- func recoverFinalStorachaPiece (ctx context.Context , dep * deps. Deps , storageID storiface.ID , targetPath string , row storachaFinalRecoveryRow ) (bool , error ) {
475+ func recoverFinalStorachaPiece (ctx context.Context , db * harmonydb. DB , si paths. SectorIndex , storageID storiface.ID , targetPath string , row storachaFinalRecoveryRow ) (bool , error ) {
476476 finalPath := storachaFinalPiecePath (targetPath , row .ID )
477477 info , err := os .Stat (finalPath )
478478 if os .IsNotExist (err ) {
@@ -496,7 +496,7 @@ func recoverFinalStorachaPiece(ctx context.Context, dep *deps.Deps, storageID st
496496 }
497497
498498 var state storachaParkedPieceState
499- comm , err := dep . DB .BeginTransaction (ctx , func (tx * harmonydb.Tx ) (commit bool , err error ) {
499+ comm , err := db .BeginTransaction (ctx , func (tx * harmonydb.Tx ) (commit bool , err error ) {
500500 state , err = claimExistingStorachaPieceTx (tx , row .ID )
501501 if err != nil {
502502 return false , err
@@ -519,11 +519,11 @@ func recoverFinalStorachaPiece(ctx context.Context, dep *deps.Deps, storageID st
519519 return false , nil
520520 }
521521
522- if err := declareStorachaPiece (ctx , dep , storageID , row .ID ); err != nil {
522+ if err := declareStorachaPiece (ctx , si , storageID , row .ID ); err != nil {
523523 return false , err
524524 }
525525 if ! state .AlreadyComplete {
526- if err := markParkedPieceComplete (ctx , dep . DB , row .ID ); err != nil {
526+ if err := markParkedPieceComplete (ctx , db , row .ID ); err != nil {
527527 return false , err
528528 }
529529 }
@@ -654,18 +654,18 @@ func ensureStorachaRefsTx(tx *harmonydb.Tx, parkedPieceID int64, pi *mk20.PieceI
654654}
655655
656656// storachaFinalPiecePath mirrors Curio's piece-park sector naming: parked piece
657- // id N is stored as miner-zero piece sector s-t00-N under the target piece dir .
657+ // id N is stored as miner-zero piece sector s-t00-N under target/ piece.
658658func storachaFinalPiecePath (targetPath string , parkedPieceID int64 ) string {
659659 pieceNumber := storiface .PieceNumber (parkedPieceID )
660- return filepath .Join (targetPath , storiface .SectorName (pieceNumber .Ref ().ID ))
660+ return filepath .Join (targetPath , "piece" , storiface .SectorName (pieceNumber .Ref ().ID ))
661661}
662662
663663// declareStorachaPiece records the final piece file in sector_location. The
664664// storage index upsert is idempotent, so recovery can call this again after a
665665// crash between rename and complete=true.
666- func declareStorachaPiece (ctx context.Context , dep * deps. Deps , storageID storiface.ID , parkedPieceID int64 ) error {
666+ func declareStorachaPiece (ctx context.Context , si paths. SectorIndex , storageID storiface.ID , parkedPieceID int64 ) error {
667667 pieceNumber := storiface .PieceNumber (parkedPieceID )
668- err := dep . Si .StorageDeclareSector (ctx , storageID , pieceNumber .Ref ().ID , storiface .FTPiece , true )
668+ err := si .StorageDeclareSector (ctx , storageID , pieceNumber .Ref ().ID , storiface .FTPiece , true )
669669 if err != nil {
670670 return xerrors .Errorf ("declaring storacha piece: %w" , err )
671671 }
0 commit comments