From: Rob Browning Date: Fri, 6 Jul 2018 17:01:55 +0000 (-0500) Subject: vfs: include unique repo id in resolution cache key X-Git-Tag: 0.30~61 X-Git-Url: https://arthur.barton.de/gitweb/?p=bup.git;a=commitdiff_plain;h=2f9115072c11c39f9b66a4cb57478cfbce4b0d06 vfs: include unique repo id in resolution cache key ...since resolve() currently requires a full parent path and the root refs are only applicable to a particular repository. Use differing integers to identify repositories that may be independent (with respect to refs, tags, etc.), and use (typically small) integers rather than the repo path/address so that they'll be short if we want to embed them directly in cache keys later. Use realpath() for local repositories in order to detect when the same repository is reachable by multiple paths. (Something similar could eventually be done for remotes.) Signed-off-by: Rob Browning Tested-by: Rob Browning --- diff --git a/lib/bup/repo.py b/lib/bup/repo.py index 97547d5..cc8a3fd 100644 --- a/lib/bup/repo.py +++ b/lib/bup/repo.py @@ -1,15 +1,29 @@ from __future__ import absolute_import +from os.path import realpath from functools import partial from bup import client, git +_next_repo_id = 0 +_repo_ids = {} + +def _repo_id(key): + global _next_repo_id, _repo_ids + repo_id = _repo_ids.get(key) + if repo_id: + return repo_id + next_id = _next_repo_id = _next_repo_id + 1 + _repo_ids[key] = next_id + return next_id + class LocalRepo: def __init__(self, repo_dir=None): - self.repo_dir = repo_dir or git.repo() + self.repo_dir = realpath(repo_dir or git.repo()) self._cp = git.cp(self.repo_dir) self.rev_list = partial(git.rev_list, repo_dir=self.repo_dir) + self._id = _repo_id(self.repo_dir) def close(self): pass @@ -23,6 +37,12 @@ class LocalRepo: def __exit__(self, type, value, traceback): self.close() + def id(self): + """Return an identifier that differs from any other repository that + doesn't share the same repository-specific information + (e.g. refs, tags, etc.).""" + return self._id + def cat(self, ref): """If ref does not exist, yield (None, None, None). Otherwise yield (oidx, type, size), and then all of the data associated with @@ -52,6 +72,7 @@ class RemoteRepo: self.address = address self.client = client.Client(address) self.rev_list = self.client.rev_list + self._id = _repo_id(self.address) def close(self): if self.client: @@ -67,6 +88,12 @@ class RemoteRepo: def __exit__(self, type, value, traceback): self.close() + def id(self): + """Return an identifier that differs from any other repository that + doesn't share the same repository-specific information + (e.g. refs, tags, etc.).""" + return self._id + def cat(self, ref): """If ref does not exist, yield (None, None, None). Otherwise yield (oidx, type, size), and then all of the data associated with diff --git a/lib/bup/vfs.py b/lib/bup/vfs.py index 7ad33e4..e0aeb6f 100644 --- a/lib/bup/vfs.py +++ b/lib/bup/vfs.py @@ -253,7 +253,7 @@ def clear_cache(): def is_valid_cache_key(x): """Return logically true if x looks like it could be a valid cache key (with respect to structure). Current valid cache entries: - (path, parent, want_meta, dref) -> resolution + (repo-id, path, parent, want_meta, dref) -> resolution commit_oid -> commit commit_oid + ':r' -> rev-list i.e. rev-list -> {'.', commit, '2012...', next_commit, ...} @@ -261,7 +261,7 @@ def is_valid_cache_key(x): # Suspect we may eventually add "(container_oid, name) -> ...", and others. x_t = type(x) if x_t is tuple: - return len(x) == 4 + return len(x) == 5 if x_t is bytes: if len(x) == 20: return True @@ -759,7 +759,7 @@ def contents(repo, item, names=None, want_meta=True): yield x def _resolve_path(repo, path, parent=None, want_meta=True, deref=False): - cache_key = (tuple(path), parent, not not want_meta, not not deref) + cache_key = (repo.id(), tuple(path), parent, bool(want_meta), bool(deref)) resolution = cache_get(cache_key) if resolution: return resolution