git/list[1] front-page[2] threads[3] people[4] search[5] about
wed 2026-10-07 17:27 UTC

[PATCH v2 00/17] odb: make object database sources pluggable

From
Patrick Steinhardt <ps@pks.im>
Date
Mar 5, 2026, 14:19 UTC
Message-ID
<20260305-b4-pks-odb-source-pluggable-v2-0-3290bfd1f444@pks.im>
In-Reply-To
<20260223-b4-pks-odb-source-pluggable-v1-0-253bac1db598@pks.im>
Hi,

this patch series finally makes the object database source pluggable. This is done by moving backend-specific logics into callback functions that are part of `struct odb_source` and providing thin wrappers that call those functions.

To set expectations: this is only a start, there is still functionality missing that needs to be made pluggable. Most importantly:

  - Counting of objects.
  - Abbreviating object IDs and finding ambiguous objects.
  - Consistency checks.
  - Optimizing the object database.
  - Generating packfiles.

These will all happen in later patch series. That being said, with this patch series one already gets a lot of the basic functionality, and it's almost possible to do local workflows. Only "almost" though because we rely on abbreviating object IDs in a lot of places, but once that part is implemented in a subsequent patch series you can indeed work locally with an alternate backend.

Furthermore, what I didn't include as part of this patch series just yet is the introduction of the "objectStorage" extension. I mostly wanted to focus on the mostly-trivial parts without introducing any change in behaviour.

This series is based on top of 7c02d39fc2 (The 6th batch, 2026-02-20) with the following two series merged into it:

  - ps/odb-for-each-object at 3565faf28c (odb: drop unused
    `for_each_{loose,packed}_object()` functions, 2026-01-26)
  - ps/object-info-bits-cleanup at 732ec9b17b (odb: convert
    `odb_has_object()` flags into an enum, 2026-02-12)
Changes in v2:
  - Fix mismerge in the base of this patch series.
  - Adjust several comments and improve commit messages a bit.
  - Link to v1: https://lore.kernel.org/r/20260223-b4-pks-odb-source-pluggable-v1-0-253bac1db598@pks.im
Thanks!
Patrick
---
Patrick Steinhardt (17):
      odb: split `struct odb_source` into separate header
      odb: introduce "files" source
      odb: embed base source in the "files" backend
      odb: move reparenting logic into respective subsystems
      odb/source: introduce source type for robustness
      odb/source: make `free()` function pluggable
      odb/source: make `reprepare()` function pluggable
      odb/source: make `close()` function pluggable
      odb/source: make `read_object_info()` function pluggable
      odb/source: make `read_object_stream()` function pluggable
      odb/source: make `for_each_object()` function pluggable
      odb/source: make `freshen_object()` function pluggable
      odb/source: make `write_object()` function pluggable
      odb/source: make `write_object_stream()` function pluggable
      odb/source: make `read_alternates()` function pluggable
      odb/source: make `write_alternate()` function pluggable
      odb/source: make `begin_transaction()` function pluggable
 Makefile               |   2 +
 builtin/cat-file.c     |   3 +-
 builtin/fast-import.c  |  12 +-
 builtin/grep.c         |   6 +-
 builtin/index-pack.c   |   8 +-
 builtin/pack-objects.c |  13 +-
 commit-graph.c         |   6 +-
 http.c                 |   3 +-
 loose.c                |  23 ++-
 meson.build            |   2 +
 midx.c                 |  26 +--
 object-file.c          |  38 ++--
 odb.c                  | 191 +++-----------------
 odb.h                  |  86 +--------
 odb/source-files.c     | 239 +++++++++++++++++++++++++
 odb/source-files.h     |  35 ++++
 odb/source.c           |  38 ++++
 odb/source.h           | 468 +++++++++++++++++++++++++++++++++++++++++++++++++
 odb/streaming.c        |   8 +-
 packfile.c             |  36 ++--
 packfile.h             |   7 +-
 tmp-objdir.c           |  42 ++---
 tmp-objdir.h           |  15 --
 23 files changed, 953 insertions(+), 354 deletions(-)
