[prev in list] [next in list] [prev in thread] [next in thread]
List: git
Subject: [PATCH 05/16] Hook up replace-object to allow bulk commit replacement
From: Nguyễn Thái Ngọc Duy
Date: 2010-07-31 16:18:14
Message-ID: 1280593105-22015-6-git-send-email-pclouds () gmail ! com
[Download RAW message or body]
$GIT_DIR/subtree contains commit mapping in subtree mode. It's quite
large that putting it in $GIT_DIR/refs/replace may slow git down
significantly. Even with this, there will be a split second delay for
every git command.
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
Makefile | 2 +
replace_object.c | 5 ++
subtree.c | 117 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
subtree.h | 2 +
4 files changed, 126 insertions(+), 0 deletions(-)
create mode 100644 subtree.c
create mode 100644 subtree.h
diff --git a/Makefile b/Makefile
index f33648d..0d13538 100644
--- a/Makefile
+++ b/Makefile
@@ -525,6 +525,7 @@ LIB_H += sigchain.h
LIB_H += strbuf.h
LIB_H += string-list.h
LIB_H += submodule.h
+LIB_H += subtree.h
LIB_H += tag.h
LIB_H += transport.h
LIB_H += tree.h
@@ -629,6 +630,7 @@ LIB_OBJS += sigchain.o
LIB_OBJS += strbuf.o
LIB_OBJS += string-list.o
LIB_OBJS += submodule.o
+LIB_OBJS += subtree.o
LIB_OBJS += symlinks.o
LIB_OBJS += tag.o
LIB_OBJS += trace.o
diff --git a/replace_object.c b/replace_object.c
index eb59604..5fe4099 100644
--- a/replace_object.c
+++ b/replace_object.c
@@ -1,6 +1,7 @@
#include "cache.h"
#include "sha1-lookup.h"
#include "refs.h"
+#include "subtree.h"
static struct replace_object {
unsigned char sha1[2][20];
@@ -82,6 +83,7 @@ static void prepare_replace_object(void)
if (replace_object_prepared)
return;
+ prepare_subtree_commit();
for_each_replace_ref(register_replace_ref, NULL);
replace_object_prepared = 1;
}
@@ -99,6 +101,9 @@ const unsigned char *lookup_replace_object(const unsigned char *sha1)
prepare_replace_object();
+ if (core_subtree)
+ cur = subtree_lookup_object(cur);
+
/* Try to recursively replace the object */
do {
if (--depth < 0)
diff --git a/subtree.c b/subtree.c
new file mode 100644
index 0000000..601d827
--- /dev/null
+++ b/subtree.c
@@ -0,0 +1,117 @@
+#include "cache.h"
+#include "commit.h"
+#include "tree.h"
+#include "diff.h"
+#include "revision.h"
+#include "refs.h"
+#include "tag.h"
+#include "progress.h"
+#include "pack.h"
+#include "sha1-lookup.h"
+#include "csum-file.h"
+
+static struct replace_object {
+ unsigned char sha1[2][20];
+} **subtree_commit;
+
+static struct replace_object **subtree_commit, **subtree_commit_r;
+static int subtree_commit_nr, subtree_commit_r_nr, subtree_commit_alloc;
+
+static const unsigned char *replace_sha1_access(size_t index, void *table)
+{
+ struct replace_object **replace = table;
+ return replace[index]->sha1[0];
+}
+
+static int subtree_replace_object_pos(struct replace_object **store, int nr,
+ const unsigned char *sha1)
+{
+ return sha1_pos(sha1, store, nr, replace_sha1_access);
+}
+
+static int subtree_register_object(struct replace_object **store,
+ int *nr,
+ const unsigned char *sha1,
+ struct replace_object *replace,
+ int ignore_dups)
+{
+ int pos = subtree_replace_object_pos(store, *nr, sha1);
+
+ if (0 <= pos) {
+ if (ignore_dups)
+ free(replace);
+ else {
+ free(store[pos]);
+ store[pos] = replace;
+ }
+ return 1;
+ }
+ pos = -pos - 1;
+ (*nr)++;
+ if (pos < *nr)
+ memmove(store + pos + 1,
+ store + pos,
+ (*nr - pos - 1) *
+ sizeof(*store));
+ store[pos] = replace;
+ return 0;
+}
+
+void prepare_subtree_commit()
+{
+ int fd;
+ struct stat stat;
+ struct replace_object *ro;
+ int ro_size, ro_table_size;
+ char *subtree, *entry;
+
+ if (!core_subtree)
+ return;
+
+ fd = open(git_path("subtree"), O_RDONLY);
+ if (fd == -1)
+ return;
+
+ if (fstat(fd, &stat))
+ die("Could not stat .git/subtree");
+
+ if (stat.st_size % 82)
+ die("Invalid .git/subtree size");
+
+ subtree_commit_alloc = stat.st_size / 82;
+ ro_size = sizeof(struct replace_object) * subtree_commit_alloc;
+ ro_table_size = sizeof(struct replace_object*) * subtree_commit_alloc;
+ subtree_commit_nr = 0;
+ subtree_commit_r_nr = 0;
+
+ subtree_commit = xmalloc(ro_size + ro_table_size*2);
+ subtree_commit_r = (struct replace_object **)(((char*)subtree_commit) + ro_table_size);
+ ro = (struct replace_object *)(((char*)subtree_commit) + 2*ro_table_size);
+
+ entry = subtree = xmmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+
+ for (entry = subtree; subtree_commit_nr < subtree_commit_alloc; entry += 82, ro++) {
+ if (entry[40] != ' ' || entry[81] != '\n')
+ die("Broken .git/subtree");
+
+ get_sha1_hex(entry, ro->sha1[0]);
+ get_sha1_hex(entry+41, ro->sha1[1]);
+ if (subtree_register_object(subtree_commit, &subtree_commit_nr,
+ ro->sha1[0], ro, 1) ||
+ subtree_register_object(subtree_commit_r, &subtree_commit_r_nr,
+ ro->sha1[1], ro, 1))
+ die("duplicate replace ref: %s", sha1_to_hex(ro->sha1[0]));
+ }
+ munmap(subtree, stat.st_size);
+ close(fd);
+}
+
+const unsigned char *subtree_lookup_object(const unsigned char *sha1)
+{
+ int pos = subtree_replace_object_pos(subtree_commit,
+ subtree_commit_nr,
+ sha1);
+ if (0 <= pos)
+ return subtree_commit[pos]->sha1[1];
+ return sha1;
+}
diff --git a/subtree.h b/subtree.h
new file mode 100644
index 0000000..157153a
--- /dev/null
+++ b/subtree.h
@@ -0,0 +1,2 @@
+void prepare_subtree_commit();
+const unsigned char *subtree_lookup_object(const unsigned char *sha1);
--
1.7.1.rc1.69.g24c2f7
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic