summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAaron Merey <amerey@redhat.com>2019-06-20 18:45:33 -0400
committerAaron Merey <amerey@redhat.com>2019-06-20 18:45:33 -0400
commit143caba6cfa5f717d79be073b0fc114a0b17f633 (patch)
treebf9e24e994198e97fcfb9ee87258161683b8a66b
parentd780608b2df0d2d4afa0891c3133d6cbafb932ca (diff)
downloadelfutils-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.c200
-rwxr-xr-xtests/run-dbgserver-find.sh20
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