1
0
mirror of https://github.com/git/git synced 2024-07-07 19:39:27 +00:00

Merge branch 'nd/commit-util-to-slab'

The in-core "commit" object had an all-purpose "void *util" field,
which was tricky to use especially in library-ish part of the
code.  All of the existing uses of the field has been migrated to a
more dedicated "commit-slab" mechanism and the field is eliminated.

* nd/commit-util-to-slab:
  commit.h: delete 'util' field in struct commit
  merge: use commit-slab in merge remote desc instead of commit->util
  log: use commit-slab in prepare_bases() instead of commit->util
  show-branch: note about its object flags usage
  show-branch: use commit-slab for commit-name instead of commit->util
  name-rev: use commit-slab for rev-name instead of commit->util
  bisect.c: use commit-slab for commit weight instead of commit->util
  revision.c: use commit-slab for show_source
  sequencer.c: use commit-slab to associate todo items to commits
  sequencer.c: use commit-slab to mark seen commits
  shallow.c: use commit-slab for commit depth instead of commit->util
  describe: use commit-slab for commit names instead of commit->util
  blame: use commit-slab for blame suspects instead of commit->util
  commit-slab: support shared commit-slab
  commit-slab.h: code split
This commit is contained in:
Junio C Hamano 2018-06-25 13:22:35 -07:00
commit b3b2aaf0fd
22 changed files with 382 additions and 195 deletions

View File

