summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAaron Merey <amerey@redhat.com>2019-06-26 16:18:36 -0400
committerAaron Merey <amerey@redhat.com>2019-06-26 16:18:36 -0400
commit8c8c712a52dbb56749f29c61a0524886c4a69190 (patch)
treeb1a6d4e51cb15e99e9aebfeae2a54bb55a265815
parent33641f353a3a91851484d7c1b6747c7cb41b8b43 (diff)
downloadelfutils-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.c109
-rw-r--r--tests/dbgserver_build_id_find.c10
-rwxr-xr-xtests/run-dbgserver-find.sh30
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