mirror of
https://github.com/octoleo/restic.git
synced 2024-11-25 06:07:44 +00:00
Merge pull request #3772 from MichaelEischer/fix-mixed-index
rebuild-index: correctly rebuild index for mixed packs
This commit is contained in:
commit
621023a50b
13
changelog/unreleased/pull-3772
Normal file
13
changelog/unreleased/pull-3772
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
Bugfix: Correctly rebuild index for legacy repositories
|
||||||
|
|
||||||
|
After running `rebuild-index` on a legacy repository containing mixed pack
|
||||||
|
files, that is pack files with store both metadata and file data, `check`
|
||||||
|
printed warnings like `pack 12345678 contained in several indexes: ...`. The
|
||||||
|
warning is not critical. It has been fixed by properly handling mixed pack
|
||||||
|
files while rebuilding the index.
|
||||||
|
|
||||||
|
Running `prune` for such legacy repositories will also fix the warning by
|
||||||
|
reorganizing the pack files which cause the warning.
|
||||||
|
|
||||||
|
https://github.com/restic/restic/pull/3772
|
||||||
|
https://forum.restic.net/t/help-in-recovery-a-corrupted-repository/5044/13
|
@ -247,8 +247,8 @@ func (idx *Index) Each(ctx context.Context) <-chan restic.PackedBlob {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type EachByPackResult struct {
|
type EachByPackResult struct {
|
||||||
packID restic.ID
|
PackID restic.ID
|
||||||
blobs []restic.Blob
|
Blobs []restic.Blob
|
||||||
}
|
}
|
||||||
|
|
||||||
// EachByPack returns a channel that yields all blobs known to the index
|
// EachByPack returns a channel that yields all blobs known to the index
|
||||||
@ -269,29 +269,35 @@ func (idx *Index) EachByPack(ctx context.Context, packBlacklist restic.IDSet) <-
|
|||||||
close(ch)
|
close(ch)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
byPack := make(map[restic.ID][][]*indexEntry)
|
||||||
|
|
||||||
for typ := range idx.byType {
|
for typ := range idx.byType {
|
||||||
byPack := make(map[restic.ID][]*indexEntry)
|
|
||||||
m := &idx.byType[typ]
|
m := &idx.byType[typ]
|
||||||
m.foreach(func(e *indexEntry) bool {
|
m.foreach(func(e *indexEntry) bool {
|
||||||
packID := idx.packs[e.packIndex]
|
packID := idx.packs[e.packIndex]
|
||||||
|
if _, ok := byPack[packID]; !ok {
|
||||||
|
byPack[packID] = make([][]*indexEntry, restic.NumBlobTypes)
|
||||||
|
}
|
||||||
if !idx.final || !packBlacklist.Has(packID) {
|
if !idx.final || !packBlacklist.Has(packID) {
|
||||||
byPack[packID] = append(byPack[packID], e)
|
byPack[packID][typ] = append(byPack[packID][typ], e)
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
|
||||||
for packID, pack := range byPack {
|
for packID, packByType := range byPack {
|
||||||
var result EachByPackResult
|
var result EachByPackResult
|
||||||
result.packID = packID
|
result.PackID = packID
|
||||||
|
for typ, pack := range packByType {
|
||||||
for _, e := range pack {
|
for _, e := range pack {
|
||||||
result.blobs = append(result.blobs, idx.toPackedBlob(e, restic.BlobType(typ)).Blob)
|
result.Blobs = append(result.Blobs, idx.toPackedBlob(e, restic.BlobType(typ)).Blob)
|
||||||
}
|
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
return
|
|
||||||
case ch <- result:
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return
|
||||||
|
case ch <- result:
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
@ -574,3 +574,42 @@ func TestIndexHas(t *testing.T) {
|
|||||||
rtest.Assert(t, !idx.Has(restic.NewRandomBlobHandle()), "Index reports having a data blob not added to it")
|
rtest.Assert(t, !idx.Has(restic.NewRandomBlobHandle()), "Index reports having a data blob not added to it")
|
||||||
rtest.Assert(t, !idx.Has(restic.BlobHandle{ID: tests[0].ID, Type: restic.TreeBlob}), "Index reports having a tree blob added to it with the same id as a data blob")
|
rtest.Assert(t, !idx.Has(restic.BlobHandle{ID: tests[0].ID, Type: restic.TreeBlob}), "Index reports having a tree blob added to it with the same id as a data blob")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestMixedEachByPack(t *testing.T) {
|
||||||
|
idx := repository.NewIndex()
|
||||||
|
|
||||||
|
expected := make(map[restic.ID]int)
|
||||||
|
// create 50 packs with 2 blobs each
|
||||||
|
for i := 0; i < 50; i++ {
|
||||||
|
packID := restic.NewRandomID()
|
||||||
|
expected[packID] = 1
|
||||||
|
blobs := []restic.Blob{
|
||||||
|
{
|
||||||
|
BlobHandle: restic.BlobHandle{Type: restic.DataBlob, ID: restic.NewRandomID()},
|
||||||
|
Offset: 0,
|
||||||
|
Length: 42,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
BlobHandle: restic.BlobHandle{Type: restic.TreeBlob, ID: restic.NewRandomID()},
|
||||||
|
Offset: 42,
|
||||||
|
Length: 43,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
idx.StorePack(packID, blobs)
|
||||||
|
}
|
||||||
|
|
||||||
|
reported := make(map[restic.ID]int)
|
||||||
|
for bp := range idx.EachByPack(context.TODO(), restic.NewIDSet()) {
|
||||||
|
reported[bp.PackID]++
|
||||||
|
|
||||||
|
rtest.Equals(t, 2, len(bp.Blobs)) // correct blob count
|
||||||
|
if bp.Blobs[0].Offset > bp.Blobs[1].Offset {
|
||||||
|
bp.Blobs[1], bp.Blobs[0] = bp.Blobs[0], bp.Blobs[1]
|
||||||
|
}
|
||||||
|
b0 := bp.Blobs[0]
|
||||||
|
rtest.Assert(t, b0.Type == restic.DataBlob && b0.Offset == 0 && b0.Length == 42, "wrong blob", b0)
|
||||||
|
b1 := bp.Blobs[1]
|
||||||
|
rtest.Assert(t, b1.Type == restic.TreeBlob && b1.Offset == 42 && b1.Length == 43, "wrong blob", b1)
|
||||||
|
}
|
||||||
|
rtest.Equals(t, expected, reported)
|
||||||
|
}
|
||||||
|
@ -339,7 +339,7 @@ func (mi *MasterIndex) Save(ctx context.Context, repo restic.SaverUnpacked, pack
|
|||||||
debug.Log("adding index %d", i)
|
debug.Log("adding index %d", i)
|
||||||
|
|
||||||
for pbs := range idx.EachByPack(ctx, packBlacklist) {
|
for pbs := range idx.EachByPack(ctx, packBlacklist) {
|
||||||
newIndex.StorePack(pbs.packID, pbs.blobs)
|
newIndex.StorePack(pbs.PackID, pbs.Blobs)
|
||||||
p.Add(1)
|
p.Add(1)
|
||||||
if IndexFull(newIndex, mi.compress) {
|
if IndexFull(newIndex, mi.compress) {
|
||||||
select {
|
select {
|
||||||
|
Loading…
Reference in New Issue
Block a user