summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEdward Thomson <ethomson@github.com>2016-07-14 16:23:24 -0400
committerEdward Thomson <ethomson@github.com>2016-08-04 15:12:04 -0400
commit8f09a98e1809dcdfd9d25b8268657bac4d942e6a (patch)
tree25f4b977d9a9055569d95a5ba5b038dfbfb01d6a /src
parentd2794b0e37e98206b991ba4c8639ddf53c03bdb9 (diff)
downloadlibgit2-8f09a98e1809dcdfd9d25b8268657bac4d942e6a.tar.gz
odb: freshen existing objects when writing
When writing an object, we calculate its OID and see if it exists in the object database. If it does, we need to freshen the file that contains it.
Diffstat (limited to 'src')
-rw-r--r--src/fileops.c16
-rw-r--r--src/fileops.h5
-rw-r--r--src/odb.c47
-rw-r--r--src/odb_loose.c18
-rw-r--r--src/odb_pack.c13
5 files changed, 96 insertions, 3 deletions
diff --git a/src/fileops.c b/src/fileops.c
index 22868b489..ce64934ea 100644
--- a/src/fileops.c
+++ b/src/fileops.c
@@ -837,6 +837,22 @@ int git_futils_cp(const char *from, const char *to, mode_t filemode)
return cp_by_fd(ifd, ofd, true);
}
+int git_futils_touch(const char *path)
+{
+ struct p_timeval times[2];
+ time_t now = time(NULL);
+ int ret;
+
+ times[0].tv_sec = now;
+ times[0].tv_usec = 0;
+ times[1].tv_sec = now;
+ times[1].tv_usec = 0;
+
+ ret = p_utimes(path, times);
+
+ return (ret < 0) ? git_path_set_error(errno, path, "touch") : 0;
+}
+
static int cp_link(const char *from, const char *to, size_t link_size)
{
int error = 0;
diff --git a/src/fileops.h b/src/fileops.h
index 6c6c49dcf..e055400be 100644
--- a/src/fileops.h
+++ b/src/fileops.h
@@ -185,6 +185,11 @@ extern int git_futils_cp(
mode_t filemode);
/**
+ * Set the files atime and mtime to the current time.
+ */
+extern int git_futils_touch(const char *path);
+
+/**
* Flags that can be passed to `git_futils_cp_r`.
*
* - GIT_CPDIR_CREATE_EMPTY_DIRS: create directories even if there are no
diff --git a/src/odb.c b/src/odb.c
index 02391c4ac..253023ce1 100644
--- a/src/odb.c
+++ b/src/odb.c
@@ -654,7 +654,10 @@ void git_odb_free(git_odb *db)
GIT_REFCOUNT_DEC(db, odb_free);
}
-static int odb_exists_1(git_odb *db, const git_oid *id, bool only_refreshed)
+static int odb_exists_1(
+ git_odb *db,
+ const git_oid *id,
+ bool only_refreshed)
{
size_t i;
bool found = false;
@@ -673,6 +676,44 @@ static int odb_exists_1(git_odb *db, const git_oid *id, bool only_refreshed)
return (int)found;
}
+static int odb_freshen_1(
+ git_odb *db,
+ const git_oid *id,
+ bool only_refreshed)
+{
+ size_t i;
+ bool found = false;
+
+ for (i = 0; i < db->backends.length && !found; ++i) {
+ backend_internal *internal = git_vector_get(&db->backends, i);
+ git_odb_backend *b = internal->backend;
+
+ if (only_refreshed && !b->refresh)
+ continue;
+
+ if (b->freshen != NULL)
+ found = !b->freshen(b, id);
+ else if (b->exists != NULL)
+ found = b->exists(b, id);
+ }
+
+ return (int)found;
+}
+
+static int odb_freshen(git_odb *db, const git_oid *id)
+{
+ assert(db && id);
+
+ if (odb_freshen_1(db, id, false))
+ return 1;
+
+ if (!git_odb_refresh(db))
+ return odb_freshen_1(db, id, true);
+
+ /* Failed to refresh, hence not found */
+ return 0;
+}
+
int git_odb_exists(git_odb *db, const git_oid *id)
{
git_odb_object *object;
@@ -1131,7 +1172,7 @@ int git_odb_write(
assert(oid && db);
git_odb_hash(oid, data, len, type);
- if (git_odb_exists(db, oid))
+ if (odb_freshen(db, oid))
return 0;
for (i = 0; i < db->backends.length && error < 0; ++i) {
@@ -1257,7 +1298,7 @@ int git_odb_stream_finalize_write(git_oid *out, git_odb_stream *stream)
git_hash_final(out, stream->hash_ctx);
- if (git_odb_exists(stream->backend->odb, out))
+ if (odb_freshen(stream->backend->odb, out))
return 0;
return stream->finalize_write(stream, out);
diff --git a/src/odb_loose.c b/src/odb_loose.c
index 228d4c334..1653e2783 100644
--- a/src/odb_loose.c
+++ b/src/odb_loose.c
@@ -918,6 +918,23 @@ cleanup:
return error;
}
+static int loose_backend__freshen(
+ git_odb_backend *_backend,
+ const git_oid *oid)
+{
+ loose_backend *backend = (loose_backend *)_backend;
+ git_buf path = GIT_BUF_INIT;
+ int error;
+
+ if (object_file_name(&path, backend, oid) < 0)
+ return -1;
+
+ error = git_futils_touch(path.ptr);
+ git_buf_free(&path);
+
+ return error;
+}
+
static void loose_backend__free(git_odb_backend *_backend)
{
loose_backend *backend;
@@ -975,6 +992,7 @@ int git_odb_backend_loose(
backend->parent.exists = &loose_backend__exists;
backend->parent.exists_prefix = &loose_backend__exists_prefix;
backend->parent.foreach = &loose_backend__foreach;
+ backend->parent.freshen = &loose_backend__freshen;
backend->parent.free = &loose_backend__free;
*backend_out = (git_odb_backend *)backend;
diff --git a/src/odb_pack.c b/src/odb_pack.c
index 005d07264..3b52b6be6 100644
--- a/src/odb_pack.c
+++ b/src/odb_pack.c
@@ -363,6 +363,18 @@ static int pack_backend__read_header(
return git_packfile_resolve_header(len_p, type_p, e.p, e.offset);
}
+static int pack_backend__freshen(
+ git_odb_backend *backend, const git_oid *oid)
+{
+ struct git_pack_entry e;
+ int error;
+
+ if ((error = pack_entry_find(&e, (struct pack_backend *)backend, oid)) < 0)
+ return error;
+
+ return git_futils_touch(e.p->pack_name);
+}
+
static int pack_backend__read(
void **buffer_p, size_t *len_p, git_otype *type_p,
git_odb_backend *backend, const git_oid *oid)
@@ -560,6 +572,7 @@ static int pack_backend__alloc(struct pack_backend **out, size_t initial_size)
backend->parent.refresh = &pack_backend__refresh;
backend->parent.foreach = &pack_backend__foreach;
backend->parent.writepack = &pack_backend__writepack;
+ backend->parent.freshen = &pack_backend__freshen;
backend->parent.free = &pack_backend__free;
*out = backend;