git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH v2 00/13] Carve out loose object source

From
Patrick Steinhardt <ps@pks.im>
Date
Oct 31, 2025, 06:12 UTC
Message-ID
<20251031-b4-pks-odb-loose-backend-v2-0-920f721aef71@pks.im>
In-Reply-To
<20251024-b4-pks-odb-loose-backend-v1-0-1a4202273c38@pks.im>
Hi,

this patch series carves out loose object sources. The idea is to store all data that relates to loose objects in a single structure, similar to our `struct packfile_store`.

The series is structured as follows:
  - Patches 1 to 4 perform some cleanups in the vicinity of object
    databases.
  - Patches 5 to 8 create a new `struct odb_loose_source` and move all
    state that is specific to loose objects into it.
  - Patches 9 to 13 then adjust functions to work on top of that new
    structure.

The motivation here is to make handling of loose objects completely self-contained as a step towards pluggable object databases.

Changes in v2:
  - Rename `sturct odb_loose_source *` arguments from `source` to
    `loose`.
  - Some commit message improvements.
  - Link to v1: https://lore.kernel.org/r/20251024-b4-pks-odb-loose-backend-v1-0-1a4202273c38@pks.im
Thanks!
Patrick
---
Patrick Steinhardt (13):
      odb: fix subtle logic to check whether an alternate is usable
      odb: introduce `odb_source_new()`
      odb: adjust naming to free object sources
      object-file: move `fetch_if_missing`
      object-file: introduce `struct odb_loose_source`
      object-file: move loose object cache into loose source
      object-file: hide internals when we need to reprepare loose sources
      object-file: move loose object map into loose source
      object-file: read objects via the loose object source
      object-file: rename `has_loose_object()`
      object-file: refactor freshening of objects
      object-file: rename `write_object_file()`
      object-file: refactor writing objects via a stream
 builtin/pack-objects.c   |   4 +-
 builtin/unpack-objects.c |   7 +-
 loose.c                  |  19 ++---
 object-file.c            | 175 +++++++++++++++++++++--------------------------
 object-file.h            |  98 ++++++++++++++------------
 object-name.c            |   2 +-
 odb.c                    | 104 +++++++++++++++++++---------
 odb.h                    |  41 +++++++----
 packfile.c               |  16 +++++
 packfile.h               |   3 +
 repository.c             |  14 ++--
 streaming.c              |  11 ++-
 12 files changed, 287 insertions(+), 207 deletions(-)
