Browse Source

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.

(cherry picked from commit 423ec4ba1e5d4e3c79358e1cd90ff5aca0da06d1)
Thomas Waldmann 7 years ago
parent
commit
2493598eef
1 changed files with 26 additions and 19 deletions
  1. 26 19
      src/borg/cache.py

+ 26 - 19
src/borg/cache.py

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