Commit 5bb0dc93 by Ben Straub

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.
parent 411cb017
......@@ -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);
}
......
......@@ -5,7 +5,7 @@
#define DO_LOCAL_TEST 0
#define DO_LIVE_NETWORK_TESTS 0
#define LIVE_REPO_URL "http://github.com/libgit2/node-gitteh"
#define LIVE_REPO_URL "git://github.com/nulltoken/TestGitRepository"
static git_repository *g_repo;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment