|
38 | 38 | #define GRAPH_MIN_SIZE (5 * GRAPH_CHUNKLOOKUP_WIDTH + GRAPH_FANOUT_SIZE + \ |
39 | 39 | GRAPH_OID_LEN + 8) |
40 | 40 |
|
41 | | - |
42 | 41 | char *get_commit_graph_filename(const char *obj_dir) |
43 | 42 | { |
44 | 43 | return xstrfmt("%s/info/commit-graph", obj_dir); |
@@ -179,6 +178,145 @@ struct commit_graph *load_commit_graph_one(const char *graph_file) |
179 | 178 | exit(1); |
180 | 179 | } |
181 | 180 |
|
| 181 | +/* global storage */ |
| 182 | +struct commit_graph *commit_graph = NULL; |
| 183 | + |
| 184 | +static void prepare_commit_graph_one(const char *obj_dir) |
| 185 | +{ |
| 186 | +char *graph_name; |
| 187 | + |
| 188 | +if (commit_graph) |
| 189 | +return; |
| 190 | + |
| 191 | +graph_name = get_commit_graph_filename(obj_dir); |
| 192 | +commit_graph = load_commit_graph_one(graph_name); |
| 193 | + |
| 194 | +FREE_AND_NULL(graph_name); |
| 195 | +} |
| 196 | + |
| 197 | +static int prepare_commit_graph_run_once = 0; |
| 198 | +static void prepare_commit_graph(void) |
| 199 | +{ |
| 200 | +struct alternate_object_database *alt; |
| 201 | +char *obj_dir; |
| 202 | + |
| 203 | +if (prepare_commit_graph_run_once) |
| 204 | +return; |
| 205 | +prepare_commit_graph_run_once = 1; |
| 206 | + |
| 207 | +obj_dir = get_object_directory(); |
| 208 | +prepare_commit_graph_one(obj_dir); |
| 209 | +prepare_alt_odb(); |
| 210 | +for (alt = alt_odb_list; !commit_graph && alt; alt = alt->next) |
| 211 | +prepare_commit_graph_one(alt->path); |
| 212 | +} |
| 213 | + |
| 214 | +static void close_commit_graph(void) |
| 215 | +{ |
| 216 | +if (!commit_graph) |
| 217 | +return; |
| 218 | + |
| 219 | +if (commit_graph->graph_fd >= 0) { |
| 220 | +munmap((void *)commit_graph->data, commit_graph->data_len); |
| 221 | +commit_graph->data = NULL; |
| 222 | +close(commit_graph->graph_fd); |
| 223 | +} |
| 224 | + |
| 225 | +FREE_AND_NULL(commit_graph); |
| 226 | +} |
| 227 | + |
| 228 | +static int bsearch_graph(struct commit_graph *g, struct object_id *oid, uint32_t *pos) |
| 229 | +{ |
| 230 | +return bsearch_hash(oid->hash, g->chunk_oid_fanout, |
| 231 | + g->chunk_oid_lookup, g->hash_len, pos); |
| 232 | +} |
| 233 | + |
| 234 | +static struct commit_list **insert_parent_or_die(struct commit_graph *g, |
| 235 | + uint64_t pos, |
| 236 | + struct commit_list **pptr) |
| 237 | +{ |
| 238 | +struct commit *c; |
| 239 | +struct object_id oid; |
| 240 | +hashcpy(oid.hash, g->chunk_oid_lookup + g->hash_len * pos); |
| 241 | +c = lookup_commit(&oid); |
| 242 | +if (!c) |
| 243 | +die("could not find commit %s", oid_to_hex(&oid)); |
| 244 | +c->graph_pos = pos; |
| 245 | +return &commit_list_insert(c, pptr)->next; |
| 246 | +} |
| 247 | + |
| 248 | +static int fill_commit_in_graph(struct commit *item, struct commit_graph *g, uint32_t pos) |
| 249 | +{ |
| 250 | +struct object_id oid; |
| 251 | +uint32_t edge_value; |
| 252 | +uint32_t *parent_data_ptr; |
| 253 | +uint64_t date_low, date_high; |
| 254 | +struct commit_list **pptr; |
| 255 | +const unsigned char *commit_data = g->chunk_commit_data + (g->hash_len + 16) * pos; |
| 256 | + |
| 257 | +item->object.parsed = 1; |
| 258 | +item->graph_pos = pos; |
| 259 | + |
| 260 | +hashcpy(oid.hash, commit_data); |
| 261 | +item->tree = lookup_tree(&oid); |
| 262 | + |
| 263 | +date_high = get_be32(commit_data + g->hash_len + 8) & 0x3; |
| 264 | +date_low = get_be32(commit_data + g->hash_len + 12); |
| 265 | +item->date = (timestamp_t)((date_high << 32) | date_low); |
| 266 | + |
| 267 | +pptr = &item->parents; |
| 268 | + |
| 269 | +edge_value = get_be32(commit_data + g->hash_len); |
| 270 | +if (edge_value == GRAPH_PARENT_NONE) |
| 271 | +return 1; |
| 272 | +pptr = insert_parent_or_die(g, edge_value, pptr); |
| 273 | + |
| 274 | +edge_value = get_be32(commit_data + g->hash_len + 4); |
| 275 | +if (edge_value == GRAPH_PARENT_NONE) |
| 276 | +return 1; |
| 277 | +if (!(edge_value & GRAPH_OCTOPUS_EDGES_NEEDED)) { |
| 278 | +pptr = insert_parent_or_die(g, edge_value, pptr); |
| 279 | +return 1; |
| 280 | +} |
| 281 | + |
| 282 | +parent_data_ptr = (uint32_t*)(g->chunk_large_edges + |
| 283 | + 4 * (uint64_t)(edge_value & GRAPH_EDGE_LAST_MASK)); |
| 284 | +do { |
| 285 | +edge_value = get_be32(parent_data_ptr); |
| 286 | +pptr = insert_parent_or_die(g, |
| 287 | + edge_value & GRAPH_EDGE_LAST_MASK, |
| 288 | + pptr); |
| 289 | +parent_data_ptr++; |
| 290 | +} while (!(edge_value & GRAPH_LAST_EDGE)); |
| 291 | + |
| 292 | +return 1; |
| 293 | +} |
| 294 | + |
| 295 | +int parse_commit_in_graph(struct commit *item) |
| 296 | +{ |
| 297 | +if (!core_commit_graph) |
| 298 | +return 0; |
| 299 | +if (item->object.parsed) |
| 300 | +return 1; |
| 301 | + |
| 302 | +prepare_commit_graph(); |
| 303 | +if (commit_graph) { |
| 304 | +uint32_t pos; |
| 305 | +int found; |
| 306 | +if (item->graph_pos != COMMIT_NOT_FROM_GRAPH) { |
| 307 | +pos = item->graph_pos; |
| 308 | +found = 1; |
| 309 | +} else { |
| 310 | +found = bsearch_graph(commit_graph, &(item->object.oid), &pos); |
| 311 | +} |
| 312 | + |
| 313 | +if (found) |
| 314 | +return fill_commit_in_graph(item, commit_graph, pos); |
| 315 | +} |
| 316 | + |
| 317 | +return 0; |
| 318 | +} |
| 319 | + |
182 | 320 | static void write_graph_chunk_fanout(struct hashfile *f, |
183 | 321 | struct commit **commits, |
184 | 322 | int nr_commits) |
@@ -530,6 +668,7 @@ void write_commit_graph(const char *obj_dir) |
530 | 668 | write_graph_chunk_data(f, GRAPH_OID_LEN, commits.list, commits.nr); |
531 | 669 | write_graph_chunk_large_edges(f, commits.list, commits.nr); |
532 | 670 |
|
| 671 | +close_commit_graph(); |
533 | 672 | finalize_hashfile(f, NULL, CSUM_HASH_IN_STREAM | CSUM_FSYNC); |
534 | 673 | commit_lock_file(&lk); |
535 | 674 |
|
|
0 commit comments