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:
Diffstat (limited to 'src/odb_pack.c')
-rw-r--r--src/odb_pack.c306
1 files changed, 219 insertions, 87 deletions
diff --git a/src/odb_pack.c b/src/odb_pack.c
index 458f288d9..7240a4ac7 100644
--- a/src/odb_pack.c
+++ b/src/odb_pack.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009-2012 the libgit2 contributors
+ * Copyright (C) the libgit2 contributors. All rights reserved.
*
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
@@ -24,7 +24,11 @@ struct pack_backend {
git_vector packs;
struct git_pack_file *last_found;
char *pack_folder;
- time_t pack_folder_mtime;
+};
+
+struct pack_writepack {
+ struct git_odb_writepack parent;
+ git_indexer_stream *indexer_stream;
};
/**
@@ -128,13 +132,9 @@ struct pack_backend {
*
***********************************************************/
-static void pack_window_free_all(struct pack_backend *backend, struct git_pack_file *p);
-static int pack_window_contains(git_mwindow *win, off_t offset);
-
static int packfile_sort__cb(const void *a_, const void *b_);
static int packfile_load__cb(void *_data, git_buf *path);
-static int packfile_refresh_all(struct pack_backend *backend);
static int pack_entry_find(struct git_pack_entry *e,
struct pack_backend *backend, const git_oid *oid);
@@ -149,7 +149,7 @@ static int pack_entry_find_prefix(
struct git_pack_entry *e,
struct pack_backend *backend,
const git_oid *short_oid,
- unsigned int len);
+ size_t len);
@@ -159,23 +159,6 @@ static int pack_entry_find_prefix(
*
***********************************************************/
-GIT_INLINE(void) pack_window_free_all(struct pack_backend *backend, struct git_pack_file *p)
-{
- GIT_UNUSED(backend);
- git_mwindow_free_all(&p->mwf);
-}
-
-GIT_INLINE(int) pack_window_contains(git_mwindow *win, off_t offset)
-{
- /* We must promise at least 20 bytes (one hash) after the
- * offset is available from this window, otherwise the offset
- * is not actually in this window and a different window (which
- * has that one hash excess) must be used. This is to support
- * the object header and delta base parsing routines below.
- */
- return git_mwindow_contains(win, offset + 20);
-}
-
static int packfile_sort__cb(const void *a_, const void *b_)
{
const struct git_pack_file *a = a_;
@@ -212,7 +195,7 @@ static int packfile_load__cb(void *_data, git_buf *path)
struct pack_backend *backend = (struct pack_backend *)_data;
struct git_pack_file *pack;
int error;
- unsigned int i;
+ size_t i;
if (git__suffixcmp(path->ptr, ".idx") != 0)
return 0; /* not an index */
@@ -233,79 +216,61 @@ 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 pack_entry_find_inner(
+ struct git_pack_entry *e,
+ struct pack_backend *backend,
+ const git_oid *oid,
+ struct git_pack_file *last_found)
{
- int error;
- struct stat st;
+ size_t i;
- if (backend->pack_folder == NULL)
+ if (last_found &&
+ git_pack_entry_find(e, last_found, oid, GIT_OID_HEXSZ) == 0)
return 0;
- 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;
- git_buf_sets(&path, backend->pack_folder);
-
- /* reload all packs */
- error = git_path_direach(&path, packfile_load__cb, (void *)backend);
-
- git_buf_free(&path);
+ for (i = 0; i < backend->packs.length; ++i) {
+ struct git_pack_file *p;
- if (error < 0)
- return error;
+ p = git_vector_get(&backend->packs, i);
+ if (p == last_found)
+ continue;
- git_vector_sort(&backend->packs);
- backend->pack_folder_mtime = st.st_mtime;
+ if (git_pack_entry_find(e, p, oid, GIT_OID_HEXSZ) == 0) {
+ backend->last_found = p;
+ return 0;
+ }
}
- return 0;
+ return -1;
}
static int pack_entry_find(struct git_pack_entry *e, struct pack_backend *backend, const git_oid *oid)
{
- int error;
- unsigned int i;
-
- if ((error = packfile_refresh_all(backend)) < 0)
- return error;
+ struct git_pack_file *last_found = backend->last_found;
if (backend->last_found &&
git_pack_entry_find(e, backend->last_found, oid, GIT_OID_HEXSZ) == 0)
return 0;
- for (i = 0; i < backend->packs.length; ++i) {
- struct git_pack_file *p;
-
- p = git_vector_get(&backend->packs, i);
- if (p == backend->last_found)
- continue;
-
- if (git_pack_entry_find(e, p, oid, GIT_OID_HEXSZ) == 0) {
- backend->last_found = p;
- return 0;
- }
- }
+ if (!pack_entry_find_inner(e, backend, oid, last_found))
+ return 0;
return git_odb__error_notfound("failed to find pack entry", oid);
}
-static int pack_entry_find_prefix(
- struct git_pack_entry *e,
- struct pack_backend *backend,
- const git_oid *short_oid,
- unsigned int len)
+static unsigned pack_entry_find_prefix_inner(
+ struct git_pack_entry *e,
+ struct pack_backend *backend,
+ const git_oid *short_oid,
+ size_t len,
+ struct git_pack_file *last_found)
{
int error;
- unsigned int i;
+ size_t i;
unsigned found = 0;
- if ((error = packfile_refresh_all(backend)) < 0)
- return error;
-
- if (backend->last_found) {
- error = git_pack_entry_find(e, backend->last_found, short_oid, len);
+ if (last_found) {
+ error = git_pack_entry_find(e, last_found, short_oid, len);
if (error == GIT_EAMBIGUOUS)
return error;
if (!error)
@@ -316,7 +281,7 @@ static int pack_entry_find_prefix(
struct git_pack_file *p;
p = git_vector_get(&backend->packs, i);
- if (p == backend->last_found)
+ if (p == last_found)
continue;
error = git_pack_entry_find(e, p, short_oid, len);
@@ -329,6 +294,18 @@ static int pack_entry_find_prefix(
}
}
+ return found;
+}
+
+static int pack_entry_find_prefix(
+ struct git_pack_entry *e,
+ struct pack_backend *backend,
+ const git_oid *short_oid,
+ size_t len)
+{
+ struct git_pack_file *last_found = backend->last_found;
+ unsigned int found = pack_entry_find_prefix_inner(e, backend, short_oid, len, last_found);
+
if (!found)
return git_odb__error_notfound("no matching pack entry for prefix", short_oid);
else if (found > 1)
@@ -345,20 +322,47 @@ static int pack_entry_find_prefix(
* Implement the git_odb_backend API calls
*
***********************************************************/
+static int pack_backend__refresh(git_odb_backend *_backend)
+{
+ struct pack_backend *backend = (struct pack_backend *)_backend;
-/*
-int pack_backend__read_header(git_rawobj *obj, git_odb_backend *backend, const git_oid *oid)
+ int error;
+ struct stat st;
+ git_buf path = GIT_BUF_INIT;
+
+ if (backend->pack_folder == NULL)
+ return 0;
+
+ if (p_stat(backend->pack_folder, &st) < 0 || !S_ISDIR(st.st_mode))
+ return git_odb__error_notfound("failed to refresh packfiles", NULL);
+
+ git_buf_sets(&path, backend->pack_folder);
+
+ /* reload all packs */
+ error = git_path_direach(&path, packfile_load__cb, (void *)backend);
+
+ git_buf_free(&path);
+
+ if (error < 0)
+ return error;
+
+ git_vector_sort(&backend->packs);
+ return 0;
+}
+
+
+static int pack_backend__read_header(size_t *len_p, git_otype *type_p, struct git_odb_backend *backend, const git_oid *oid)
{
- pack_location location;
+ struct git_pack_entry e;
+ int error;
- assert(obj && backend && oid);
+ assert(len_p && type_p && backend && oid);
- if (locate_packfile(&location, (struct pack_backend *)backend, oid) < 0)
- return GIT_ENOTFOUND;
+ if ((error = pack_entry_find(&e, (struct pack_backend *)backend, oid)) < 0)
+ return error;
- return read_header_packed(obj, &location);
+ return git_packfile_resolve_header(len_p, type_p, e.p, e.offset);
}
-*/
static int pack_backend__read(void **buffer_p, size_t *len_p, git_otype *type_p, git_odb_backend *backend, const git_oid *oid)
{
@@ -384,7 +388,7 @@ static int pack_backend__read_prefix(
git_otype *type_p,
git_odb_backend *backend,
const git_oid *short_oid,
- unsigned int len)
+ size_t len)
{
int error = 0;
@@ -420,18 +424,101 @@ static int pack_backend__exists(git_odb_backend *backend, const git_oid *oid)
return pack_entry_find(&e, (struct pack_backend *)backend, oid) == 0;
}
-static void pack_backend__free(git_odb_backend *_backend)
+static int pack_backend__foreach(git_odb_backend *_backend, git_odb_foreach_cb cb, void *data)
{
+ int error;
+ struct git_pack_file *p;
struct pack_backend *backend;
unsigned int i;
+ assert(_backend && cb);
+ backend = (struct pack_backend *)_backend;
+
+ /* Make sure we know about the packfiles */
+ if ((error = pack_backend__refresh(_backend)) < 0)
+ return error;
+
+ git_vector_foreach(&backend->packs, i, p) {
+ if ((error = git_pack_foreach_entry(p, cb, data)) < 0)
+ return error;
+ }
+
+ return 0;
+}
+
+static int pack_backend__writepack_add(struct git_odb_writepack *_writepack, const void *data, size_t size, git_transfer_progress *stats)
+{
+ struct pack_writepack *writepack = (struct pack_writepack *)_writepack;
+
+ assert(writepack);
+
+ return git_indexer_stream_add(writepack->indexer_stream, data, size, stats);
+}
+
+static int pack_backend__writepack_commit(struct git_odb_writepack *_writepack, git_transfer_progress *stats)
+{
+ struct pack_writepack *writepack = (struct pack_writepack *)_writepack;
+
+ assert(writepack);
+
+ return git_indexer_stream_finalize(writepack->indexer_stream, stats);
+}
+
+static void pack_backend__writepack_free(struct git_odb_writepack *_writepack)
+{
+ struct pack_writepack *writepack = (struct pack_writepack *)_writepack;
+
+ assert(writepack);
+
+ git_indexer_stream_free(writepack->indexer_stream);
+ git__free(writepack);
+}
+
+static int pack_backend__writepack(struct git_odb_writepack **out,
+ git_odb_backend *_backend,
+ git_transfer_progress_callback progress_cb,
+ void *progress_payload)
+{
+ struct pack_backend *backend;
+ struct pack_writepack *writepack;
+
+ assert(out && _backend);
+
+ *out = NULL;
+
+ backend = (struct pack_backend *)_backend;
+
+ writepack = git__calloc(1, sizeof(struct pack_writepack));
+ GITERR_CHECK_ALLOC(writepack);
+
+ if (git_indexer_stream_new(&writepack->indexer_stream,
+ backend->pack_folder, progress_cb, progress_payload) < 0) {
+ git__free(writepack);
+ return -1;
+ }
+
+ writepack->parent.backend = _backend;
+ writepack->parent.add = pack_backend__writepack_add;
+ writepack->parent.commit = pack_backend__writepack_commit;
+ writepack->parent.free = pack_backend__writepack_free;
+
+ *out = (git_odb_writepack *)writepack;
+
+ return 0;
+}
+
+static void pack_backend__free(git_odb_backend *_backend)
+{
+ struct pack_backend *backend;
+ size_t i;
+
assert(_backend);
backend = (struct pack_backend *)_backend;
for (i = 0; i < backend->packs.length; ++i) {
struct git_pack_file *p = git_vector_get(&backend->packs, i);
- packfile_free(p);
+ git_packfile_free(p);
}
git_vector_free(&backend->packs);
@@ -439,6 +526,43 @@ static void pack_backend__free(git_odb_backend *_backend)
git__free(backend);
}
+int git_odb_backend_one_pack(git_odb_backend **backend_out, const char *idx)
+{
+ struct pack_backend *backend = NULL;
+ struct git_pack_file *packfile = NULL;
+
+ if (git_packfile_check(&packfile, idx) < 0)
+ return -1;
+
+ backend = git__calloc(1, sizeof(struct pack_backend));
+ GITERR_CHECK_ALLOC(backend);
+ backend->parent.version = GIT_ODB_BACKEND_VERSION;
+
+ if (git_vector_init(&backend->packs, 1, NULL) < 0)
+ goto on_error;
+
+ if (git_vector_insert(&backend->packs, packfile) < 0)
+ goto on_error;
+
+ backend->parent.read = &pack_backend__read;
+ backend->parent.read_prefix = &pack_backend__read_prefix;
+ backend->parent.read_header = &pack_backend__read_header;
+ backend->parent.exists = &pack_backend__exists;
+ backend->parent.refresh = &pack_backend__refresh;
+ backend->parent.foreach = &pack_backend__foreach;
+ backend->parent.free = &pack_backend__free;
+
+ *backend_out = (git_odb_backend *)backend;
+
+ return 0;
+
+on_error:
+ git_vector_free(&backend->packs);
+ git__free(backend);
+ git__free(packfile);
+ return -1;
+}
+
int git_odb_backend_pack(git_odb_backend **backend_out, const char *objects_dir)
{
struct pack_backend *backend = NULL;
@@ -446,6 +570,7 @@ int git_odb_backend_pack(git_odb_backend **backend_out, const char *objects_dir)
backend = git__calloc(1, sizeof(struct pack_backend));
GITERR_CHECK_ALLOC(backend);
+ backend->parent.version = GIT_ODB_BACKEND_VERSION;
if (git_vector_init(&backend->packs, 8, packfile_sort__cb) < 0 ||
git_buf_joinpath(&path, objects_dir, "pack") < 0)
@@ -455,14 +580,21 @@ int git_odb_backend_pack(git_odb_backend **backend_out, const char *objects_dir)
}
if (git_path_isdir(git_buf_cstr(&path)) == true) {
+ int error;
+
backend->pack_folder = git_buf_detach(&path);
- backend->pack_folder_mtime = 0;
+ error = pack_backend__refresh((git_odb_backend *)backend);
+ if (error < 0)
+ return error;
}
backend->parent.read = &pack_backend__read;
backend->parent.read_prefix = &pack_backend__read_prefix;
- backend->parent.read_header = NULL;
+ backend->parent.read_header = &pack_backend__read_header;
backend->parent.exists = &pack_backend__exists;
+ backend->parent.refresh = &pack_backend__refresh;
+ backend->parent.foreach = &pack_backend__foreach;
+ backend->parent.writepack = &pack_backend__writepack;
backend->parent.free = &pack_backend__free;
*backend_out = (git_odb_backend *)backend;