commit b46b8f09728040b4d8ff7a93ea5236b90412f768 from: Stefan Sperling date: Thu Aug 14 16:45:11 2025 UTC improve selection of pack files for pinning in the open pack file cache If two given pack files contain the same amount of requested commits, prefer the pack file which contains the larger amount of total objects to increase our chances of full history traversal. Also, require the first element of the list of requested commits to be present in the pack file since the caller will very likely try to process this commit immediately when we return. This fixes cases where offloading of commit coloring to got-read-pack was ineffective, causing us to take the slow path instead. ok op@ commit - fff7e4bcbac58d0ef1b91d51636955f122c69aea commit + b46b8f09728040b4d8ff7a93ea5236b90412f768 blob - 4b84755e2c4557df4a09e1117470fc18cf23bcd9 blob + b0aa5bc15b2f5adb37972b7c68f53df5bbe8485d --- lib/pack_create.c +++ lib/pack_create.c @@ -1143,8 +1143,8 @@ got_pack_find_pack_for_commit_painting(struct got_pack *best_packidx = NULL; /* - * Find the largest pack which contains at least some of the - * commits we are interested in. + * Find the largest pack which contains the commit at the head + * of the queue and some other commits we are interested in. */ RB_FOREACH(pe, got_pathlist_head, &repo->packidx_paths) { const char *path_packidx = pe->path; @@ -1157,15 +1157,24 @@ got_pack_find_pack_for_commit_painting(struct got_pack break; nobj = be32toh(packidx->hdr.fanout_table[0xff]); - if (nobj <= nobj_max) + if (nobj < nobj_max) continue; - STAILQ_FOREACH(qid, ids, entry) { + qid = STAILQ_FIRST(ids); + idx = got_packidx_get_object_idx(packidx, &qid->id); + if (idx == -1) + continue; + ncommits++; + + qid = STAILQ_NEXT(qid, entry); + while (qid) { idx = got_packidx_get_object_idx(packidx, &qid->id); if (idx != -1) ncommits++; + qid = STAILQ_NEXT(qid, entry); } - if (ncommits > ncommits_max) { + + if (ncommits >= ncommits_max) { best_packidx_path = path_packidx; nobj_max = nobj; ncommits_max = ncommits; @@ -1280,9 +1289,12 @@ find_pack_for_enumeration(struct got_packidx **best_pa *best_packidx = NULL; + if (nids == 0) + return NULL; + /* - * Find the largest pack which contains at least some of the - * commits and tags we are interested in. + * Find the largest pack which contains the commit at the head + * of the queue and some other commits we are interested in. */ RB_FOREACH(pe, got_pathlist_head, &repo->packidx_paths) { const char *path_packidx = pe->path; @@ -1294,15 +1306,20 @@ find_pack_for_enumeration(struct got_packidx **best_pa break; nobj = be32toh(packidx->hdr.fanout_table[0xff]); - if (nobj <= nobj_max) + if (nobj < nobj_max) + continue; + + idx = got_packidx_get_object_idx(packidx, ids[0]); + if (idx == -1) continue; + ncommits++; - for (i = 0; i < nids; i++) { + for (i = 1; i < nids; i++) { idx = got_packidx_get_object_idx(packidx, ids[i]); if (idx != -1) ncommits++; } - if (ncommits > ncommits_max) { + if (ncommits >= ncommits_max) { best_packidx_path = path_packidx; nobj_max = nobj; ncommits_max = ncommits;