Browse Source

[mod_userdir] use 2-element cache

use 2-element cache, can be getpwnam() lookup is expensive

cache lifetime is 60 seconds
homedir paths are not expected to change quickly
master
Glenn Strauss 9 months ago
parent
commit
4eeff345b1
  1. 47
      src/mod_userdir.c

47
src/mod_userdir.c

@ -31,12 +31,23 @@ typedef struct {
PLUGIN_DATA;
plugin_config defaults;
plugin_config conf;
time_t cache_ts[2];
buffer cache_user[2];
buffer cache_path[2];
} plugin_data;
INIT_FUNC(mod_userdir_init) {
return calloc(1, sizeof(plugin_data));
}
FREE_FUNC(mod_userdir_free) {
plugin_data * const p = p_d;
free(p->cache_user[0].ptr);
free(p->cache_user[1].ptr);
free(p->cache_path[0].ptr);
free(p->cache_path[1].ptr);
}
static void mod_userdir_merge_config_cpv(plugin_config * const pconf, const config_plugin_value_t * const cpv) {
switch (cpv->k_id) { /* index into static config_plugin_keys_t cpk[] */
case 0: /* userdir.path */
@ -149,14 +160,41 @@ static handler_t mod_userdir_docroot_construct(request_st * const r, plugin_data
if (buffer_string_is_empty(p->conf.basepath)) {
#ifdef HAVE_PWD_H
/* XXX: future: might add cache; getpwnam() lookup is expensive */
struct passwd *pwd = getpwnam(u);
if (pwd) {
buffer_copy_string(b, pwd->pw_dir);
/* getpwnam() lookup is expensive; first check 2-element cache */
const time_t cur_ts = log_monotonic_secs;
int cached = -1;
const int cache_sz =(int)(sizeof(p->cache_user)/sizeof(*p->cache_user));
for (int i = 0; i < cache_sz; ++i) {
if (cur_ts - p->cache_ts[i] < 60 && p->cache_user[i].used
&& buffer_eq_slen(&p->cache_user[i], u, ulen)) {
cached = i;
break;
}
}
struct passwd *pwd;
if (cached >= 0) {
buffer_copy_buffer(b, &p->cache_path[cached]);
buffer_append_path_len(b, CONST_BUF_LEN(p->conf.path));
}
else if ((pwd = getpwnam(u))) {
const size_t plen = strlen(pwd->pw_dir);
buffer_copy_string_len(b, pwd->pw_dir, plen);
buffer_append_path_len(b, CONST_BUF_LEN(p->conf.path));
if (!stat_cache_path_isdir(b)) {
return HANDLER_GO_ON;
}
/* update cache, replacing oldest entry */
cached = 0;
time_t cache_ts = p->cache_ts[0];
for (int i = 1; i < cache_sz; ++i) {
if (cache_ts > p->cache_ts[i]) {
cache_ts = p->cache_ts[i];
cached = i;
}
}
p->cache_ts[cached] = cur_ts;
buffer_copy_string_len(&p->cache_path[cached], b->ptr, plen);
buffer_copy_string_len(&p->cache_user[cached], u, ulen);
}
else /* user not found */
#endif
@ -277,6 +315,7 @@ int mod_userdir_plugin_init(plugin *p) {
p->name = "userdir";
p->init = mod_userdir_init;
p->cleanup = mod_userdir_free;
p->handle_physical = mod_userdir_docroot_handler;
p->set_defaults = mod_userdir_set_defaults;

Loading…
Cancel
Save