summaryrefslogtreecommitdiff
path: root/commit.c
diff options
context:
space:
mode:
authorJunio C Hamano <gitster@pobox.com>2014-07-16 11:16:38 -0700
committerJunio C Hamano <gitster@pobox.com>2014-07-16 11:16:38 -0700
commit5c18fde0d96cfcbc321caad8f809028b0c63aaeb (patch)
tree0fbc3fd1a5ca630e2eeb6a0aa4484f848455bf5e /commit.c
parent64630d807ae0a9717ae39c87bd1458bf15c62142 (diff)
parent218aa3a6162b80696a82b8745daa38fa826985ae (diff)
downloadgit-5c18fde0d96cfcbc321caad8f809028b0c63aaeb.tar.gz
Merge branch 'jk/commit-buffer-length' into maint
A handful of code paths had to read the commit object more than once when showing header fields that are usually not parsed. The internal data structure to keep track of the contents of the commit object has been updated to reduce the need for this double-reading, and to allow the caller find the length of the object. * 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 f4793316a2..ebd7ad8465 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))