Skip to content

Commit 995c0e3

Browse files
LorenzoPegorarigitster
authored andcommitted
pack-write: add helper to fill promisor file after repack
A ".promisor" file may contain ref names (and their associated hashes) that were fetched at the time the corresponding packfile was downloaded. This information is used for debugging reasons. This information is stored as lines structured like this: "<oid> <ref>". Create a `copy_promisor_content()` helper function that allows this debugging info to not be lost after a `repack`, by copying it inside a new ".promisor" file. The function logic is the following: * Take all ".promisor" files contained inside the given `repo`. * Ignore those whose name is contained inside the given `strset not_repacked_names`, which basically acts as a "promisor ignorelist" (intended to be used for packfiles that have not been repacked). * Read each line of the remaining ".promisor" files, which can be: * "<oid> <ref>" if the ".promisor" file was never repacked. If so, add the time (in Unix time) at which the ".promisor" file was last modified <time> to the line, to obtain: "<oid> <ref> <time>". * "<oid> <ref> <time>" if the ".promisor" file was repacked. If so, don't modify it. * Ignore the line if its <oid> is not present inside the "<packtmp>-<dest_hex>.idx" file. * If the destination file "<packtmp>-<dest_hex>.promisor" does not already contain the line, append it to the file. The function assumes that the contents of all ".promisor" files are correctly formed. The time of last data modification, for never-repacked ".promisor" file, can be used when comparing the entries in it with entries in another ".promisor" file that did get repacked. With these timestamps, the debugger will be able to tell at which time the refs at the remote repository pointed at what object. Also, when looking at already repacked ".promisor" files, the same ref may appear multiple times, and having timestamps will help understanding what happened over time. Signed-off-by: LorenzoPegorari <lorenzo.pegorari2002@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent a9ee493 commit 995c0e3

File tree

1 file changed

+116
-0
lines changed

1 file changed

+116
-0
lines changed

repack-promisor.c

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,122 @@ static int write_oid(const struct object_id *oid,
3434
return 0;
3535
}
3636

37+
/*
38+
* Go through all .promisor files contained in repo (excluding those whose name
39+
* appears in not_repacked_basenames, which acts as a ignorelist), and copies
40+
* their content inside the destination file "<packtmp>-<dest_hex>.promisor".
41+
* Each line of a never repacked .promisor file is: "<oid> <ref>" (as described
42+
* in the write_promisor_file() function).
43+
* After a repack, the copied lines will be: "<oid> <ref> <time>", where <time>
44+
* is the time (in Unix time) at which the .promisor file was last modified.
45+
* Only the lines whose <oid> is present inside "<packtmp>-<dest_hex>.idx" will
46+
* be copied.
47+
* The contents of all .promisor files are assumed to be correctly formed.
48+
*/
49+
static void copy_promisor_content(struct repository *repo,
50+
const char *dest_hex,
51+
const char *packtmp,
52+
struct strset *not_repacked_basenames)
53+
{
54+
char *dest_idx_name;
55+
char *dest_promisor_name;
56+
FILE *dest;
57+
struct strset dest_content = STRSET_INIT;
58+
struct strbuf dest_to_write = STRBUF_INIT;
59+
struct strbuf source_promisor_name = STRBUF_INIT;
60+
struct strbuf line = STRBUF_INIT;
61+
struct object_id dest_oid;
62+
struct packed_git *dest_pack, *p;
63+
int err;
64+
65+
dest_idx_name = mkpathdup("%s-%s.idx", packtmp, dest_hex);
66+
get_oid_hex_algop(dest_hex, &dest_oid, repo->hash_algo);
67+
dest_pack = parse_pack_index(repo, dest_oid.hash, dest_idx_name);
68+
69+
/* Open the .promisor dest file, and fill dest_content with its content */
70+
dest_promisor_name = mkpathdup("%s-%s.promisor", packtmp, dest_hex);
71+
dest = xfopen(dest_promisor_name, "r+");
72+
while (strbuf_getline(&line, dest) != EOF)
73+
strset_add(&dest_content, line.buf);
74+
75+
repo_for_each_pack(repo, p) {
76+
FILE *source;
77+
struct stat source_stat;
78+
79+
if (!p->pack_promisor)
80+
continue;
81+
82+
if (not_repacked_basenames &&
83+
strset_contains(not_repacked_basenames, pack_basename(p)))
84+
continue;
85+
86+
strbuf_reset(&source_promisor_name);
87+
strbuf_addstr(&source_promisor_name, p->pack_name);
88+
strbuf_strip_suffix(&source_promisor_name, ".pack");
89+
strbuf_addstr(&source_promisor_name, ".promisor");
90+
91+
if (stat(source_promisor_name.buf, &source_stat))
92+
die(_("File not found: %s"), source_promisor_name.buf);
93+
94+
source = xfopen(source_promisor_name.buf, "r");
95+
96+
while (strbuf_getline(&line, source) != EOF) {
97+
struct string_list line_sections = STRING_LIST_INIT_DUP;
98+
struct object_id oid;
99+
100+
/* Split line into <oid>, <ref> and <time> (if <time> exists) */
101+
string_list_split(&line_sections, line.buf, " ", 3);
102+
103+
/* Ignore the lines where <oid> doesn't appear in the dest_pack */
104+
get_oid_hex_algop(line_sections.items[0].string, &oid, repo->hash_algo);
105+
if (!find_pack_entry_one(&oid, dest_pack)) {
106+
string_list_clear(&line_sections, 0);
107+
continue;
108+
}
109+
110+
/* If <time> doesn't exist, retrieve it and add it to line */
111+
if (line_sections.nr < 3)
112+
strbuf_addf(&line, " %lld", (long long int)source_stat.st_mtim.tv_sec);
113+
114+
/*
115+
* Add the finalized line to dest_to_write and dest_content if it
116+
* wasn't already present inside dest_content
117+
*/
118+
if (strset_add(&dest_content, line.buf)) {
119+
strbuf_addbuf(&dest_to_write, &line);
120+
strbuf_addch(&dest_to_write, '\n');
121+
}
122+
123+
string_list_clear(&line_sections, 0);
124+
}
125+
126+
err = ferror(source);
127+
err |= fclose(source);
128+
if (err)
129+
die(_("Could not read '%s' promisor file"), source_promisor_name.buf);
130+
}
131+
132+
/* If dest_to_write is not empty, then there are new lines to append */
133+
if (dest_to_write.len) {
134+
if (fseek(dest, 0L, SEEK_END))
135+
die_errno(_("fseek failed"));
136+
fprintf(dest, "%s", dest_to_write.buf);
137+
}
138+
139+
err = ferror(dest);
140+
err |= fclose(dest);
141+
if (err)
142+
die(_("Could not write '%s' promisor file"), dest_promisor_name);
143+
144+
close_pack_index(dest_pack);
145+
free(dest_idx_name);
146+
free(dest_promisor_name);
147+
strset_clear(&dest_content);
148+
strbuf_release(&dest_to_write);
149+
strbuf_release(&source_promisor_name);
150+
strbuf_release(&line);
151+
}
152+
37153
static void finish_repacking_promisor_objects(struct repository *repo,
38154
struct child_process *cmd,
39155
struct string_list *names,

0 commit comments

Comments
 (0)