Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/libgit2.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Straub <bs@github.com>2012-09-14 01:02:46 +0400
committerBen Straub <bs@github.com>2012-09-19 15:41:24 +0400
commit5bb0dc9390edf9f056cd67c12c258b10d0648871 (patch)
tree2dc8b38a98f66aff909d943ea73fdc05be60e828 /src/odb_pack.c
parent411cb017c21e0490ed1c6438c7d5fa1b4ee9f63f (diff)
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.c36
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);
}