summaryrefslogtreecommitdiff
path: root/commit.c
diff options
context:
space:
mode:
authorJunio C Hamano <gitster@pobox.com>2014-07-02 12:53:02 -0700
committerJunio C Hamano <gitster@pobox.com>2014-07-02 12:53:02 -0700
commit8061ae8b4618d69a67ff6cfb687d7044964d4b04 (patch)
treefd75c5ef40caf10107f15e320bbb9501017ba695 /commit.c
parent95acfc2479967ba5f3e2ddfee1fa2eb89b386c4f (diff)
parent218aa3a6162b80696a82b8745daa38fa826985ae (diff)
downloadgit-8061ae8b4618d69a67ff6cfb687d7044964d4b04.tar.gz
Merge branch 'jk/commit-buffer-length'
Move "commit->buffer" out of the in-core commit object and keep track of their lengths. Use this to optimize the code paths to validate GPG signatures in commit objects. * jk/commit-buffer-length: reuse cached commit buffer when parsing signatures commit: record buffer length in cache commit: convert commit->buffer to a slab commit-slab: provide a static initializer use get_commit_buffer everywhere convert logmsg_reencode to get_commit_buffer use get_commit_buffer to avoid duplicate code use get_cached_commit_buffer where appropriate provide helpers to access the commit buffer provide a helper to set the commit buffer provide a helper to free commit buffer sequencer: use logmsg_reencode in get_message logmsg_reencode: return const buffer do not create "struct commit" with xcalloc commit: push commit_index update into alloc_commit_node alloc: include any-object allocations in alloc_report replace dangerous uses of strbuf_attach commit_tree: take a pointer/len pair rather than a const strbuf
Diffstat (limited to 'commit.c')
-rw-r--r--commit.c129
1 files changed, 91 insertions, 38 deletions
diff --git a/commit.c b/commit.c
index 881be3baa3..4ff8077dbf 100644
--- a/commit.c
+++ b/commit.c
@@ -17,7 +17,6 @@ static struct commit_extra_header *read_commit_extra_header_lines(const char *bu
int save_commit_buffer = 1;
const char *commit_type = "commit";
-static int commit_count;
static struct commit *check_commit(struct object *obj,
const unsigned char *sha1,
@@ -64,7 +63,6 @@ struct commit *lookup_commit(const unsigned char *sha1)
struct object *obj = lookup_object(sha1);
if (!obj) {
struct commit *c = alloc_commit_node();
- c->index = commit_count++;
return create_object(sha1, OBJ_COMMIT, c);
}
if (!obj->type)
@@ -247,6 +245,76 @@ int unregister_shallow(const unsigned char *sha1)
return 0;
}
+struct commit_buffer {
+ void *buffer;
+ unsigned long size;
+};
+define_commit_slab(buffer_slab, struct commit_buffer);
+static struct buffer_slab buffer_slab = COMMIT_SLAB_INIT(1, buffer_slab);
+
+void set_commit_buffer(struct commit *commit, void *buffer, unsigned long size)
+{
+ struct commit_buffer *v = buffer_slab_at(&buffer_slab, commit);
+ v->buffer = buffer;
+ v->size = size;
+}
+
+const void *get_cached_commit_buffer(const struct commit *commit, unsigned long *sizep)
+{
+ struct commit_buffer *v = buffer_slab_at(&buffer_slab, commit);
+ if (sizep)
+ *sizep = v->size;
+ return v->buffer;
+}
+
+const void *get_commit_buffer(const struct commit *commit, unsigned long *sizep)
+{
+ const void *ret = get_cached_commit_buffer(commit, sizep);
+ if (!ret) {
+ enum object_type type;
+ unsigned long size;
+ ret = read_sha1_file(commit->object.sha1, &type, &size);
+ if (!ret)
+ die("cannot read commit object %s",
+ sha1_to_hex(commit->object.sha1));
+ if (type != OBJ_COMMIT)
+ die("expected commit for %s, got %s",
+ sha1_to_hex(commit->object.sha1), typename(type));
+ if (sizep)
+ *sizep = size;
+ }
+ return ret;
+}
+
+void unuse_commit_buffer(const struct commit *commit, const void *buffer)
+{
+ struct commit_buffer *v = buffer_slab_at(&buffer_slab, commit);
+ if (v->buffer != buffer)
+ free((void *)buffer);
+}
+
+void free_commit_buffer(struct commit *commit)
+{
+ struct commit_buffer *v = buffer_slab_at(&buffer_slab, commit);
+ free(v->buffer);
+ v->buffer = NULL;
+ v->size = 0;
+}
+
+const void *detach_commit_buffer(struct commit *commit, unsigned long *sizep)
+{
+ struct commit_buffer *v = buffer_slab_at(&buffer_slab, commit);
+ void *ret;
+
+ ret = v->buffer;
+ if (sizep)
+ *sizep = v->size;
+
+ v->buffer = NULL;
+ v->size = 0;
+ return ret;
+}
+
int parse_commit_buffer(struct commit *item, const void *buffer, unsigned long size)
{
const char *tail = buffer;
@@ -324,7 +392,7 @@ int parse_commit(struct commit *item)
}
ret = parse_commit_buffer(item, buffer, size);
if (save_commit_buffer && !ret) {
- item->buffer = buffer;
+ set_commit_buffer(item, buffer, size);
return 0;
}
free(buffer);
@@ -539,22 +607,12 @@ static void record_author_date(struct author_date_slab *author_date,
struct commit *commit)
{
const char *buf, *line_end, *ident_line;
- char *buffer = NULL;
+ const char *buffer = get_commit_buffer(commit, NULL);
struct ident_split ident;
char *date_end;
unsigned long date;
- if (!commit->buffer) {
- unsigned long size;
- enum object_type type;
- buffer = read_sha1_file(commit->object.sha1, &type, &size);
- if (!buffer)
- return;
- }
-
- for (buf = commit->buffer ? commit->buffer : buffer;
- buf;
- buf = line_end + 1) {
+ for (buf = buffer; buf; buf = line_end + 1) {
line_end = strchrnul(buf, '\n');
ident_line = skip_prefix(buf, "author ");
if (!ident_line) {
@@ -575,7 +633,7 @@ static void record_author_date(struct author_date_slab *author_date,
*(author_date_slab_at(author_date, commit)) = date;
fail_exit:
- free(buffer);
+ unuse_commit_buffer(commit, buffer);
}
static int compare_commits_by_author_date(const void *a_, const void *b_,
@@ -1080,17 +1138,14 @@ static int do_sign_commit(struct strbuf *buf, const char *keyid)
return 0;
}
-int parse_signed_commit(const unsigned char *sha1,
+int parse_signed_commit(const struct commit *commit,
struct strbuf *payload, struct strbuf *signature)
{
+
unsigned long size;
- enum object_type type;
- char *buffer = read_sha1_file(sha1, &type, &size);
+ const char *buffer = get_commit_buffer(commit, &size);
int in_signature, saw_signature = -1;
- char *line, *tail;
-
- if (!buffer || type != OBJ_COMMIT)
- goto cleanup;
+ const char *line, *tail;
line = buffer;
tail = buffer + size;
@@ -1098,7 +1153,7 @@ int parse_signed_commit(const unsigned char *sha1,
saw_signature = 0;
while (line < tail) {
const char *sig = NULL;
- char *next = memchr(line, '\n', tail - line);
+ const char *next = memchr(line, '\n', tail - line);
next = next ? next + 1 : tail;
if (in_signature && line[0] == ' ')
@@ -1119,8 +1174,7 @@ int parse_signed_commit(const unsigned char *sha1,
}
line = next;
}
- cleanup:
- free(buffer);
+ unuse_commit_buffer(commit, buffer);
return saw_signature;
}
@@ -1211,8 +1265,7 @@ void check_commit_signature(const struct commit* commit, struct signature_check
sigc->result = 'N';
- if (parse_signed_commit(commit->object.sha1,
- &payload, &signature) <= 0)
+ if (parse_signed_commit(commit, &payload, &signature) <= 0)
goto out;
status = verify_signed_buffer(payload.buf, payload.len,
signature.buf, signature.len,
@@ -1257,11 +1310,9 @@ struct commit_extra_header *read_commit_extra_headers(struct commit *commit,
{
struct commit_extra_header *extra = NULL;
unsigned long size;
- enum object_type type;
- char *buffer = read_sha1_file(commit->object.sha1, &type, &size);
- if (buffer && type == OBJ_COMMIT)
- extra = read_commit_extra_header_lines(buffer, size, exclude);
- free(buffer);
+ const char *buffer = get_commit_buffer(commit, &size);
+ extra = read_commit_extra_header_lines(buffer, size, exclude);
+ unuse_commit_buffer(commit, buffer);
return extra;
}
@@ -1344,7 +1395,8 @@ void free_commit_extra_headers(struct commit_extra_header *extra)
}
}
-int commit_tree(const struct strbuf *msg, const unsigned char *tree,
+int commit_tree(const char *msg, size_t msg_len,
+ const unsigned char *tree,
struct commit_list *parents, unsigned char *ret,
const char *author, const char *sign_commit)
{
@@ -1352,7 +1404,7 @@ int commit_tree(const struct strbuf *msg, const unsigned char *tree,
int result;
append_merge_tag_headers(parents, &tail);
- result = commit_tree_extended(msg, tree, parents, ret,
+ result = commit_tree_extended(msg, msg_len, tree, parents, ret,
author, sign_commit, extra);
free_commit_extra_headers(extra);
return result;
@@ -1473,7 +1525,8 @@ static const char commit_utf8_warn[] =
"You may want to amend it after fixing the message, or set the config\n"
"variable i18n.commitencoding to the encoding your project uses.\n";
-int commit_tree_extended(const struct strbuf *msg, const unsigned char *tree,
+int commit_tree_extended(const char *msg, size_t msg_len,
+ const unsigned char *tree,
struct commit_list *parents, unsigned char *ret,
const char *author, const char *sign_commit,
struct commit_extra_header *extra)
@@ -1484,7 +1537,7 @@ int commit_tree_extended(const struct strbuf *msg, const unsigned char *tree,
assert_sha1_type(tree, OBJ_TREE);
- if (memchr(msg->buf, '\0', msg->len))
+ if (memchr(msg, '\0', msg_len))
return error("a NUL byte in commit log message not allowed.");
/* Not having i18n.commitencoding is the same as having utf-8 */
@@ -1523,7 +1576,7 @@ int commit_tree_extended(const struct strbuf *msg, const unsigned char *tree,
strbuf_addch(&buffer, '\n');
/* And add the comment */
- strbuf_addbuf(&buffer, msg);
+ strbuf_add(&buffer, msg, msg_len);
/* And check the encoding */
if (encoding_is_utf8 && !verify_utf8(&buffer))