Skip to content

Commit d75badf

Browse files
committed
Merge branch 'ps/odb-generic-object-name-handling'
Object name handling (disambiguation and abbreviation) has been refactored to be backend-generic, moving logic into the respective object database backends. * ps/odb-generic-object-name-handling: odb: introduce generic `odb_find_abbrev_len()` object-file: move logic to compute packed abbreviation length object-name: move logic to compute loose abbreviation length object-name: simplify computing common prefixes object-name: abbreviate loose object names without `disambiguate_state` object-name: merge `update_candidates()` and `match_prefix()` object-name: backend-generic `get_short_oid()` object-name: backend-generic `repo_collect_ambiguous()` object-name: extract function to parse object ID prefixes object-name: move logic to iterate through packed prefixed objects object-name: move logic to iterate through loose prefixed objects odb: introduce `struct odb_for_each_object_options` oidtree: extend iteration to allow for arbitrary return codes oidtree: modernize the code a bit object-file: fix sparse 'plain integer as NULL pointer' error
2 parents 2f8c3f6 + 83869e1 commit d75badf

19 files changed

Lines changed: 782 additions & 471 deletions

builtin/cat-file.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -848,6 +848,9 @@ static void batch_each_object(struct batch_options *opt,
848848
.callback = callback,
849849
.payload = _payload,
850850
};
851+
struct odb_for_each_object_options opts = {
852+
.flags = flags,
853+
};
851854
struct bitmap_index *bitmap = NULL;
852855
struct odb_source *source;
853856

@@ -860,7 +863,7 @@ static void batch_each_object(struct batch_options *opt,
860863
odb_prepare_alternates(the_repository->objects);
861864
for (source = the_repository->objects->sources; source; source = source->next) {
862865
int ret = odb_source_loose_for_each_object(source, NULL, batch_one_object_oi,
863-
&payload, flags);
866+
&payload, &opts);
864867
if (ret)
865868
break;
866869
}
@@ -884,7 +887,7 @@ static void batch_each_object(struct batch_options *opt,
884887
for (source = the_repository->objects->sources; source; source = source->next) {
885888
struct odb_source_files *files = odb_source_files_downcast(source);
886889
int ret = packfile_store_for_each_object(files->packed, &oi,
887-
batch_one_object_oi, &payload, flags);
890+
batch_one_object_oi, &payload, &opts);
888891
if (ret)
889892
break;
890893
}

builtin/pack-objects.c

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4359,6 +4359,12 @@ static void add_objects_in_unpacked_packs(void)
43594359
{
43604360
struct odb_source *source;
43614361
time_t mtime;
4362+
struct odb_for_each_object_options opts = {
4363+
.flags = ODB_FOR_EACH_OBJECT_PACK_ORDER |
4364+
ODB_FOR_EACH_OBJECT_LOCAL_ONLY |
4365+
ODB_FOR_EACH_OBJECT_SKIP_IN_CORE_KEPT_PACKS |
4366+
ODB_FOR_EACH_OBJECT_SKIP_ON_DISK_KEPT_PACKS,
4367+
};
43624368
struct object_info oi = {
43634369
.mtimep = &mtime,
43644370
};
@@ -4371,11 +4377,7 @@ static void add_objects_in_unpacked_packs(void)
43714377
continue;
43724378

43734379
if (packfile_store_for_each_object(files->packed, &oi,
4374-
add_object_in_unpacked_pack, NULL,
4375-
ODB_FOR_EACH_OBJECT_PACK_ORDER |
4376-
ODB_FOR_EACH_OBJECT_LOCAL_ONLY |
4377-
ODB_FOR_EACH_OBJECT_SKIP_IN_CORE_KEPT_PACKS |
4378-
ODB_FOR_EACH_OBJECT_SKIP_ON_DISK_KEPT_PACKS))
4380+
add_object_in_unpacked_pack, NULL, &opts))
43794381
die(_("cannot open pack index"));
43804382
}
43814383
}

cbtree.c

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -96,26 +96,28 @@ struct cb_node *cb_lookup(struct cb_tree *t, const uint8_t *k, size_t klen)
9696
return p && !memcmp(p->k, k, klen) ? p : NULL;
9797
}
9898

