restic/cmd/restic/cmd_rebuild_index.go

134 lines
3.2 KiB
Go
Raw Normal View History

2015-10-25 16:24:52 +00:00
package main
2016-09-17 10:36:05 +00:00
import (
2020-10-10 19:51:11 +00:00
"github.com/restic/restic/internal/repository"
2017-07-24 15:42:25 +00:00
"github.com/restic/restic/internal/restic"
2015-10-25 16:24:52 +00:00
2016-09-17 10:36:05 +00:00
"github.com/spf13/cobra"
)
2015-10-25 16:24:52 +00:00
2016-09-17 10:36:05 +00:00
var cmdRebuildIndex = &cobra.Command{
Use: "rebuild-index [flags]",
2020-10-10 19:51:11 +00:00
Short: "Build a new index",
2016-09-17 10:36:05 +00:00
Long: `
The "rebuild-index" command creates a new index based on the pack files in the
repository.
EXIT STATUS
===========
Exit status is 0 if the command was successful, and non-zero if there was any error.
2016-09-17 10:36:05 +00:00
`,
DisableAutoGenTag: true,
2016-09-17 10:36:05 +00:00
RunE: func(cmd *cobra.Command, args []string) error {
2020-10-10 19:51:11 +00:00
return runRebuildIndex(rebuildIndexOptions, globalOptions)
2016-09-17 10:36:05 +00:00
},
2015-10-25 16:24:52 +00:00
}
2020-10-10 19:51:11 +00:00
// RebuildIndexOptions collects all options for the rebuild-index command.
type RebuildIndexOptions struct {
ReadAllPacks bool
}
var rebuildIndexOptions RebuildIndexOptions
2015-10-25 16:24:52 +00:00
func init() {
2016-09-17 10:36:05 +00:00
cmdRoot.AddCommand(cmdRebuildIndex)
2020-10-10 19:51:11 +00:00
f := cmdRebuildIndex.Flags()
f.BoolVar(&rebuildIndexOptions.ReadAllPacks, "read-all-packs", false, "read all pack files to generate new index from scratch")
2015-10-25 16:24:52 +00:00
}
2020-10-10 19:51:11 +00:00
func runRebuildIndex(opts RebuildIndexOptions, gopts GlobalOptions) error {
2016-09-17 10:36:05 +00:00
repo, err := OpenRepository(gopts)
2015-10-25 16:24:52 +00:00
if err != nil {
return err
}
2020-08-09 11:24:47 +00:00
lock, err := lockRepoExclusive(gopts.ctx, repo)
2015-10-25 16:24:52 +00:00
defer unlockRepo(lock)
if err != nil {
return err
}
2020-10-10 19:51:11 +00:00
return rebuildIndex(opts, gopts, repo, restic.NewIDSet())
}
2020-10-10 19:51:11 +00:00
func rebuildIndex(opts RebuildIndexOptions, gopts GlobalOptions, repo *repository.Repository, ignorePacks restic.IDSet) error {
ctx := gopts.ctx
2020-10-10 19:51:31 +00:00
var obsoleteIndexes restic.IDs
2020-10-10 19:51:11 +00:00
packSizeFromList := make(map[restic.ID]int64)
2020-10-10 19:51:31 +00:00
removePacks := restic.NewIDSet()
2020-10-10 19:51:11 +00:00
if opts.ReadAllPacks {
// get old index files
err := repo.List(ctx, restic.IndexFile, func(id restic.ID, size int64) error {
2020-10-10 19:51:31 +00:00
obsoleteIndexes = append(obsoleteIndexes, id)
2020-10-10 19:51:11 +00:00
return nil
})
if err != nil {
return err
}
2020-10-10 19:51:11 +00:00
Verbosef("finding pack files in repo...\n")
err = repo.List(ctx, restic.PackFile, func(id restic.ID, size int64) error {
packSizeFromList[id] = size
2020-10-10 19:51:31 +00:00
removePacks.Insert(id)
2020-10-10 19:51:11 +00:00
return nil
})
if err != nil {
return err
}
} else {
Verbosef("loading indexes...\n")
err := repo.LoadIndex(gopts.ctx)
if err != nil {
return err
}
2020-10-10 19:51:11 +00:00
Verbosef("getting pack files to read...\n")
2020-11-16 03:51:53 +00:00
packSizeFromIndex := repo.Index().PackSize(ctx, false)
2020-10-10 19:51:11 +00:00
err = repo.List(ctx, restic.PackFile, func(id restic.ID, packSize int64) error {
size, ok := packSizeFromIndex[id]
if !ok || size != packSize {
// Pack was not referenced in index or size does not match
packSizeFromList[id] = packSize
2020-10-10 19:51:31 +00:00
removePacks.Insert(id)
2020-10-10 19:51:11 +00:00
}
delete(packSizeFromIndex, id)
return nil
})
if err != nil {
return err
}
for id := range packSizeFromIndex {
2020-10-10 19:51:31 +00:00
// forget pack files that are referenced in the index but do not exist
2020-10-10 19:51:11 +00:00
// when rebuilding the index
2020-10-10 19:51:31 +00:00
removePacks.Insert(id)
}
}
2020-10-10 19:51:11 +00:00
if len(packSizeFromList) > 0 {
Verbosef("reading pack files\n")
bar := newProgressMax(!globalOptions.Quiet, uint64(len(packSizeFromList)), "packs")
2020-10-10 19:51:31 +00:00
invalidFiles, err := repo.CreateIndexFromPacks(ctx, packSizeFromList, bar)
2020-10-10 19:51:11 +00:00
if err != nil {
return err
}
2020-10-10 19:51:11 +00:00
for _, id := range invalidFiles {
Verboseff("skipped incomplete pack file: %v\n", id)
}
}
err := rebuildIndexFiles(gopts, repo, removePacks, obsoleteIndexes)
if err != nil {
2020-10-10 19:51:11 +00:00
return err
}
2020-10-10 19:51:11 +00:00
Verbosef("done\n")
return nil
2015-10-25 16:24:52 +00:00
}