Range-diff versus v1:
 1:  28258657d5 =  1:  6dd89d5721 odb: split `struct odb_source` into separate header
 2:  38fa6650e7 =  2:  aaf6175ad7 odb: introduce "files" source
 3:  bbdfe087d3 !  3:  1188bc969a odb: embed base source in the "files" backend
    @@ odb/source-files.h: struct packfile_store;
      void odb_source_files_free(struct odb_source_files *files);
      
     +/*
    -+ * Cast the given object database source to the files backend. This will cause
    -+ * a BUG in case the source doesn't use this backend.
    ++ * Cast the given object database source to the files backend.
     + */
     +static inline struct odb_source_files *odb_source_files_downcast(struct odb_source *source)
     +{
 4:  1f545a0b28 !  4:  a5deca0da9 odb: move reparenting logic into respective subsystems
    @@ Commit message
         odb: move reparenting logic into respective subsystems
     
         The primary object database source may be initialized with a relative
    -    path. When reparenting the process to a different working directory we
    -    thus have to update this path and have it point to the same path, but
    +    path. When the process changes its current working directory we thus
    +    have to update this path and have it point to the same path, but
         relative to the new working directory.
     
         This logic is handled in the object database layer. It consists of three
 5:  f3f0f3daeb !  5:  defb03a1b9 odb/source: introduce source type for robustness
    @@ odb/source-files.c: struct odb_source_files *odb_source_files_new(struct object_
      
     
      ## odb/source-files.h ##
    -@@ odb/source-files.h: void odb_source_files_free(struct odb_source_files *files);
    +@@ odb/source-files.h: struct odb_source_files *odb_source_files_new(struct object_database *odb,
    + void odb_source_files_free(struct odb_source_files *files);
    + 
    + /*
    +- * Cast the given object database source to the files backend.
    ++ * Cast the given object database source to the files backend. This will cause
    ++ * a BUG in case the source doesn't use this backend.
       */
      static inline struct odb_source_files *odb_source_files_downcast(struct odb_source *source)
      {
    @@ odb/source.h
      
     +enum odb_source_type {
     +	/*
    -+	 * The "unknown" type, which should never be in use. This is type
    -+	 * mostly exists to catch cases where the type field remains zeroed
    -+	 * out.
    ++	 * The "unknown" type, which should never be in use. This type mostly
    ++	 * exists to catch cases where the type field remains zeroed out.
     +	 */
     +	ODB_SOURCE_UNKNOWN,
     +
 6:  c86a03bf7c =  6:  df5c9e7584 odb/source: make `free()` function pluggable
 7:  b1645d0de0 =  7:  6787995a2c odb/source: make `reprepare()` function pluggable
 8:  e873c4f32c =  8:  9942876dbe odb/source: make `close()` function pluggable
 9:  0ccf994441 !  9:  9902f4561b odb/source: make `read_object_info()` function pluggable
    @@ Commit message
         Signed-off-by: Patrick Steinhardt <ps@pks.im>
     
      ## object-file.c ##
    -@@ object-file.c: static int read_object_info_from_path(struct odb_source *source,
    - int odb_source_loose_read_object_info(struct odb_source *source,
    - 				      const struct object_id *oid,
    - 				      struct object_info *oi,
    --				      unsigned flags)
    -+				      enum object_info_flags flags)
    +@@ object-file.c: int odb_source_loose_read_object_info(struct odb_source *source,
    + 				      enum object_info_flags flags)
      {
      	static struct strbuf buf = STRBUF_INIT;
     +
10:  f98a8adfed = 10:  99299ed03e odb/source: make `read_object_stream()` function pluggable
11:  b8a9b9fe16 ! 11:  274a6020ab odb/source: make `for_each_object()` function pluggable
    @@ odb/source.h: struct odb_source {
     +	 * valid to yield the same object multiple time. A non-zero exit code
     +	 * from the object callback shall abort iteration.
     +	 *
    -+	 * The optional `oi` structure shall be populated similar to how an individual
    -+	 * call to `odb_source_read_object_info()` would have behaved. If the caller
    -+	 * passes a `NULL` pointer then the object itself shall not be read.
    ++	 * The optional `request` structure should serve as a template for
    ++	 * looking up object info for every individual iterated object. It
    ++	 * should not be modified directly and should instead be copied into a
    ++	 * separate `struct object_info` that gets passed to the callback. If
    ++	 * the caller passes a `NULL` pointer then the object itself shall not
    ++	 * be read.
     +	 *
     +	 * The callback is expected to return a negative error code in case the
     +	 * iteration has failed to read all objects, 0 otherwise. When the
    @@ odb/source.h: static inline int odb_source_read_object_stream(struct odb_read_st
     + * callback function aborts iteration. There is no guarantee that objects
     + * are only iterated over once.
     + *
    -+ * The optional `oi` structure shall be populated similar to how an individual
    -+ * call to `odb_source_read_object_info()` would have behaved. If the caller
    -+ * passes a `NULL` pointer then the object itself shall not be read.
    ++ * The optional `request` structure serves as a template for retrieving the
    ++ * object info for each indvidual iterated object and will be populated as if
    ++ * `odb_source_read_object_info()` was called on the object. It will not be
    ++ * modified, the callback will instead be invoked with a separate `struct
    ++ * object_info` for every object. Object info will not be read when passing a
    ++ * `NULL` pointer.
     + *
     + * The flags is a bitfield of `ODB_FOR_EACH_OBJECT_*` flags. Not all flags may
     + * apply to a specific backend, so whether or not they are honored is defined
12:  406826905d = 12:  abc1bc6f81 odb/source: make `freshen_object()` function pluggable
13:  59a3678799 ! 13:  9a995ff455 odb/source: make `write_object()` function pluggable
    @@ odb/source.h
     +
      enum odb_source_type {
      	/*
    - 	 * The "unknown" type, which should never be in use. This is type
    + 	 * The "unknown" type, which should never be in use. This type mostly
     @@ odb/source.h: struct odb_source {
      	 */
      	int (*freshen_object)(struct odb_source *source,
14:  e5c47518ef = 14:  8c938de272 odb/source: make `write_object_stream()` function pluggable
15:  ca0e6dfb1a ! 15:  16a826e24c odb/source: make `read_alternates()` function pluggable
    @@ odb/source.h: struct odb_source {
     +	 * This callback is expected to read the list of alternate object
     +	 * database sources connected to it and write them into the `strvec`.
     +	 *
    -+	 * The format is expected to follow the "objectStorage" extension
    -+	 * format with `(backend://)?payload` syntax. If the payload contains
    -+	 * paths, these paths must be resolved to absolute paths.
    ++	 * The result is expected to be paths to the alternates. All paths must
    ++	 * be resolved to absolute paths.
     +	 *
     +	 * The callback is expected to return 0 on success, a negative error
     +	 * code otherwise.
16:  7e36a7ec8f = 16:  2f6bf3aedc odb/source: make `write_alternate()` function pluggable
17:  dc918d3fc5 = 17:  118b442202 odb/source: make `begin_transaction()` function pluggable

--- base-commit: b1af291b4adf1c433ad2b79f0390f7d6b516a964 change-id: 20260120-b4-pks-odb-source-pluggable-5c724250b3c8

Previous: Patrick SteinhardtNext: Patrick Steinhardt
Message 54 of 77 in “odb: make object database sources pluggable”
  1. 00/17 odb: make object database sources pluggablePatrick Steinhardt, Feb 23, 2026
  2. 01/17 odb: split `struct odb_source` into separate headerPatrick Steinhardt, Feb 23, 2026
  3. 02/17 odb: introduce "files" sourcePatrick Steinhardt, Feb 23, 2026
  4. 03/17 odb: embed base source in the "files" backendPatrick Steinhardt, Feb 23, 2026
  5. 04/17 odb: move reparenting logic into respective subsystemsPatrick Steinhardt, Feb 23, 2026
  6. 05/17 odb/source: introduce source type for robustnessPatrick Steinhardt, Feb 23, 2026
  7. 06/17 odb/source: make `free()` function pluggablePatrick Steinhardt, Feb 23, 2026
  8. 07/17 odb/source: make `reprepare()` function pluggablePatrick Steinhardt, Feb 23, 2026
  9. 08/17 odb/source: make `close()` function pluggablePatrick Steinhardt, Feb 23, 2026
  10. 09/17 odb/source: make `read_object_info()` function pluggablePatrick Steinhardt, Feb 23, 2026
  11. 10/17 odb/source: make `read_object_stream()` function pluggablePatrick Steinhardt, Feb 23, 2026
  12. 11/17 odb/source: make `for_each_object()` function pluggablePatrick Steinhardt, Feb 23, 2026
  13. 12/17 odb/source: make `freshen_object()` function pluggablePatrick Steinhardt, Feb 23, 2026
  14. 13/17 odb/source: make `write_object()` function pluggablePatrick Steinhardt, Feb 23, 2026
  15. 14/17 odb/source: make `write_object_stream()` function pluggablePatrick Steinhardt, Feb 23, 2026
  16. 15/17 odb/source: make `read_alternates()` function pluggablePatrick Steinhardt, Feb 23, 2026
  17. 16/17 odb/source: make `write_alternate()` function pluggablePatrick Steinhardt, Feb 23, 2026
  18. 17/17 odb/source: make `begin_transaction()` function pluggablePatrick Steinhardt, Feb 23, 2026
  19. Patrick SteinhardtFeb 23, 2026
  20. Junio C HamanoFeb 23, 2026
  21. Patrick SteinhardtFeb 24, 2026
  22. Justin ToblerMar 4, 2026
  23. Justin ToblerMar 4, 2026
  24. Justin ToblerMar 4, 2026
  25. Justin ToblerMar 4, 2026
  26. Justin ToblerMar 4, 2026
  27. Justin ToblerMar 4, 2026
  28. Justin ToblerMar 4, 2026
  29. Justin ToblerMar 4, 2026
  30. Justin ToblerMar 4, 2026
  31. Justin ToblerMar 4, 2026
  32. Justin ToblerMar 4, 2026
  33. Karthik NayakMar 5, 2026
  34. Karthik NayakMar 5, 2026
  35. Karthik NayakMar 5, 2026
  36. Karthik NayakMar 5, 2026
  37. Karthik NayakMar 5, 2026
  38. Karthik NayakMar 5, 2026
  39. Karthik NayakMar 5, 2026
  40. Patrick SteinhardtMar 5, 2026
  41. Karthik NayakMar 5, 2026
  42. Patrick SteinhardtMar 5, 2026
  43. Patrick SteinhardtMar 5, 2026
  44. Patrick SteinhardtMar 5, 2026
  45. Patrick SteinhardtMar 5, 2026
  46. Patrick SteinhardtMar 5, 2026
  47. Patrick SteinhardtMar 5, 2026
  48. Patrick SteinhardtMar 5, 2026
  49. Patrick SteinhardtMar 5, 2026
  50. Patrick SteinhardtMar 5, 2026
  51. Patrick SteinhardtMar 5, 2026
  52. Patrick SteinhardtMar 5, 2026
  53. Patrick SteinhardtMar 5, 2026
  54. 00/17 odb: make object database sources pluggablePatrick Steinhardt, Mar 5, 2026
  55. 01/17 odb: split `struct odb_source` into separate headerPatrick Steinhardt, Mar 5, 2026
  56. 02/17 odb: introduce "files" sourcePatrick Steinhardt, Mar 5, 2026
  57. 03/17 odb: embed base source in the "files" backendPatrick Steinhardt, Mar 5, 2026
  58. 04/17 odb: move reparenting logic into respective subsystemsPatrick Steinhardt, Mar 5, 2026
  59. 05/17 odb/source: introduce source type for robustnessPatrick Steinhardt, Mar 5, 2026
  60. 06/17 odb/source: make `free()` function pluggablePatrick Steinhardt, Mar 5, 2026
  61. 07/17 odb/source: make `reprepare()` function pluggablePatrick Steinhardt, Mar 5, 2026
  62. 08/17 odb/source: make `close()` function pluggablePatrick Steinhardt, Mar 5, 2026
  63. 09/17 odb/source: make `read_object_info()` function pluggablePatrick Steinhardt, Mar 5, 2026
  64. 10/17 odb/source: make `read_object_stream()` function pluggablePatrick Steinhardt, Mar 5, 2026
  65. 11/17 odb/source: make `for_each_object()` function pluggablePatrick Steinhardt, Mar 5, 2026
  66. 12/17 odb/source: make `freshen_object()` function pluggablePatrick Steinhardt, Mar 5, 2026
  67. 13/17 odb/source: make `write_object()` function pluggablePatrick Steinhardt, Mar 5, 2026
  68. 14/17 odb/source: make `write_object_stream()` function pluggablePatrick Steinhardt, Mar 5, 2026
  69. 15/17 odb/source: make `read_alternates()` function pluggablePatrick Steinhardt, Mar 5, 2026
  70. 16/17 odb/source: make `write_alternate()` function pluggablePatrick Steinhardt, Mar 5, 2026
  71. 17/17 odb/source: make `begin_transaction()` function pluggablePatrick Steinhardt, Mar 5, 2026
  72. Justin ToblerMar 5, 2026
  73. Justin ToblerMar 5, 2026
  74. Justin ToblerMar 5, 2026
  75. Justin ToblerMar 5, 2026
  76. Junio C HamanoMar 5, 2026
  77. Patrick SteinhardtMar 10, 2026

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.