diff options
author | Aaron Merey <amerey@redhat.com> | 2019-06-20 18:45:33 -0400 |
---|---|---|
committer | Aaron Merey <amerey@redhat.com> | 2019-06-20 18:45:33 -0400 |
commit | 143caba6cfa5f717d79be073b0fc114a0b17f633 (patch) | |
tree | bf9e24e994198e97fcfb9ee87258161683b8a66b | |
parent | d780608b2df0d2d4afa0891c3133d6cbafb932ca (diff) | |
download | elfutils-143caba6cfa5f717d79be073b0fc114a0b17f633.tar.gz |
dbgserver: add caching to client.
libdwfl/dbgserver-client.c: maintain cache of files downloaded from server
and avoid downloading a file if it exists in the cache.
TODO: cache cleaning.
tests/run-dbgserver-find.sh: run test with an empty cache, then run
test again with the server killed. Second round of tests should
find the target file in the cache.
Signed-off-by: Aaron Merey <amerey@redhat.com>
-rw-r--r-- | libdwfl/dbgserver-client.c | 200 | ||||
-rwxr-xr-x | tests/run-dbgserver-find.sh | 20 |
2 files changed, 183 insertions, 37 deletions
diff --git a/libdwfl/dbgserver-client.c b/libdwfl/dbgserver-client.c index 493e38cc..350b7d02 100644 --- a/libdwfl/dbgserver-client.c +++ b/libdwfl/dbgserver-client.c @@ -3,18 +3,20 @@ #include <stdio.h> #include <stdlib.h> #include <unistd.h> +#include <fcntl.h> #include <string.h> #include <stdbool.h> #include <sys/syscall.h> +#include <sys/types.h> +#include <sys/stat.h> #include <curl/curl.h> #define MAX_BUILD_ID_BYTES 64 - #define _(Str) "dbgserver-client: "Str"\n" const char *url_delim = " "; const char *server_urls_envvar = "DEBUGINFO_SERVER"; -const char *tmp_filename = "dbgserver_anon"; +char *cache_name = ".dbgserver_client_cache"; int dbgserver_enabled (void) @@ -36,8 +38,119 @@ write_callback (char *ptr, size_t size, size_t nmemb, void *fdptr) return (size_t)res; } +/* Assign all of the paths needed for querying and caching. + cache_path, target_cache_dir and target_cache_path + must be manually free'd. + + example format + cache_path: $HOME/.dbgserver_cache + target_cache_dir: $HOME/.dbgserver_cache/0123abcd + target_cache_path: $HOME/.dbgserver_cache/0123abcd/debuginfo +*/ +void +assign_paths (char *build_id, + char *type, + char **cache_path_ptr, + char **target_cache_dir_ptr, + char **target_cache_path_ptr) +{ + char *cache_parent = getenv("HOME") ?: "/"; + char *cache_path; + char *target_cache_dir; + char *target_cache_path; + + cache_path = malloc(strlen(cache_parent) + + strlen("/") + + strlen(cache_name) + + 1); + + if (cache_path == NULL) + { + fprintf(stderr, _("out of memory")); + return; + } + sprintf(cache_path, "%s/%s", cache_parent, cache_name); + + target_cache_dir = malloc(strlen(cache_path) + + strlen("/") + + strlen(build_id) + + 1); + + if (target_cache_dir == NULL) + { + fprintf(stderr, _("out of memory")); + return; + } + sprintf(target_cache_dir, "%s/%s", cache_path, build_id); + + target_cache_path = malloc(strlen(target_cache_dir) + + strlen("/") + + strlen(type) + + 1); + + if (target_cache_path == NULL) + { + fprintf(stderr, _("out of memory")); + return; + } + sprintf(target_cache_path, "%s/%s", target_cache_dir, type); + + *cache_path_ptr = cache_path; + *target_cache_dir_ptr = target_cache_dir; + *target_cache_path_ptr = target_cache_path; + + return; +} + +int +get_file_from_cache (char *target_cache_path) +{ + int fd; + struct stat st; + + if (stat(target_cache_path, &st) == -1) + return -1; + + fd = open(target_cache_path, O_RDONLY); + if (fd < 0) + fprintf(stderr, _("error opening target from cache")); + + return fd; +} + int -query_server (char *target) +add_file_to_cache (char *cache_path, + char *target_cache_dir, + char *target_cache_path) +{ + int fd; + struct stat st; + + /* create cache if not found. */ + if (stat(cache_path, &st) == -1 && mkdir(cache_path, 0777) < 0) + fprintf(stderr, _("error finding cache")); + + /* create target directory in cache if not found. */ + if (stat(target_cache_dir, &st) == -1 && mkdir(target_cache_dir, 0777) < 0) + fprintf(stderr, _("error finding target cache directory")); + + /* create target file if not found. */ + fd = open(target_cache_path, O_CREAT | O_RDWR, 0666); + if (fd < 0) + fprintf(stderr, _("error finding target in cache")); + + return fd; +} + +void +clean_cache(char *cache_path) +{ + (void) cache_path; + return; +} + +int +query_server (char *build_id, char *type) { int fd = -1; bool success = false; @@ -46,6 +159,9 @@ query_server (char *target) char *envvar; char *server_url; char *server_urls; + char *cache_path; + char *target_cache_dir; + char *target_cache_path; CURL *session; CURLcode curl_res; @@ -68,30 +184,50 @@ query_server (char *target) { fprintf(stderr, _("unable to initialize curl")); return -1; - } + } session = curl_easy_init(); if (session == NULL) { fprintf(stderr, _("unable to begin curl session")); curl_global_cleanup(); + return -1; } - fd = syscall(__NR_memfd_create, tmp_filename, 0); + assign_paths(build_id, + type, + &cache_path, + &target_cache_dir, + &target_cache_path); + + fd = get_file_from_cache(target_cache_path); + if (fd >= 0) + goto cleanup; + + fd = add_file_to_cache(cache_path, target_cache_dir, target_cache_path); + if (fd < 0) + /* encountered an error adding file to cache. */ + goto cleanup; /* query servers until we find the target or run out of urls to try. */ server_url = strtok(server_urls, url_delim); while (! success && server_url != NULL) { - char *url = malloc(strlen(target) + strlen(server_url) + 1); + char *url = malloc(strlen(server_url) + + strlen("/buildid//") + + strlen(build_id) + + strlen(type) + + 1); if (server_url == NULL) { fprintf(stderr, _("out of memory")); - return -1; + close(fd); + fd = -1; + goto cleanup; } - sprintf(url, "%s/%s", server_url, target); + sprintf(url, "%s/buildid/%s/%s", server_url, build_id, type); curl_easy_setopt(session, CURLOPT_URL, url); curl_easy_setopt(session, CURLOPT_WRITEFUNCTION, write_callback); @@ -100,15 +236,17 @@ query_server (char *target) curl_res = curl_easy_perform(session); curl_easy_getinfo(session, CURLINFO_RESPONSE_CODE, &resp_code); - free(url); - if (curl_res == CURLE_OK && resp_code == 200) - success = 1; - // these kinds of diagnostic messages can cause unrelated elfutils - // tests to fail. - // - //else if (curl_res == CURLE_OPERATION_TIMEDOUT) - // fprintf(stderr, _("GET request timed out, url=%s"), url); + if (curl_res == CURLE_OK) + switch (resp_code) + { + case 200: + success = true; + break; + default: + ; + } + free(url); server_url = strtok(NULL, url_delim); } @@ -116,12 +254,19 @@ query_server (char *target) curl_easy_cleanup(session); curl_global_cleanup(); - if (resp_code != 200) + if (! success) { close(fd); - return -1; + remove(target_cache_path); + fd = -1; } +cleanup: + clean_cache(cache_path); + free(cache_path); + free(target_cache_dir); + free(target_cache_path); + return fd; } @@ -130,9 +275,6 @@ dbgserver_build_id_find (enum dbgserver_file_type file_type, const unsigned char *build_id, int build_id_len) { - int fd; - int url_len; - char *url; char *type; char id_buf[MAX_BUILD_ID_BYTES + 1]; @@ -155,19 +297,5 @@ dbgserver_build_id_find (enum dbgserver_file_type file_type, assert(0); } - /* url format: $DEBUGINFO_SERVER/buildid/HEXCODE/debuginfo */ - url_len = strlen("buildid/") + build_id_len * 2 + strlen(type) + 2; - - url = (char*)malloc(url_len); - if (url == NULL) - { - fprintf(stderr, _("out of memory")); - return -1; - } - - sprintf(url, "buildid/%s/%s", id_buf, type); - fd = query_server(url); - free(url); - - return fd; + return query_server(id_buf, type); } diff --git a/tests/run-dbgserver-find.sh b/tests/run-dbgserver-find.sh index 1d9a72a9..3175792a 100755 --- a/tests/run-dbgserver-find.sh +++ b/tests/run-dbgserver-find.sh @@ -17,7 +17,7 @@ . $srcdir/test-subr.sh -if [ -z "$DEBUGINFO_SERVER" ]; then +if [ -z $DEBUGINFO_SERVER ]; then echo "unknown server url" exit 77 fi @@ -27,6 +27,18 @@ 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 + ../../src/dbgserver -vvv -d $DB -F testfile-dbgserver.debug & PID=$! sleep 5 @@ -37,4 +49,10 @@ testrun ${abs_builddir}/dbgserver_build_id_find -e testfile-dbgserver.exec 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 + +rm -rf $CACHE_DIR + exit 0 |