99-
static enum cb_next cb_descend(struct cb_node *p, cb_iter fn, void *arg)
99+
static int cb_descend(struct cb_node *p, cb_iter fn, void *arg)
100100
{
101101
if (1 & (uintptr_t)p) {
102102
struct cb_node *q = cb_node_of(p);
103-
enum cb_next n = cb_descend(q->child[0], fn, arg);
104-
105-
return n == CB_BREAK ? n : cb_descend(q->child[1], fn, arg);
103+
int ret = cb_descend(q->child[0], fn, arg);
104+
if (ret)
105+
return ret;
106+
return cb_descend(q->child[1], fn, arg);
106107
} else {
107108
return fn(p, arg);
108109
}
109110
}
110111

111-
void cb_each(struct cb_tree *t, const uint8_t *kpfx, size_t klen,
112-
cb_iter fn, void *arg)
112+
int cb_each(struct cb_tree *t, const uint8_t *kpfx, size_t klen,
113+
cb_iter fn, void *arg)
113114
{
114115
struct cb_node *p = t->root;
115116
struct cb_node *top = p;
116117
size_t i = 0;
117118

118-
if (!p) return; /* empty tree */
119+
if (!p)
120+
return 0; /* empty tree */
119121

120122
/* Walk tree, maintaining top pointer */
121123
while (1 & (uintptr_t)p) {
@@ -130,7 +132,8 @@ void cb_each(struct cb_tree *t, const uint8_t *kpfx, size_t klen,
130132

131133
for (i = 0; i < klen; i++) {
132134
if (p->k[i] != kpfx[i])
133-
return; /* "best" match failed */
135+
return 0; /* "best" match failed */
134136
}
135-
cb_descend(top, fn, arg);
137+
138+
return cb_descend(top, fn, arg);
136139
}

cbtree.h

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,6 @@ struct cb_tree {
3030
struct cb_node *root;
3131
};
3232

33-
enum cb_next {
34-
CB_CONTINUE = 0,
35-
CB_BREAK = 1
36-
};
37-
3833
#define CBTREE_INIT { 0 }
3934

4035
static inline void cb_init(struct cb_tree *t)
@@ -46,9 +41,15 @@ static inline void cb_init(struct cb_tree *t)
4641
struct cb_node *cb_lookup(struct cb_tree *, const uint8_t *k, size_t klen);
4742
struct cb_node *cb_insert(struct cb_tree *, struct cb_node *, size_t klen);
4843

49-
typedef enum cb_next (*cb_iter)(struct cb_node *, void *arg);
44+
/*
45+
* Callback invoked by `cb_each()` for each node in the critbit tree. A return
46+
* value of 0 will cause the iteration to continue, a non-zero return code will
47+
* cause iteration to abort. The error code will be relayed back from
48+
* `cb_each()` in that case.
49+
*/
50+
typedef int (*cb_iter)(struct cb_node *, void *arg);
5051

51-
void cb_each(struct cb_tree *, const uint8_t *kpfx, size_t klen,
52-
cb_iter, void *arg);
52+
int cb_each(struct cb_tree *, const uint8_t *kpfx, size_t klen,
53+
cb_iter, void *arg);
5354

5455
#endif /* CBTREE_H */

commit-graph.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1969,6 +1969,9 @@ static void fill_oids_from_all_packs(struct write_commit_graph_context *ctx)
19691969
{
19701970
struct odb_source *source;
19711971
enum object_type type;
1972+
struct odb_for_each_object_options opts = {
1973+
.flags = ODB_FOR_EACH_OBJECT_PACK_ORDER,
1974+
};
19721975
struct object_info oi = {
19731976
.typep = &type,
19741977
};
@@ -1983,7 +1986,7 @@ static void fill_oids_from_all_packs(struct write_commit_graph_context *ctx)
19831986
for (source = ctx->r->objects->sources; source; source = source->next) {
19841987
struct odb_source_files *files = odb_source_files_downcast(source);
19851988
packfile_store_for_each_object(files->packed, &oi, add_packed_commits_oi,
1986-
ctx, ODB_FOR_EACH_OBJECT_PACK_ORDER);
1989+
ctx, &opts);
19871990
}
19881991

19891992
if (ctx->progress_done < ctx->approx_nr_objects)

hash.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,3 +317,21 @@ const struct git_hash_algo *unsafe_hash_algo(const struct git_hash_algo *algop)
317317
/* Otherwise use the default one. */
318318
return algop;
319319
}
320+
321+
unsigned oid_common_prefix_hexlen(const struct object_id *a,
322+
const struct object_id *b)
323+
{
324+
unsigned rawsz = hash_algos[a->algo].rawsz;
325+
326+
for (unsigned i = 0; i < rawsz; i++) {
327+
if (a->hash[i] == b->hash[i])
328+
continue;
329+
330+
if ((a->hash[i] ^ b->hash[i]) & 0xf0)
331+
return i * 2;
332+
else
333+
return i * 2 + 1;
334+
}
335+
336+
return rawsz * 2;
337+
}

hash.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,9 @@ static inline int oideq(const struct object_id *oid1, const struct object_id *oi
396396
return !memcmp(oid1->hash, oid2->hash, GIT_MAX_RAWSZ);
397397
}
398398

399+
unsigned oid_common_prefix_hexlen(const struct object_id *a,
400+
const struct object_id *b);
401+
399402
static inline void oidcpy(struct object_id *dst, const struct object_id *src)
400403
{
401404
memcpy(dst->hash, src->hash, GIT_MAX_RAWSZ);

object-file.c

Lines changed: 70 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@
3333
/* The maximum size for an object header. */
3434
#define MAX_HEADER_LEN 32
3535

36+
static struct oidtree *odb_source_loose_cache(struct odb_source *source,
37+
const struct object_id *oid);
38+
3639
static int get_conv_flags(unsigned flags)
3740
{
3841
if (flags & INDEX_RENORMALIZE)
@@ -1845,11 +1848,28 @@ static int for_each_object_wrapper_cb(const struct object_id *oid,
18451848
}
18461849
}
18471850

1851+
static int for_each_prefixed_object_wrapper_cb(const struct object_id *oid,
1852+
void *cb_data)
1853+
{
1854+
struct for_each_object_wrapper_data *data = cb_data;
1855+
if (data->request) {
1856+
struct object_info oi = *data->request;
1857+
1858+
if (odb_source_loose_read_object_info(data->source,
1859+
oid, &oi, 0) < 0)
1860+
return -1;
1861+
1862+
return data->cb(oid, &oi, data->cb_data);
1863+
} else {
1864+
return data->cb(oid, NULL, data->cb_data);
1865+
}
1866+
}
1867+
18481868
int odb_source_loose_for_each_object(struct odb_source *source,
18491869
const struct object_info *request,
18501870
odb_for_each_object_cb cb,
18511871
void *cb_data,
1852-
unsigned flags)
1872+
const struct odb_for_each_object_options *opts)
18531873
{
18541874
struct for_each_object_wrapper_data data = {
18551875
.source = source,
@@ -1859,11 +1879,16 @@ int odb_source_loose_for_each_object(struct odb_source *source,
18591879
};
18601880

18611881
/* There are no loose promisor objects, so we can return immediately. */
1862-
if ((flags & ODB_FOR_EACH_OBJECT_PROMISOR_ONLY))
1882+
if ((opts->flags & ODB_FOR_EACH_OBJECT_PROMISOR_ONLY))
18631883
return 0;
1864-
if ((flags & ODB_FOR_EACH_OBJECT_LOCAL_ONLY) && !source->local)
1884+
if ((opts->flags & ODB_FOR_EACH_OBJECT_LOCAL_ONLY) && !source->local)
18651885
return 0;
18661886

1887+
if (opts->prefix)
1888+
return oidtree_each(odb_source_loose_cache(source, opts->prefix),
1889+
opts->prefix, opts->prefix_hex_len,
1890+
for_each_prefixed_object_wrapper_cb, &data);
1891+
18671892
return for_each_loose_file_in_source(source, for_each_object_wrapper_cb,
18681893
NULL, NULL, &data);
18691894
}
@@ -1914,9 +1939,10 @@ int odb_source_loose_count_objects(struct odb_source *source,
19141939
*out = count * 256;
19151940
ret = 0;
19161941
} else {
1942+
struct odb_for_each_object_options opts = { 0 };
19171943
*out = 0;
19181944
ret = odb_source_loose_for_each_object(source, NULL, count_loose_object,
1919-
out, 0);
1945+
out, &opts);
19201946
}
19211947

19221948
out:
@@ -1926,6 +1952,44 @@ int odb_source_loose_count_objects(struct odb_source *source,
19261952
return ret;
19271953
}
19281954

1955+
struct find_abbrev_len_data {
1956+
const struct object_id *oid;
1957+
unsigned len;
1958+
};
1959+
1960+
static int find_abbrev_len_cb(const struct object_id *oid,
1961+
struct object_info *oi UNUSED,
1962+
void *cb_data)
1963+
{
1964+
struct find_abbrev_len_data *data = cb_data;
1965+
unsigned len = oid_common_prefix_hexlen(oid, data->oid);
1966+
if (len != hash_algos[oid->algo].hexsz && len >= data->len)
1967+
data->len = len + 1;
1968+
return 0;
1969+
}
1970+
1971+
int odb_source_loose_find_abbrev_len(struct odb_source *source,
1972+
const struct object_id *oid,
1973+
unsigned min_len,
1974+
unsigned *out)
1975+
{
1976+
struct odb_for_each_object_options opts = {
1977+
.prefix = oid,
1978+
.prefix_hex_len = min_len,
1979+
};
1980+
struct find_abbrev_len_data data = {
1981+
.oid = oid,
1982+
.len = min_len,
1983+
};
1984+
int ret;
1985+
1986+
ret = odb_source_loose_for_each_object(source, NULL, find_abbrev_len_cb,
1987+
&data, &opts);
1988+
*out = data.len;
1989+
1990+
return ret;
1991+
}
1992+
19291993
static int append_loose_object(const struct object_id *oid,
19301994
const char *path UNUSED,
19311995
void *data)
@@ -1934,8 +1998,8 @@ static int append_loose_object(const struct object_id *oid,
19341998
return 0;
19351999
}
19362000

1937-
struct oidtree *odb_source_loose_cache(struct odb_source *source,
1938-
const struct object_id *oid)
2001+
static struct oidtree *odb_source_loose_cache(struct odb_source *source,
2002+
const struct object_id *oid)
19392003
{
19402004
struct odb_source_files *files = odb_source_files_downcast(source);
19412005
int subdir_nr = oid->hash[0];

object-file.h

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -74,13 +74,6 @@ int odb_source_loose_write_stream(struct odb_source *source,
7474
struct odb_write_stream *stream, size_t len,
7575
struct object_id *oid);
7676

77-
/*
78-
* Populate and return the loose object cache array corresponding to the
79-
* given object ID.
80-
*/
81-
struct oidtree *odb_source_loose_cache(struct odb_source *source,
82-
const struct object_id *oid);
83-
8477
/*
8578
* Put in `buf` the name of the file in the local object database that
8679
* would be used to store a loose object with the specified oid.
@@ -137,7 +130,7 @@ int odb_source_loose_for_each_object(struct odb_source *source,
137130
const struct object_info *request,
138131
odb_for_each_object_cb cb,
139132
void *cb_data,
140-
unsigned flags);
133+
const struct odb_for_each_object_options *opts);
141134

142135
/*
143136
* Count the number of loose objects in this source.
@@ -153,6 +146,18 @@ int odb_source_loose_count_objects(struct odb_source *source,
153146
enum odb_count_objects_flags flags,
154147
unsigned long *out);
155148

149+
/*
150+
* Find the shortest unique prefix for the given object ID, where `min_len` is
151+
* the minimum length that the prefix should have.
152+
*
153+
* Returns 0 on success, in which case the computed length will be written to
154+
* `out`. Otherwise, a negative error code is returned.
155+
*/
156+
int odb_source_loose_find_abbrev_len(struct odb_source *source,
157+
const struct object_id *oid,
158+
unsigned min_len,
159+
unsigned *out);
160+
156161
/**
157162
* format_object_header() is a thin wrapper around s xsnprintf() that
158163
* writes the initial "<type> <obj-len>" part of the loose object

0 commit comments

Comments
 (0)