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

[PATCH v2 01/13] repository: introduce parsed objects field

From
Stefan Beller <sbeller@google.com>
Date
May 7, 2018, 22:59 UTC
Message-ID
<20180507225916.155236-2-sbeller@google.com>
In-Reply-To
<20180507225916.155236-1-sbeller@google.com>

Convert the existing global cache for parsed objects (obj_hash) into repository-specific parsed object caches. Existing code that uses obj_hash are modified to use the parsed object cache of the_repository; future patches will use the parsed object caches of other repositories.

Another future use case for a pool of objects is ease of memory management in revision walking: If we can free the rev-list related memory early in pack-objects (e.g. part of repack operation) then it could lower memory pressure significantly when running on large repos. While this has been discussed on the mailing list lately, this series doesn't implement this.

Signed-off-by: Stefan Beller <sbeller@google.com>
---
 object.c     | 63 +++++++++++++++++++++++++++++++++-------------------
 object.h     |  8 +++++++
 repository.c |  7 ++++++
 repository.h | 13 ++++++++++-
 4 files changed, 67 insertions(+), 24 deletions(-)
diff --git a/object.c b/object.c
index 5044d08e96c..f7c624a7ba6 100644
--- a/object.c
+++ b/object.c
@@ -8,17 +8,14 @@
 #include "object-store.h"
 #include "packfile.h"
 
-static struct object **obj_hash;
-static int nr_objs, obj_hash_size;
-
 unsigned int get_max_object_index(void)
 {
-	return obj_hash_size;
+	return the_repository->parsed_objects->obj_hash_size;
 }
 
 struct object *get_indexed_object(unsigned int idx)
 {
-	return obj_hash[idx];
+	return the_repository->parsed_objects->obj_hash[idx];
 }
 
 static const char *object_type_strings[] = {
@@ -90,15 +87,16 @@ struct object *lookup_object(const unsigned char *sha1)
 	unsigned int i, first;
 	struct object *obj;
 
-	if (!obj_hash)
+	if (!the_repository->parsed_objects->obj_hash)
 		return NULL;
 
-	first = i = hash_obj(sha1, obj_hash_size);
-	while ((obj = obj_hash[i]) != NULL) {
+	first = i = hash_obj(sha1,
+			     the_repository->parsed_objects->obj_hash_size);
+	while ((obj = the_repository->parsed_objects->obj_hash[i]) != NULL) {
 		if (!hashcmp(sha1, obj->oid.hash))
 			break;
 		i++;
-		if (i == obj_hash_size)
+		if (i == the_repository->parsed_objects->obj_hash_size)
 			i = 0;
 	}
 	if (obj && i != first) {
@@ -107,7 +105,8 @@ struct object *lookup_object(const unsigned char *sha1)
 		 * that we do not need to walk the hash table the next
 		 * time we look for it.
 		 */
-		SWAP(obj_hash[i], obj_hash[first]);
+		SWAP(the_repository->parsed_objects->obj_hash[i],
+		     the_repository->parsed_objects->obj_hash[first]);
 	}
 	return obj;
 }
@@ -124,19 +123,19 @@ static void grow_object_hash(void)
 	 * Note that this size must always be power-of-2 to match hash_obj
 	 * above.
 	 */
-	int new_hash_size = obj_hash_size < 32 ? 32 : 2 * obj_hash_size;
+	int new_hash_size = the_repository->parsed_objects->obj_hash_size < 32 ? 32 : 2 * the_repository->parsed_objects->obj_hash_size;
 	struct object **new_hash;
 
 	new_hash = xcalloc(new_hash_size, sizeof(struct object *));
-	for (i = 0; i < obj_hash_size; i++) {
-		struct object *obj = obj_hash[i];
+	for (i = 0; i < the_repository->parsed_objects->obj_hash_size; i++) {
+		struct object *obj = the_repository->parsed_objects->obj_hash[i];
 		if (!obj)
 			continue;
 		insert_obj_hash(obj, new_hash, new_hash_size);
 	}
-	free(obj_hash);
-	obj_hash = new_hash;
-	obj_hash_size = new_hash_size;
+	free(the_repository->parsed_objects->obj_hash);
+	the_repository->parsed_objects->obj_hash = new_hash;
+	the_repository->parsed_objects->obj_hash_size = new_hash_size;
 }
 
 void *create_object(const unsigned char *sha1, void *o)
@@ -147,11 +146,12 @@ void *create_object(const unsigned char *sha1, void *o)
 	obj->flags = 0;
 	hashcpy(obj->oid.hash, sha1);
 
-	if (obj_hash_size - 1 <= nr_objs * 2)
+	if (the_repository->parsed_objects->obj_hash_size - 1 <= the_repository->parsed_objects->nr_objs * 2)
 		grow_object_hash();
 
-	insert_obj_hash(obj, obj_hash, obj_hash_size);
-	nr_objs++;
+	insert_obj_hash(obj, the_repository->parsed_objects->obj_hash,
+			the_repository->parsed_objects->obj_hash_size);
+	the_repository->parsed_objects->nr_objs++;
 	return obj;
 }
 
