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

[PATCH 1/9] odb: compute compat object ID in `odb_write_object_ext()`

From
Patrick Steinhardt <ps@pks.im>
Date
Jul 17, 2026, 09:32 UTC
Message-ID
<20260717-pks-odb-move-loose-object-writing-v1-1-46446a3cb5b7@pks.im>
In-Reply-To
<20260717-pks-odb-move-loose-object-writing-v1-0-46446a3cb5b7@pks.im>

Repositories can have a compatibility hash configured, which means that such a repository is expected to maintain a mapping between canonical and compatibility object hashes. Maintaining this mapping is the responsibility of the object database sources, where we either store them as part of the loose objects map or in packfile indices v3 (once we gain support for this feature).

But besides storing these compatibility hashes, the sources are also responsible for generating the compatibility hash in the first place. This is somewhat unnecessary though, as the compatibility hash should be computed the same no matter which source is being used. The consequence is that we need to duplicate this functionality across the different backends, which does not make a lot of sense.

Refactor the code so that we instead compute the compatibility hash in `odb_write_object_ext()` and then pass the computed value to the sources. No callers need adjustment as there are none that write objects via the source interfaces directly.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 odb.c                 | 26 ++++++++++++++++++++++++--
 odb.h                 | 10 ++++++----
 odb/source-files.c    |  2 +-
 odb/source-inmemory.c |  2 +-
 odb/source-loose.c    | 24 +++---------------------
 odb/source-packed.c   |  2 +-
 odb/source.h          |  4 ++--
 7 files changed, 38 insertions(+), 32 deletions(-)
