files cache: improve exception handling, fixes #3553

now deals with:
- corrupted files cache (truncated or modified not by borg)
- inaccessible/unreadable files cache
- missing files cache

The latter fix is not sufficient, the cache transaction processing
would still stumble over expected, but missing files in the cache.
This commit is contained in:
Thomas Waldmann 2018-01-20 06:36:54 +01:00
parent 3dd8d4097a
commit 423ec4ba1e
1 changed files with 26 additions and 19 deletions

View File

@ -502,25 +502,32 @@ class LocalCache(CacheStatsMixin):
self.files = {} self.files = {}
self._newest_cmtime = None self._newest_cmtime = None
logger.debug('Reading files cache ...') logger.debug('Reading files cache ...')
msg = None
with IntegrityCheckedFile(path=os.path.join(self.path, 'files'), write=False, try:
integrity_data=self.cache_config.integrity.get('files')) as fd: with IntegrityCheckedFile(path=os.path.join(self.path, 'files'), write=False,
u = msgpack.Unpacker(use_list=True) integrity_data=self.cache_config.integrity.get('files')) as fd:
while True: u = msgpack.Unpacker(use_list=True)
data = fd.read(64 * 1024) while True:
if not data: data = fd.read(64 * 1024)
break if not data:
u.feed(data) break
try: u.feed(data)
for path_hash, item in u: try:
entry = FileCacheEntry(*item) for path_hash, item in u:
# in the end, this takes about 240 Bytes per file entry = FileCacheEntry(*item)
self.files[path_hash] = msgpack.packb(entry._replace(age=entry.age + 1)) # in the end, this takes about 240 Bytes per file
except (TypeError, ValueError) as exc: self.files[path_hash] = msgpack.packb(entry._replace(age=entry.age + 1))
logger.warning('The files cache seems corrupt, ignoring it. ' except (TypeError, ValueError) as exc:
'Expect lower performance. [%s]' % str(exc)) msg = "The files cache seems invalid. [%s]" % str(exc)
self.files = {} break
return except OSError as exc:
msg = "The files cache can't be read. [%s]" % str(exc)
except FileIntegrityError as fie:
msg = "The files cache is corrupted. [%s]" % str(fie)
if msg is not None:
logger.warning(msg)
logger.warning('Continuing without files cache - expect lower performance.')
self.files = {}
def begin_txn(self): def begin_txn(self):
# Initialize transaction snapshot # Initialize transaction snapshot