@@ -431,8 +431,8 @@ void clear_object_flags(unsigned flags)
 {
 	int i;
 
-	for (i=0; i < obj_hash_size; i++) {
-		struct object *obj = obj_hash[i];
+	for (i=0; i < the_repository->parsed_objects->obj_hash_size; i++) {
+		struct object *obj = the_repository->parsed_objects->obj_hash[i];
 		if (obj)
 			obj->flags &= ~flags;
 	}
@@ -442,13 +442,20 @@ void clear_commit_marks_all(unsigned int flags)
 {
 	int i;
 
-	for (i = 0; i < obj_hash_size; i++) {
-		struct object *obj = obj_hash[i];
+	for (i = 0; i < the_repository->parsed_objects->obj_hash_size; i++) {
+		struct object *obj = the_repository->parsed_objects->obj_hash[i];
 		if (obj && obj->type == OBJ_COMMIT)
 			obj->flags &= ~flags;
 	}
 }
 
+struct parsed_object_pool *parsed_object_pool_new(void)
+{
+	struct parsed_object_pool *o = xmalloc(sizeof(*o));
+	memset(o, 0, sizeof(*o));
+	return o;
+}
+
 struct raw_object_store *raw_object_store_new(void)
 {
 	struct raw_object_store *o = xmalloc(sizeof(*o));
@@ -488,3 +495,13 @@ void raw_object_store_clear(struct raw_object_store *o)
 	close_all_packs(o);
 	o->packed_git = NULL;
 }
+
+void parsed_object_pool_clear(struct parsed_object_pool *o)
+{
+	/*
+	 * TOOD free objects in o->obj_hash.
+	 *
+	 * As objects are allocated in slabs (see alloc.c), we do
+	 * not need to free each object, but each slab instead.
+	 */
+}
diff --git a/object.h b/object.h
index f13f85b2a94..cecda7da370 100644
--- a/object.h
+++ b/object.h
@@ -1,6 +1,14 @@
 #ifndef OBJECT_H
 #define OBJECT_H
 
+struct parsed_object_pool {
+	struct object **obj_hash;
+	int nr_objs, obj_hash_size;
+};
+
+struct parsed_object_pool *parsed_object_pool_new(void);
+void parsed_object_pool_clear(struct parsed_object_pool *o);
+
 struct object_list {
 	struct object *item;
 	struct object_list *next;
diff --git a/repository.c b/repository.c
index a4848c1bd05..c23404677eb 100644
--- a/repository.c
+++ b/repository.c
@@ -2,6 +2,7 @@
 #include "repository.h"
 #include "object-store.h"
 #include "config.h"
+#include "object.h"
 #include "submodule-config.h"
 
 /* The main repository */
@@ -14,6 +15,8 @@ void initialize_the_repository(void)
 
 	the_repo.index = &the_index;
 	the_repo.objects = raw_object_store_new();
+	the_repo.parsed_objects = parsed_object_pool_new();
+
 	repo_set_hash_algo(&the_repo, GIT_HASH_SHA1);
 }
 
@@ -143,6 +146,7 @@ static int repo_init(struct repository *repo,
 	memset(repo, 0, sizeof(*repo));
 
 	repo->objects = raw_object_store_new();
+	repo->parsed_objects = parsed_object_pool_new();
 
 	if (repo_init_gitdir(repo, gitdir))
 		goto error;
@@ -226,6 +230,9 @@ void repo_clear(struct repository *repo)
 	raw_object_store_clear(repo->objects);
 	FREE_AND_NULL(repo->objects);
 
+	parsed_object_pool_clear(repo->parsed_objects);
+	FREE_AND_NULL(repo->parsed_objects);
+
 	if (repo->config) {
 		git_configset_clear(repo->config);
 		FREE_AND_NULL(repo->config);
diff --git a/repository.h b/repository.h
index e6e00f541bd..73389e81afd 100644
--- a/repository.h
+++ b/repository.h
@@ -22,10 +22,21 @@ struct repository {
 	char *commondir;
 
 	/*
-	 * Holds any information related to accessing the raw object content.
+	 * Holds any information needed to retrieve the raw content
+	 * of objects. The object_parser uses this to get object
+	 * content which it then parses.
 	 */
 	struct raw_object_store *objects;
 
+	/*
+	 * All objects in this repository that have been parsed. This structure
+	 * owns all objects it references, so users of "struct object *"
+	 * generally do not need to free them; instead, when a repository is no
+	 * longer used, call parsed_object_pool_clear() on this structure, which
+	 * is called by the repositories repo_clear on its desconstruction.
+	 */
+	struct parsed_object_pool *parsed_objects;
+
 	/* The store in which the refs are held. */
 	struct ref_store *refs;
 
-- 
2.17.0.255.g8bfb7c0704
Previous: Stefan BellerNext: Jonathan Tan
Message 52 of 95 in “object store: alloc”
  1. 00/13 object store: allocStefan Beller, May 1, 2018
  2. 01/13 repository: introduce object parser fieldStefan Beller, May 1, 2018
  3. Duy NguyenMay 2, 2018
  4. Stefan BellerMay 2, 2018
  5. Duy NguyenMay 2, 2018
  6. Jonathan TanMay 2, 2018
  7. 02/13 object: add repository argument to create_objectStefan Beller, May 1, 2018
  8. Eric SunshineMay 1, 2018
  9. 05/13 alloc: add repository argument to alloc_tree_nodeStefan Beller, May 1, 2018
  10. 07/13 alloc: add repository argument to alloc_tag_nodeStefan Beller, May 1, 2018
  11. 09/13 alloc: add repository argument to alloc_reportStefan Beller, May 1, 2018
  12. 10/13 alloc: add repository argument to alloc_commit_indexStefan Beller, May 1, 2018
  13. 12/13 object: allow create_object to handle arbitrary repositoriesStefan Beller, May 1, 2018
  14. Jonathan TanMay 2, 2018
  15. 13/13 alloc: allow arbitrary repositories for alloc functionsStefan Beller, May 1, 2018
  16. Duy NguyenMay 2, 2018
  17. Stefan BellerMay 3, 2018
  18. Duy NguyenMay 3, 2018
  19. Jonathan TanMay 2, 2018
  20. Stefan BellerMay 3, 2018
  21. Duy NguyenMay 3, 2018
  22. 11/13 object: allow grow_object_hash to handle arbitrary repositoriesStefan Beller, May 1, 2018
  23. 06/13 alloc: add repository argument to alloc_commit_nodeStefan Beller, May 1, 2018
  24. 08/13 alloc: add repository argument to alloc_object_nodeStefan Beller, May 1, 2018
  25. 03/13 object: add repository argument to grow_object_hashStefan Beller, May 1, 2018
  26. 04/13 alloc: add repository argument to alloc_blob_nodeStefan Beller, May 1, 2018
  27. Jonathan TanMay 2, 2018
  28. Duy NguyenMay 2, 2018
  29. Jameson MillerMay 2, 2018
  30. Duy NguyenMay 2, 2018
  31. Jameson MillerMay 2, 2018
  32. Stefan BellerMay 3, 2018
  33. Junio C HamanoMay 7, 2018
  34. Stefan BellerMay 7, 2018
  35. 00/13 object store: allocStefan Beller, May 7, 2018
  36. 02/13 object: add repository argument to create_objectStefan Beller, May 7, 2018
  37. 03/13 object: add repository argument to grow_object_hashStefan Beller, May 7, 2018
  38. 04/13 alloc: add repository argument to alloc_blob_nodeStefan Beller, May 7, 2018
  39. 08/13 alloc: add repository argument to alloc_object_nodeStefan Beller, May 7, 2018
  40. 10/13 alloc: add repository argument to alloc_commit_indexStefan Beller, May 7, 2018
  41. 11/13 object: allow grow_object_hash to handle arbitrary repositoriesStefan Beller, May 7, 2018
  42. 12/13 object: allow create_object to handle arbitrary repositoriesStefan Beller, May 7, 2018
  43. 13/13 alloc: allow arbitrary repositories for alloc functionsStefan Beller, May 7, 2018
  44. Jeff KingMay 8, 2018
  45. Duy NguyenMay 8, 2018
  46. Stefan BellerMay 8, 2018
  47. Jonathan TanMay 8, 2018
  48. 05/13 alloc: add repository argument to alloc_tree_nodeStefan Beller, May 7, 2018
  49. 06/13 alloc: add repository argument to alloc_commit_nodeStefan Beller, May 7, 2018
  50. 07/13 alloc: add repository argument to alloc_tag_nodeStefan Beller, May 7, 2018
  51. 09/13 alloc: add repository argument to alloc_reportStefan Beller, May 7, 2018
  52. 01/13 repository: introduce parsed objects fieldStefan Beller, May 7, 2018
  53. Jonathan TanMay 8, 2018
  54. 00/13 object store: allocStefan Beller, May 8, 2018
  55. 01/13 repository: introduce parsed objects fieldStefan Beller, May 8, 2018
  56. 02/13 object: add repository argument to create_objectStefan Beller, May 8, 2018
  57. 05/13 alloc: add repository argument to alloc_tree_nodeStefan Beller, May 8, 2018
  58. 07/13 alloc: add repository argument to alloc_tag_nodeStefan Beller, May 8, 2018
  59. 09/13 alloc: add repository argument to alloc_reportStefan Beller, May 8, 2018
  60. 10/13 alloc: add repository argument to alloc_commit_indexStefan Beller, May 8, 2018
  61. 11/13 object: allow grow_object_hash to handle arbitrary repositoriesStefan Beller, May 8, 2018
  62. 12/13 object: allow create_object to handle arbitrary repositoriesStefan Beller, May 8, 2018
  63. 13/13 alloc: allow arbitrary repositories for alloc functionsStefan Beller, May 8, 2018
  64. Jonathan TanMay 8, 2018
  65. Stefan BellerMay 8, 2018
  66. Duy NguyenMay 9, 2018
  67. Duy NguyenMay 9, 2018
  68. Stefan BellerMay 9, 2018
  69. Duy NguyenMay 10, 2018
  70. 08/13 alloc: add repository argument to alloc_object_nodeStefan Beller, May 8, 2018
  71. 03/13 object: add repository argument to grow_object_hashStefan Beller, May 8, 2018
  72. 04/13 alloc: add repository argument to alloc_blob_nodeStefan Beller, May 8, 2018
  73. 06/13 alloc: add repository argument to alloc_commit_nodeStefan Beller, May 8, 2018
  74. 00/13 object store: allocStefan Beller, May 10, 2018
  75. 01/13 repository: introduce parsed objects fieldStefan Beller, May 10, 2018
  76. 03/13 object: add repository argument to grow_object_hashStefan Beller, May 10, 2018
  77. 06/13 alloc: add repository argument to alloc_commit_nodeStefan Beller, May 10, 2018
  78. 08/13 alloc: add repository argument to alloc_object_nodeStefan Beller, May 10, 2018
  79. 10/13 alloc: add repository argument to alloc_commit_indexStefan Beller, May 10, 2018
  80. 12/13 object: allow create_object to handle arbitrary repositoriesStefan Beller, May 10, 2018
  81. 11/13 object: allow grow_object_hash to handle arbitrary repositoriesStefan Beller, May 10, 2018
  82. 13/13 alloc: allow arbitrary repositories for alloc functionsStefan Beller, May 10, 2018
  83. 05/13 alloc: add repository argument to alloc_tree_nodeStefan Beller, May 10, 2018
  84. 09/13 alloc: add repository argument to alloc_reportStefan Beller, May 10, 2018
  85. 07/13 alloc: add repository argument to alloc_tag_nodeStefan Beller, May 10, 2018
  86. 02/13 object: add repository argument to create_objectStefan Beller, May 10, 2018
  87. 04/13 alloc: add repository argument to alloc_blob_nodeStefan Beller, May 10, 2018
  88. Jonathan TanMay 10, 2018
  89. Stefan BellerMay 10, 2018
  90. Jonathan TanMay 10, 2018
  91. Stefan BellerMay 10, 2018
  92. alloc: allow arbitrary repositories for alloc functionsStefan Beller, May 11, 2018
  93. Eric SunshineMay 11, 2018
  94. alloc: allow arbitrary repositories for alloc functionsStefan Beller, May 15, 2018
  95. Junio C HamanoMay 16, 2018

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.