diff options
author | Aaron Merey <amerey@redhat.com> | 2019-06-26 16:18:36 -0400 |
---|---|---|
committer | Aaron Merey <amerey@redhat.com> | 2019-06-26 16:18:36 -0400 |
commit | 8c8c712a52dbb56749f29c61a0524886c4a69190 (patch) | |
tree | b1a6d4e51cb15e99e9aebfeae2a54bb55a265815 | |
parent | 33641f353a3a91851484d7c1b6747c7cb41b8b43 (diff) | |
download | elfutils-fche/dbgserver.tar.gz |
dbgserver-client: add cache cleaning.fche/dbgserver
libdwfl/dbgserver-client.c: add clean_cache(), run it before attempting
to download anything from a server and when we fail to find the target
on any server. Add $DBGSERVER_CACHE_CLEAN_INTERVAL_S for controlling
when files are deleted from the cache.
tests/run-dbgserver-find.sh: Remove any manual handling of the cache,
instead set $DBGSERVER_CACHE_PATH and $DBGSERVER_CACHE_CLEAN_INTERVAL_S.
Pass an additional argument to the tests that indicates whether or not
the test should expect to find the target debuginfo from the server.
Add a test for checking that clean_cache() actually cleans the cache.
tests/dbgserver_build_id_find.c: Incorporate the additional argument
described above.
Signed-off-by: Aaron Merey <amerey@redhat.com>
-rw-r--r-- | libdwfl/dbgserver-client.c | 109 | ||||
-rw-r--r-- | tests/dbgserver_build_id_find.c | 10 | ||||
-rwxr-xr-x | tests/run-dbgserver-find.sh | 30 |
3 files changed, 107 insertions, 42 deletions
diff --git a/libdwfl/dbgserver-client.c b/libdwfl/dbgserver-client.c index 2864d866..5ae8765c 100644 --- a/libdwfl/dbgserver-client.c +++ b/libdwfl/dbgserver-client.c @@ -1,12 +1,16 @@ #include "dbgserver-client.h" #include <assert.h> +#include <dirent.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> +#include <errno.h> #include <fcntl.h> +#include <fts.h> #include <string.h> #include <stdbool.h> #include <linux/limits.h> +#include <time.h> #include <sys/syscall.h> #include <sys/types.h> #include <sys/stat.h> @@ -15,12 +19,21 @@ #define MAX_BUILD_ID_BYTES 64 #define _(Str) "dbgserver-client: "Str"\n" -const char *url_delim = " "; +/* URLs of dbgservers, separated by url_delim. + This env var must be set for dbgserver-client to run. */ const char *server_urls_envvar = "DBGSERVER_URLS"; +const char *url_delim = " "; + +/* Location of the cache of files downloaded from dbgservers. + The default parent directory is $HOME, or '/' if $HOME doesn't exist. */ const char *cache_path_envvar = "DBGSERVER_CACHE_PATH"; -const char *cache_clean_interval_envvar = "DBGSERVER_CACHE_CLEAN_INTERVAL"; const char *cache_default_name = ".dbgserver_client_cache"; +/* Files will be removed from the cache when the number of seconds + since their st_mtime is greater than or equal to this env var. */ +const char *cache_clean_interval_envvar = "DBGSERVER_CACHE_CLEAN_INTERVAL_S"; +const unsigned long cache_clean_interval_default = 86400; /* 1 day */ + int dbgserver_enabled (void) { @@ -81,38 +94,81 @@ add_file_to_cache (char *cache_path, return fd; } +/* Delete any files that have been unmodied for a period + longer than $DBGSERVER_CACHE_CLEAN_INTERVAL_S. */ void clean_cache(char *cache_path) { - (void) cache_path; - return; + char * const dirs[] = { cache_path, NULL, }; + + FTS *fts = fts_open(dirs, 0, NULL); + if (fts == NULL) + { + if (errno == ENOENT) + { + errno = 0; + return; + } + + fprintf(stderr, _("error cleaning cache, cannot fts_open")); + return; + } + + time_t clean_interval; + const char *interval_str = getenv(cache_clean_interval_envvar); + if (interval_str == NULL + || sscanf(interval_str, "%ld", &clean_interval) != 1) + clean_interval = cache_clean_interval_default; + + FTSENT *f; + DIR *d; + while ((f = fts_read(fts)) != NULL) + { + switch (f->fts_info) + { + case FTS_F: + /* delete file if cache clean interval has been met or exceeded. */ + if (time(NULL) - f->fts_statp->st_mtime >= clean_interval) + remove(f->fts_path); + break; + + case FTS_DP: + d = opendir(f->fts_path); + /* delete directory if it doesn't contain files besides . and .. */ + (void) readdir(d); + (void) readdir(d); + if (readdir(d) == NULL) + remove(f->fts_path); + closedir(d); + break; + + default: + ; + } + } + + fts_close(fts); } int query_server (char *build_id, char *type) { - int fd = -1; - bool success = false; - long resp_code = -1; - long timeout = 5; - char *envvar; - char *server_url; + char *urls_envvar; char *server_urls; char cache_path[PATH_MAX]; char target_cache_dir[PATH_MAX]; char target_cache_path[PATH_MAX]; - CURL *session; - CURLcode curl_res; - envvar = getenv(server_urls_envvar); - if (envvar == NULL) + urls_envvar = getenv(server_urls_envvar); + if (urls_envvar == NULL) { fprintf(stderr, _("cannot find server urls environment variable")); return -1; } - server_urls = malloc(strlen(envvar) + 1); - strcpy(server_urls, envvar); + /* make a copy of the envvar so it can be safely modified. */ + server_urls = malloc(strlen(urls_envvar) + 1); + strcpy(server_urls, urls_envvar); if (server_urls == NULL) { fprintf(stderr, _("out of memory")); @@ -125,7 +181,7 @@ query_server (char *build_id, char *type) return -1; } - session = curl_easy_init(); + CURL *session = curl_easy_init(); if (session == NULL) { fprintf(stderr, _("unable to begin curl session")); @@ -133,7 +189,7 @@ query_server (char *build_id, char *type) return -1; } - /* set paths needed to perform query + /* set paths needed to perform the query example format cache_path: $HOME/.dbgserver_cache @@ -158,7 +214,9 @@ query_server (char *build_id, char *type) strncat(target_cache_path, "/", PATH_MAX - strlen(target_cache_dir)); strncat(target_cache_path, type, PATH_MAX - strlen(target_cache_dir)); - fd = get_file_from_cache(target_cache_path); + clean_cache(cache_path); + + int fd = get_file_from_cache(target_cache_path); if (fd >= 0) return fd; @@ -167,10 +225,13 @@ query_server (char *build_id, char *type) /* encountered an error adding file to cache. */ return -1; - /* query servers until we find the target or run out of urls to try. */ - server_url = strtok(server_urls, url_delim); + long timeout = 5; /* XXX grab from env var. */ + bool success = false; + char *server_url = strtok(server_urls, url_delim); while (! success && server_url != NULL) { + /* query servers until we find the target or run out of urls to try. */ + long resp_code; char *url = malloc(strlen(server_url) + strlen("/buildid//") + strlen(build_id) @@ -190,7 +251,8 @@ query_server (char *build_id, char *type) curl_easy_setopt(session, CURLOPT_WRITEFUNCTION, write_callback); curl_easy_setopt(session, CURLOPT_WRITEDATA, (void*)&fd); curl_easy_setopt(session, CURLOPT_TIMEOUT, timeout); - curl_res = curl_easy_perform(session); + + CURLcode curl_res = curl_easy_perform(session); curl_easy_getinfo(session, CURLINFO_RESPONSE_CODE, &resp_code); if (curl_res == CURLE_OK) @@ -215,10 +277,11 @@ query_server (char *build_id, char *type) { close(fd); remove(target_cache_path); + /* remove any unnecessary directories that were just created. */ + clean_cache(cache_path); return -1; } - clean_cache(cache_path); return fd; } diff --git a/tests/dbgserver_build_id_find.c b/tests/dbgserver_build_id_find.c index 30b55e3a..8e302c8e 100644 --- a/tests/dbgserver_build_id_find.c +++ b/tests/dbgserver_build_id_find.c @@ -25,6 +25,7 @@ #include <dwarf.h> #include <argp.h> #include <assert.h> +#include <string.h> static const char *debuginfo_path = ""; static const Dwfl_Callbacks cb = @@ -38,6 +39,7 @@ static const Dwfl_Callbacks cb = int main (int argc __attribute__ ((unused)), char **argv) { + int expect_pass = strcmp(argv[3], "0"); Dwarf_Addr bias = 0; Dwfl *dwfl = dwfl_begin(&cb); dwfl_report_begin(dwfl); @@ -47,6 +49,12 @@ main (int argc __attribute__ ((unused)), char **argv) /* The corresponding debuginfo will not be found in debuginfo_path (since it's empty), causing the server to be queried. */ - assert(dwfl_module_getdwarf(mod, &bias)); + + Dwarf *res = dwfl_module_getdwarf(mod, &bias); + if (expect_pass) + assert(res); + else + assert(!res); + return 0; } diff --git a/tests/run-dbgserver-find.sh b/tests/run-dbgserver-find.sh index e39fdd29..cf547dfe 100755 --- a/tests/run-dbgserver-find.sh +++ b/tests/run-dbgserver-find.sh @@ -16,8 +16,7 @@ . $srcdir/test-subr.sh - -if [ -z $DBGSERVER_URLS ]; then +if [ -z "$DBGSERVER_URLS" ]; then echo "unknown server url" exit 77 fi @@ -25,34 +24,29 @@ fi testfiles testfile-dbgserver.exec testfiles testfile-dbgserver.debug -DB="$PWD/.dbgserver_tmp.sqlite" - -if [ -z $HOME ]; then - CACHE_DIR="/.dbgserver_client_cache" -else - CACHE_DIR="$HOME/.dbgserver_client_cache" -fi - -# Clear the cache -if [ -d $CACHE_DIR ]; then - echo "t" - rm -rf $CACHE_DIR -fi +EXPECT_FAIL=0 +EXPECT_PASS=1 +DB=${PWD}/.dbgserver_tmp.sqlite +export DBGSERVER_CACHE_PATH=${PWD}/.client_cache +export DBGSERVER_CACHE_CLEAN_INTERVAL_S=100 ../../src/dbgserver -vvv -d $DB -F $PWD & PID=$! sleep 5 # Test whether the server is able to fetch the file from the local dbgserver. -testrun ${abs_builddir}/dbgserver_build_id_find -e testfile-dbgserver.exec +testrun ${abs_builddir}/dbgserver_build_id_find -e testfile-dbgserver.exec $EXPECT_PASS kill $PID rm $DB # Run the test again without the server running. The target file should # be found in the cache. -testrun ${abs_builddir}/dbgserver_build_id_find -e testfile-dbgserver.exec +testrun ${abs_builddir}/dbgserver_build_id_find -e testfile-dbgserver.exec $EXPECT_PASS -rm -rf $CACHE_DIR +# Trigger a cache clean and run the test again. The client should be unable to +# find the target. +export DBGSERVER_CACHE_CLEAN_INTERVAL_S=0 +testrun ${abs_builddir}/dbgserver_build_id_find -e testfile-dbgserver.exec $EXPECT_FAIL exit 0 |