github.com/cosmos/cosmos-sdk@v0.50.10/client/snapshot/load.go (about) 1 package snapshot 2 3 import ( 4 "archive/tar" 5 "bytes" 6 "compress/gzip" 7 "fmt" 8 "io" 9 "os" 10 "reflect" 11 "strconv" 12 13 "github.com/spf13/cobra" 14 15 snapshottypes "cosmossdk.io/store/snapshots/types" 16 17 "github.com/cosmos/cosmos-sdk/server" 18 ) 19 20 const SnapshotFileName = "_snapshot" 21 22 // LoadArchiveCmd load a portable archive format snapshot into snapshot store 23 func LoadArchiveCmd() *cobra.Command { 24 return &cobra.Command{ 25 Use: "load <archive-file>", 26 Short: "Load a snapshot archive file (.tar.gz) into snapshot store", 27 Args: cobra.ExactArgs(1), 28 RunE: func(cmd *cobra.Command, args []string) error { 29 ctx := server.GetServerContextFromCmd(cmd) 30 snapshotStore, err := server.GetSnapshotStore(ctx.Viper) 31 if err != nil { 32 return err 33 } 34 35 path := args[0] 36 fp, err := os.Open(path) 37 if err != nil { 38 return fmt.Errorf("failed to open archive file: %w", err) 39 } 40 reader, err := gzip.NewReader(fp) 41 if err != nil { 42 return fmt.Errorf("failed to create gzip reader: %w", err) 43 } 44 45 var snapshot snapshottypes.Snapshot 46 tr := tar.NewReader(reader) 47 if err != nil { 48 return fmt.Errorf("failed to create tar reader: %w", err) 49 } 50 51 hdr, err := tr.Next() 52 if err != nil { 53 return fmt.Errorf("failed to read snapshot file header: %w", err) 54 } 55 if hdr.Name != SnapshotFileName { 56 return fmt.Errorf("invalid archive, expect file: snapshot, got: %s", hdr.Name) 57 } 58 bz, err := io.ReadAll(tr) 59 if err != nil { 60 return fmt.Errorf("failed to read snapshot file: %w", err) 61 } 62 if err := snapshot.Unmarshal(bz); err != nil { 63 return fmt.Errorf("failed to unmarshal snapshot: %w", err) 64 } 65 66 // make sure the channel is unbuffered, because the tar reader can't do concurrency 67 chunks := make(chan io.ReadCloser) 68 quitChan := make(chan *snapshottypes.Snapshot) 69 go func() { 70 defer close(quitChan) 71 72 savedSnapshot, err := snapshotStore.Save(snapshot.Height, snapshot.Format, chunks) 73 if err != nil { 74 cmd.Println("failed to save snapshot", err) 75 return 76 } 77 quitChan <- savedSnapshot 78 }() 79 80 for i := uint32(0); i < snapshot.Chunks; i++ { 81 hdr, err = tr.Next() 82 if err != nil { 83 if err == io.EOF { 84 break 85 } 86 return err 87 } 88 89 if hdr.Name != strconv.FormatInt(int64(i), 10) { 90 return fmt.Errorf("invalid archive, expect file: %d, got: %s", i, hdr.Name) 91 } 92 93 bz, err := io.ReadAll(tr) 94 if err != nil { 95 return fmt.Errorf("failed to read chunk file: %w", err) 96 } 97 chunks <- io.NopCloser(bytes.NewReader(bz)) 98 } 99 close(chunks) 100 101 savedSnapshot := <-quitChan 102 if savedSnapshot == nil { 103 return fmt.Errorf("failed to save snapshot") 104 } 105 106 if !reflect.DeepEqual(&snapshot, savedSnapshot) { 107 _ = snapshotStore.Delete(snapshot.Height, snapshot.Format) 108 return fmt.Errorf("invalid archive, the saved snapshot is not equal to the original one") 109 } 110 111 return nil 112 }, 113 } 114 }