diff --git a/odb.c b/odb.c
index cf6e7938c0..1d6538163b 100644
--- a/odb.c
+++ b/odb.c
@@ -989,11 +989,33 @@ int odb_write_object_ext(struct object_database *odb,
 			 const void *buf, unsigned long len,
 			 enum object_type type,
 			 struct object_id *oid,
-			 struct object_id *compat_oid,
+			 const struct object_id *compat_oid_in,
 			 enum odb_write_object_flags flags)
 {
+	const struct git_hash_algo *compat = odb->repo->compat_hash_algo;
+	struct object_id compat_oid, *compat_oid_p = NULL;
+
+	if (compat) {
+		const struct git_hash_algo *algo = odb->repo->hash_algo;
+
+		if (compat_oid_in) {
+			oidcpy(&compat_oid, compat_oid_in);
+		} else if (type == OBJ_BLOB) {
+			hash_object_file(compat, buf, len, type, &compat_oid);
+		} else {
+			struct strbuf converted = STRBUF_INIT;
+			convert_object_file(odb->repo, &converted, algo, compat,
+					    buf, len, type, 0);
+			hash_object_file(compat, converted.buf, converted.len,
+					 type, &compat_oid);
+			strbuf_release(&converted);
+		}
+
+		compat_oid_p = &compat_oid;
+	}
+
 	return odb_source_write_object(odb->sources, buf, len, type,
-				       oid, compat_oid, flags);
+				       oid, compat_oid_p, flags);
 }
 
 int odb_write_object_stream(struct object_database *odb,
diff --git a/odb.h b/odb.h
index 94754643d2..066560113e 100644
--- a/odb.h
+++ b/odb.h
@@ -585,9 +585,11 @@ enum odb_write_object_flags {
 
 /*
  * Write an object into the object database. The object is being written into
- * the local alternate of the repository. If provided, the converted object ID
- * as well as the compatibility object ID are written to the respective
- * pointers.
+ * the local alternate of the repository. If provided, the object ID of the
+ * final object is written into `oid`.
+ *
+ * If the caller provides a `compat_oid`, then this compatibility object hash
+ * will be stored instead of computing the compatibility hash ad-hoc.
  *
  * Returns 0 on success, a negative error code otherwise.
  */
@@ -595,7 +597,7 @@ int odb_write_object_ext(struct object_database *odb,
 			 const void *buf, unsigned long len,
 			 enum object_type type,
 			 struct object_id *oid,
-			 struct object_id *compat_oid,
+			 const struct object_id *compat_oid,
 			 enum odb_write_object_flags flags);
 
 static inline int odb_write_object(struct object_database *odb,
diff --git a/odb/source-files.c b/odb/source-files.c
index 4138758511..3d9f5eca32 100644
--- a/odb/source-files.c
+++ b/odb/source-files.c
@@ -163,7 +163,7 @@ static int odb_source_files_write_object(struct odb_source *source,
 					 const void *buf, size_t len,
 					 enum object_type type,
 					 struct object_id *oid,
-					 struct object_id *compat_oid,
+					 const struct object_id *compat_oid,
 					 enum odb_write_object_flags flags)
 {
 	struct odb_source_files *files = odb_source_files_downcast(source);
diff --git a/odb/source-inmemory.c b/odb/source-inmemory.c
index e47bfd8fcc..e727aba427 100644
--- a/odb/source-inmemory.c
+++ b/odb/source-inmemory.c
@@ -231,7 +231,7 @@ static int odb_source_inmemory_write_object(struct odb_source *source,
 					    const void *buf, size_t len,
 					    enum object_type type,
 					    struct object_id *oid,
-					    struct object_id *compat_oid UNUSED,
+					    const struct object_id *compat_oid UNUSED,
 					    enum odb_write_object_flags flags UNUSED)
 {
 	struct odb_source_inmemory *inmemory = odb_source_inmemory_downcast(source);
diff --git a/odb/source-loose.c b/odb/source-loose.c
index 3f7d04a56e..ca223109cd 100644
--- a/odb/source-loose.c
+++ b/odb/source-loose.c
@@ -585,32 +585,14 @@ static int odb_source_loose_freshen_object(struct odb_source *source,
 static int odb_source_loose_write_object(struct odb_source *source,
 					 const void *buf, size_t len,
 					 enum object_type type, struct object_id *oid,
-					 struct object_id *compat_oid_in,
+					 const struct object_id *compat_oid,
 					 enum odb_write_object_flags flags)
 {
 	struct odb_source_loose *loose = odb_source_loose_downcast(source);
 	const struct git_hash_algo *algo = source->odb->repo->hash_algo;
-	const struct git_hash_algo *compat = source->odb->repo->compat_hash_algo;
-	struct object_id compat_oid;
 	char hdr[MAX_HEADER_LEN];
 	size_t hdrlen = sizeof(hdr);
 
-	/* Generate compat_oid */
-	if (compat) {
-		if (compat_oid_in)
-			oidcpy(&compat_oid, compat_oid_in);
-		else if (type == OBJ_BLOB)
-			hash_object_file(compat, buf, len, type, &compat_oid);
-		else {
-			struct strbuf converted = STRBUF_INIT;
-			convert_object_file(source->odb->repo, &converted, algo, compat,
-					    buf, len, type, 0);
-			hash_object_file(compat, converted.buf, converted.len,
-					 type, &compat_oid);
-			strbuf_release(&converted);
-		}
-	}
-
 	/* Normally if we have it in the pack then we do not bother writing
 	 * it out into .git/objects/??/?{38} file.
 	 */
@@ -619,8 +601,8 @@ static int odb_source_loose_write_object(struct odb_source *source,
 		return 0;
 	if (write_loose_object(loose, oid, hdr, hdrlen, buf, len, 0, flags))
 		return -1;
-	if (compat)
-		return repo_add_loose_object_map(loose, oid, &compat_oid);
+	if (compat_oid)
+		return repo_add_loose_object_map(loose, oid, compat_oid);
 	return 0;
 }
 
diff --git a/odb/source-packed.c b/odb/source-packed.c
index 8d9ce197cc..af0d533375 100644
--- a/odb/source-packed.c
+++ b/odb/source-packed.c
@@ -530,7 +530,7 @@ static int odb_source_packed_write_object(struct odb_source *source UNUSED,
 					  size_t len UNUSED,
 					  enum object_type type UNUSED,
 					  struct object_id *oid UNUSED,
-					  struct object_id *compat_oid UNUSED,
+					  const struct object_id *compat_oid UNUSED,
 					  unsigned flags UNUSED)
 {
 	return error("packed backend cannot write objects");
diff --git a/odb/source.h b/odb/source.h
index cd63dba91f..b3c1ca3a66 100644
--- a/odb/source.h
+++ b/odb/source.h
@@ -207,7 +207,7 @@ struct odb_source {
 			    const void *buf, size_t len,
 			    enum object_type type,
 			    struct object_id *oid,
-			    struct object_id *compat_oid,
+			    const struct object_id *compat_oid,
 			    enum odb_write_object_flags flags);
 
 	/*
@@ -417,7 +417,7 @@ static inline int odb_source_write_object(struct odb_source *source,
 					  const void *buf, unsigned long len,
 					  enum object_type type,
 					  struct object_id *oid,
-					  struct object_id *compat_oid,
+					  const struct object_id *compat_oid,
 					  enum odb_write_object_flags flags)
 {
 	return source->write_object(source, buf, len, type, oid,
-- 
2.55.0.407.g700c83d4f3.dirty
Previous: Patrick SteinhardtNext: Justin Tobler
Message 2 of 17 in “object-file: move writing of loose objects into "loose" source”
  1. 0/9 object-file: move writing of loose objects into "loose" sourcePatrick Steinhardt, Jul 17, 2026
  2. 1/9 odb: compute compat object ID in `odb_write_object_ext()`Patrick Steinhardt, Jul 17, 2026
  3. Justin ToblerJul 28, 2026
  4. 2/9 t/u-odb-inmemory: implement wrapper for writing objectsPatrick Steinhardt, Jul 17, 2026
  5. Justin ToblerJul 28, 2026
  6. 3/9 odb: compute object hash in `odb_write_object_ext()`Patrick Steinhardt, Jul 17, 2026
  7. 4/9 odb: lift object existence check out of the "loose" backendPatrick Steinhardt, Jul 17, 2026
  8. Toon ClaesJul 22, 2026
  9. 5/9 odb: support setting mtime when writing objectsPatrick Steinhardt, Jul 17, 2026
  10. 6/9 object-file: fix memory leak in `force_object_loose()`Patrick Steinhardt, Jul 17, 2026
  11. 7/9 object-file: force objects loose via generic interfacePatrick Steinhardt, Jul 17, 2026
  12. 8/9 object-file: move `force_object_loose()`Patrick Steinhardt, Jul 17, 2026
  13. 9/9 object-file: move logic to write loose objectsPatrick Steinhardt, Jul 17, 2026
  14. Toon ClaesJul 22, 2026
  15. SZEDER GáborJul 18, 2026
  16. Junio C HamanoJul 19, 2026
  17. Junio C HamanoJul 19, 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.