From: Stefan Sperling Subject: gotwebd: cache repos in struct server To: gameoftrees@openbsd.org Date: Wed, 31 Aug 2022 10:54:15 +0200 gotwebd currently opens repositories per-request (and usually closes them once the request is done, but fails to close them under certain error conditions). With this patch we keep a list of cached repositories in the server context. Only one cached repo can be used when serving a request because we only have one set of pack_fd temp files available. However, the cache reduces per-request overhead and also ensures that repositories get closed properly as they cycle out of cache and when the server terminates. ok? diff e9d3ad59c92a3ce340f8ac1bd0b0dff75dc3d951 d898889eba4d97976180925a137adb3552b197d7 commit - e9d3ad59c92a3ce340f8ac1bd0b0dff75dc3d951 commit + d898889eba4d97976180925a137adb3552b197d7 blob - 72a93ffe88a0fd5d23ee1850893733ac1c37c39c blob + 5798ec5536a4fda9cd332ebcce68ea242b0e00b4 --- gotwebd/gotweb.c +++ gotwebd/gotweb.c @@ -292,8 +292,6 @@ err: if (html && fcgi_printf(c, "\n") == -1) return; done: - if (c->t->repo != NULL && qs && qs->action != INDEX) - got_repo_close(c->t->repo); if (html && srv != NULL) gotweb_render_footer(c); } @@ -1096,9 +1094,6 @@ render: gotweb_free_repo_dir(repo_dir); repo_dir = NULL; - error = got_repo_close(t->repo); - if (error) - goto done; t->next_disp++; if (d_disp == srv->max_repos_display) break; @@ -1911,13 +1906,62 @@ done: return error; } +static struct got_repository * +find_cached_repo(struct server *srv, const char *path) +{ + int i; + + for (i = 0; i < srv->ncached_repos; i++) { + if (strcmp(srv->cached_repos[i].path, path) == 0) + return srv->cached_repos[i].repo; + } + + return NULL; +} + static const struct got_error * +cache_repo(struct got_repository **new, struct server *srv, + struct repo_dir *repo_dir, struct socket *sock) +{ + const struct got_error *error = NULL; + struct got_repository *repo; + struct cached_repo *cr; + + if (srv->ncached_repos >= nitems(srv->cached_repos)) { + cr = &srv->cached_repos[srv->ncached_repos]; + error = got_repo_close(cr->repo); + memset(cr, 0, sizeof(*cr)); + srv->ncached_repos--; + if (error) + return error; + memmove(&srv->cached_repos[1], &srv->cached_repos[0], + srv->ncached_repos * sizeof(srv->cached_repos[0])); + cr = &srv->cached_repos[0]; + } else { + cr = &srv->cached_repos[srv->ncached_repos]; + } + + error = got_repo_open(&repo, repo_dir->path, NULL, sock->pack_fds); + if (error) + return error; + if (strlcpy(cr->path, repo_dir->path, sizeof(cr->path)) + >= sizeof(cr->path)) + return got_error(GOT_ERR_NO_SPACE); + + cr->repo = repo; + srv->ncached_repos++; + *new = repo; + return NULL; +} + +static const struct got_error * gotweb_load_got_path(struct request *c, struct repo_dir *repo_dir) { const struct got_error *error = NULL; struct socket *sock = c->sock; struct server *srv = c->srv; struct transport *t = c->t; + struct got_repository *repo = NULL; DIR *dt; char *dir_test; int opened = 0; @@ -1977,9 +2021,13 @@ gotweb_load_got_path(struct request *c, struct repo_di } else opened = 1; done: - error = got_repo_open(&t->repo, repo_dir->path, NULL, sock->pack_fds); - if (error) - goto err; + repo = find_cached_repo(srv, repo_dir->path); + if (repo == NULL) { + error = cache_repo(&repo, srv, repo_dir, sock); + if (error) + goto err; + } + t->repo = repo; error = gotweb_get_repo_description(&repo_dir->description, srv, repo_dir->path); if (error) blob - ae08f3df1ae9fb58a5fac19a6fcfd02a1aad9247 blob + 74ee67ae6734f6af0af3ab58f3276ceeccc8863a --- gotwebd/gotwebd.h +++ gotwebd/gotwebd.h @@ -46,6 +46,7 @@ #define GOTWEBD_MAXPORT 6 #define GOTWEBD_NUMPROC 3 #define GOTWEBD_MAXIFACE 16 +#define GOTWEBD_REPO_CACHESIZE 4 /* GOTWEB DEFAULTS */ #define MAX_QUERYSTRING 2048 @@ -250,10 +251,18 @@ struct address { }; TAILQ_HEAD(addresslist, address); +struct cached_repo { + char path[PATH_MAX]; + struct got_repository *repo; +}; + struct server { TAILQ_ENTRY(server) entry; struct addresslist al; + struct cached_repo cached_repos[GOTWEBD_REPO_CACHESIZE]; + int ncached_repos; + char name[GOTWEBD_MAXTEXT]; char repos_path[PATH_MAX]; blob - 7e510af9c4ae6f2609874519758443d006c1afc3 blob + c0691c5575dca8c931af0e8e30d9e086b5a5bccc --- gotwebd/sockets.c +++ gotwebd/sockets.c @@ -51,6 +51,7 @@ #include "got_error.h" #include "got_opentemp.h" +#include "got_repository.h" #include "proc.h" #include "gotwebd.h" @@ -351,6 +352,7 @@ sockets_shutdown(void) { struct server *srv, *tsrv; struct socket *sock, *tsock; + int i; sockets_purge(gotwebd_env); @@ -362,8 +364,11 @@ sockets_shutdown(void) } /* clean servers */ - TAILQ_FOREACH_SAFE(srv, &gotwebd_env->servers, entry, tsrv) + TAILQ_FOREACH_SAFE(srv, &gotwebd_env->servers, entry, tsrv) { + for (i = 0; i < srv->ncached_repos; i++) + got_repo_close(srv->cached_repos[i].repo); free(srv); + } free(gotwebd_env); }