Skip to content

Commit 5b3e9a8

Browse files
committed
odb: add write_packfile, for_each_unique_abbrev, convert_object_id
Add three vtable methods to odb_source that were not part of the recent ps/odb-sources and ps/object-counting series: - write_packfile: ingest a pack from a file descriptor. The files backend chooses between index-pack (large packs) and unpack-objects (small packs below fetch.unpackLimit). Options cover thin-pack fixing, promisor marking, fsck, lockfile capture, and shallow file passing. - for_each_unique_abbrev: iterate objects matching a hex prefix for disambiguation. Searches loose objects via oidtree, then multi-pack indices, then non-MIDX packs. - convert_object_id: translate between hash algorithms using the loose object map. Used during SHA-1 to SHA-256 migration. Also add ODB_SOURCE_HELPER to the source type enum, preparing for the helper backend in the next commit. The write_packfile vtable method replaces the pattern where callers spawn index-pack/unpack-objects directly. fast-import already uses odb_write_packfile() and this allows non-files backends to handle pack ingestion through their own mechanism. Signed-off-by: Aaron Paterson <apaterson@pm.me>
1 parent 41688c1 commit 5b3e9a8

File tree

6 files changed

+498
-36
lines changed

6 files changed

+498
-36
lines changed

builtin/fast-import.c

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -876,10 +876,7 @@ static void end_packfile(void)
876876
running = 1;
877877
clear_delta_base_cache();
878878
if (object_count) {
879-
struct odb_source_files *files = odb_source_files_downcast(pack_data->repo->objects->sources);
880-
struct packed_git *new_p;
881879
struct object_id cur_pack_oid;
882-
char *idx_name;
883880
int i;
884881
struct branch *b;
885882
struct tag *t;
@@ -891,26 +888,25 @@ static void end_packfile(void)
891888
object_count, cur_pack_oid.hash,
892889
pack_size);
893890

894-
if (object_count <= unpack_limit) {
895-
if (!loosen_small_pack(pack_data)) {
896-
invalidate_pack_id(pack_id);
897-
goto discard_pack;
898-
}
899-
}
891+
if (lseek(pack_data->pack_fd, 0, SEEK_SET) < 0)
892+
die_errno(_("failed seeking to start of '%s'"),
893+
pack_data->pack_name);
900894

901-
close(pack_data->pack_fd);
902-
idx_name = keep_pack(create_index());
895+
if (odb_write_packfile(the_repository->objects,
896+
pack_data->pack_fd, NULL))
897+
die(_("failed to ingest pack"));
903898

904-
/* Register the packfile with core git's machinery. */
905-
new_p = packfile_store_load_pack(files->packed, idx_name, 1);
906-
if (!new_p)
907-
die(_("core Git rejected index %s"), idx_name);
908-
all_packs[pack_id] = new_p;
909-
free(idx_name);
899+
/*
900+
* Non-files backends do not register a pack on disk,
901+
* so NULL out the slot to prevent use-after-free in
902+
* gfi_unpack_entry.
903+
*/
904+
all_packs[pack_id] = NULL;
910905

