mirror of
https://github.com/borgbackup/borg.git
synced 2026-07-08 01:31:04 -04:00
repository: raise PackNotFound when get_many hits a missing pack
This commit is contained in:
parent
87bd65c054
commit
cbc94ae837
2 changed files with 33 additions and 1 deletions
|
|
@ -287,6 +287,19 @@ class Repository:
|
|||
id = bin_to_hex(id)
|
||||
super().__init__(id, repo)
|
||||
|
||||
class PackNotFound(ErrorWithTraceback):
|
||||
"""Object with key {} is indexed to pack {}, but that whole pack is missing from repository {}."""
|
||||
|
||||
exit_mcode = 23
|
||||
|
||||
# a missing pack means the index is stale or more than one object was lost.
|
||||
def __init__(self, id, pack_id, repo):
|
||||
if isinstance(id, bytes):
|
||||
id = bin_to_hex(id)
|
||||
if isinstance(pack_id, bytes):
|
||||
pack_id = bin_to_hex(pack_id)
|
||||
super().__init__(id, pack_id, repo)
|
||||
|
||||
class ParentPathDoesNotExist(Error):
|
||||
"""The parent path of the repository directory [{}] does not exist."""
|
||||
|
||||
|
|
@ -836,7 +849,7 @@ class Repository:
|
|||
reader = self._cached_pack_reader(entry.pack_id)
|
||||
except StoreObjectNotFound:
|
||||
if raise_missing:
|
||||
raise self.ObjectNotFound(id_, str(self._location)) from None
|
||||
raise self.PackNotFound(id_, entry.pack_id, str(self._location)) from None
|
||||
yield None
|
||||
else:
|
||||
yield reader.read(entry.obj_offset, entry.obj_size)
|
||||
|
|
|
|||
|
|
@ -253,6 +253,25 @@ def test_get_many_missing_id_yields_none(repo_fixtures, request):
|
|||
assert result[2] == repository.get(H(2))
|
||||
|
||||
|
||||
def test_get_many_missing_pack_raises_pack_not_found(repo_fixtures, request):
|
||||
# get_many raises PackNotFound when a chunk's index entry points to a pack that is not in the
|
||||
# store; with raise_missing=False it yields None instead.
|
||||
objects = [(H(i), fchunk(b"payload-%02d" % i, chunk_id=H(i))) for i in range(2)]
|
||||
with get_repository_from_fixture(repo_fixtures, request) as repository:
|
||||
repository._pack_writer.max_count = 2 # one pack: {H0, H1}
|
||||
for chunk_id, chunk in objects:
|
||||
repository.put(chunk_id, chunk)
|
||||
repository.flush()
|
||||
pack_id = repository.chunks[H(0)].pack_id
|
||||
repository.store_delete("packs/" + bin_to_hex(pack_id)) # delete the pack, keep its index entry
|
||||
|
||||
with pytest.raises(Repository.PackNotFound):
|
||||
list(repository.get_many([H(0)]))
|
||||
with pytest.raises(Repository.PackNotFound):
|
||||
list(repository.get_many([H(0), H(1)])) # one id's pack missing in a batch
|
||||
assert list(repository.get_many([H(0)], raise_missing=False)) == [None] # raise_missing=False -> None
|
||||
|
||||
|
||||
def test_get_many_repeated_ids(repo_fixtures, request):
|
||||
# A dedup'd item repeats chunk ids, e.g. [A, A, B, C, B]. Each repeat returns the right bytes
|
||||
# and each pack is loaded once: the cached pack serves the later visits.
|
||||
|
|
|
|||
Loading…
Reference in a new issue