Repository: borgbackup/borg

Issue:
Traceback after incomplete backup (due to crash) and break-lock
I had a server crash on Monday morning. 

The backup run on Monday evening failed with:

```
 borg create -v /backup/path::prefix-$date /path/to/backup
Failed to create/acquire the lock /home/$user/.cache/borg/f97b24025b7434b08b9f9fe342d8ad6f27ef32b6feb76580080afd74df5d54e6/lock.exclusive (timeout).
```

Hmm, not nice, let's break the lock then:

```
borg break-lock /backup/path
```

Now, I'm harvesting a traceback:

```
borg create -v --stats --compression lz4 /backup/path::prefix-$date /path/to/backup
Local Exception.
Traceback (most recent call last):
  File "/usr/lib64/python3.4/site-packages/borg/archiver.py", line 1609, in main
    exit_code = archiver.run(args)
  File "/usr/lib64/python3.4/site-packages/borg/archiver.py", line 1546, in run
    return args.func(args)
  File "/usr/lib64/python3.4/site-packages/borg/archiver.py", line 81, in wrapper
    return method(self, args, repository=repository, **kwargs)
  File "/usr/lib64/python3.4/site-packages/borg/archiver.py", line 242, in do_create
    with Cache(repository, key, manifest, do_files=args.cache_files, lock_wait=self.lock_wait) as cache:
  File "/usr/lib64/python3.4/site-packages/borg/cache.py", line 69, in __init__
    self.open(lock_wait=lock_wait)
  File "/usr/lib64/python3.4/site-packages/borg/cache.py", line 156, in open
    self.rollback()
  File "/usr/lib64/python3.4/site-packages/borg/cache.py", line 231, in rollback
    self._do_open()
  File "/usr/lib64/python3.4/site-packages/borg/cache.py", line 143, in _do_open
    raise Exception('%s does not look like a Borg cache.' % config_path) from None
Exception: /home/$user/.cache/borg/f97b24025b7434b08b9f9fe342d8ad6f27ef32b6feb76580080afd74df5d54e6/config does not look like a Borg cache.

Platform: Linux $hostname 4.2.5-12-default #1 SMP PREEMPT Wed Oct 28 17:49:15 UTC 2015 (0491388) x86_64 x86_64
Linux: openSUSE  13.2 x86_64
Borg: 1.0.6  Python: CPython 3.4.5
PID: 32161  CWD: /home/$user
sys.argv: ['/usr/bin/borg', 'create', '-v', '--stats', '--compression', 'lz4', '/backup/path::prefix-$date', '/path/to/backup']
SSH_ORIGINAL_COMMAND: None
```

Hmm, the config file in question is just empty.

While at it, this is the only cache dir with a non empty chunks.archive.d (127 MiB).
This is rather suspicious: why does borg store chunk data in users home dir?
$HOME might be nfs mounted (as in my case). I would expect borg to put the chunks somewhere in the backup hierarchy **only**, which is the only safe place, if **performance is a matter**.



Discussion:
If the entire server / machine / kernel crashed, then things like this (empty files etc) can happen (though it can't /shouldn't corrupt the repository itself)., although recently there was some work to avoid situations like that.

A `borg delete --cache-only /repository` fixes that (or you can manually delete `/home/$user/.cache/borg/f97b24025b7434b08b9f9fe342d8ad6f27ef32b6feb76580080afd74df5d54e6`, it has the same effect.

>  This is rather suspicious: why does borg store chunk data in users home dir?

It doesn't; the chunks.archive.d stores partial chunk caches (which don't cache chunks themselves, but metadata).

Thanks, @enkore, will clean up.

BTW, subsequent backup attempts after the traceback resulted (again) in:

```
borg create -v --stats --compression lz4 /backup/borg::prefix-$date
Failed to create/acquire the lock /home/$user/.cache/borg/f97b24025b7434b08b9f9fe342d8ad6f27ef32b6feb76580080afd74df5d54e6/lock.exclusive (timeout).
```

Borg should give up its locks even if an unhandled exception is thrown...

Ok, I have to look into that one. Might be that the lock isn't cleared correctly if the cache config is absent. Thanks for the report


Resolving patch:
diff --git a/borg/cache.py b/borg/cache.py
--- a/borg/cache.py
+++ b/borg/cache.py
@@ -137,9 +137,11 @@ def _do_open(self):
             cache_version = self.config.getint('cache', 'version')
             wanted_version = 1
             if cache_version != wanted_version:
+                self.close()
                 raise Exception('%s has unexpected cache version %d (wanted: %d).' % (
                     config_path, cache_version, wanted_version))
         except configparser.NoSectionError:
+            self.close()
             raise Exception('%s does not look like a Borg cache.' % config_path) from None
         self.id = self.config.get('cache', 'repository')
         self.manifest_id = unhexlify(self.config.get('cache', 'manifest'))


Test patch: