summaryrefslogtreecommitdiff
path: root/packfile.c
AgeCommit message (Collapse)AuthorFilesLines
13 daysMerge branch 'ps/odb-eagerly-load-alternates'Junio C Hamano1-1/+0
The object database layer has been simplified by eagerly loading alternate object directories upon initialization, instead of deferring it to the first object lookup. This eliminates the need for scattered lazy-loading calls throughout the codebase and paves the way for integrating alternates with the pluggable backends. * ps/odb-eagerly-load-alternates: odb: drop `alternates_db` field odb: drop `loaded_alternates` field odb: eagerly initialize alternates odb: decouple source path comparisons from `the_repository` setup: create ref and object databases after config is written
13 daysMerge branch 'ps/odb-generic-corrupt-objects'Junio C Hamano1-21/+8
The object database (odb) API has been refactored to distinguish between missing objects and corrupt ones by returning more descriptive error statuses. Both the packed and loose backends now faithfully propagate error details using a generic strbuf error mechanism, removing backend-specific leakage from central lookup paths. * ps/odb-generic-corrupt-objects: odb: handle `OBJECT_INFO_DIE_IF_CORRUPT` generically odb/source: allow `read_object_info()` to bubble up error messages odb/source: let callers discern missing and corrupt objects odb/source: introduce error status when reading objects odb/source-packed: flag known-bad objects as corrupt and not missing
2026-08-25Merge branch 'js/packfile-fast-append'Junio C Hamano1-1/+1
The performance of adding numerous new packfiles has been improved by introducing a fast path for known-new packfiles to skip an unnecessary traversal in packfile_list_append(), avoiding a quadratic complexity regression on load. * js/packfile-fast-append: packfile: fix perf regression with many packs
2026-08-24Merge branch 'js/pack-objects-delta-size-t'Junio C Hamano1-7/+5
The 'pack-objects' and delta-encoding code paths have been updated to use 'size_t' instead of 'unsigned long' for object sizes and offset limits, avoiding potential truncation issues on 64-bit Windows. * js/pack-objects-delta-size-t: packfile: widen `unpack_object_header_buffer()` to `size_t` git-zlib: widen `git_deflate_bound()` to `size_t` t/helper/test-pack-deltas: widen `do_compress()`'s maxsize local to `size_t` http-push: widen `start_put()`'s size local from `ssize_t` to `size_t` diff: widen `deflate_it()`'s bound local from int to `size_t` archive-zip: widen `zlib_deflate_raw()`'s maxsize local to `size_t` packfile, git-zlib: widen `use_pack()` and zstream avail fields to `size_t` delta: widen `create_delta()` and `diff_delta()` to `size_t` pack-objects: widen `mem_usage` and `try_delta()`'s out-param to `size_t` pack-objects: widen `free_unpacked()` return to `size_t` pack-objects: widen delta-cache accounting to `size_t` delta: widen `create_delta_index()` parameter to `size_t` diff-delta: widen `struct delta_index`' size fields to `size_t`
2026-08-19odb: handle `OBJECT_INFO_DIE_IF_CORRUPT` genericallyPatrick Steinhardt1-17/+0
When a lookup with `OBJECT_INFO_DIE_IF_CORRUPT` fails we want to die in case the object exists, but cannot be read. This flag is handled in two different spots right now: - `do_oid_object_info_extended()` calls `has_packed_and_bad()` to check whether the object is known to be corrupt in any packfile. This function reaches into the internals of the packed source and thus breaks the abstraction provided by our object sources. - The loose source handles the flag itself and dies directly in `read_object_info_from_path()`, which means that we die even in cases where another source may still have a good copy of the object. Besides being inconsistent, it also ties us to the specific backend used by the database sources because `has_packed_and_bad()` assumes that they use the "files" backend. Any other backend will instead cause us to die when calling `odb_source_files_downcast()`, even if the object was simply nonexistent. In the preceding commits we've carved out the infrastructure to make this mechanism fully generic. On the one hand, all backends now tell us whether the object is missing or corrupt via their return values. And on the other hand, they have been taught to provide a readable error message to the caller. Adapt `do_oid_object_info_extended()` to use those new mechanisms. This means that we won't die immediately anymore when a loose object is corrupt, and we properly handle backends other than the "files" backend. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-08-19odb/source: allow `read_object_info()` to bubble up error messagesPatrick Steinhardt1-1/+1
When reading an object fails even though it exists, the sources know best what exactly went wrong and where the corrupt object is located. This information is lost though when bubbling up the error to the object database layer, which forces that layer to reconstruct it after the fact. This is exactly what `do_oid_object_info_extended()` does via `has_packed_and_bad()`, but that function only really knows to handle the "files" backend by reaching into its internals. Introduce a new `errmsg` parameter for the `read_object_info()` callback that sources are expected to populate with a human-readable message in case reading the object has failed. Adapt the packed and loose sources to populate the buffer with the messages that we ultimately want to surface to the user. For now, all callers are adapted to pass a `NULL` pointer. We will add a user of this new infrastructure in a subsequent commit. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-08-19odb/source-packed: flag known-bad objects as corrupt and not missingPatrick Steinhardt1-3/+7
When reading packed objects we know to tell apart missing objects and corrupt objects by returning a positive error code in the former case, and a negative one in the latter case. We do that by distinguishing between errors returned by `find_pack_entry()`, which yields the offset of the object, and `packed_object_info()`, which reads the object contents. But even though we already distinguish those cases when reading packed objects, the logic is broken in case a caller tries to read an object that has been marked as corrupt. In that case, `find_pack_entry()` will tell us that the object in question does not exist, and consequently we'll not flag the object as corrupt but as missing. Fix this issue by bubbling up whether the object is corrupt and, if so, which packfile contains the corrupted object. Note that we don't yet need the information about the specific packfile, so we could've just as well made this a `bool *corrupted` pointer. But we'll need information about the containing packfile in a subsequent commit so that we can generate a proper error message telling the user which packfile contains the broken object. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-08-17odb: eagerly initialize alternatesPatrick Steinhardt1-1/+0
When creating the object database we initialize the main object database source, but we don't yet initialize its alternates. Instead, we have many calls to `odb_prepare_alternates()` cluttered around the code base whenever we are about to iterate through the sources. This lazy loading doesn't really add much value: the moment where we read any object we _have_ to load the alternates anyway. So given that most of our commands would access the object database this optimization is not really buying us much in the first place. Quite on the contrary, it makes the code harder to understand and is a potential source of bugs in case any callsite forgot to prepare alternates before we iterate through the sources. Historically though there was a reason why we deferred lazy-loading: it may happen that the repository has "core.ignoreCase" configured, and we use that to deduplicate the list of alternates in case we had the same alternate configured multiple times, but with different casing. We used to initialize the object database before we had fully configured the owning repository though, and consequently we couldn't access that configuration yet. This has changed in the preceding commit though where we started to parse "core.ignoreCase" manually. Eagerly prepare alternates both when creating the object database and when flushing its caches. Drop the now-unneeded calls to prepare the alternates that are scattered across the code base. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-08-13packfile: fix perf regression with many packsJohannes Schindelin1-1/+1
Since 589127caa730 (packfile: move list of packs into the packfile store, 2025-10-30), there is a performance regression when many packfiles need to be loaded: `packfile_store_add_pack()` now calls `packfile_list_remove_internal()` to detect whether the packfile was _already_ in the list, and if so, move it to the end of the list. This function linearly scans the existing list before every insertion. Newly loading N packs therefore has complexity O(N²). In one reported use case (https://github.com/microsoft/git/issues/970), N equals 37,815 and caused a slow-down of a simple `git rev-parse --short HEAD` (which is regularly executed as part of `GIT_PS1`) from 0.4s to 4.5s. Let's fix this by establishing a fast path for known-new packfiles. The keen reader will note that there is currently only a single, "known-new" caller of the `packfile_list_append()` function, and wonder why not simply remove this check whether the packfile already exists in the list? Originally, when above-mentioned commit introduced that logic, there was a second caller in `prepare_midx()`, which would have required that check, but that caller was removed in 6aff1f25a046 (packfile: always add packfiles to MRU when adding a pack, 2025-10-30). Still, the function is declared in a header file, and to avoid any problems with in-flight or downstream callers, it is safer to extend the signature to be explicit whether or not to skip that check. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-08-13packfile: widen `unpack_object_header_buffer()` to `size_t`Johannes Schindelin1-6/+4
As part of the ongoing effort to replace `unsigned long` data types with `size_t` wherever appropriate (mainly to fix all those problems on Windows with objects larger than 4GB), let's also adjust the return type and the type of the `len` parameter of this function. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-08-13packfile, git-zlib: widen `use_pack()` and zstream avail fields to `size_t`Johannes Schindelin1-2/+2
Bundling the two widenings: four call sites pass `&stream.avail_in` directly to `use_pack()`, and widening either type fencepost alone would force a bridge variable at each. Doing both together is the simpler end state and is the prerequisite for the `do_compress()` widening in the next commit, which is what lets `write_no_reuse_object()` lose its last `cast_size_t_to_ulong()` shim. The unsigned-long locals widened at the other `use_pack()` callers (avail / remaining / left) hold pack-window sizes bounded by `core.packedGitWindowSize`, so the change is type consistency rather than a new >4GB capability. `git_zstream.avail_in`/`avail_out` likewise reach zlib's `uInt` fields only after `zlib_buf_cap()`'s 1 GiB cap, so the wrapper already accepted `size_t`-shaped inputs in practice. Assisted-by: Opus 4.7 Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-08-05odb/streaming: rename `struct odb_read_stream`Patrick Steinhardt1-4/+4
Rename `struct odb_read_stream` to just `struct odb_stream`. This prepares for unification of the two different types of streams, as these provide the same functionality with the preceding refactorings. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-07-15Merge branch 'ps/odb-drop-whence'Junio C Hamano1-19/+26
The 'whence' field in 'struct object_info' has been removed. The backend-specific object information retrieval has been refactored into an opt-in 'struct object_info_source' structure. * ps/odb-drop-whence: odb: document object info fields odb: drop `whence` field from object info treewide: convert users of `whence` to the new source field odb: add `source` field to struct object_info_source odb: make backend-specific fields optional packfile: thread odb_source_packed through packed_object_info()
2026-07-13Merge branch 'ps/odb-generalize-prepare'Junio C Hamano1-1/+1
The 'reprepare()' callback for object database sources has been generalized into a 'prepare()' callback with an optional flush cache flag, and a new 'odb_prepare()' wrapper has been introduced to allow pre-opening object database sources. * ps/odb-generalize-prepare: odb: introduce `odb_prepare()` odb/source: generalize `reprepare()` callback
2026-07-06Merge branch 'ps/odb-source-packed'Junio C Hamano1-769/+15
The packed object source has been refactored into a proper struct odb_source. * ps/odb-source-packed: odb/source-packed: drop pointer to "files" parent source midx: refactor interfaces to work on "packed" source odb/source-packed: stub out remaining functions odb/source-packed: wire up `freshen_object()` callback odb/source-packed: wire up `find_abbrev_len()` callback odb/source-packed: wire up `count_objects()` callback odb/source-packed: wire up `for_each_object()` callback odb/source-packed: wire up `read_object_stream()` callback odb/source-packed: wire up `read_object_info()` callback packfile: use higher-level interface to implement `has_object_pack()` odb/source-packed: wire up `reprepare()` callback odb/source-packed: wire up `close()` callback odb/source-packed: start converting to a proper `struct odb_source` odb/source-packed: store pointer to "files" instead of generic source packfile: move packed source into "odb/" subsystem packfile: split out packfile list logic packfile: rename `struct packfile_store` to `odb_source_packed`
2026-07-02odb: drop `whence` field from object infoPatrick Steinhardt1-2/+0
In the preceding commits we have migrated all callers to derive their information of how a specific object is stored to use the new object info source instead, and hence the field is now unused. Drop it. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-07-02odb: add `source` field to struct object_info_sourcePatrick Steinhardt1-8/+12
The previous commit introduced `struct object_info_source` as an opt-in container for backend-specific information, but for now we only moved preexisting data into this structure. Most importantly, the caller has no way yet to learn about which source an object was actually looked up from. Instead, callers have to rely on the `whence` enum to distinguish the object type, but cannot use that enum to tell the object source. Add a `struct odb_source *source` field to the structure and populate it from each backend's lookup path. The `whence` enum is still set and used by callers; it will be removed in a subsequent commit now that `sourcep->source` can identify the backend on its own. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-07-02odb: make backend-specific fields optionalPatrick Steinhardt1-15/+18
The `struct object_info` carries two pieces of information about how an object was looked up: - The `whence` enum identifying the backend. - The backend-tagged union `u` exposing backend-specific details (currently only the packed-source case, which records the owning pack, offset and packed object type). The union is populated unconditionally, even though most callers don't care about provenance at all. Split the backend-specific union out into a new public type, `struct object_info_source`, and make the object info structure carry it via just another opt-in request pointer. As with all the other requestable information, callers that need source info allocate a `struct object_info_source` on the stack and point `sourcep` at it; callers that don't care about it simply leave the field as a `NULL` pointer. Adapt callers accordingly. Note that the `whence` enum is strictly-speaking also backend-specific information, so it would be another good candidate to be moved into the `struct object_info_source`. For now though it is left alone, as it will be replaced by a `struct odb_source` pointer in a subsequent commit. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-07-02packfile: thread odb_source_packed through packed_object_info()Patrick Steinhardt1-3/+5
Add an optional `struct odb_source_packed *source` parameter to `packed_object_info()` and `packed_object_info_with_index_pos()`. This parameter is unused at this point in time, but it will be used in a follow-up commit so that we can record the source of a specific object. Note that callers in "odb/source-packed.c" pass the already-available source, but all other callers pass `NULL` instead. This is fine though, as we only care about populating this info when called via the packed store. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-06-24Merge branch 'ps/odb-source-packed' into ps/odb-drop-whenceJunio C Hamano1-769/+15
* ps/odb-source-packed: odb/source-packed: drop pointer to "files" parent source midx: refactor interfaces to work on "packed" source odb/source-packed: stub out remaining functions odb/source-packed: wire up `freshen_object()` callback odb/source-packed: wire up `find_abbrev_len()` callback odb/source-packed: wire up `count_objects()` callback odb/source-packed: wire up `for_each_object()` callback odb/source-packed: wire up `read_object_stream()` callback odb/source-packed: wire up `read_object_info()` callback packfile: use higher-level interface to implement `has_object_pack()` odb/source-packed: wire up `reprepare()` callback odb/source-packed: wire up `close()` callback odb/source-packed: start converting to a proper `struct odb_source` odb/source-packed: store pointer to "files" instead of generic source packfile: move packed source into "odb/" subsystem packfile: split out packfile list logic packfile: rename `struct packfile_store` to `odb_source_packed`
2026-06-22odb/source: generalize `reprepare()` callbackPatrick Steinhardt1-1/+1
The `reprepare()` callback function can be used to flush caches of a given object source and then prepare it anew. This is for example used when a concurrent process may have written new objects. Ultimately, this can be seen as doing two separate steps: 1. We drop any caches. 2. We prepare the source. We have one callsite in git-grep(1) though that really only want to do (2). This is done by reaching into the "files" backend directly and then calling `odb_source_packed_prepare()`, which of course may not work with alternate backends. We could in theory just call `reprepare()` here, and that would likely not have any significant downside. But this would certainly feel like a code smell. Instead, generalize the `reprepare()` callback to `prepare()` with a flag that optionally instructs the backend to also flush the caches, which allows us to drop the external `odb_source_packed_prepare()` declaration. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-06-17odb/source-packed: drop pointer to "files" parent sourcePatrick Steinhardt1-1/+1
Over the last commits we have turned the packfile store into a proper object database source that can be used as a standalone backend. As such, it is no longer necessary to have it coupled to the "files" parent source. Remove the pointer to the owning "files" source so that the "packed" source can be used as a standalone entity. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-06-17odb/source-packed: wire up `freshen_object()` callbackPatrick Steinhardt1-16/+0
Move `packfile_store_freshen_object()` and from "packfile.c" into "odb/source-packed.c" and wire it up as the `freshen_object()` callback of the "packed" source. Note that this removes the last external caller of `find_pack_entry()` from "packfile.c", which means that we can now make this function static. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-06-17odb/source-packed: wire up `find_abbrev_len()` callbackPatrick Steinhardt1-111/+0
Move `packfile_store_find_abbrev_len()` and its associated helpers from "packfile.c" into "odb/source-packed.c" and wire it up as the `find_abbrev_len()` callback of the "packed" source. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-06-17odb/source-packed: wire up `count_objects()` callbackPatrick Steinhardt1-31/+0
Move `packfile_store_count_objects()` from "packfile.c" into "odb/source-packed.c" and wire it up as the `count_objects()` callback of the "packed" source. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-06-17odb/source-packed: wire up `for_each_object()` callbackPatrick Steinhardt1-258/+2
Move `packfile_store_for_each_object()` and its associated helpers from "packfile.c" into "odb/source-packed.c" and wire it up as the `for_each_object()` callback of the "packed" source. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-06-17odb/source-packed: wire up `read_object_stream()` callbackPatrick Steinhardt1-12/+0
Wire up the `read_object_stream()` callback for the packed source and call it in the "files" source via the `odb_source_read_object_stream()` interface. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-06-17odb/source-packed: wire up `read_object_info()` callbackPatrick Steinhardt1-66/+8
Move the logic to read object info from a "packed" source into "odb/source-packed.c" and wire it up as the `read_object_info()` callback. Note that we also move around the supporting `find_pack_entry()`, but we still have to expose it to other callers that exist in "packfile.c". This will be fixed in subsequent commits though, where all callers in "packfile.c" will have been moved into "odb/source-packed.c", and at that point we'll be able to make `find_pack_entry()` file-local again. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-06-17packfile: use higher-level interface to implement `has_object_pack()`Patrick Steinhardt1-4/+2
In `has_object_pack()` we're checking whether a specific object exists as part of a packfile. This is done by calling the low-level function `find_pack_entry()`, but this function will eventually be moved into "odb/source-packed.c" and made file-local. Refactor the code to use `packfile_store_read_object_info()` instead. This refactoring is functionally equivalent as that function will call `find_pack_entry()` itself and then return immediately when it ain't got no object info pointer as parameter. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-06-17odb/source-packed: wire up `reprepare()` callbackPatrick Steinhardt1-157/+3
Move the logic to prepare and reprepare the "packed" source into "odb/source-packed.c" and wire it up as the `reprepare()` callback. Note that "preparing" a source is not yet generic. Eventually, it would probably make sense to turn the existing `reprepare()` callback into a `prepare()` callback with an optional flag to force re-preparing. But this step will be handled in a separate patch series. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-06-17odb/source-packed: wire up `close()` callbackPatrick Steinhardt1-12/+0
Wire up a new `close()` callback for the packed source and call it from the "files" source via the generic `odb_source_close()` interface. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-06-17odb/source-packed: start converting to a proper `struct odb_source`Patrick Steinhardt1-10/+0
Start converting `struct odb_source_packed` into a proper pluggable `struct odb_source` by embedding the base struct and assigning it the new `ODB_SOURCE_PACKED` type. Furthermore, wire up lifecycle management of this source by implementing the `free` callback and taking ownership of the chdir notifications. Note that the packed source is not yet functional as a standalone `struct odb_source`, as it's missing all of the callback implementations. These will be wired up in subsequent commits. Further note that we're also registering a `chdir_notify` callback to reparent our path. This wasn't previously necessary (and still isn't at this point in time) because all paths are taken from the owning "files" source, and that source already handles the reparenting for us. But a subsequent commit will change that so that we're using the path of the "packed" source, and once that happens we'll need it to be updated when changing the working directory. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-06-17odb/source-packed: store pointer to "files" instead of generic sourcePatrick Steinhardt1-6/+6
The `struct odb_source_packed` holds a pointer to its owning parent source. The way that Git is currently structured, this parent is always the "files" source. In subsequent commits we're going to detangle that so that the "packed" source doesn't have any owning parent source at all, which makes it usable as a completely standalone source. Detangling this mess is somewhat intricate though, and is made even more intricate because it's not always clear which kind of source one is holding at a specific point in time -- either the parent "files" source, or the child "packed" source. Make this relationship more explicit by storing a pointer to the "files" source instead of storing a pointer to a generic `struct odb_source`. This will help make subsequent steps a bit clearer by making it more obvious whether we're using the generic "base" source or the owning "files" source. Note that this is a temporary step, only. At the end of this series we will have dropped the "files" pointer completely. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-06-17packfile: move packed source into "odb/" subsystemPatrick Steinhardt1-9/+0
In subsequent patches we'll be turning `struct odb_source_packed` into a proper `struct odb_source`. As a first step towards this goal, move its struct out of "packfile.{c,h}" and into "odb/source-packed.{c,h}". This detaches the implementation of the packfile object source from the generic packfile code, following the same convention already used by the "files" and "in-memory" sources. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-06-17packfile: split out packfile list logicPatrick Steinhardt1-83/+0
In the next commit we're about to introduce the "packed" object database source. This source will embed a packfile list, and consequently we'll have to include "packfile.h" to make the struct definition available. This will unfortunately lead to a cyclic dependency that we cannot resolve with a forward declaration. Split out the code that relates to the packfile list into a separate compilation unit so that both "packfile.h" and "odb/source-packed.h" can include it. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-06-17packfile: rename `struct packfile_store` to `odb_source_packed`Patrick Steinhardt1-28/+28
Not too long ago, we have introduced the packfile store in b7983adb51 (packfile: introduce a new `struct packfile_store`, 2025-09-23). This struct is responsible for managing all of our access to packfiles and is used as one of the two sources of objects for the "files" source. Back when I introduced this structure I didn't have the clear vision yet that it will eventually also turn into a proper object database source, and how exactly that infrastructure will look like. Now though it's becoming increasingly clear that it does make sense to treat it just the same as any of our other ODB sources. The consequence is that the naming is now a bit out-of-date: it's just another source and will be turned into a proper `struct odb_source` over the next couple of commits, but it's not named accordingly. Rename the structure to `odb_source_packed` to align it with this goal and to bring it in line with the other sources we already have. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-06-15odb: use size_t for object_info.sizep and the size APIsJohannes Schindelin1-9/+3
When `js/objects-larger-than-4gb-on-windows` widened the streaming, index-pack and unpack-objects code paths, in the interest of keeping the patches somewhat reasonably-sized, it left the public ODB API still typed in `unsigned long`. In particular `struct object_info::sizep` and the four wrappers built on top of it (`odb_read_object`, `odb_read_object_peeled`, `odb_read_object_info`, `odb_pretend_object`) still return the unpacked size through `unsigned long *`, so on Windows `cat-file -s` and the `git add` / `git status` paths for a >4 GiB blob silently cap at 4 GiB. Widen the field and the four wrappers. The previous commits already widened the `unpack_entry()` cascade and pack-objects' in-core size accessors, so most of the cascade arrives here with no further work: the temporary shims in `packed_object_info_with_index_pos()` and in `unpack_entry()`'s delta-base recovery path go away, the two `SET_SIZE(entry, cast_size_t_to_ulong(canonical_size))` calls in `check_object()` and the matching one in `drop_reused_delta()` collapse to plain `SET_SIZE`, and `oe_get_size_slow()`'s tail `cast_size_t_to_ulong()` is gone too. What remains narrow are the boundaries this series does not intend to touch: the diff, blame, textconv and fast-import machinery. Even so, this patch is unfortunately quite large. Assisted-by: Opus 4.7 Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-06-15packfile,delta: drop the `cast_size_t_to_ulong()` wrappersJohannes Schindelin1-20/+8
When I started the transition from `unsigned long` to `size_t`, in the interest of keeping the patches reviewable, I introduced these calls to prevent data type narrowing from silently failing to handle large object sizes. I also introduced `*_sz()` variants that would allow most of the callers to keep using that `unsigned long` that the 90s kindly asked to be returned. After the preceding commits, the only places that called the narrow wrappers either no longer exist or already use the `_sz` form internally, so the wrappers just narrow values back through `cast_size_t_to_ulong()` for no reason. Drop them and rename the `_sz` variants back to the natural names. Assisted-by: Opus 4.7 Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-06-15packfile: widen unpack_entry()'s size out-parameter to size_tJohannes Schindelin1-11/+17
The topic `js/objects-larger-than-4gb-on-windows` widened the streaming, index-pack and unpack-objects paths to `size_t` but deliberately stopped at the in-memory `unpack_entry()` cascade, which still hands back the unpacked size through `unsigned long *`. On Windows that boundary truncates above 4 GiB because that data type is only 32 bits wide on that platform. Widen the code path. Except `packed_object_info_with_index_pos()`: It cannot yet pass `oi->sizep` directly because the field is still `unsigned long *`; bridge it with a `size_t` temporary that narrows back, and let a later commit drop the bridge once the field is wide too. `gfi_unpack_entry()` keeps its narrow signature because fast-import tracks sizes through `unsigned long` everywhere it crosses subsystem boundaries, keeping its signature allows the scope of this commit to be somewhat reasonable, still. Assisted-by: Opus 4.7 Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-06-15patch-delta: use size_t for sizesJohannes Schindelin1-3/+1
`patch_delta()` takes the source and delta sizes by value and writes back the reconstructed target size through an `unsigned long *`. That datatype cannot represent a value that exceeds 4 GiB on systems where `unsigned long` is 32-bit (notably 64-bit Windows builds), though, even though the delta encoding itself, the on-disk layout, and the in-memory buffers happily carry such sizes. A `size_t` companion to `get_delta_hdr_size()`, `get_delta_hdr_size_sz()`, was introduced in 17fa077596 (delta, packfile: use size_t for delta header sizes, 2026-05-08) precisely so that `patch_delta()` could be widened without changing the on-the-wire decoding helper's signature. Widen `patch_delta()`'s three size parameters to `size_t` and switch its internal use of `get_delta_hdr_size()` to the `_sz` variant. Then propagate the wider type through the callers. Assisted-by: Opus 4.7 Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-05-27Merge branch 'tb/incremental-midx-part-3.3'Junio C Hamano1-0/+2
The repacking code has been refactored and compaction of MIDX layers have been implemented, and incremental strategy that does not require all-into-one repacking has been introduced. * tb/incremental-midx-part-3.3: repack: allow `--write-midx=incremental` without `--geometric` repack: introduce `--write-midx=incremental` repack: implement incremental MIDX repacking packfile: ensure `close_pack_revindex()` frees in-memory revindex builtin/repack.c: convert `--write-midx` to an `OPT_CALLBACK` repack-geometry: prepare for incremental MIDX repacking repack-midx: extract `repack_fill_midx_stdin_packs()` repack-midx: factor out `repack_prepare_midx_command()` midx: expose `midx_layer_contains_pack()` repack: track the ODB source via existing_packs midx: support custom `--base` for incremental MIDX writes midx: introduce `--no-write-chain-file` for incremental MIDX writes midx: use `strvec` for `keep_hashes` midx: build `keep_hashes` array in order midx: use `strset` for retained MIDX files midx-write: handle noop writes when converting incremental chains
2026-05-20packfile: ensure `close_pack_revindex()` frees in-memory revindexTaylor Blau1-0/+2
The following commit will introduce a case where we write a MIDX bitmap over packs that do not themselves have on-disk *.rev files. This case is supported within Git, and we will simply fall back to generating the revindex in memory. But we don't ever release that memory, causing a leak that is exposed by a test introduced in the following commit. (As far as I could find, we never free()'d memory allocated as a byproduct of creating an in-memory revindex, likely because that code predates the leak-checking niceties we have in the test suite now.) Rectify this by calling `FREE_AND_NULL()` on the `p->revindex` field when calling `close_pack_revindex()`. Signed-off-by: Taylor Blau <me@ttaylorr.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-05-09delta, packfile: use size_t for delta header sizesJohannes Schindelin1-9/+24
The delta header decoding functions return unsigned long, which truncates on Windows for objects larger than 4GB. Introduce size_t variants get_delta_hdr_size_sz() and get_size_from_delta_sz() that preserve the full 64-bit size, and use them in packed_object_info() where the size is needed for streaming decisions. This was originally authored by LordKiRon <https://github.com/LordKiRon>, who preferred not to reveal their real name and therefore agreed that I take over authorship. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-05-09odb, packfile: use size_t for streaming object sizesJohannes Schindelin1-9/+15
The odb_read_stream structure uses unsigned long for the size field, which is 32-bit on Windows even in 64-bit builds. When streaming objects larger than 4GB, the size would be truncated to zero or an incorrect value, resulting in empty files being written to disk. Change the size field in odb_read_stream to size_t and introduce unpack_object_header_sz() to return sizes via size_t pointer. Since object_info.sizep remains unsigned long for API compatibility, use temporary variables where the types differ, with comments noting the truncation limitation for code paths that still use unsigned long. Widening the producers to size_t in this way introduces a handful of silent size_t -> unsigned long narrowings on Windows, all in builtin/pack-objects.c, where the consumers are still typed unsigned long. Make those narrowings explicit with cast_size_t_to_ulong() so they assert loudly the moment an object actually exceeds ULONG_MAX bytes: - oe_get_size_slow() returns unsigned long but holds a size_t locally; cast at the return. - write_reuse_object() passes a size_t into check_pack_inflate(), whose expect parameter is unsigned long; cast at the call. - check_object() routes a size_t through SET_SIZE() and SET_DELTA_SIZE(), both of which take unsigned long via oe_set_size() / oe_set_delta_size(); cast at the three call sites in the OBJ_OFS_DELTA / OBJ_REF_DELTA branches and in the non-delta default arm. The cast-only treatment is deliberately a stop-gap. Properly widening oe_set_size, oe_get_size_slow's return type, check_pack_inflate's expect parameter, object_info.sizep, patch_delta, and the OE_SIZE_BITS bit-fields cascades into a series that is too large to be reviewable, so the proper widening is deferred to a follow-up topic. Until then, cast_size_t_to_ulong() at least makes the truncation explicit at the source: it documents the boundary, and on a 64-bit non-Windows platform it is a no-op. This was originally authored by LordKiRon <https://github.com/LordKiRon>, who preferred not to reveal their real name and therefore agreed that I take over authorship. Helped-by: Torsten Bögershausen <tboegi@web.de> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-04-08Merge branch 'ps/odb-cleanup'Junio C Hamano1-1/+1
Various code clean-up around odb subsystem. * ps/odb-cleanup: odb: drop unneeded headers and forward decls odb: rename `odb_has_object()` flags odb: use enum for `odb_write_object` flags odb: rename `odb_write_object()` flags treewide: use enum for `odb_for_each_object()` flags CodingGuidelines: document our style for flags
2026-04-06Merge branch 'tb/stdin-packs-excluded-but-open'Junio C Hamano1-1/+2
pack-objects's --stdin-packs=follow mode learns to handle excluded-but-open packs. * tb/stdin-packs-excluded-but-open: repack: mark non-MIDX packs above the split as excluded-open pack-objects: support excluded-open packs with --stdin-packs t7704: demonstrate failure with once-cruft objects above the geometric split pack-objects: refactor `read_packs_list_from_stdin()` to use `strmap` pack-objects: plug leak in `read_stdin_packs()`
2026-03-31treewide: use enum for `odb_for_each_object()` flagsPatrick Steinhardt1-1/+1
We've got a couple of callsites where we pass `odb_for_each_object()` flags, but accept an `unsigned` flags field instead of the corresponding enum. Adapt these to accept the enum type instead. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-03-27pack-objects: support excluded-open packs with --stdin-packsTaylor Blau1-1/+2
In cd846bacc7d (pack-objects: introduce '--stdin-packs=follow', 2025-06-23), pack-objects learned to traverse through commits in included packs when using '--stdin-packs=follow', rescuing reachable objects from unlisted packs into the output. When we encounter a commit in an excluded pack during this rescuing phase we will traverse through its parents. But because we set `revs.no_kept_objects = 1`, commit simplification will prevent us from showing it via `get_revision()`. (In practice, `--stdin-packs=follow` walks commits down to the roots, but only opens up trees for ones that do not appear in an excluded pack.) But there are certain cases where we *do* need to see the parents of an object in an excluded pack. Namely, if an object is rescue-able, but only reachable from object(s) which appear in excluded packs, then commit simplification will exclude those commits from the object traversal, and we will never see a copy of that object, and thus not rescue it. This is what causes the failure in the previous commit during repacking. When performing a geometric repack, packs above the geometric split that weren't part of the previous MIDX (e.g., packs pushed directly into `$GIT_DIR/objects/pack`) may not have full object closure. When those packs are listed as excluded via the '^' marker, the reachability traversal encounters the sequence described above, and may miss objects which we expect to rescue with `--stdin-packs=follow`. Introduce a new "excluded-open" pack prefix, '!'. Like '^'-prefixed packs, objects from '!'-prefixed packs are excluded from the resulting pack. But unlike '^', commits in '!'-prefixed packs *are* used as starting points for the follow traversal, and the traversal does not treat them as a closure boundary. In order to distinguish excluded-closed from excluded-open packs during the traversal, introduce a new `pack_keep_in_core_open` bit on `struct packed_git`, along with a corresponding `KEPT_PACK_IN_CORE_OPEN` flag for the kept-pack cache. In `add_object_entry_from_pack()`, move the `want_object_in_pack()` check to *after* `add_pending_oid()`. This is necessary so that commits from excluded-open packs are added as traversal tips even though their objects won't appear in the output. As a consequence, the caller `for_each_object_in_pack()` will always provide a non-NULL 'p', hence we are able to drop the "if (p)" conditional. The `include_check` and `include_check_obj` callbacks on `rev_info` are used to halt the walk at closed-excluded packs, since objects behind a '^' boundary are guaranteed to have closure and need not be rescued. The following commit will make use of this new functionality within the repack layer to resolve the test failure demonstrated in the previous commit. Signed-off-by: Taylor Blau <me@ttaylorr.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-03-20object-file: move logic to compute packed abbreviation lengthPatrick Steinhardt1-0/+111
Same as the preceding commit, move the logic that computes the minimum required prefix length to make a given object ID unique for the packfile store into a new function `packfile_store_find_abbrev_len()` that is part of "packfile.c". This prepares for making the logic fully generic via pluggable object databases. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-03-20object-name: move logic to iterate through packed prefixed objectsPatrick Steinhardt1-0/+174
Similar to the preceding commit, move the logic to iterate through objects that have a given prefix into "packfile.c". Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>