Commit 1943de014775b966dbd5307f839f666123bb26f1

Stefan Sperling 2018-06-22T10:46:10

add a commit cache as well

diff --git a/include/got_object.h b/include/got_object.h
index 32c6146..df0f4ad 100644
--- a/include/got_object.h
+++ b/include/got_object.h
@@ -48,6 +48,8 @@ struct got_commit_object {
 	char *committer;
 	struct tm tm_committer;	/* UTC */
 	char *logmsg;
+
+	int refcnt; /* for internal use only */
 };
 
 /* A generic object. Used as a handle which holds an ID and an object type. */
diff --git a/lib/got_lib_repository.h b/lib/got_lib_repository.h
index fbcf7b5..f25073b 100644
--- a/lib/got_lib_repository.h
+++ b/lib/got_lib_repository.h
@@ -21,7 +21,8 @@
 
 enum got_object_chache_type {
 	GOT_OBJECT_CACHE_TYPE_OBJ,
-	GOT_OBJECT_CACHE_TYPE_TREE
+	GOT_OBJECT_CACHE_TYPE_TREE,
+	GOT_OBJECT_CACHE_TYPE_COMMIT,
 };
 
 struct got_object_cache_entry {
@@ -29,6 +30,7 @@ struct got_object_cache_entry {
 	union {
 		struct got_object *obj;
 		struct got_tree_object *tree;
+		struct got_commit_object *commit;
 	} data;
 };
 
@@ -52,6 +54,7 @@ struct got_repository {
 	/* Caches for opened objects. */
 	struct got_object_cache objcache;
 	struct got_object_cache treecache;
+	struct got_object_cache commitcache;
 };
 
 const struct got_error*got_repo_cache_object(struct got_repository *,
@@ -62,3 +65,7 @@ const struct got_error*got_repo_cache_tree(struct got_repository *,
     struct got_object_id *, struct got_tree_object *);
 struct got_tree_object *got_repo_get_cached_tree(struct got_repository *,
     struct got_object_id *);
+const struct got_error*got_repo_cache_commit(struct got_repository *,
+    struct got_object_id *, struct got_commit_object *);
+struct got_commit_object *got_repo_get_cached_commit(struct got_repository *,
+    struct got_object_id *);
diff --git a/lib/object.c b/lib/object.c
index 07109c3..499cfb5 100644
--- a/lib/object.c
+++ b/lib/object.c
@@ -971,6 +971,12 @@ got_object_commit_open(struct got_commit_object **commit,
 {
 	const struct got_error *err = NULL;
 
+	*commit = got_repo_get_cached_commit(repo, &obj->id);
+	if (*commit != NULL) {
+		(*commit)->refcnt++;
+		return NULL;
+	}
+
 	if (obj->type != GOT_OBJ_TYPE_COMMIT)
 		return got_error(GOT_ERR_OBJ_TYPE);
 
@@ -991,6 +997,12 @@ got_object_commit_open(struct got_commit_object **commit,
 		err = read_commit_object_privsep(commit, repo, obj, fd);
 		close(fd);
 	}
+
+	if (err == NULL) {
+		(*commit)->refcnt++;
+		err = got_repo_cache_commit(repo, &obj->id, *commit);
+	}
+
 	return err;
 }
 
@@ -999,6 +1011,11 @@ got_object_commit_close(struct got_commit_object *commit)
 {
 	struct got_object_qid *qid;
 
+	if (commit->refcnt > 0) {
+		commit->refcnt--;
+		return;
+	}
+
 	while (!SIMPLEQ_EMPTY(&commit->parent_ids)) {
 		qid = SIMPLEQ_FIRST(&commit->parent_ids);
 		SIMPLEQ_REMOVE_HEAD(&commit->parent_ids, entry);
diff --git a/lib/repository.c b/lib/repository.c
index a688bda..73293f2 100644
--- a/lib/repository.c
+++ b/lib/repository.c
@@ -169,6 +169,9 @@ cache_add(struct got_object_cache *cache, struct got_object_id *id, void *item)
 		case GOT_OBJECT_CACHE_TYPE_TREE:
 			got_object_tree_close(ce->data.tree);
 			break;
+		case GOT_OBJECT_CACHE_TYPE_COMMIT:
+			got_object_commit_close(ce->data.commit);
+			break;
 		}
 		free(ce);
 	}
@@ -184,6 +187,9 @@ cache_add(struct got_object_cache *cache, struct got_object_id *id, void *item)
 	case GOT_OBJECT_CACHE_TYPE_TREE:
 		ce->data.tree = (struct got_tree_object *)item;
 		break;
+	case GOT_OBJECT_CACHE_TYPE_COMMIT:
+		ce->data.commit = (struct got_commit_object *)item;
+		break;
 	}
 	err = got_object_idset_add(NULL, cache->set, id, ce);
 	if (err) {
@@ -256,6 +262,35 @@ got_repo_get_cached_tree(struct got_repository *repo,
 	return NULL;
 }
 
+const struct got_error *
+got_repo_cache_commit(struct got_repository *repo, struct got_object_id *id,
+    struct got_commit_object *commit)
+{
+	const struct got_error *err = NULL;
+
+	err = cache_add(&repo->commitcache, id, commit);
+	if (err)
+		return err;
+
+	commit->refcnt++;
+	return NULL;
+}
+
+struct got_commit_object *
+got_repo_get_cached_commit(struct got_repository *repo,
+    struct got_object_id *id)
+{
+	struct got_object_cache_entry *ce;
+
+	ce = got_object_idset_get(repo->commitcache.set, id);
+	if (ce) {
+		repo->commitcache.cache_hit++;
+		return ce->data.commit;
+	}
+
+	repo->commitcache.cache_miss++;
+	return NULL;
+}
 
 const struct got_error *
 got_repo_open(struct got_repository **ret, const char *path)
@@ -291,6 +326,13 @@ got_repo_open(struct got_repository **ret, const char *path)
 	}
 	repo->treecache.type = GOT_OBJECT_CACHE_TYPE_TREE;
 
+	repo->commitcache.set = got_object_idset_alloc();
+	if (repo->commitcache.set == NULL) {
+		err = got_error_from_errno();
+		goto done;
+	}
+	repo->commitcache.type = GOT_OBJECT_CACHE_TYPE_COMMIT;
+
 	repo->path = got_path_normalize(abspath);
 	if (repo->path == NULL) {
 		err = got_error(GOT_ERR_BAD_PATH);
@@ -345,6 +387,16 @@ done:
 	return err;
 }
 
+static void
+print_cache_stats(struct got_object_cache *cache, const char *name)
+{
+#if 0
+	fprintf(stderr, "%s cache: %d elements, %d hits, %d missed\n",
+	    name, got_object_idset_num_elements(cache->set), cache->cache_hit,
+	    cache->cache_miss);
+#endif
+}
+
 void
 got_repo_close(struct got_repository *repo)
 {
@@ -364,9 +416,14 @@ got_repo_close(struct got_repository *repo)
 
 	free(repo->path);
 	free(repo->path_git_dir);
+	print_cache_stats(&repo->objcache, "object");
+	print_cache_stats(&repo->treecache, "tree");
+	print_cache_stats(&repo->commitcache, "commit");
 	if (repo->objcache.set)
 		got_object_idset_free(repo->objcache.set);
 	if (repo->treecache.set)
 		got_object_idset_free(repo->treecache.set);
+	if (repo->commitcache.set)
+		got_object_idset_free(repo->commitcache.set);
 	free(repo);
 }