mirror of
https://github.com/octoleo/restic.git
synced 2024-11-29 16:23:59 +00:00
Refactor index decoding
Decoding old-format indices no longer requires loading and decrypting twice.
This commit is contained in:
parent
6003dada14
commit
27db3ec262
@ -117,12 +117,16 @@ func (c *Checker) LoadIndex(ctx context.Context) (hints []error, errs []error) {
|
|||||||
debug.Log("worker got file %v", fi.ID.Str())
|
debug.Log("worker got file %v", fi.ID.Str())
|
||||||
var err error
|
var err error
|
||||||
var idx *repository.Index
|
var idx *repository.Index
|
||||||
idx, buf, err = repository.LoadIndexWithDecoder(ctx, c.repo, buf[:0], fi.ID, repository.DecodeIndex)
|
oldFormat := false
|
||||||
if errors.Cause(err) == repository.ErrOldIndexFormat {
|
|
||||||
|
buf, err = c.repo.LoadAndDecrypt(ctx, buf[:0], restic.IndexFile, fi.ID)
|
||||||
|
if err == nil {
|
||||||
|
idx, oldFormat, err = repository.DecodeIndex(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
if oldFormat {
|
||||||
debug.Log("index %v has old format", fi.ID.Str())
|
debug.Log("index %v has old format", fi.ID.Str())
|
||||||
hints = append(hints, ErrOldIndexFormat{fi.ID})
|
hints = append(hints, ErrOldIndexFormat{fi.ID})
|
||||||
|
|
||||||
idx, buf, err = repository.LoadIndexWithDecoder(ctx, c.repo, buf[:0], fi.ID, repository.DecodeOldIndex)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
err = errors.Wrapf(err, "error loading index %v", fi.ID.Str())
|
err = errors.Wrapf(err, "error loading index %v", fi.ID.Str())
|
||||||
|
@ -522,11 +522,8 @@ func isErrOldIndex(err error) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// ErrOldIndexFormat means an index with the old format was detected.
|
// DecodeIndex unserializes an index from buf.
|
||||||
var ErrOldIndexFormat = errors.New("index has old format")
|
func DecodeIndex(buf []byte) (idx *Index, oldFormat bool, err error) {
|
||||||
|
|
||||||
// DecodeIndex loads and unserializes an index from rd.
|
|
||||||
func DecodeIndex(buf []byte) (idx *Index, err error) {
|
|
||||||
debug.Log("Start decoding index")
|
debug.Log("Start decoding index")
|
||||||
idxJSON := &jsonIndex{}
|
idxJSON := &jsonIndex{}
|
||||||
|
|
||||||
@ -536,10 +533,11 @@ func DecodeIndex(buf []byte) (idx *Index, err error) {
|
|||||||
|
|
||||||
if isErrOldIndex(err) {
|
if isErrOldIndex(err) {
|
||||||
debug.Log("index is probably old format, trying that")
|
debug.Log("index is probably old format, trying that")
|
||||||
err = ErrOldIndexFormat
|
idx, err = decodeOldIndex(buf)
|
||||||
|
return idx, err == nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, errors.Wrap(err, "Decode")
|
return nil, false, errors.Wrap(err, "DecodeIndex")
|
||||||
}
|
}
|
||||||
|
|
||||||
idx = NewIndex()
|
idx = NewIndex()
|
||||||
@ -571,11 +569,11 @@ func DecodeIndex(buf []byte) (idx *Index, err error) {
|
|||||||
idx.final = true
|
idx.final = true
|
||||||
|
|
||||||
debug.Log("done")
|
debug.Log("done")
|
||||||
return idx, nil
|
return idx, false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DecodeOldIndex loads and unserializes an index in the old format from rd.
|
// DecodeOldIndex loads and unserializes an index in the old format from rd.
|
||||||
func DecodeOldIndex(buf []byte) (idx *Index, err error) {
|
func decodeOldIndex(buf []byte) (idx *Index, err error) {
|
||||||
debug.Log("Start decoding old index")
|
debug.Log("Start decoding old index")
|
||||||
list := []*packJSON{}
|
list := []*packJSON{}
|
||||||
|
|
||||||
@ -615,23 +613,3 @@ func DecodeOldIndex(buf []byte) (idx *Index, err error) {
|
|||||||
debug.Log("done")
|
debug.Log("done")
|
||||||
return idx, nil
|
return idx, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadIndexWithDecoder loads the index and decodes it with fn.
|
|
||||||
func LoadIndexWithDecoder(ctx context.Context, repo restic.Repository, buf []byte, id restic.ID, fn func([]byte) (*Index, error)) (*Index, []byte, error) {
|
|
||||||
debug.Log("Loading index %v", id)
|
|
||||||
|
|
||||||
buf, err := repo.LoadAndDecrypt(ctx, buf[:0], restic.IndexFile, id)
|
|
||||||
if err != nil {
|
|
||||||
return nil, buf[:0], err
|
|
||||||
}
|
|
||||||
|
|
||||||
idx, err := fn(buf)
|
|
||||||
if err != nil {
|
|
||||||
debug.Log("error while decoding index %v: %v", id, err)
|
|
||||||
return nil, buf[:0], err
|
|
||||||
}
|
|
||||||
|
|
||||||
idx.ids = append(idx.ids, id)
|
|
||||||
|
|
||||||
return idx, buf, nil
|
|
||||||
}
|
|
||||||
|
@ -56,10 +56,11 @@ func TestIndexSerialize(t *testing.T) {
|
|||||||
err := idx.Encode(wr)
|
err := idx.Encode(wr)
|
||||||
rtest.OK(t, err)
|
rtest.OK(t, err)
|
||||||
|
|
||||||
idx2, err := repository.DecodeIndex(wr.Bytes())
|
idx2, oldFormat, err := repository.DecodeIndex(wr.Bytes())
|
||||||
rtest.OK(t, err)
|
rtest.OK(t, err)
|
||||||
rtest.Assert(t, idx2 != nil,
|
rtest.Assert(t, idx2 != nil,
|
||||||
"nil returned for decoded index")
|
"nil returned for decoded index")
|
||||||
|
rtest.Assert(t, !oldFormat, "new index format recognized as old format")
|
||||||
|
|
||||||
wr2 := bytes.NewBuffer(nil)
|
wr2 := bytes.NewBuffer(nil)
|
||||||
err = idx2.Encode(wr2)
|
err = idx2.Encode(wr2)
|
||||||
@ -135,12 +136,13 @@ func TestIndexSerialize(t *testing.T) {
|
|||||||
rtest.OK(t, err)
|
rtest.OK(t, err)
|
||||||
rtest.Equals(t, restic.IDs{id}, ids)
|
rtest.Equals(t, restic.IDs{id}, ids)
|
||||||
|
|
||||||
idx3, err := repository.DecodeIndex(wr3.Bytes())
|
idx3, oldFormat, err := repository.DecodeIndex(wr3.Bytes())
|
||||||
rtest.OK(t, err)
|
rtest.OK(t, err)
|
||||||
rtest.Assert(t, idx3 != nil,
|
rtest.Assert(t, idx3 != nil,
|
||||||
"nil returned for decoded index")
|
"nil returned for decoded index")
|
||||||
rtest.Assert(t, idx3.Final(),
|
rtest.Assert(t, idx3.Final(),
|
||||||
"decoded index is not final")
|
"decoded index is not final")
|
||||||
|
rtest.Assert(t, !oldFormat, "new index format recognized as old format")
|
||||||
|
|
||||||
// all new blobs must be in the index
|
// all new blobs must be in the index
|
||||||
for _, testBlob := range newtests {
|
for _, testBlob := range newtests {
|
||||||
@ -285,8 +287,9 @@ var exampleLookupTest = struct {
|
|||||||
func TestIndexUnserialize(t *testing.T) {
|
func TestIndexUnserialize(t *testing.T) {
|
||||||
oldIdx := restic.IDs{restic.TestParseID("ed54ae36197f4745ebc4b54d10e0f623eaaaedd03013eb7ae90df881b7781452")}
|
oldIdx := restic.IDs{restic.TestParseID("ed54ae36197f4745ebc4b54d10e0f623eaaaedd03013eb7ae90df881b7781452")}
|
||||||
|
|
||||||
idx, err := repository.DecodeIndex(docExample)
|
idx, oldFormat, err := repository.DecodeIndex(docExample)
|
||||||
rtest.OK(t, err)
|
rtest.OK(t, err)
|
||||||
|
rtest.Assert(t, !oldFormat, "new index format recognized as old format")
|
||||||
|
|
||||||
for _, test := range exampleTests {
|
for _, test := range exampleTests {
|
||||||
list := idx.Lookup(test.id, test.tpe, nil)
|
list := idx.Lookup(test.id, test.tpe, nil)
|
||||||
@ -338,7 +341,7 @@ func BenchmarkDecodeIndex(b *testing.B) {
|
|||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
_, err := repository.DecodeIndex(benchmarkIndexJSON)
|
_, _, err := repository.DecodeIndex(benchmarkIndexJSON)
|
||||||
rtest.OK(b, err)
|
rtest.OK(b, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -349,15 +352,16 @@ func BenchmarkDecodeIndexParallel(b *testing.B) {
|
|||||||
|
|
||||||
b.RunParallel(func(pb *testing.PB) {
|
b.RunParallel(func(pb *testing.PB) {
|
||||||
for pb.Next() {
|
for pb.Next() {
|
||||||
_, err := repository.DecodeIndex(benchmarkIndexJSON)
|
_, _, err := repository.DecodeIndex(benchmarkIndexJSON)
|
||||||
rtest.OK(b, err)
|
rtest.OK(b, err)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestIndexUnserializeOld(t *testing.T) {
|
func TestIndexUnserializeOld(t *testing.T) {
|
||||||
idx, err := repository.DecodeOldIndex(docOldExample)
|
idx, oldFormat, err := repository.DecodeIndex(docOldExample)
|
||||||
rtest.OK(t, err)
|
rtest.OK(t, err)
|
||||||
|
rtest.Assert(t, oldFormat, "old index format recognized as new format")
|
||||||
|
|
||||||
for _, test := range exampleTests {
|
for _, test := range exampleTests {
|
||||||
list := idx.Lookup(test.id, test.tpe, nil)
|
list := idx.Lookup(test.id, test.tpe, nil)
|
||||||
|
@ -457,14 +457,13 @@ func (r *Repository) LoadIndex(ctx context.Context) error {
|
|||||||
var buf []byte
|
var buf []byte
|
||||||
for fi := range ch {
|
for fi := range ch {
|
||||||
var err error
|
var err error
|
||||||
var idx *Index
|
buf, err = r.LoadAndDecrypt(ctx, buf[:0], restic.IndexFile, fi.ID)
|
||||||
idx, buf, err = LoadIndexWithDecoder(ctx, r, buf[:0], fi.ID, DecodeIndex)
|
|
||||||
if err != nil && errors.Cause(err) == ErrOldIndexFormat {
|
|
||||||
idx, buf, err = LoadIndexWithDecoder(ctx, r, buf[:0], fi.ID, DecodeOldIndex)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, fmt.Sprintf("unable to load index %v", fi.ID.Str()))
|
return errors.Wrapf(err, "unable to load index %s", fi.ID.Str())
|
||||||
|
}
|
||||||
|
idx, _, err := DecodeIndex(buf)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "unable to decode index %s", fi.ID.Str())
|
||||||
}
|
}
|
||||||
|
|
||||||
select {
|
select {
|
||||||
@ -580,20 +579,18 @@ func (r *Repository) PrepareCache(indexIDs restic.IDSet) error {
|
|||||||
|
|
||||||
// LoadIndex loads the index id from backend and returns it.
|
// LoadIndex loads the index id from backend and returns it.
|
||||||
func LoadIndex(ctx context.Context, repo restic.Repository, id restic.ID) (*Index, error) {
|
func LoadIndex(ctx context.Context, repo restic.Repository, id restic.ID) (*Index, error) {
|
||||||
idx, _, err := LoadIndexWithDecoder(ctx, repo, nil, id, DecodeIndex)
|
buf, err := repo.LoadAndDecrypt(ctx, nil, restic.IndexFile, id)
|
||||||
if err == nil {
|
if err != nil {
|
||||||
return idx, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if errors.Cause(err) == ErrOldIndexFormat {
|
|
||||||
fmt.Fprintf(os.Stderr, "index %v has old format\n", id.Str())
|
|
||||||
idx, _, err := LoadIndexWithDecoder(ctx, repo, nil, id, DecodeOldIndex)
|
|
||||||
return idx, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
idx, oldFormat, err := DecodeIndex(buf)
|
||||||
|
if oldFormat {
|
||||||
|
fmt.Fprintf(os.Stderr, "index %v has old format\n", id.Str())
|
||||||
|
}
|
||||||
|
return idx, err
|
||||||
|
}
|
||||||
|
|
||||||
// SearchKey finds a key with the supplied password, afterwards the config is
|
// SearchKey finds a key with the supplied password, afterwards the config is
|
||||||
// read and parsed. It tries at most maxKeys key files in the repo.
|
// read and parsed. It tries at most maxKeys key files in the repo.
|
||||||
func (r *Repository) SearchKey(ctx context.Context, password string, maxKeys int, keyHint string) error {
|
func (r *Repository) SearchKey(ctx context.Context, password string, maxKeys int, keyHint string) error {
|
||||||
|
Loading…
Reference in New Issue
Block a user