|
3 | 3 | #include "object-store.h" |
4 | 4 | #include "packfile.h" |
5 | 5 | #include "config.h" |
| 6 | +#include "midx.h" |
6 | 7 |
|
7 | 8 | struct revindex_entry { |
8 | 9 | off_t offset; |
@@ -292,6 +293,43 @@ int load_pack_revindex(struct packed_git *p) |
292 | 293 | return -1; |
293 | 294 | } |
294 | 295 |
|
| 296 | +int load_midx_revindex(struct multi_pack_index *m) |
| 297 | +{ |
| 298 | + char *revindex_name; |
| 299 | + int ret; |
| 300 | + if (m->revindex_data) |
| 301 | + return 0; |
| 302 | + |
| 303 | + revindex_name = get_midx_rev_filename(m); |
| 304 | + |
| 305 | + ret = load_revindex_from_disk(revindex_name, |
| 306 | + m->num_objects, |
| 307 | + &m->revindex_map, |
| 308 | + &m->revindex_len); |
| 309 | + if (ret) |
| 310 | + goto cleanup; |
| 311 | + |
| 312 | + m->revindex_data = (const uint32_t *)((const char *)m->revindex_map + RIDX_HEADER_SIZE); |
| 313 | + |
| 314 | +cleanup: |
| 315 | + free(revindex_name); |
| 316 | + return ret; |
| 317 | +} |
| 318 | + |
| 319 | +int close_midx_revindex(struct multi_pack_index *m) |
| 320 | +{ |
| 321 | + if (!m || !m->revindex_map) |
| 322 | + return 0; |
| 323 | + |
| 324 | + munmap((void*)m->revindex_map, m->revindex_len); |
| 325 | + |
| 326 | + m->revindex_map = NULL; |
| 327 | + m->revindex_data = NULL; |
| 328 | + m->revindex_len = 0; |
| 329 | + |
| 330 | + return 0; |
| 331 | +} |
| 332 | + |
295 | 333 | int offset_to_pack_pos(struct packed_git *p, off_t ofs, uint32_t *pos) |
296 | 334 | { |
297 | 335 | unsigned lo, hi; |
@@ -346,3 +384,91 @@ off_t pack_pos_to_offset(struct packed_git *p, uint32_t pos) |
346 | 384 | else |
347 | 385 | return nth_packed_object_offset(p, pack_pos_to_index(p, pos)); |
348 | 386 | } |
| 387 | + |
| 388 | +uint32_t pack_pos_to_midx(struct multi_pack_index *m, uint32_t pos) |
| 389 | +{ |
| 390 | + if (!m->revindex_data) |
| 391 | + BUG("pack_pos_to_midx: reverse index not yet loaded"); |
| 392 | + if (m->num_objects <= pos) |
| 393 | + BUG("pack_pos_to_midx: out-of-bounds object at %"PRIu32, pos); |
| 394 | + return get_be32(m->revindex_data + pos); |
| 395 | +} |
| 396 | + |
| 397 | +struct midx_pack_key { |
| 398 | + uint32_t pack; |
| 399 | + off_t offset; |
| 400 | + |
| 401 | + uint32_t preferred_pack; |
| 402 | + struct multi_pack_index *midx; |
| 403 | +}; |
| 404 | + |
| 405 | +static int midx_pack_order_cmp(const void *va, const void *vb) |
| 406 | +{ |
| 407 | + const struct midx_pack_key *key = va; |
| 408 | + struct multi_pack_index *midx = key->midx; |
| 409 | + |
| 410 | + uint32_t versus = pack_pos_to_midx(midx, (uint32_t*)vb - (const uint32_t *)midx->revindex_data); |
| 411 | + uint32_t versus_pack = nth_midxed_pack_int_id(midx, versus); |
| 412 | + off_t versus_offset; |
| 413 | + |
| 414 | + uint32_t key_preferred = key->pack == key->preferred_pack; |
| 415 | + uint32_t versus_preferred = versus_pack == key->preferred_pack; |
| 416 | + |
| 417 | + /* |
| 418 | + * First, compare the preferred-ness, noting that the preferred pack |
| 419 | + * comes first. |
| 420 | + */ |
| 421 | + if (key_preferred && !versus_preferred) |
| 422 | + return -1; |
| 423 | + else if (!key_preferred && versus_preferred) |
| 424 | + return 1; |
| 425 | + |
| 426 | + /* Then, break ties first by comparing the pack IDs. */ |
| 427 | + if (key->pack < versus_pack) |
| 428 | + return -1; |
| 429 | + else if (key->pack > versus_pack) |
| 430 | + return 1; |
| 431 | + |
| 432 | + /* Finally, break ties by comparing offsets within a pack. */ |
| 433 | + versus_offset = nth_midxed_offset(midx, versus); |
| 434 | + if (key->offset < versus_offset) |
| 435 | + return -1; |
| 436 | + else if (key->offset > versus_offset) |
| 437 | + return 1; |
| 438 | + |
| 439 | + return 0; |
| 440 | +} |
| 441 | + |
| 442 | +int midx_to_pack_pos(struct multi_pack_index *m, uint32_t at, uint32_t *pos) |
| 443 | +{ |
| 444 | + struct midx_pack_key key; |
| 445 | + uint32_t *found; |
| 446 | + |
| 447 | + if (!m->revindex_data) |
| 448 | + BUG("midx_to_pack_pos: reverse index not yet loaded"); |
| 449 | + if (m->num_objects <= at) |
| 450 | + BUG("midx_to_pack_pos: out-of-bounds object at %"PRIu32, at); |
| 451 | + |
| 452 | + key.pack = nth_midxed_pack_int_id(m, at); |
| 453 | + key.offset = nth_midxed_offset(m, at); |
| 454 | + key.midx = m; |
| 455 | + /* |
| 456 | + * The preferred pack sorts first, so determine its identifier by |
| 457 | + * looking at the first object in pseudo-pack order. |
| 458 | + * |
| 459 | + * Note that if no --preferred-pack is explicitly given when writing a |
| 460 | + * multi-pack index, then whichever pack has the lowest identifier |
| 461 | + * implicitly is preferred (and includes all its objects, since ties are |
| 462 | + * broken first by pack identifier). |
| 463 | + */ |
| 464 | + key.preferred_pack = nth_midxed_pack_int_id(m, pack_pos_to_midx(m, 0)); |
| 465 | + |
| 466 | + found = bsearch(&key, m->revindex_data, m->num_objects, |
| 467 | + sizeof(*m->revindex_data), midx_pack_order_cmp); |
| 468 | + |
| 469 | + if (!found) |
| 470 | + return error("bad offset for revindex"); |
| 471 | + |
| 472 | + *pos = found - m->revindex_data; |
| 473 | + return 0; |
| 474 | +} |
0 commit comments