commit f6be5c308af39aaf5dd86f08ed270f009ba12ed8 from: Stefan Sperling date: Fri Jun 22 08:33:04 2018 UTC add a tree object cache to struct got_repository commit - 54f20211c589e3522ed62f05814143d5450a49a7 commit + f6be5c308af39aaf5dd86f08ed270f009ba12ed8 blob - 9268ff826f30da37420b9969e0b0283db36d0455 blob + 32c6146fa5cf6b5944f483716a79e0969bbc4e4b --- include/got_object.h +++ include/got_object.h @@ -28,6 +28,8 @@ struct got_tree_entry { struct got_tree_object { int nentries; SIMPLEQ_HEAD(, got_tree_entry) entries; + + int refcnt; /* for internal use only */ }; struct got_object_qid { blob - db2876225fd8367257df47e56a7a1744ac8632b5 blob + 4eb219f9241f6980f82035f28f5128cab0f988c5 --- lib/got_lib_repository.h +++ lib/got_lib_repository.h @@ -19,12 +19,21 @@ #define GOT_OBJECT_CACHE_SIZE 8192 +enum got_object_chache_type { + GOT_OBJECT_CACHE_TYPE_OBJ, + GOT_OBJECT_CACHE_TYPE_TREE +}; + struct got_object_cache_entry { struct got_object_id id; - struct got_object *obj; + union { + struct got_object *obj; + struct got_tree_object *tree; + } data; }; struct got_object_cache { + enum got_object_chache_type type; struct got_object_idset *set; int ncached; int cache_hit; @@ -41,11 +50,16 @@ struct got_repository { /* Open file handles for pack files. */ struct got_pack packs[GOT_PACK_CACHE_SIZE]; + /* Caches for opened objects. */ struct got_object_cache objcache; + struct got_object_cache treecache; }; -const struct got_error* -got_repo_cache_object(struct got_repository *, struct got_object_id *, - struct got_object *); +const struct got_error*got_repo_cache_object(struct got_repository *, + struct got_object_id *, struct got_object *); struct got_object *got_repo_get_cached_object(struct got_repository *, struct got_object_id *); +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 *); blob - 7fb951947c95f4ddf2f4abdfc5f7cd461226ea3f blob + 07109c33e693f77141506e564316ba71e746ba5e --- lib/object.c +++ lib/object.c @@ -1120,6 +1120,12 @@ got_object_tree_open(struct got_tree_object **tree, struct got_repository *repo, struct got_object *obj) { const struct got_error *err = NULL; + + *tree = got_repo_get_cached_tree(repo, &obj->id); + if (*tree != NULL) { + (*tree)->refcnt++; + return NULL; + } if (obj->type != GOT_OBJ_TYPE_TREE) return got_error(GOT_ERR_OBJ_TYPE); @@ -1141,6 +1147,12 @@ got_object_tree_open(struct got_tree_object **tree, err = read_tree_object_privsep(tree, obj, fd); close(fd); } + + if (err == NULL) { + (*tree)->refcnt++; + err = got_repo_cache_tree(repo, &obj->id, *tree); + } + return err; } @@ -1171,6 +1183,11 @@ void got_object_tree_close(struct got_tree_object *tree) { struct got_tree_entry *te; + + if (tree->refcnt > 0) { + tree->refcnt--; + return; + } while (!SIMPLEQ_EMPTY(&tree->entries)) { te = SIMPLEQ_FIRST(&tree->entries); blob - 9a2fb62cf1d7a941a30ddef9c72e45717d09a5e6 blob + 5900746421a52c01d51c4bbf365e42cce22e01f2 --- lib/repository.c +++ lib/repository.c @@ -149,42 +149,67 @@ done: } -const struct got_error * -got_repo_cache_object(struct got_repository *repo, struct got_object_id *id, - struct got_object *obj) +static const struct got_error * +cache_add(struct got_object_cache *cache, struct got_object_id *id, void *item) { const struct got_error *err = NULL; struct got_object_cache_entry *ce; - if (repo->objcache.ncached >= GOT_OBJECT_CACHE_SIZE) { + if (cache->ncached >= GOT_OBJECT_CACHE_SIZE) { err = got_object_idset_remove_random((void **)&ce, - repo->objcache.set); + cache->set); if (err) return err; - got_object_close(ce->obj); + switch (cache->type) { + case GOT_OBJECT_CACHE_TYPE_OBJ: + got_object_close(ce->data.obj); + break; + case GOT_OBJECT_CACHE_TYPE_TREE: + got_object_tree_close(ce->data.tree); + break; + } free(ce); - repo->objcache.ncached--; + cache->ncached--; } ce = calloc(1, sizeof(*ce)); if (ce == NULL) return got_error_from_errno(); memcpy(&ce->id, id, sizeof(ce->id)); - ce->obj = obj; - err = got_object_idset_add(NULL, repo->objcache.set, id, ce); + switch (cache->type) { + case GOT_OBJECT_CACHE_TYPE_OBJ: + ce->data.obj = (struct got_object *)item; + break; + case GOT_OBJECT_CACHE_TYPE_TREE: + ce->data.tree = (struct got_tree_object *)item; + break; + } + err = got_object_idset_add(NULL, cache->set, id, ce); if (err) { if (err->code == GOT_ERR_OBJ_EXISTS) { free(ce); err = NULL; } - } else { - obj->refcnt++; - repo->objcache.ncached++; - } + } else + cache->ncached++; return err; } +const struct got_error * +got_repo_cache_object(struct got_repository *repo, struct got_object_id *id, + struct got_object *obj) +{ + const struct got_error *err = NULL; + + err = cache_add(&repo->objcache, id, obj); + if (err) + return err; + + obj->refcnt++; + return NULL; +} + struct got_object * got_repo_get_cached_object(struct got_repository *repo, struct got_object_id *id) @@ -194,13 +219,45 @@ got_repo_get_cached_object(struct got_repository *repo ce = got_object_idset_get(repo->objcache.set, id); if (ce) { repo->objcache.cache_hit++; - return ce->obj; + return ce->data.obj; } + repo->objcache.cache_miss++; return NULL; } const struct got_error * +got_repo_cache_tree(struct got_repository *repo, struct got_object_id *id, + struct got_tree_object *tree) +{ + const struct got_error *err = NULL; + + err = cache_add(&repo->treecache, id, tree); + if (err) + return err; + + tree->refcnt++; + return NULL; +} + +struct got_tree_object * +got_repo_get_cached_tree(struct got_repository *repo, + struct got_object_id *id) +{ + struct got_object_cache_entry *ce; + + ce = got_object_idset_get(repo->treecache.set, id); + if (ce) { + repo->treecache.cache_hit++; + return ce->data.tree; + } + + repo->treecache.cache_miss++; + return NULL; +} + + +const struct got_error * got_repo_open(struct got_repository **ret, const char *path) { struct got_repository *repo = NULL; @@ -225,7 +282,15 @@ got_repo_open(struct got_repository **ret, const char err = got_error_from_errno(); goto done; } + repo->objcache.type = GOT_OBJECT_CACHE_TYPE_OBJ; + repo->treecache.set = got_object_idset_alloc(); + if (repo->treecache.set == NULL) { + err = got_error_from_errno(); + goto done; + } + repo->treecache.type = GOT_OBJECT_CACHE_TYPE_TREE; + repo->path = got_path_normalize(abspath); if (repo->path == NULL) { err = got_error(GOT_ERR_BAD_PATH); @@ -301,5 +366,7 @@ got_repo_close(struct got_repository *repo) free(repo->path_git_dir); if (repo->objcache.set) got_object_idset_free(repo->objcache.set); + if (repo->treecache.set) + got_object_idset_free(repo->treecache.set); free(repo); }