Range-diff versus v1:
 1:  b43ef34ba3d !  1:  f0bd0c69c8c odb: fix subtle logic to check whether an alternate is usable
    @@ Commit message
         mechanism.
     
         Make the relationship more explicit by not storing the path as part of
    -    `alt_odb_usable()`. Instead, we store the path after we have created the
    -    source now so that we can use the source's path pointer directly.
    +    `alt_odb_usable()`. Instead, store the path after we have created the
    +    source so that we can use the source's path pointer directly.
     
         Signed-off-by: Patrick Steinhardt <ps@pks.im>
     
 2:  a56c17be445 =  2:  b11d557b69d odb: introduce `odb_source_new()`
 3:  8d5d4f98d0c !  3:  eab62039169 odb: adjust naming to free object sources
    @@ Commit message
         are responsible for freeing a single object source or all object sources
         connected to an object database, respectively. The associated structure
         has been renamed from `struct object_directory` to `struct odb_source`
    -    recently though, so the names are somewhat stale nowadays.
    +    in a1e2581a1e (object-store: rename `object_directory` to `odb_source`,
    +    2025-07-01) though, so the names are somewhat stale nowadays.
     
         Rename them to mention the new struct name instead. Furthermore, while
         at it, adapt them to our modern naming schema where we first have the
 4:  c2e85285be2 =  4:  6afdd2679d8 object-file: move `fetch_if_missing`
 5:  3a532fcac19 !  5:  7de78e1e32b object-file: introduce `struct odb_loose_source`
    @@ object-file.c: void object_file_transaction_commit(struct odb_transaction *trans
     +	return loose;
     +}
     +
    -+void odb_loose_source_free(struct odb_loose_source *source)
    ++void odb_loose_source_free(struct odb_loose_source *loose)
     +{
    -+	free(source);
    ++	free(loose);
     +}
     
      ## object-file.h ##
    @@ object-file.h: int index_path(struct index_state *istate, struct object_id *oid,
     +};
     +
     +struct odb_loose_source *odb_loose_source_new(struct odb_source *source);
    -+void odb_loose_source_free(struct odb_loose_source *source);
    ++void odb_loose_source_free(struct odb_loose_source *loose);
     +
      /*
       * Populate and return the loose object cache array corresponding to the
 6:  4e15e659e25 !  6:  3d14e9c3b66 object-file: move loose object cache into loose source
    @@ object-file.c: static int append_loose_object(const struct object_id *oid,
      static int check_stream_oid(git_zstream *stream,
     @@ object-file.c: struct odb_loose_source *odb_loose_source_new(struct odb_source *source)
      
    - void odb_loose_source_free(struct odb_loose_source *source)
    + void odb_loose_source_free(struct odb_loose_source *loose)
      {
    -+	if (!source)
    ++	if (!loose)
     +		return;
    -+	odb_clear_loose_cache(source->source);
    - 	free(source);
    ++	odb_clear_loose_cache(loose->source);
    + 	free(loose);
      }
     
      ## object-file.h ##
    @@ object-file.h: struct odb_source;
      };
      
      struct odb_loose_source *odb_loose_source_new(struct odb_source *source);
    -@@ object-file.h: void odb_loose_source_free(struct odb_loose_source *source);
    +@@ object-file.h: void odb_loose_source_free(struct odb_loose_source *loose);
       * Populate and return the loose object cache array corresponding to the
       * given object ID.
       */
 7:  59d08a2b560 !  7:  2167b592c03 object-file: hide internals when we need to reprepare loose sources
    @@ object-file.c: struct oidtree *odb_loose_source_cache(struct odb_source *source,
      }
      
     -void odb_clear_loose_cache(struct odb_source *source)
    -+static void odb_loose_source_clear_cache(struct odb_loose_source *source)
    ++static void odb_loose_source_clear_cache(struct odb_loose_source *loose)
      {
     -	oidtree_clear(source->loose->cache);
     -	FREE_AND_NULL(source->loose->cache);
     -	memset(&source->loose->subdir_seen, 0,
     -	       sizeof(source->loose->subdir_seen));
    -+	oidtree_clear(source->cache);
    -+	FREE_AND_NULL(source->cache);
    -+	memset(&source->subdir_seen, 0,
    -+	       sizeof(source->subdir_seen));
    ++	oidtree_clear(loose->cache);
    ++	FREE_AND_NULL(loose->cache);
    ++	memset(&loose->subdir_seen, 0,
    ++	       sizeof(loose->subdir_seen));
     +}
     +
     +void odb_loose_source_reprepare(struct odb_source *source)
    @@ object-file.c: struct oidtree *odb_loose_source_cache(struct odb_source *source,
      }
      
      static int check_stream_oid(git_zstream *stream,
    -@@ object-file.c: void odb_loose_source_free(struct odb_loose_source *source)
    +@@ object-file.c: void odb_loose_source_free(struct odb_loose_source *loose)
      {
    - 	if (!source)
    + 	if (!loose)
      		return;
    --	odb_clear_loose_cache(source->source);
    -+	odb_loose_source_clear_cache(source);
    - 	free(source);
    +-	odb_clear_loose_cache(loose->source);
    ++	odb_loose_source_clear_cache(loose);
    + 	free(loose);
      }
     
      ## object-file.h ##
     @@ object-file.h: struct odb_loose_source {
      struct odb_loose_source *odb_loose_source_new(struct odb_source *source);
    - void odb_loose_source_free(struct odb_loose_source *source);
    + void odb_loose_source_free(struct odb_loose_source *loose);
      
     +/* Reprepare the loose source by emptying the loose object cache. */
     +void odb_loose_source_reprepare(struct odb_source *source);
    @@ object-file.h: struct odb_loose_source {
      /*
       * Populate and return the loose object cache array corresponding to the
       * given object ID.
    -@@ object-file.h: void odb_loose_source_free(struct odb_loose_source *source);
    +@@ object-file.h: void odb_loose_source_free(struct odb_loose_source *loose);
      struct oidtree *odb_loose_source_cache(struct odb_source *source,
      				       const struct object_id *oid);
      
 8:  8c04cdc54a0 !  8:  a9a1637a863 object-file: move loose object map into loose source
    @@ loose.c: int repo_loose_object_map_oid(struct repository *repo,
      		map = (to == repo->compat_hash_algo) ?
     
      ## object-file.c ##
    -@@ object-file.c: void odb_loose_source_free(struct odb_loose_source *source)
    - 	if (!source)
    +@@ object-file.c: void odb_loose_source_free(struct odb_loose_source *loose)
    + 	if (!loose)
      		return;
    - 	odb_loose_source_clear_cache(source);
    -+	loose_object_map_clear(&source->map);
    - 	free(source);
    + 	odb_loose_source_clear_cache(loose);
    ++	loose_object_map_clear(&loose->map);
    + 	free(loose);
      }
     
      ## object-file.h ##
 9:  8847142a317 !  9:  99d4c039bd5 object-file: read objects via the loose object source
    @@ object-file.c: int stream_object_signature(struct repository *r, const struct ob
       * call to stat_loose_object().
       */
     -static int stat_loose_object(struct repository *r, const struct object_id *oid,
    -+static int stat_loose_object(struct odb_loose_source *source,
    ++static int stat_loose_object(struct odb_loose_source *loose,
     +			     const struct object_id *oid,
      			     struct stat *st, const char **path)
      {
    @@ object-file.c: int stream_object_signature(struct repository *r, const struct ob
     -		if (!lstat(*path, st))
     -			return 0;
     -	}
    -+	*path = odb_loose_path(source->source, &buf, oid);
    ++	*path = odb_loose_path(loose->source, &buf, oid);
     +	if (!lstat(*path, st))
     +		return 0;
      
    @@ object-file.c: static int stat_loose_object(struct repository *r, const struct o
       * descriptor. See the caveats on the "path" parameter above.
       */
     -static int open_loose_object(struct repository *r,
    -+static int open_loose_object(struct odb_loose_source *source,
    ++static int open_loose_object(struct odb_loose_source *loose,
      			     const struct object_id *oid, const char **path)
      {
     -	int fd;
    @@ object-file.c: static int stat_loose_object(struct repository *r, const struct o
     -		fd = git_open(*path);
     -		if (fd >= 0)
     -			return fd;
    -+	*path = odb_loose_path(source->source, &buf, oid);
    ++	*path = odb_loose_path(loose->source, &buf, oid);
     +	fd = git_open(*path);
     +	if (fd >= 0)
     +		return fd;
    @@ object-file.c: static int stat_loose_object(struct repository *r, const struct o
      }
      
     -static int quick_has_loose(struct repository *r,
    -+static int quick_has_loose(struct odb_loose_source *source,
    ++static int quick_has_loose(struct odb_loose_source *loose,
      			   const struct object_id *oid)
      {
     -	struct odb_source *source;
    @@ object-file.c: static int stat_loose_object(struct repository *r, const struct o
     -			return 1;
     -	}
     -	return 0;
    -+	return !!oidtree_contains(odb_loose_source_cache(source->source, oid), oid);
    ++	return !!oidtree_contains(odb_loose_source_cache(loose->source, oid), oid);
      }
      
      /*
    @@ object-file.c: int loose_object_info(struct repository *r,
      			error_errno(_("unable to open loose object %s"), oid_to_hex(oid));
     
      ## object-file.h ##
    -@@ object-file.h: void odb_loose_source_free(struct odb_loose_source *source);
    +@@ object-file.h: void odb_loose_source_free(struct odb_loose_source *loose);
      /* Reprepare the loose source by emptying the loose object cache. */
      void odb_loose_source_reprepare(struct odb_source *source);
      
10:  c1a2d001b37 = 10:  873dedf2efc object-file: rename `has_loose_object()`
11:  2aef29ba790 = 11:  86810514083 object-file: refactor freshening of objects
12:  5c5d6928af2 = 12:  89348b4c540 object-file: rename `write_object_file()`
13:  116f8065a2a = 13:  2dd87a1f135 object-file: refactor writing objects via a stream

--- base-commit: c54a18ef67e59cdbcd77d6294916d42c98c62d1d change-id: 20251017-b4-pks-odb-loose-backend-b1e003c41107

Previous: Karthik NayakNext: Patrick Steinhardt
Message 30 of 58 in “Carve out loose object source”
  1. 00/13 Carve out loose object sourcePatrick Steinhardt, Oct 24, 2025
  2. 01/13 odb: fix subtle logic to check whether an alternate is usablePatrick Steinhardt, Oct 24, 2025
  3. Junio C HamanoOct 24, 2025
  4. Karthik NayakOct 30, 2025
  5. 02/13 odb: introduce `odb_source_new()`Patrick Steinhardt, Oct 24, 2025
  6. Junio C HamanoOct 24, 2025
  7. Patrick SteinhardtOct 27, 2025
  8. 03/13 odb: adjust naming to free object sourcesPatrick Steinhardt, Oct 24, 2025
  9. Karthik NayakOct 30, 2025
  10. 04/13 object-file: move `fetch_if_missing`Patrick Steinhardt, Oct 24, 2025
  11. 05/13 object-file: introduce `struct odb_loose_source`Patrick Steinhardt, Oct 24, 2025
  12. Karthik NayakOct 30, 2025
  13. Patrick SteinhardtOct 30, 2025
  14. Patrick SteinhardtOct 31, 2025
  15. Junio C HamanoOct 31, 2025
  16. Patrick SteinhardtNov 3, 2025
  17. Junio C HamanoOct 31, 2025
  18. 06/13 object-file: move loose object cache into loose sourcePatrick Steinhardt, Oct 24, 2025
  19. Junio C HamanoOct 24, 2025
  20. Patrick SteinhardtOct 27, 2025
  21. 07/13 object-file: hide internals when we need to reprepare loose sourcesPatrick Steinhardt, Oct 24, 2025
  22. 08/13 object-file: move loose object map into loose sourcePatrick Steinhardt, Oct 24, 2025
  23. 09/13 object-file: read objects via the loose object sourcePatrick Steinhardt, Oct 24, 2025
  24. Karthik NayakOct 30, 2025
  25. 10/13 object-file: rename `has_loose_object()`Patrick Steinhardt, Oct 24, 2025
  26. 11/13 object-file: refactor freshening of objectsPatrick Steinhardt, Oct 24, 2025
  27. 12/13 object-file: rename `write_object_file()`Patrick Steinhardt, Oct 24, 2025
  28. 13/13 object-file: refactor writing objects via a streamPatrick Steinhardt, Oct 24, 2025
  29. Karthik NayakOct 30, 2025
  30. 00/13 Carve out loose object sourcePatrick Steinhardt, Oct 31, 2025
  31. 01/13 odb: fix subtle logic to check whether an alternate is usablePatrick Steinhardt, Oct 31, 2025
  32. 02/13 odb: introduce `odb_source_new()`Patrick Steinhardt, Oct 31, 2025
  33. 03/13 odb: adjust naming to free object sourcesPatrick Steinhardt, Oct 31, 2025
  34. 04/13 object-file: move `fetch_if_missing`Patrick Steinhardt, Oct 31, 2025
  35. 05/13 object-file: introduce `struct odb_loose_source`Patrick Steinhardt, Oct 31, 2025
  36. 06/13 object-file: move loose object cache into loose sourcePatrick Steinhardt, Oct 31, 2025
  37. 07/13 object-file: hide internals when we need to reprepare loose sourcesPatrick Steinhardt, Oct 31, 2025
  38. 08/13 object-file: move loose object map into loose sourcePatrick Steinhardt, Oct 31, 2025
  39. 09/13 object-file: read objects via the loose object sourcePatrick Steinhardt, Oct 31, 2025
  40. 10/13 object-file: rename `has_loose_object()`Patrick Steinhardt, Oct 31, 2025
  41. 11/13 object-file: refactor freshening of objectsPatrick Steinhardt, Oct 31, 2025
  42. 12/13 object-file: rename `write_object_file()`Patrick Steinhardt, Oct 31, 2025
  43. 13/13 object-file: refactor writing objects via a streamPatrick Steinhardt, Oct 31, 2025
  44. 00/13 Carve out loose object sourcePatrick Steinhardt, Nov 3, 2025
  45. 01/13 odb: fix subtle logic to check whether an alternate is usablePatrick Steinhardt, Nov 3, 2025
  46. 02/13 odb: introduce `odb_source_new()`Patrick Steinhardt, Nov 3, 2025
  47. 03/13 odb: adjust naming to free object sourcesPatrick Steinhardt, Nov 3, 2025
  48. 04/13 object-file: move `fetch_if_missing`Patrick Steinhardt, Nov 3, 2025
  49. 05/13 object-file: introduce `struct odb_source_loose`Patrick Steinhardt, Nov 3, 2025
  50. 06/13 object-file: move loose object cache into loose sourcePatrick Steinhardt, Nov 3, 2025
  51. 07/13 object-file: hide internals when we need to reprepare loose sourcesPatrick Steinhardt, Nov 3, 2025
  52. 08/13 object-file: move loose object map into loose sourcePatrick Steinhardt, Nov 3, 2025
  53. 09/13 object-file: read objects via the loose object sourcePatrick Steinhardt, Nov 3, 2025
  54. 10/13 object-file: rename `has_loose_object()`Patrick Steinhardt, Nov 3, 2025
  55. 11/13 object-file: refactor freshening of objectsPatrick Steinhardt, Nov 3, 2025
  56. 12/13 object-file: rename `write_object_file()`Patrick Steinhardt, Nov 3, 2025
  57. 13/13 object-file: refactor writing objects via a streamPatrick Steinhardt, Nov 3, 2025
  58. Karthik NayakNov 3, 2025

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.