diff options
author | Ben Straub <bs@github.com> | 2012-09-13 14:02:46 -0700 |
---|---|---|
committer | Ben Straub <bs@github.com> | 2012-09-19 04:41:24 -0700 |
commit | 5bb0dc9390edf9f056cd67c12c258b10d0648871 (patch) | |
tree | 2dc8b38a98f66aff909d943ea73fdc05be60e828 /src/odb_pack.c | |
parent | 411cb017c21e0490ed1c6438c7d5fa1b4ee9f63f (diff) | |
download | libgit2-5bb0dc9390edf9f056cd67c12c258b10d0648871.tar.gz |
ODB: re-load packfiles on failed lookup
The old method was avoiding re-loading of packfiles by watching the mtime of the
pack directory. This causes the ODB to become stale if the directory and packfile
are written within the same clock millisecond, as when cloning a fairly small
repo.
This method tries to find the object in the cached packs, and forces a refresh when
that fails. This will cause extra stat'ing on a miss, but speeds up the success
case and avoids this race condition.
Diffstat (limited to 'src/odb_pack.c')
-rw-r--r-- | src/odb_pack.c | 36 |
1 files changed, 28 insertions, 8 deletions
diff --git a/src/odb_pack.c b/src/odb_pack.c index b4f958b6f..5d3f0e6e5 100644 --- a/src/odb_pack.c +++ b/src/odb_pack.c @@ -233,10 +233,11 @@ static int packfile_load__cb(void *_data, git_buf *path) return git_vector_insert(&backend->packs, pack); } -static int packfile_refresh_all(struct pack_backend *backend) +static int packfile_refresh_all_maybe(struct pack_backend *backend, bool force) { int error; struct stat st; + git_buf path = GIT_BUF_INIT; if (backend->pack_folder == NULL) return 0; @@ -244,8 +245,7 @@ static int packfile_refresh_all(struct pack_backend *backend) if (p_stat(backend->pack_folder, &st) < 0 || !S_ISDIR(st.st_mode)) return git_odb__error_notfound("failed to refresh packfiles", NULL); - if (st.st_mtime != backend->pack_folder_mtime) { - git_buf path = GIT_BUF_INIT; + if (force || st.st_mtime != backend->pack_folder_mtime) { git_buf_sets(&path, backend->pack_folder); /* reload all packs */ @@ -263,9 +263,14 @@ static int packfile_refresh_all(struct pack_backend *backend) return 0; } -static int pack_entry_find(struct git_pack_entry *e, struct pack_backend *backend, const git_oid *oid) +static int packfile_refresh_all(struct pack_backend *backend) { + return packfile_refresh_all_maybe(backend, false); +} + +static int pack_entry_find_inner(struct git_pack_entry *e, + struct pack_backend *backend, + const git_oid *oid) { - int error; unsigned int i; struct git_pack_file *last_found = backend->last_found; @@ -273,9 +278,6 @@ static int pack_entry_find(struct git_pack_entry *e, struct pack_backend *backen git_pack_entry_find(e, last_found, oid, GIT_OID_HEXSZ) == 0) return 0; - if ((error = packfile_refresh_all(backend)) < 0) - return error; - for (i = 0; i < backend->packs.length; ++i) { struct git_pack_file *p; @@ -289,6 +291,24 @@ static int pack_entry_find(struct git_pack_entry *e, struct pack_backend *backen } } + return -1; +} + +static int pack_entry_find(struct git_pack_entry *e, struct pack_backend *backend, const git_oid *oid) +{ + int error; + + if (backend->last_found && + git_pack_entry_find(e, backend->last_found, oid, GIT_OID_HEXSZ) == 0) + return 0; + + if (!pack_entry_find_inner(e, backend, oid)) + return 0; + if ((error = packfile_refresh_all_maybe(backend, true)) < 0) + return error; + if (!pack_entry_find_inner(e, backend, oid)) + return 0; + return git_odb__error_notfound("failed to find pack entry", oid); } |