911906
/* Print the boundary */
912907
if (pack_edges) {
913-
fprintf(pack_edges, "%s:", new_p->pack_name);
908+
fprintf(pack_edges, "pack-%s:",
909+
hash_to_hex(pack_data->hash));
914910
for (i = 0; i < branch_table_sz; i++) {
915911
for (b = branch_table[i]; b; b = b->table_next_branch) {
916912
if (b->pack_id == pack_id)
@@ -1239,6 +1235,17 @@ static void *gfi_unpack_entry(
12391235
{
12401236
enum object_type type;
12411237
struct packed_git *p = all_packs[oe->pack_id];
1238+
if (!p) {
1239+
/*
1240+
* Pack was ingested by a non-files backend via
1241+
* odb_write_packfile() and is no longer on disk.
1242+
* Read the object back through the ODB instead.
1243+
*/
1244+
enum object_type type;
1245+
enum object_type odb_type;
1246+
return odb_read_object(the_repository->objects,
1247+
&oe->idx.oid, &odb_type, sizep);
1248+
}
12421249
if (p == pack_data && p->pack_size < (pack_size + the_hash_algo->rawsz)) {
12431250
/* The object is stored in the packfile we are writing to
12441251
* and we have modified it since the last time we scanned

object-name.c

Lines changed: 61 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "packfile.h"
2121
#include "pretty.h"
2222
#include "object-file.h"
23+
#include "odb/source.h"
2324
#include "read-cache-ll.h"
2425
#include "repo-settings.h"
2526
#include "repository.h"
@@ -111,13 +112,28 @@ static enum cb_next match_prefix(const struct object_id *oid, void *arg)
111112
return ds->ambiguous ? CB_BREAK : CB_CONTINUE;
112113
}
113114

115+
static int disambiguate_cb(const struct object_id *oid,
116+
struct object_info *oi UNUSED, void *data)
117+
{
118+
struct disambiguate_state *ds = data;
119+
update_candidates(ds, oid);
120+
return ds->ambiguous ? 1 : 0;
121+
}
122+
114123
static void find_short_object_filename(struct disambiguate_state *ds)
115124
{
116125
struct odb_source *source;
117126

118-
for (source = ds->repo->objects->sources; source && !ds->ambiguous; source = source->next)
119-
oidtree_each(odb_source_loose_cache(source, &ds->bin_pfx),
120-
&ds->bin_pfx, ds->len, match_prefix, ds);
127+
for (source = ds->repo->objects->sources; source && !ds->ambiguous; source = source->next) {
128+
if (source->for_each_unique_abbrev) {
129+
odb_source_for_each_unique_abbrev(
130+
source, &ds->bin_pfx, ds->len,
131+
disambiguate_cb, ds);
132+
} else {
133+
oidtree_each(odb_source_loose_cache(source, &ds->bin_pfx),
134+
&ds->bin_pfx, ds->len, match_prefix, ds);
135+
}
136+
}
121137
}
122138

123139
static int match_hash(unsigned len, const unsigned char *a, const unsigned char *b)
@@ -208,15 +224,23 @@ static void find_short_packed_object(struct disambiguate_state *ds)
208224

209225
odb_prepare_alternates(ds->repo->objects);
210226
for (source = ds->repo->objects->sources; source && !ds->ambiguous; source = source->next) {
211-
struct multi_pack_index *m = get_multi_pack_index(source);
212-
if (m)
213-
unique_in_midx(m, ds);
227+
if (source->for_each_unique_abbrev) {
228+
odb_source_for_each_unique_abbrev(
229+
source, &ds->bin_pfx, ds->len,
230+
disambiguate_cb, ds);
231+
} else {
232+
struct multi_pack_index *m = get_multi_pack_index(source);
233+
if (m)
234+
unique_in_midx(m, ds);
235+
}
214236
}
215237

216-
repo_for_each_pack(ds->repo, p) {
217-
if (ds->ambiguous)
218-
break;
219-
unique_in_pack(p, ds);
238+
if (!ds->repo->objects->sources->for_each_unique_abbrev) {
239+
repo_for_each_pack(ds->repo, p) {
240+
if (ds->ambiguous)
241+
break;
242+
unique_in_pack(p, ds);
243+
}
220244
}
221245
}
222246

@@ -796,19 +820,38 @@ static void find_abbrev_len_for_pack(struct packed_git *p,
796820
mad->init_len = mad->cur_len;
797821
}
798822

799-
static void find_abbrev_len_packed(struct min_abbrev_data *mad)
823+
static int abbrev_len_cb(const struct object_id *oid,
824+
struct object_info *oi UNUSED, void *data)
800825
{
801-
struct packed_git *p;
826+
struct min_abbrev_data *mad = data;
827+
extend_abbrev_len(oid, mad);
828+
return 0;
829+
}
802830

831+
static void find_abbrev_len_packed(struct min_abbrev_data *mad)
832+
{
803833
odb_prepare_alternates(mad->repo->objects);
804-
for (struct odb_source *source = mad->repo->objects->sources; source; source = source->next) {
805-
struct multi_pack_index *m = get_multi_pack_index(source);
806-
if (m)
807-
find_abbrev_len_for_midx(m, mad);
834+
835+
for (struct odb_source *source = mad->repo->objects->sources;
836+
source; source = source->next) {
837+
if (source->for_each_unique_abbrev) {
838+
mad->init_len = 0;
839+
odb_source_for_each_unique_abbrev(
840+
source, mad->oid, mad->cur_len,
841+
abbrev_len_cb, mad);
842+
mad->init_len = mad->cur_len;
843+
} else {
844+
struct multi_pack_index *m = get_multi_pack_index(source);
845+
if (m)
846+
find_abbrev_len_for_midx(m, mad);
847+
}
808848
}
809849

810-
repo_for_each_pack(mad->repo, p)
811-
find_abbrev_len_for_pack(p, mad);
850+
if (!mad->repo->objects->sources->for_each_unique_abbrev) {
851+
struct packed_git *p;
852+
repo_for_each_pack(mad->repo, p)
853+
find_abbrev_len_for_pack(p, mad);
854+
}
812855
}
813856

814857
void strbuf_repo_add_unique_abbrev(struct strbuf *sb, struct repository *repo,

odb.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -981,6 +981,32 @@ int odb_write_object_stream(struct object_database *odb,
981981
return odb_source_write_object_stream(odb->sources, stream, len, oid);
982982
}
983983

984+
int odb_write_packfile(struct object_database *odb,
985+
int pack_fd,
986+
struct odb_write_packfile_options *opts)
987+
{
988+
return odb_source_write_packfile(odb->sources, pack_fd, opts);
989+
}
990+
991+
int odb_for_each_unique_abbrev(struct object_database *odb,
992+
const struct object_id *oid_prefix,
993+
unsigned int prefix_len,
994+
odb_for_each_object_cb cb,
995+
void *cb_data)
996+
{
997+
int ret;
998+
999+
odb_prepare_alternates(odb);
1000+
for (struct odb_source *source = odb->sources; source; source = source->next) {
1001+
ret = odb_source_for_each_unique_abbrev(source, oid_prefix,
1002+
prefix_len, cb, cb_data);
1003+
if (ret)
1004+
return ret;
1005+
}
1006+
1007+
return 0;
1008+
}
1009+
9841010
struct object_database *odb_new(struct repository *repo,
9851011
const char *primary_source,
9861012
const char *secondary_sources)

odb.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -570,6 +570,25 @@ int odb_write_object_stream(struct object_database *odb,
570570
struct odb_write_stream *stream, size_t len,
571571
struct object_id *oid);
572572

573+
/*
574+
* Ingest a pack from a file descriptor into the primary source.
575+
* Returns 0 on success, a negative error code otherwise.
576+
*/
577+
struct odb_write_packfile_options;
578+
int odb_write_packfile(struct object_database *odb,
579+
int pack_fd,
580+
struct odb_write_packfile_options *opts);
581+
582+
/*
583+
* Iterate over all objects across all sources whose ID starts with
584+
* the given prefix. Used for object name disambiguation.
585+
*/
586+
int odb_for_each_unique_abbrev(struct object_database *odb,
587+
const struct object_id *oid_prefix,
588+
unsigned int prefix_len,
589+
odb_for_each_object_cb cb,
590+
void *cb_data);
591+
573592
void parse_alternates(const char *string,
574593
int sep,
575594
const char *relative_base,

0 commit comments

Comments
 (0)