@ -12,6 +12,7 @@
#include "bisect.h"
#include "sha1-array.h"
#include "argv-array.h"
#include "commit-slab.h"
static struct oid_array good_revs;
static struct oid_array skipped_revs;
@ -70,16 +71,19 @@ static void clear_distance(struct commit_list *list)
}
}
define_commit_slab(commit_weight, int *);
static struct commit_weight commit_weight;
#define DEBUG_BISECT 0
static inline int weight(struct commit_list *elem)
{
return *((int*)(elem->item->util));
return **commit_weight_at(&commit_weight, elem->item);
}
static inline void weight_set(struct commit_list *elem, int weight)
{
*((int*)(elem->item->util)) = weight;
**commit_weight_at(&commit_weight, elem->item) = weight;
}
static int count_interesting_parents(struct commit *commit)
@ -265,7 +269,7 @@ static struct commit_list *do_find_bisection(struct commit_list *list,
struct commit *commit = p->item;
unsigned flags = commit->object.flags;
p->item->util = &weights[n++];
*commit_weight_at(&commit_weight, p->item) = &weights[n++];
switch (count_interesting_parents(commit)) {
case 0:
if (!(flags & TREESAME)) {
@ -372,6 +376,7 @@ void find_bisection(struct commit_list **commit_list, int *reaches,
int *weights;
show_list("bisection 2 entry", 0, 0, *commit_list);
init_commit_weight(&commit_weight);
/*
* Count the number of total and tree-changing items on the
@ -412,6 +417,7 @@ void find_bisection(struct commit_list **commit_list, int *reaches,
}
free(weights);
*commit_list = best;
clear_commit_weight(&commit_weight);
}
static int register_ref(const char *refname, const struct object_id *oid,

42
blame.c
View File

@ -6,6 +6,24 @@
#include "diffcore.h"
#include "tag.h"
#include "blame.h"
#include "commit-slab.h"
define_commit_slab(blame_suspects, struct blame_origin *);
static struct blame_suspects blame_suspects;
struct blame_origin *get_blame_suspects(struct commit *commit)
{
struct blame_origin **result;
result = blame_suspects_peek(&blame_suspects, commit);
return result ? *result : NULL;
}
static void set_blame_suspects(struct commit *commit, struct blame_origin *origin)
{
*blame_suspects_at(&blame_suspects, commit) = origin;
}
void blame_origin_decref(struct blame_origin *o)
{
@ -15,12 +33,12 @@ void blame_origin_decref(struct blame_origin *o)
blame_origin_decref(o->previous);
free(o->file.ptr);
/* Should be present exactly once in commit chain */
for (p = o->commit->util; p; l = p, p = p->next) {
for (p = get_blame_suspects(o->commit); p; l = p, p = p->next) {
if (p == o) {
if (l)
l->next = p->next;
else
o->commit->util = p->next;
set_blame_suspects(o->commit, p->next);
free(o);
return;
}
@ -41,8 +59,8 @@ static struct blame_origin *make_origin(struct commit *commit, const char *path)
FLEX_ALLOC_STR(o, path, path);
o->commit = commit;
o->refcnt = 1;
o->next = commit->util;
commit->util = o;
o->next = get_blame_suspects(commit);
set_blame_suspects(commit, o);
return o;
}
@ -54,13 +72,13 @@ static struct blame_origin *get_origin(struct commit *commit, const char *path)
{
struct blame_origin *o, *l;
for (o = commit->util, l = NULL; o; l = o, o = o->next) {
for (o = get_blame_suspects(commit), l = NULL; o; l = o, o = o->next) {
if (!strcmp(o->path, path)) {
/* bump to front */
if (l) {
l->next = o->next;
o->next = commit->util;
commit->util = o;
o->next = get_blame_suspects(commit);
set_blame_suspects(commit, o);
}
return blame_origin_incref(o);
}
@ -478,7 +496,7 @@ static void queue_blames(struct blame_scoreboard *sb, struct blame_origin *porig
porigin->suspects = blame_merge(porigin->suspects, sorted);
else {
struct blame_origin *o;
for (o = porigin->commit->util; o; o = o->next) {
for (o = get_blame_suspects(porigin->commit); o; o = o->next) {
if (o->suspects) {
porigin->suspects = sorted;
return;
@ -525,7 +543,7 @@ static struct blame_origin *find_origin(struct commit *parent,
const char *paths[2];
/* First check any existing origins */
for (porigin = parent->util; porigin; porigin = porigin->next)
for (porigin = get_blame_suspects(parent); porigin; porigin = porigin->next)
if (!strcmp(porigin->path, origin->path)) {
/*
* The same path between origin and its parent
@ -1550,7 +1568,7 @@ void assign_blame(struct blame_scoreboard *sb, int opt)
while (commit) {
struct blame_entry *ent;
struct blame_origin *suspect = commit->util;
struct blame_origin *suspect = get_blame_suspects(commit);
/* find one suspect to break down */
while (suspect && !suspect->suspects)
@ -1752,6 +1770,8 @@ void setup_scoreboard(struct blame_scoreboard *sb, const char *path, struct blam
struct commit *final_commit = NULL;
enum object_type type;
init_blame_suspects(&blame_suspects);
if (sb->reverse && sb->contents_from)
die(_("--contents and --reverse do not blend well."));
@ -1815,7 +1835,7 @@ void setup_scoreboard(struct blame_scoreboard *sb, const char *path, struct blam
}
if (is_null_oid(&sb->final->object.oid)) {
o = sb->final->util;
o = get_blame_suspects(sb->final);
sb->final_buf = xmemdupz(o->file.ptr, o->file.size);
sb->final_buf_size = o->file.size;
}

View File

@ -172,4 +172,6 @@ extern void setup_scoreboard(struct blame_scoreboard *sb, const char *path, stru
extern struct blame_entry *blame_entry_prepend(struct blame_entry *head, long start, long end, struct blame_origin *o);
extern struct blame_origin *get_blame_suspects(struct commit *commit);
#endif /* BLAME_H */

View File

@ -543,7 +543,7 @@ static void output(struct blame_scoreboard *sb, int option)
struct commit *commit = ent->suspect->commit;
if (commit->object.flags & MORE_THAN_ONE_PATH)
continue;
for (suspect = commit->util; suspect; suspect = suspect->next) {
for (suspect = get_blame_suspects(commit); suspect; suspect = suspect->next) {
if (suspect->guilty && count++) {
commit->object.flags |= MORE_THAN_ONE_PATH;
break;

View File

@ -15,9 +15,12 @@
#include "run-command.h"
#include "revision.h"
#include "list-objects.h"
#include "commit-slab.h"
#define MAX_TAGS (FLAG_BITS - 1)
define_commit_slab(commit_names, struct commit_name *);
static const char * const describe_usage[] = {
N_("git describe [<options>] [<commit-ish>...]"),
N_("git describe [<options>] --dirty"),
@ -37,6 +40,7 @@ static struct string_list patterns = STRING_LIST_INIT_NODUP;
static struct string_list exclude_patterns = STRING_LIST_INIT_NODUP;
static int always;
static const char *suffix, *dirty, *broken;
static struct commit_names commit_names;
/* diff-index command arguments to check if working tree is dirty. */
static const char *diff_index_args[] = {
@ -321,11 +325,14 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst)
if (!have_util) {
struct hashmap_iter iter;
struct commit *c;
struct commit_name *n = hashmap_iter_first(&names, &iter);
struct commit_name *n;
init_commit_names(&commit_names);
n = hashmap_iter_first(&names, &iter);
for (; n; n = hashmap_iter_next(&iter)) {
c = lookup_commit_reference_gently(&n->peeled, 1);
if (c)
c->util = n;
*commit_names_at(&commit_names, c) = n;
}
have_util = 1;
}
@ -336,8 +343,11 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst)
while (list) {
struct commit *c = pop_commit(&list);
struct commit_list *parents = c->parents;
struct commit_name **slot;
seen_commits++;
n = c->util;
slot = commit_names_peek(&commit_names, c);
n = slot ? *slot : NULL;
if (n) {
if (!tags && !all && n->prio < 2) {
unannotated_cnt++;

View File

@ -22,6 +22,7 @@
#include "quote.h"
#include "remote.h"
#include "blob.h"
#include "commit-slab.h"
static const char *fast_export_usage[] = {
N_("git fast-export [rev-list-opts]"),
@ -38,6 +39,7 @@ static int full_tree;
static struct string_list extra_refs = STRING_LIST_INIT_NODUP;
static struct refspec refspecs = REFSPEC_INIT_FETCH;
static int anonymize;
static struct revision_sources revision_sources;
static int parse_opt_signed_tag_mode(const struct option *opt,
const char *arg, int unset)
@ -589,7 +591,7 @@ static void handle_commit(struct commit *commit, struct rev_info *rev,
if (!S_ISGITLINK(diff_queued_diff.queue[i]->two->mode))
export_blob(&diff_queued_diff.queue[i]->two->oid);
refname = commit->util;
refname = *revision_sources_at(&revision_sources, commit);
if (anonymize) {
refname = anonymize_refname(refname);
anonymize_ident_line(&committer, &committer_end);
@ -861,10 +863,11 @@ static void get_tags_and_duplicates(struct rev_cmdline_info *info)
* This ref will not be updated through a commit, lets make
* sure it gets properly updated eventually.
*/
if (commit->util || commit->object.flags & SHOWN)
if (*revision_sources_at(&revision_sources, commit) ||
commit->object.flags & SHOWN)
string_list_append(&extra_refs, full_name)->util = commit;
if (!commit->util)
commit->util = full_name;
if (!*revision_sources_at(&revision_sources, commit))
*revision_sources_at(&revision_sources, commit) = full_name;
}
}
@ -1028,8 +1031,9 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
git_config(git_default_config, NULL);
init_revisions(&revs, prefix);
init_revision_sources(&revision_sources);
revs.topo_order = 1;
revs.show_source = 1;
revs.sources = &revision_sources;
revs.rewrite_parents = 1;
argc = parse_options(argc, argv, prefix, options, fast_export_usage,
PARSE_OPT_KEEP_ARGV0 | PARSE_OPT_KEEP_UNKNOWN);

View File

@ -28,6 +28,7 @@
#include "mailmap.h"
#include "gpg-interface.h"
#include "progress.h"
#include "commit-slab.h"
#define MAIL_DEFAULT_WRAP 72
@ -148,6 +149,7 @@ static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
static struct string_list decorate_refs_include = STRING_LIST_INIT_NODUP;
struct decoration_filter decoration_filter = {&decorate_refs_include,
&decorate_refs_exclude};
static struct revision_sources revision_sources;
const struct option builtin_log_options[] = {
OPT__QUIET(&quiet, N_("suppress diff output")),
@ -194,8 +196,10 @@ static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
rev->diffopt.filter || rev->diffopt.flags.follow_renames)
rev->always_show_header = 0;
if (source)
rev->show_source = 1;
if (source) {
init_revision_sources(&revision_sources);
rev->sources = &revision_sources;
}
if (mailmap) {
rev->mailmap = xcalloc(1, sizeof(struct string_list));
@ -1337,6 +1341,8 @@ static struct commit *get_base_commit(const char *base_commit,
return base;
}
define_commit_slab(commit_base, int);
static void prepare_bases(struct base_tree_info *bases,
struct commit *base,
struct commit **list,
@ -1345,11 +1351,13 @@ static void prepare_bases(struct base_tree_info *bases,
struct commit *commit;
struct rev_info revs;
struct diff_options diffopt;
struct commit_base commit_base;
int i;
if (!base)
return;
init_commit_base(&commit_base);
diff_setup(&diffopt);
diffopt.flags.recursive = 1;
diff_setup_done(&diffopt);
@ -1362,7 +1370,7 @@ static void prepare_bases(struct base_tree_info *bases,
for (i = 0; i < total; i++) {
list[i]->object.flags &= ~UNINTERESTING;
add_pending_object(&revs, &list[i]->object, "rev_list");
list[i]->util = (void *)1;
*commit_base_at(&commit_base, list[i]) = 1;
}
base->object.flags |= UNINTERESTING;
add_pending_object(&revs, &base->object, "base");
@ -1376,7 +1384,7 @@ static void prepare_bases(struct base_tree_info *bases,
while ((commit = get_revision(&revs)) != NULL) {
struct object_id oid;
struct object_id *patch_id;
if (commit->util)
if (*commit_base_at(&commit_base, commit))
continue;
if (commit_patch_id(commit, &diffopt, &oid, 0))
die(_("cannot get patch id"));
@ -1385,6 +1393,7 @@ static void prepare_bases(struct base_tree_info *bases,
oidcpy(patch_id, &oid);
bases->nr_patch_id++;
}
clear_commit_base(&commit_base);
}
static void print_bases(struct base_tree_info *bases, FILE *file)

View File

@ -445,6 +445,7 @@ static void merge_name(const char *remote, struct strbuf *msg)
struct object_id branch_head;
struct strbuf buf = STRBUF_INIT;
struct strbuf bname = STRBUF_INIT;
struct merge_remote_desc *desc;
const char *ptr;
char *found_ref;
int len, early;
@ -517,16 +518,13 @@ static void merge_name(const char *remote, struct strbuf *msg)
strbuf_release(&truname);
}
if (remote_head->util) {
struct merge_remote_desc *desc;
desc = merge_remote_util(remote_head);
if (desc && desc->obj && desc->obj->type == OBJ_TAG) {
strbuf_addf(msg, "%s\t\t%s '%s'\n",
oid_to_hex(&desc->obj->oid),
type_name(desc->obj->type),
remote);
goto cleanup;
}
desc = merge_remote_util(remote_head);
if (desc && desc->obj && desc->obj->type == OBJ_TAG) {
strbuf_addf(msg, "%s\t\t%s '%s'\n",
oid_to_hex(&desc->obj->oid),
type_name(desc->obj->type),
remote);
goto cleanup;
}
strbuf_addf(msg, "%s\t\tcommit '%s'\n",
@ -934,8 +932,11 @@ static void write_merge_heads(struct commit_list *remoteheads)
for (j = remoteheads; j; j = j->next) {
struct object_id *oid;
struct commit *c = j->item;
if (c->util && merge_remote_util(c)->obj) {
oid = &merge_remote_util(c)->obj->oid;
struct merge_remote_desc *desc;
desc = merge_remote_util(c);
if (desc && desc->obj) {
oid = &desc->obj->oid;
} else {
oid = &c->object.oid;
}

View File

@ -6,6 +6,7 @@
#include "refs.h"
#include "parse-options.h"
#include "sha1-lookup.h"
#include "commit-slab.h"
#define CUTOFF_DATE_SLOP 86400 /* one day */
@ -17,11 +18,26 @@ typedef struct rev_name {
int from_tag;
} rev_name;
define_commit_slab(commit_rev_name, struct rev_name *);
static timestamp_t cutoff = TIME_MAX;
static struct commit_rev_name rev_names;
/* How many generations are maximally preferred over _one_ merge traversal? */
#define MERGE_TRAVERSAL_WEIGHT 65535
static struct rev_name *get_commit_rev_name(struct commit *commit)
{
struct rev_name **slot = commit_rev_name_peek(&rev_names, commit);
return slot ? *slot : NULL;
}
static void set_commit_rev_name(struct commit *commit, struct rev_name *name)
{
*commit_rev_name_at(&rev_names, commit) = name;
}
static int is_better_name(struct rev_name *name,
const char *tip_name,
timestamp_t taggerdate,
@ -65,7 +81,7 @@ static void name_rev(struct commit *commit,
int generation, int distance, int from_tag,
int deref)
{
struct rev_name *name = (struct rev_name *)commit->util;
struct rev_name *name = get_commit_rev_name(commit);
struct commit_list *parents;
int parent_number = 1;
char *to_free = NULL;
@ -84,7 +100,7 @@ static void name_rev(struct commit *commit,
if (name == NULL) {
name = xmalloc(sizeof(rev_name));
commit->util = name;
set_commit_rev_name(commit, name);
goto copy_data;
} else if (is_better_name(name, tip_name, taggerdate,
generation, distance, from_tag)) {
@ -296,7 +312,7 @@ static const char *get_rev_name(const struct object *o, struct strbuf *buf)
if (o->type != OBJ_COMMIT)
return get_exact_ref_match(o);
c = (struct commit *) o;
n = c->util;
n = get_commit_rev_name(c);
if (!n)
return NULL;
@ -413,6 +429,7 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix)
OPT_END(),
};
init_commit_rev_name(&rev_names);
git_config(git_default_config, NULL);
argc = parse_options(argc, argv, prefix, opts, name_rev_usage, 0);
if (all + transform_stdin + !!argc > 1) {

View File

@ -7,6 +7,7 @@
#include "argv-array.h"
#include "parse-options.h"
#include "dir.h"
#include "commit-slab.h"
static const char* show_branch_usage[] = {
N_("git show-branch [-a | --all] [-r | --remotes] [--topo-order | --date-order]\n"
@ -21,6 +22,11 @@ static int showbranch_use_color = -1;
static struct argv_array default_args = ARGV_ARRAY_INIT;
/*
* TODO: convert this use of commit->object.flags to commit-slab
* instead to store a pointer to ref name directly. Then use the same
* UNINTERESTING definition from revision.h here.
*/
#define UNINTERESTING 01
#define REV_SHIFT 2
@ -59,15 +65,27 @@ struct commit_name {
int generation; /* how many parents away from head_name */
};
define_commit_slab(commit_name_slab, struct commit_name *);
static struct commit_name_slab name_slab;
static struct commit_name *commit_to_name(struct commit *commit)
{
return *commit_name_slab_at(&name_slab, commit);
}
/* Name the commit as nth generation ancestor of head_name;
* we count only the first-parent relationship for naming purposes.
*/
static void name_commit(struct commit *commit, const char *head_name, int nth)
{
struct commit_name *name;
if (!commit->util)
commit->util = xmalloc(sizeof(struct commit_name));
name = commit->util;
name = *commit_name_slab_at(&name_slab, commit);
if (!name) {
name = xmalloc(sizeof(*name));
*commit_name_slab_at(&name_slab, commit) = name;
}
name->head_name = head_name;
name->generation = nth;
}
@ -79,8 +97,8 @@ static void name_commit(struct commit *commit, const char *head_name, int nth)
*/
static void name_parent(struct commit *commit, struct commit *parent)
{
struct commit_name *commit_name = commit->util;
struct commit_name *parent_name = parent->util;
struct commit_name *commit_name = commit_to_name(commit);
struct commit_name *parent_name = commit_to_name(parent);
if (!commit_name)
return;
if (!parent_name ||
@ -94,12 +112,12 @@ static int name_first_parent_chain(struct commit *c)
int i = 0;
while (c) {
struct commit *p;
if (!c->util)
if (!commit_to_name(c))
break;
if (!c->parents)
break;
p = c->parents->item;
if (!p->util) {
if (!commit_to_name(p)) {
name_parent(c, p);
i++;
}
@ -122,7 +140,7 @@ static void name_commits(struct commit_list *list,
/* First give names to the given heads */
for (cl = list; cl; cl = cl->next) {
c = cl->item;
if (c->util)
if (commit_to_name(c))
continue;
for (i = 0; i < num_rev; i++) {
if (rev[i] == c) {
@ -148,9 +166,9 @@ static void name_commits(struct commit_list *list,
struct commit_name *n;
int nth;
c = cl->item;
if (!c->util)
if (!commit_to_name(c))
continue;
n = c->util;
n = commit_to_name(c);
parents = c->parents;
nth = 0;
while (parents) {
@ -158,7 +176,7 @@ static void name_commits(struct commit_list *list,
struct strbuf newname = STRBUF_INIT;
parents = parents->next;
nth++;
if (p->util)
if (commit_to_name(p))
continue;
switch (n->generation) {
case 0:
@ -271,7 +289,7 @@ static void show_one_commit(struct commit *commit, int no_name)
{
struct strbuf pretty = STRBUF_INIT;
const char *pretty_str = "(unavailable)";
struct commit_name *name = commit->util;
struct commit_name *name = commit_to_name(commit);
if (commit->object.parsed) {
pp_commit_easy(CMIT_FMT_ONELINE, commit, &pretty);
@ -660,6 +678,8 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
OPT_END()
};
init_commit_name_slab(&name_slab);
git_config(git_show_branch_config, NULL);
/* If nothing is specified, try the default first */

43
commit-slab-decl.h Normal file
View File

@ -0,0 +1,43 @@
#ifndef COMMIT_SLAB_HDR_H
#define COMMIT_SLAB_HDR_H
/* allocate ~512kB at once, allowing for malloc overhead */
#ifndef COMMIT_SLAB_SIZE
#define COMMIT_SLAB_SIZE (512*1024-32)
#endif
#define declare_commit_slab(slabname, elemtype) \
\
struct slabname { \
unsigned slab_size; \
unsigned stride; \
unsigned slab_count; \
elemtype **slab; \
}
/*
* Statically initialize a commit slab named "var". Note that this
* evaluates "stride" multiple times! Example:
*
* struct indegree indegrees = COMMIT_SLAB_INIT(1, indegrees);
*
*/
#define COMMIT_SLAB_INIT(stride, var) { \
COMMIT_SLAB_SIZE / sizeof(**((var).slab)) / (stride), \
(stride), 0, NULL \
}
#define declare_commit_slab_prototypes(slabname, elemtype) \
\
void init_ ##slabname## _with_stride(struct slabname *s, unsigned stride); \
void init_ ##slabname(struct slabname *s); \
void clear_ ##slabname(struct slabname *s); \
elemtype *slabname## _at_peek(struct slabname *s, const struct commit *c, int add_if_missing); \
elemtype *slabname## _at(struct slabname *s, const struct commit *c); \
elemtype *slabname## _peek(struct slabname *s, const struct commit *c)
#define define_shared_commit_slab(slabname, elemtype) \
declare_commit_slab(slabname, elemtype); \
declare_commit_slab_prototypes(slabname, elemtype)
#endif /* COMMIT_SLAB_HDR_H */

97
commit-slab-impl.h Normal file
View File

@ -0,0 +1,97 @@
#ifndef COMMIT_SLAB_IMPL_H
#define COMMIT_SLAB_IMPL_H
#define MAYBE_UNUSED __attribute__((__unused__))
#define implement_static_commit_slab(slabname, elemtype) \
implement_commit_slab(slabname, elemtype, static MAYBE_UNUSED)
#define implement_shared_commit_slab(slabname, elemtype) \
implement_commit_slab(slabname, elemtype, )
#define implement_commit_slab(slabname, elemtype, scope) \
\
static int stat_ ##slabname## realloc; \
\
scope void init_ ##slabname## _with_stride(struct slabname *s, \
unsigned stride) \
{ \
unsigned int elem_size; \
if (!stride) \
stride = 1; \
s->stride = stride; \
elem_size = sizeof(elemtype) * stride; \
s->slab_size = COMMIT_SLAB_SIZE / elem_size; \
s->slab_count = 0; \
s->slab = NULL; \
} \
\
scope void init_ ##slabname(struct slabname *s) \
{ \
init_ ##slabname## _with_stride(s, 1); \
} \
\
scope void clear_ ##slabname(struct slabname *s) \
{ \
unsigned int i; \
for (i = 0; i < s->slab_count; i++) \
free(s->slab[i]); \
s->slab_count = 0; \
FREE_AND_NULL(s->slab); \
} \
\
scope elemtype *slabname## _at_peek(struct slabname *s, \
const struct commit *c, \
int add_if_missing) \
{ \
unsigned int nth_slab, nth_slot; \
\
nth_slab = c->index / s->slab_size; \
nth_slot = c->index % s->slab_size; \
\
if (s->slab_count <= nth_slab) { \
unsigned int i; \
if (!add_if_missing) \
return NULL; \
REALLOC_ARRAY(s->slab, nth_slab + 1); \
stat_ ##slabname## realloc++; \
for (i = s->slab_count; i <= nth_slab; i++) \
s->slab[i] = NULL; \
s->slab_count = nth_slab + 1; \
} \
if (!s->slab[nth_slab]) { \
if (!add_if_missing) \
return NULL; \
s->slab[nth_slab] = xcalloc(s->slab_size, \
sizeof(**s->slab) * s->stride); \
} \
return &s->slab[nth_slab][nth_slot * s->stride]; \
} \
\
scope elemtype *slabname## _at(struct slabname *s, \
const struct commit *c) \
{ \
return slabname##_at_peek(s, c, 1); \
} \
\
scope elemtype *slabname## _peek(struct slabname *s, \
const struct commit *c) \
{ \
return slabname##_at_peek(s, c, 0); \
} \
\
struct slabname
/*
* Note that this redundant forward declaration is required
* to allow a terminating semicolon, which makes instantiations look
* like function declarations. I.e., the expansion of
*
* implement_commit_slab(indegree, int, static);
*
* ends in 'struct indegree;'. This would otherwise
* be a syntax error according (at least) to ISO C. It's hard to
* catch because GCC silently parses it by default.
*/
#endif /* COMMIT_SLAB_IMPL_H */

View File

@ -1,6 +1,9 @@
#ifndef COMMIT_SLAB_H
#define COMMIT_SLAB_H
#include "commit-slab-decl.h"
#include "commit-slab-impl.h"
/*
* define_commit_slab(slabname, elemtype) creates boilerplate code to define
* a new struct (struct slabname) that is used to associate a piece of data
@ -41,114 +44,8 @@
* leaking memory.
*/
/* allocate ~512kB at once, allowing for malloc overhead */
#ifndef COMMIT_SLAB_SIZE
#define COMMIT_SLAB_SIZE (512*1024-32)
#endif
#define MAYBE_UNUSED __attribute__((__unused__))
#define define_commit_slab(slabname, elemtype) \
\
struct slabname { \
unsigned slab_size; \
unsigned stride; \
unsigned slab_count; \
elemtype **slab; \
}; \
static int stat_ ##slabname## realloc; \
\
static MAYBE_UNUSED void init_ ##slabname## _with_stride(struct slabname *s, \
unsigned stride) \
{ \
unsigned int elem_size; \
if (!stride) \
stride = 1; \
s->stride = stride; \
elem_size = sizeof(elemtype) * stride; \
s->slab_size = COMMIT_SLAB_SIZE / elem_size; \
s->slab_count = 0; \
s->slab = NULL; \
} \
\
static MAYBE_UNUSED void init_ ##slabname(struct slabname *s) \
{ \
init_ ##slabname## _with_stride(s, 1); \
} \
\
static MAYBE_UNUSED void clear_ ##slabname(struct slabname *s) \
{ \
unsigned int i; \
for (i = 0; i < s->slab_count; i++) \
free(s->slab[i]); \
s->slab_count = 0; \
FREE_AND_NULL(s->slab); \
} \
\
static MAYBE_UNUSED elemtype *slabname## _at_peek(struct slabname *s, \
const struct commit *c, \
int add_if_missing) \
{ \
unsigned int nth_slab, nth_slot; \
\
nth_slab = c->index / s->slab_size; \
nth_slot = c->index % s->slab_size; \
\
if (s->slab_count <= nth_slab) { \
unsigned int i; \
if (!add_if_missing) \
return NULL; \
REALLOC_ARRAY(s->slab, nth_slab + 1); \
stat_ ##slabname## realloc++; \
for (i = s->slab_count; i <= nth_slab; i++) \
s->slab[i] = NULL; \
s->slab_count = nth_slab + 1; \
} \
if (!s->slab[nth_slab]) { \
if (!add_if_missing) \
return NULL; \
s->slab[nth_slab] = xcalloc(s->slab_size, \
sizeof(**s->slab) * s->stride); \
} \
return &s->slab[nth_slab][nth_slot * s->stride]; \
} \
\
static MAYBE_UNUSED elemtype *slabname## _at(struct slabname *s, \
const struct commit *c) \
{ \
return slabname##_at_peek(s, c, 1); \
} \
\
static MAYBE_UNUSED elemtype *slabname## _peek(struct slabname *s, \
const struct commit *c) \
{ \
return slabname##_at_peek(s, c, 0); \
} \
\
struct slabname
/*
* Note that this redundant forward declaration is required
* to allow a terminating semicolon, which makes instantiations look
* like function declarations. I.e., the expansion of
*
* define_commit_slab(indegree, int);
*
* ends in 'struct indegree;'. This would otherwise
* be a syntax error according (at least) to ISO C. It's hard to
* catch because GCC silently parses it by default.
*/
/*
* Statically initialize a commit slab named "var". Note that this
* evaluates "stride" multiple times! Example:
*
* struct indegree indegrees = COMMIT_SLAB_INIT(1, indegrees);
*
*/
#define COMMIT_SLAB_INIT(stride, var) { \
COMMIT_SLAB_SIZE / sizeof(**((var).slab)) / (stride), \
(stride), 0, NULL \
}
#define define_commit_slab(slabname, elemtype) \
declare_commit_slab(slabname, elemtype); \
implement_static_commit_slab(slabname, elemtype)
#endif /* COMMIT_SLAB_H */

View File

@ -1605,13 +1605,21 @@ int commit_tree_extended(const char *msg, size_t msg_len,
return result;
}
define_commit_slab(merge_desc_slab, struct merge_remote_desc *);
static struct merge_desc_slab merge_desc_slab = COMMIT_SLAB_INIT(1, merge_desc_slab);
struct merge_remote_desc *merge_remote_util(struct commit *commit)
{
return *merge_desc_slab_at(&merge_desc_slab, commit);
}
void set_merge_remote_desc(struct commit *commit,
const char *name, struct object *obj)
{
struct merge_remote_desc *desc;
FLEX_ALLOC_STR(desc, name, name);
desc->obj = obj;
commit->util = desc;
*merge_desc_slab_at(&merge_desc_slab, commit) = desc;
}
struct commit *get_merge_parent(const char *name)
@ -1623,7 +1631,7 @@ struct commit *get_merge_parent(const char *name)
return NULL;
obj = parse_object(&oid);
commit = (struct commit *)peel_to_type(name, 0, obj, OBJ_COMMIT);
if (commit && !commit->util)
if (commit && !merge_remote_util(commit))
set_merge_remote_desc(commit, name, obj);
return commit;
}

View File

@ -16,9 +16,13 @@ struct commit_list {
struct commit_list *next;
};
/*
* The size of this struct matters in full repo walk operations like
* 'git clone' or 'git gc'. Consider using commit-slab to attach data
* to a commit instead of adding new fields here.
*/
struct commit {
struct object object;
void *util;
timestamp_t date;
struct commit_list *parents;
@ -312,7 +316,7 @@ struct merge_remote_desc {
struct object *obj; /* the named object, could be a tag */
char name[FLEX_ARRAY];
};
#define merge_remote_util(commit) ((struct merge_remote_desc *)((commit)->util))
extern struct merge_remote_desc *merge_remote_util(struct commit *);
extern void set_merge_remote_desc(struct commit *commit,
const char *name, struct object *obj);

View File

@ -295,8 +295,12 @@ void show_decorations(struct rev_info *opt, struct commit *commit)
{
struct strbuf sb = STRBUF_INIT;
if (opt->show_source && commit->util)
fprintf(opt->diffopt.file, "\t%s", (char *) commit->util);
if (opt->sources) {
char **slot = revision_sources_peek(opt->sources, commit);
if (slot && *slot)
fprintf(opt->diffopt.file, "\t%s", *slot);
}
if (!opt->show_decorations)
return;
format_decorations(&sb, commit, opt->diffopt.use_color);

View File

@ -286,10 +286,12 @@ static void output(struct merge_options *o, int v, const char *fmt, ...)
static void output_commit_title(struct merge_options *o, struct commit *commit)
{
struct merge_remote_desc *desc;
strbuf_addchars(&o->obuf, ' ', o->call_depth * 2);
if (commit->util)
strbuf_addf(&o->obuf, "virtual %s\n",
merge_remote_util(commit)->name);
desc = merge_remote_util(commit);
if (desc)
strbuf_addf(&o->obuf, "virtual %s\n", desc->name);
else {
strbuf_add_unique_abbrev(&o->obuf, &commit->object.oid,
DEFAULT_ABBREV);

View File

@ -42,6 +42,7 @@ struct object_array {
* builtin/index-pack.c: 2021
* builtin/pack-objects.c: 20
* builtin/reflog.c: 10--12
* builtin/show-branch.c: 0-------------------------------------------26
* builtin/unpack-objects.c: 2021
*/
#define FLAG_BITS 27

View File

@ -29,6 +29,8 @@ volatile show_early_output_fn_t show_early_output;
static const char *term_bad;
static const char *term_good;
implement_shared_commit_slab(revision_sources, char *);
void show_object_with_name(FILE *out, struct object *obj, const char *name)
{
const char *p;
@ -265,14 +267,19 @@ static struct commit *handle_commit(struct rev_info *revs,
*/
if (object->type == OBJ_COMMIT) {
struct commit *commit = (struct commit *)object;
if (parse_commit(commit) < 0)
die("unable to parse commit %s", name);
if (flags & UNINTERESTING) {
mark_parents_uninteresting(commit);
revs->limited = 1;
}
if (revs->show_source && !commit->util)
commit->util = xstrdup(name);
if (revs->sources) {
char **slot = revision_sources_at(revs->sources, commit);
if (!*slot)
*slot = xstrdup(name);
}
return commit;
}
@ -824,8 +831,12 @@ static int add_parents_to_list(struct rev_info *revs, struct commit *commit,
}
return -1;
}
if (revs->show_source && !p->util)
p->util = commit->util;
if (revs->sources) {
char **slot = revision_sources_at(revs->sources, p);
if (!*slot)
*slot = *revision_sources_at(revs->sources, commit);
}
p->object.flags |= left_flag;
if (!(p->object.flags & SEEN)) {
p->object.flags |= SEEN;

View File

@ -6,6 +6,7 @@
#include "notes.h"
#include "pretty.h"
#include "diff.h"
#include "commit-slab-decl.h"
/* Remember to update object flag allocation in object.h */
#define SEEN (1u<<0)
@ -29,6 +30,7 @@ struct rev_info;
struct log_info;
struct string_list;
struct saved_parents;
define_shared_commit_slab(revision_sources, char *);
struct rev_cmdline_info {
unsigned int nr;
@ -111,7 +113,6 @@ struct rev_info {
right_only:1,
rewrite_parents:1,
print_parents:1,
show_source:1,
show_decorations:1,
reverse:1,
reverse_output_stage:1,
@ -224,6 +225,8 @@ struct rev_info {
struct commit_list *previous_parents;
const char *break_bar;
struct revision_sources *sources;
};
extern int ref_excluded(struct string_list *, const char *path);

View File

@ -27,6 +27,7 @@
#include "worktree.h"
#include "oidmap.h"
#include "oidset.h"
#include "commit-slab.h"
#include "alias.h"
#define GIT_REFLOG_ACTION "GIT_REFLOG_ACTION"
@ -4238,6 +4239,7 @@ static enum check_level get_missing_commit_check_level(void)
return CHECK_IGNORE;
}
define_commit_slab(commit_seen, unsigned char);
/*
* Check if the user dropped some commits by mistake
* Behaviour determined by rebase.missingCommitsCheck.
@ -4251,6 +4253,9 @@ int check_todo_list(void)
struct todo_list todo_list = TODO_LIST_INIT;
struct strbuf missing = STRBUF_INIT;
int advise_to_edit_todo = 0, res = 0, i;
struct commit_seen commit_seen;
init_commit_seen(&commit_seen);
strbuf_addstr(&todo_file, rebase_path_todo());
if (strbuf_read_file_or_whine(&todo_list.buf, todo_file.buf) < 0) {
@ -4267,7 +4272,7 @@ int check_todo_list(void)
for (i = 0; i < todo_list.nr; i++) {
struct commit *commit = todo_list.items[i].commit;
if (commit)
commit->util = (void *)1;
*commit_seen_at(&commit_seen, commit) = 1;
}
todo_list_release(&todo_list);
@ -4283,11 +4288,11 @@ int check_todo_list(void)
for (i = todo_list.nr - 1; i >= 0; i--) {
struct todo_item *item = todo_list.items + i;
struct commit *commit = item->commit;
if (commit && !commit->util) {
if (commit && !*commit_seen_at(&commit_seen, commit)) {
strbuf_addf(&missing, " - %s %.*s\n",
short_commit_name(commit),
item->arg_len, item->arg);
commit->util = (void *)1;
*commit_seen_at(&commit_seen, commit) = 1;
}
}
@ -4313,6 +4318,7 @@ int check_todo_list(void)
"The possible behaviours are: ignore, warn, error.\n\n"));
leave_check:
clear_commit_seen(&commit_seen);
strbuf_release(&todo_file);
todo_list_release(&todo_list);
@ -4433,6 +4439,8 @@ static int subject2item_cmp(const void *fndata,
return key ? strcmp(a->subject, key) : strcmp(a->subject, b->subject);
}
define_commit_slab(commit_todo_item, struct todo_item *);
/*
* Rearrange the todo list that has both "pick commit-id msg" and "pick
* commit-id fixup!/squash! msg" in it so that the latter is put immediately
@ -4449,6 +4457,7 @@ int rearrange_squash(void)
struct hashmap subject2item;
int res = 0, rearranged = 0, *next, *tail, i;
char **subjects;
struct commit_todo_item commit_todo;
if (strbuf_read_file_or_whine(&todo_list.buf, todo_file) < 0)
return -1;
@ -4457,6 +4466,7 @@ int rearrange_squash(void)
return -1;
}
init_commit_todo_item(&commit_todo);
/*
* The hashmap maps onelines to the respective todo list index.
*
@ -4487,10 +4497,11 @@ int rearrange_squash(void)
if (is_fixup(item->command)) {
todo_list_release(&todo_list);
clear_commit_todo_item(&commit_todo);
return error(_("the script was already rearranged."));
}
item->commit->util = item;
*commit_todo_item_at(&commit_todo, item->commit) = item;
parse_commit(item->commit);
commit_buffer = get_commit_buffer(item->commit, NULL);
@ -4517,9 +4528,9 @@ int rearrange_squash(void)
else if (!strchr(p, ' ') &&
(commit2 =
lookup_commit_reference_by_name(p)) &&
commit2->util)
*commit_todo_item_at(&commit_todo, commit2))
/* found by commit name */
i2 = (struct todo_item *)commit2->util
i2 = *commit_todo_item_at(&commit_todo, commit2)
- todo_list.items;
else {
/* copy can be a prefix of the commit subject */
@ -4596,5 +4607,6 @@ int rearrange_squash(void)
hashmap_free(&subject2item, 1);
todo_list_release(&todo_list);
clear_commit_todo_item(&commit_todo);
return res;
}

View File

@ -12,6 +12,7 @@
#include "commit-slab.h"
#include "revision.h"
#include "list-objects.h"
#include "commit-slab.h"
static int is_shallow = -1;
static struct stat_validity shallow_stat;
@ -74,6 +75,11 @@ int is_repository_shallow(void)
return is_shallow;
}
/*
* TODO: use "int" elemtype instead of "int *" when/if commit-slab
* supports a "valid" flag.
*/
define_commit_slab(commit_depth, int *);
struct commit_list *get_shallow_commits(struct object_array *heads, int depth,
int shallow_flag, int not_shallow_flag)
{
@ -82,25 +88,29 @@ struct commit_list *get_shallow_commits(struct object_array *heads, int depth,
struct object_array stack = OBJECT_ARRAY_INIT;
struct commit *commit = NULL;
struct commit_graft *graft;
struct commit_depth depths;
init_commit_depth(&depths);
while (commit || i < heads->nr || stack.nr) {
struct commit_list *p;
if (!commit) {
if (i < heads->nr) {
int **depth_slot;
commit = (struct commit *)
deref_tag(heads->objects[i++].item, NULL, 0);
if (!commit || commit->object.type != OBJ_COMMIT) {
commit = NULL;
continue;
}
if (!commit->util)
commit->util = xmalloc(sizeof(int));
*(int *)commit->util = 0;
depth_slot = commit_depth_at(&depths, commit);
if (!*depth_slot)
*depth_slot = xmalloc(sizeof(int));
**depth_slot = 0;
cur_depth = 0;
} else {
commit = (struct commit *)
object_array_pop(&stack);
cur_depth = *(int *)commit->util;
cur_depth = **commit_depth_at(&depths, commit);
}
}
parse_commit_or_die(commit);
@ -116,25 +126,31 @@ struct commit_list *get_shallow_commits(struct object_array *heads, int depth,
}
commit->object.flags |= not_shallow_flag;
for (p = commit->parents, commit = NULL; p; p = p->next) {
if (!p->item->util) {
int *pointer = xmalloc(sizeof(int));
p->item->util = pointer;
*pointer = cur_depth;
int **depth_slot = commit_depth_at(&depths, p->item);
if (!*depth_slot) {
*depth_slot = xmalloc(sizeof(int));
**depth_slot = cur_depth;
} else {
int *pointer = p->item->util;
if (cur_depth >= *pointer)
if (cur_depth >= **depth_slot)
continue;
*pointer = cur_depth;
**depth_slot = cur_depth;
}
if (p->next)
add_object_array(&p->item->object,
NULL, &stack);
else {
commit = p->item;
cur_depth = *(int *)commit->util;
cur_depth = **commit_depth_at(&depths, commit);
}
}
}
for (i = 0; i < depths.slab_count; i++) {
int j;
for (j = 0; j < depths.slab_size; j++)
free(depths.slab[i][j]);
}
clear_commit_depth(&depths);
return result;
}