diff --git a/repository/index.go b/repository/index.go index 2ffac231c..1f9d65ad1 100644 --- a/repository/index.go +++ b/repository/index.go @@ -132,6 +132,26 @@ func (idx *Index) Lookup(id backend.ID) (pb PackedBlob, err error) { return PackedBlob{}, fmt.Errorf("id %v not found in index", id) } +// ListPack returns a list of blobs contained in a pack. +func (idx *Index) ListPack(id backend.ID) (list []PackedBlob) { + idx.m.Lock() + defer idx.m.Unlock() + + for blobID, entry := range idx.pack { + if entry.packID == id { + list = append(list, PackedBlob{ + ID: blobID, + Type: entry.tpe, + Length: entry.length, + Offset: entry.offset, + PackID: entry.packID, + }) + } + } + + return list +} + // Has returns true iff the id is listed in the index. func (idx *Index) Has(id backend.ID) bool { _, err := idx.Lookup(id) diff --git a/repository/index_test.go b/repository/index_test.go index 480619fa6..85674de77 100644 --- a/repository/index_test.go +++ b/repository/index_test.go @@ -240,6 +240,18 @@ var exampleTests = []struct { }, } +var exampleLookupTest = struct { + packID backend.ID + blobs backend.IDSet +}{ + ParseID("73d04e6125cf3c28a299cc2f3cca3b78ceac396e4fcf9575e34536b26782413c"), + backend.IDSet{ + ParseID("3ec79977ef0cf5de7b08cd12b874cd0f62bbaf7f07f3497a5b1bbcc8cb39b1ce"): struct{}{}, + ParseID("9ccb846e60d90d4eb915848add7aa7ea1e4bbabfc60e573db9f7bfb2789afbae"): struct{}{}, + ParseID("d3dc577b4ffd38cc4b32122cabf8655a0223ed22edfd93b353dc0c3f2b0fdf66"): struct{}{}, + }, +} + func TestIndexUnserialize(t *testing.T) { oldIdx := backend.IDs{ParseID("ed54ae36197f4745ebc4b54d10e0f623eaaaedd03013eb7ae90df881b7781452")} @@ -257,6 +269,17 @@ func TestIndexUnserialize(t *testing.T) { } Equals(t, oldIdx, idx.Supersedes()) + + blobs := idx.ListPack(exampleLookupTest.packID) + if len(blobs) != len(exampleLookupTest.blobs) { + t.Fatalf("expected %d blobs in pack, got %d", len(exampleLookupTest.blobs), len(blobs)) + } + + for _, blob := range blobs { + if !exampleLookupTest.blobs.Has(blob.ID) { + t.Errorf("unexpected blob %v found", blob.ID.Str()) + } + } } func TestIndexUnserializeOld(t *testing.T) { diff --git a/repository/master_index.go b/repository/master_index.go index 5a5e499e6..bc3dea768 100644 --- a/repository/master_index.go +++ b/repository/master_index.go @@ -67,6 +67,22 @@ func (mi *MasterIndex) LookupSize(id backend.ID) (uint, error) { return 0, fmt.Errorf("id %v not found in any index", id) } +// ListPack returns the list of blobs in a pack. The first matching index is +// returned, or nil if no index contains information about the pack id. +func (mi *MasterIndex) ListPack(id backend.ID) (list []PackedBlob) { + mi.idxMutex.RLock() + defer mi.idxMutex.RUnlock() + + for _, idx := range mi.idx { + list := idx.ListPack(id) + if len(list) > 0 { + return list + } + } + + return nil +} + // Has queries all known Indexes for the ID and returns the first match. func (mi *MasterIndex) Has(id backend.ID) bool { mi.idxMutex.RLock()