diff options
author | Lars Wirzenius <liw@liw.fi> | 2013-08-03 21:21:31 +0100 |
---|---|---|
committer | Lars Wirzenius <liw@liw.fi> | 2013-08-03 21:21:31 +0100 |
commit | 85b29665dbca3e865161c95e4e3c16db2b9038d2 (patch) | |
tree | 07fbb7a50069257e8eb94636de830db3fb5c96d2 /larch | |
parent | e47a3c3cfea4dd44a7d9025aeff60f0712adaa72 (diff) | |
download | larch-85b29665dbca3e865161c95e4e3c16db2b9038d2.tar.gz |
Bugfix: Use uncomitted journal when read-only
What used to happen:
* Instance 1 would crash in the middle of committing a journal.
* Instance 2 would open the B-tree in read-only mode, and not
read files from the journal. It would then crash, because the
partly modified B-tree made no sense.
What happens now:
* When a B-tree is opened in read-only mode, and the journal
is partly comitted, the journal is checked in preference
for files in the B-tree proper. No confusion anymore.
Diffstat (limited to 'larch')
-rw-r--r-- | larch/journal.py | 45 |
1 files changed, 28 insertions, 17 deletions
diff --git a/larch/journal.py b/larch/journal.py index 36b38a5..c83fc82 100644 --- a/larch/journal.py +++ b/larch/journal.py @@ -82,15 +82,19 @@ class Journal(object): self.flag_file = os.path.join(self.storedir, self.flag_basename) self.new_flag = os.path.join(self.newdir, self.flag_basename) + self.new_flag_seen = self.fs.exists(self.new_flag) + tracing.trace('self.new_flag_seen: %s' % self.new_flag_seen) if self.allow_writes: - if self.fs.exists(self.new_flag): + if self.new_flag_seen: logging.debug('Automatically committing remaining changes') self.commit() else: logging.debug('Automatically rolling back remaining changes') self.rollback() - self.new_files = set() - self.deleted_files = set() + else: + logging.debug('Not committing/rolling back since read-only') + self.new_files = set() + self.deleted_files = set() def _require_rw(self): '''Raise error if modifications are not allowed.''' @@ -114,14 +118,20 @@ class Journal(object): '''Return real name for a file in a journal temporary directory.''' assert filename.startswith(journaldir) return os.path.join(self.storedir, filename[len(journaldir):]) - + + def _is_in_new(self, filename): + new = self._new(filename) + return new in self.new_files or self.fs.exists(new) + + def _is_in_deleted(self, filename): + deleted = self._deleted(filename) + return deleted in self.deleted_files or self.fs.exists(deleted) + def exists(self, filename): - if self.allow_writes: - new = self._new(filename) - deleted = self._deleted(filename) - if new in self.new_files: + if self.allow_writes or self.new_flag_seen: + if self._is_in_new(filename): return True - elif deleted in self.deleted_files: + elif self._is_in_deleted(filename): return False return self.fs.exists(filename) @@ -140,16 +150,17 @@ class Journal(object): self.new_files.add(new) def cat(self, filename): - if self.allow_writes: - new = self._new(filename) - deleted = self._deleted(filename) - if new in self.new_files: - return self.fs.cat(new) - elif deleted in self.deleted_files: + tracing.trace('filename=%s' % filename) + tracing.trace('allow_writes=%s' % self.allow_writes) + tracing.trace('new_flag_seen=%s' % self.new_flag_seen) + if self.allow_writes or self.new_flag_seen: + if self._is_in_new(filename): + return self.fs.cat(self._new(filename)) + elif self._is_in_deleted(filename): raise OSError( errno.ENOENT, os.strerror(errno.ENOENT), filename) return self.fs.cat(filename) - + def remove(self, filename): tracing.trace(filename) self._require_rw() @@ -176,7 +187,7 @@ class Journal(object): assert not dirname.startswith(self.newdir) assert not dirname.startswith(self.deletedir) - if self.allow_writes: + if self.allow_writes or self.new_flag_seen: if self.fs.exists(dirname): for x in self.climb(dirname, files_only=True): if self.exists(x): |