summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backends/sqlite.c2
-rw-r--r--src/git2.h4
-rw-r--r--src/git2/odb.h19
-rw-r--r--src/git2/odb_backend.h2
-rw-r--r--src/odb.c82
-rw-r--r--src/odb_loose.c2
-rw-r--r--src/odb_pack.c2
-rw-r--r--tests/t11-sqlite.c2
-rw-r--r--tests/t12-repo.c100
-rw-r--r--tests/test_main.c2
10 files changed, 187 insertions, 30 deletions
diff --git a/src/backends/sqlite.c b/src/backends/sqlite.c
index ad5b679f9..b4c941a59 100644
--- a/src/backends/sqlite.c
+++ b/src/backends/sqlite.c
@@ -264,8 +264,6 @@ int git_odb_backend_sqlite(git_odb_backend **backend_out, const char *sqlite_db)
backend->parent.exists = &sqlite_backend__exists;
backend->parent.free = &sqlite_backend__free;
- backend->parent.priority = 0;
-
*backend_out = (git_odb_backend *)backend;
return GIT_SUCCESS;
diff --git a/src/git2.h b/src/git2.h
index 70ab811f1..e6042d050 100644
--- a/src/git2.h
+++ b/src/git2.h
@@ -26,9 +26,9 @@
#ifndef INCLUDE_git_git_h__
#define INCLUDE_git_git_h__
-#define LIBGIT2_VERSION "0.3.0"
+#define LIBGIT2_VERSION "0.4.0"
#define LIBGIT2_VER_MAJOR 0
-#define LIBGIT2_VER_MINOR 3
+#define LIBGIT2_VER_MINOR 4
#define LIBGIT2_VER_REVISION 0
#include "git2/common.h"
diff --git a/src/git2/odb.h b/src/git2/odb.h
index 2f2741135..0d285897c 100644
--- a/src/git2/odb.h
+++ b/src/git2/odb.h
@@ -79,7 +79,24 @@ GIT_EXTERN(int) git_odb_open(git_odb **out, const char *objects_dir);
* @paramm backend pointer to a git_odb_backend instance
* @return 0 on sucess; error code otherwise
*/
-GIT_EXTERN(int) git_odb_add_backend(git_odb *odb, git_odb_backend *backend);
+GIT_EXTERN(int) git_odb_add_backend(git_odb *odb, git_odb_backend *backend, int priority);
+
+/**
+ * Add a custom backend to an existing Object DB; this
+ * backend will work as an alternate.
+ *
+ * Alternate backends are always checked for objects *after*
+ * all the main backends have been exhausted.
+ *
+ * Writing is disabled on alternate backends.
+ *
+ * Read <odb_backends.h> for more information.
+ *
+ * @param odb database to add the backend to
+ * @paramm backend pointer to a git_odb_backend instance
+ * @return 0 on sucess; error code otherwise
+ */
+GIT_EXTERN(int) git_odb_add_alternate(git_odb *odb, git_odb_backend *backend, int priority);
/**
* Close an open object database.
diff --git a/src/git2/odb_backend.h b/src/git2/odb_backend.h
index ee7e5dfde..9cdd358ee 100644
--- a/src/git2/odb_backend.h
+++ b/src/git2/odb_backend.h
@@ -42,8 +42,6 @@ GIT_BEGIN_DECL
struct git_odb_backend {
git_odb *odb;
- int priority;
-
int (* read)(
git_rawobj *,
struct git_odb_backend *,
diff --git a/src/odb.c b/src/odb.c
index b5996c826..4e54c749a 100644
--- a/src/odb.c
+++ b/src/odb.c
@@ -35,6 +35,17 @@
#define GIT_ALTERNATES_FILE "info/alternates"
+/* TODO: is this correct? */
+#define GIT_LOOSE_PRIORITY 2
+#define GIT_PACKED_PRIORITY 1
+
+typedef struct
+{
+ git_odb_backend *backend;
+ int priority;
+ int is_alternate;
+} backend_internal;
+
static int format_object_header(char *hdr, size_t n, git_rawobj *obj)
{
const char *type_str = git_object_type2string(obj->type);
@@ -136,10 +147,13 @@ int git_odb__inflate_buffer(void *in, size_t inlen, void *out, size_t outlen)
int backend_sort_cmp(const void *a, const void *b)
{
- const git_odb_backend *backend_a = *(const git_odb_backend **)(a);
- const git_odb_backend *backend_b = *(const git_odb_backend **)(b);
+ const backend_internal *backend_a = *(const backend_internal **)(a);
+ const backend_internal *backend_b = *(const backend_internal **)(b);
+
+ if (backend_a->is_alternate == backend_b->is_alternate)
+ return (backend_b->priority - backend_a->priority);
- return (backend_b->priority - backend_a->priority);
+ return backend_a->is_alternate ? 1 : -1;
}
int git_odb_new(git_odb **out)
@@ -157,23 +171,44 @@ int git_odb_new(git_odb **out)
return GIT_SUCCESS;
}
-int git_odb_add_backend(git_odb *odb, git_odb_backend *backend)
+static int add_backend_internal(git_odb *odb, git_odb_backend *backend, int priority, int is_alternate)
{
+ backend_internal *internal;
+
assert(odb && backend);
if (backend->odb != NULL && backend->odb != odb)
return GIT_EBUSY;
- backend->odb = odb;
+ internal = git__malloc(sizeof(backend_internal));
+ if (internal == NULL)
+ return GIT_ENOMEM;
+
+ internal->backend = backend;
+ internal->priority = priority;
+ internal->is_alternate = is_alternate;
- if (git_vector_insert(&odb->backends, backend) < 0)
+ if (git_vector_insert(&odb->backends, internal) < 0) {
+ free(internal);
return GIT_ENOMEM;
+ }
git_vector_sort(&odb->backends);
+ internal->backend->odb = odb;
return GIT_SUCCESS;
}
-static int add_default_backends(git_odb *db, const char *objects_dir)
+int git_odb_add_backend(git_odb *odb, git_odb_backend *backend, int priority)
+{
+ return add_backend_internal(odb, backend, priority, 0);
+}
+
+int git_odb_add_alternate(git_odb *odb, git_odb_backend *backend, int priority)
+{
+ return add_backend_internal(odb, backend, priority, 1);
+}
+
+static int add_default_backends(git_odb *db, const char *objects_dir, int as_alternates)
{
git_odb_backend *loose, *packed;
int error;
@@ -183,7 +218,7 @@ static int add_default_backends(git_odb *db, const char *objects_dir)
if (error < GIT_SUCCESS)
return error;
- error = git_odb_add_backend(db, loose);
+ error = add_backend_internal(db, loose, GIT_LOOSE_PRIORITY, as_alternates);
if (error < GIT_SUCCESS)
return error;
@@ -192,7 +227,7 @@ static int add_default_backends(git_odb *db, const char *objects_dir)
if (error < GIT_SUCCESS)
return error;
- error = git_odb_add_backend(db, packed);
+ error = add_backend_internal(db, packed, GIT_PACKED_PRIORITY, as_alternates);
if (error < GIT_SUCCESS)
return error;
@@ -221,7 +256,7 @@ static int load_alternates(git_odb *odb, const char *objects_dir)
/* add each alternate as a new backend; one alternate per line */
while ((error == GIT_SUCCESS) && (buffer = git__strtok(alternate, buffer, "\r\n")) != NULL)
- error = add_default_backends(odb, alternate);
+ error = add_default_backends(odb, alternate, 1);
gitfo_free_buf(&alternates_buf);
return error;
@@ -239,7 +274,7 @@ int git_odb_open(git_odb **out, const char *objects_dir)
if ((error = git_odb_new(&db)) < 0)
return error;
- if ((error = add_default_backends(db, objects_dir)) < GIT_SUCCESS)
+ if ((error = add_default_backends(db, objects_dir, 0)) < GIT_SUCCESS)
goto cleanup;
if ((error = load_alternates(db, objects_dir)) < GIT_SUCCESS)
@@ -261,10 +296,13 @@ void git_odb_close(git_odb *db)
return;
for (i = 0; i < db->backends.length; ++i) {
- git_odb_backend *b = git_vector_get(&db->backends, i);
+ backend_internal *internal = git_vector_get(&db->backends, i);
+ git_odb_backend *backend = internal->backend;
- if (b->free) b->free(b);
- else free(b);
+ if (backend->free) backend->free(backend);
+ else free(backend);
+
+ free(internal);
}
git_vector_free(&db->backends);
@@ -279,7 +317,8 @@ int git_odb_exists(git_odb *db, const git_oid *id)
assert(db && id);
for (i = 0; i < db->backends.length && !found; ++i) {
- git_odb_backend *b = git_vector_get(&db->backends, i);
+ backend_internal *internal = git_vector_get(&db->backends, i);
+ git_odb_backend *b = internal->backend;
if (b->exists != NULL)
found = b->exists(b, id);
@@ -296,7 +335,8 @@ int git_odb_read_header(git_rawobj *out, git_odb *db, const git_oid *id)
assert(out && db && id);
for (i = 0; i < db->backends.length && error < 0; ++i) {
- git_odb_backend *b = git_vector_get(&db->backends, i);
+ backend_internal *internal = git_vector_get(&db->backends, i);
+ git_odb_backend *b = internal->backend;
if (b->read_header != NULL)
error = b->read_header(out, b, id);
@@ -322,7 +362,8 @@ int git_odb_read(git_rawobj *out, git_odb *db, const git_oid *id)
assert(out && db && id);
for (i = 0; i < db->backends.length && error < 0; ++i) {
- git_odb_backend *b = git_vector_get(&db->backends, i);
+ backend_internal *internal = git_vector_get(&db->backends, i);
+ git_odb_backend *b = internal->backend;
if (b->read != NULL)
error = b->read(out, b, id);
@@ -339,7 +380,12 @@ int git_odb_write(git_oid *id, git_odb *db, git_rawobj *obj)
assert(obj && db && id);
for (i = 0; i < db->backends.length && error < 0; ++i) {
- git_odb_backend *b = git_vector_get(&db->backends, i);
+ backend_internal *internal = git_vector_get(&db->backends, i);
+ git_odb_backend *b = internal->backend;
+
+ /* we don't write in alternates! */
+ if (internal->is_alternate)
+ continue;
if (b->write != NULL)
error = b->write(id, b, obj);
diff --git a/src/odb_loose.c b/src/odb_loose.c
index f89eb71ff..735d9394f 100644
--- a/src/odb_loose.c
+++ b/src/odb_loose.c
@@ -653,8 +653,6 @@ int git_odb_backend_loose(git_odb_backend **backend_out, const char *objects_dir
backend->parent.exists = &loose_backend__exists;
backend->parent.free = &loose_backend__free;
- backend->parent.priority = 2; /* higher than packfiles */
-
*backend_out = (git_odb_backend *)backend;
return GIT_SUCCESS;
}
diff --git a/src/odb_pack.c b/src/odb_pack.c
index 6141c57ef..664b00139 100644
--- a/src/odb_pack.c
+++ b/src/odb_pack.c
@@ -1203,8 +1203,6 @@ int git_odb_backend_pack(git_odb_backend **backend_out, const char *objects_dir)
backend->parent.exists = &pack_backend__exists;
backend->parent.free = &pack_backend__free;
- backend->parent.priority = 1;
-
*backend_out = (git_odb_backend *)backend;
return GIT_SUCCESS;
}
diff --git a/tests/t11-sqlite.c b/tests/t11-sqlite.c
index bc75f5668..9b8cc6bf8 100644
--- a/tests/t11-sqlite.c
+++ b/tests/t11-sqlite.c
@@ -51,7 +51,7 @@ static git_odb *open_sqlite_odb(void)
if (git_odb_backend_sqlite(&sqlite, ":memory") < GIT_SUCCESS)
return NULL;
- if (git_odb_add_backend(odb, sqlite) < GIT_SUCCESS)
+ if (git_odb_add_backend(odb, sqlite, 0) < GIT_SUCCESS)
return NULL;
return odb;
diff --git a/tests/t12-repo.c b/tests/t12-repo.c
new file mode 100644
index 000000000..2916f3c86
--- /dev/null
+++ b/tests/t12-repo.c
@@ -0,0 +1,100 @@
+/*
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2,
+ * as published by the Free Software Foundation.
+ *
+ * In addition to the permissions in the GNU General Public License,
+ * the authors give you unlimited permission to link the compiled
+ * version of this file into combinations with other programs,
+ * and to distribute those combinations without any restriction
+ * coming from the use of this file. (The General Public License
+ * restrictions do apply in other respects; for example, they cover
+ * modification of the file, and distribution when not linked into
+ * a combined executable.)
+ *
+ * This file is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#include "test_lib.h"
+#include "test_helpers.h"
+
+#include "odb.h"
+#include "git2/odb_backend.h"
+
+typedef struct {
+ git_odb_backend base;
+ int position;
+} fake_backend;
+
+git_odb_backend *new_backend(int position)
+{
+ fake_backend *b;
+
+ b = git__malloc(sizeof(fake_backend));
+ if (b == NULL)
+ return NULL;
+
+ memset(b, 0x0, sizeof(fake_backend));
+ b->position = position;
+ return (git_odb_backend *)b;
+}
+
+int test_backend_sorting(git_odb *odb)
+{
+ unsigned int i;
+
+ for (i = 0; i < odb->backends.length; ++i) {
+ fake_backend *internal = *((fake_backend **)git_vector_get(&odb->backends, i));
+
+ if (internal == NULL)
+ return GIT_ERROR;
+
+ if (internal->position != (int)i)
+ return GIT_ERROR;
+ }
+
+ return GIT_SUCCESS;
+}
+
+BEGIN_TEST("odb", backend_sorting)
+ git_odb *odb;
+ must_pass(git_odb_new(&odb));
+ must_pass(git_odb_add_backend(odb, new_backend(0), 5));
+ must_pass(git_odb_add_backend(odb, new_backend(2), 3));
+ must_pass(git_odb_add_backend(odb, new_backend(1), 4));
+ must_pass(git_odb_add_backend(odb, new_backend(3), 1));
+ must_pass(test_backend_sorting(odb));
+ git_odb_close(odb);
+END_TEST
+
+BEGIN_TEST("odb", backend_alternates_sorting)
+ git_odb *odb;
+ must_pass(git_odb_new(&odb));
+ must_pass(git_odb_add_backend(odb, new_backend(0), 5));
+ must_pass(git_odb_add_backend(odb, new_backend(2), 3));
+ must_pass(git_odb_add_backend(odb, new_backend(1), 4));
+ must_pass(git_odb_add_backend(odb, new_backend(3), 1));
+ must_pass(git_odb_add_alternate(odb, new_backend(4), 5));
+ must_pass(git_odb_add_alternate(odb, new_backend(6), 3));
+ must_pass(git_odb_add_alternate(odb, new_backend(5), 4));
+ must_pass(git_odb_add_alternate(odb, new_backend(7), 1));
+ must_pass(test_backend_sorting(odb));
+ git_odb_close(odb);
+END_TEST
+
+git_testsuite *libgit2_suite_repository(void)
+{
+ git_testsuite *suite = git_testsuite_new("Repository");
+
+ ADD_TEST(suite, "odb", backend_sorting);
+ ADD_TEST(suite, "odb", backend_alternates_sorting);
+
+ return suite;
+}
diff --git a/tests/test_main.c b/tests/test_main.c
index 191cd39a4..01e7d5123 100644
--- a/tests/test_main.c
+++ b/tests/test_main.c
@@ -41,6 +41,7 @@ extern git_testsuite *libgit2_suite_tag(void);
extern git_testsuite *libgit2_suite_tree(void);
extern git_testsuite *libgit2_suite_refs(void);
extern git_testsuite *libgit2_suite_sqlite(void);
+extern git_testsuite *libgit2_suite_repository(void);
typedef git_testsuite *(*libgit2_suite)(void);
@@ -57,6 +58,7 @@ static libgit2_suite suite_methods[]= {
libgit2_suite_tree,
libgit2_suite_refs,
libgit2_suite_sqlite,
+ libgit2_suite_repository,
};
#define GIT_SUITE_COUNT (ARRAY_SIZE(suite_methods))