From afb2a8fe6c15e7a2f9c2e34a3697290ba8194ffc Mon Sep 17 00:00:00 2001 From: Fufu Fang Date: Sat, 31 Aug 2019 21:21:28 +0100 Subject: [PATCH] Directory listing performance improvement while file transfers are going on - Added a LinkTable generation priority lock - This allows LinkTable generation to be run exclusively. This effectively gives LinkTable generation priority over file transfer. --- README.md | 5 +++-- src/cache.c | 20 +++++++++++--------- src/link.c | 41 +++++++++++++++++++++++++++++++++++++++++ src/link.h | 5 +++++ src/main.c | 3 +++ src/network.c | 34 +++++++++++++++++++++++++++++++--- 6 files changed, 94 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index a383f44..e9820fc 100644 --- a/README.md +++ b/README.md @@ -113,9 +113,10 @@ OpenSSL 1.1 do not. ### Debugging Mutexes By default the debugging output associated with mutexes are not compiled. To -enable them, compile the program using the following command: +enable them, compile the program with the ``-DCACHE_LOCK_DEBUG``, the +``-DNETWORK_LOCK_DEBUG`` and/or the ``-DLINK_LOCK_DEBUG`` CPPFLAGS, e.g. - make CPPFLAGS=-DLOCK_DEBUG + make CPPFLAGS=-DCACHE_LOCK_DEBUG ## The Technical Details This program downloads the HTML web pages/files using diff --git a/src/cache.c b/src/cache.c index c84082c..3cde97c 100644 --- a/src/cache.c +++ b/src/cache.c @@ -755,7 +755,7 @@ cf->content_length: %ld, Data_size(fn): %ld.\n", fn, cf->content_length, void Cache_close(Cache *cf) { -#ifdef LOCK_DEBUG +#ifdef CACHE_LOCK_DEBUG /* Must wait for the background download thread to stop */ fprintf(stderr, "Cache_close(): locking bgt_lock;\n"); pthread_mutex_lock(&cf->bgt_lock); @@ -815,7 +815,7 @@ static void Seg_set(Cache *cf, off_t offset, int i) static void *Cache_bgdl(void *arg) { Cache *cf = (Cache *) arg; -#ifdef LOCK_DEBUG +#ifdef CACHE_LOCK_DEBUG fprintf(stderr, "Cache_bgdl(): thread %lu: locking rw_lock;\n", pthread_self()); #endif @@ -834,12 +834,12 @@ static void *Cache_bgdl(void *arg) "Cache_bgdl(): received %ld, possible network error.\n", recv); } free(recv_buf); -#ifdef LOCK_DEBUG +#ifdef CACHE_LOCK_DEBUG fprintf(stderr, "Cache_bgdl(): thread %lu: unlocking bgt_lock;\n", pthread_self()); #endif pthread_mutex_unlock(&cf->bgt_lock); -#ifdef LOCK_DEBUG +#ifdef CACHE_LOCK_DEBUG fprintf(stderr, "Cache_bgdl(): thread %lu: unlocking rw_lock;\n", pthread_self()); #endif @@ -874,18 +874,18 @@ long Cache_read(Cache *cf, char *output_buf, off_t len, off_t offset) goto bgdl; } else { -#ifdef LOCK_DEBUG +#ifdef CACHE_LOCK_DEBUG /* Wait for the background download thread to finish */ fprintf(stderr, "Cache_read(): thread %lu: locking bgt_lock;\n", pthread_self()); #endif pthread_mutex_lock(&cf->bgt_lock); -#ifdef LOCK_DEBUG +#ifdef CACHE_LOCK_DEBUG fprintf(stderr, "Cache_read(): thread %lu: unlocking bgt_lock;\n", pthread_self()); #endif pthread_mutex_unlock(&cf->bgt_lock); -#ifdef LOCK_DEBUG +#ifdef CACHE_LOCK_DEBUG /* Wait for any other download thread to finish*/ fprintf(stderr, "Cache_read(): thread %lu: locking rw_lock;\n", pthread_self()); @@ -895,7 +895,7 @@ long Cache_read(Cache *cf, char *output_buf, off_t len, off_t offset) /* The segment already exists - it was downloaded by other * download thread. Send it off and unlock the I/O */ send = Data_read(cf, (uint8_t *) output_buf, len, offset); -#ifdef LOCK_DEBUG +#ifdef CACHE_LOCK_DEBUG fprintf(stderr, "Cache_read(): thread %lu: unlocking rw_lock;\n", pthread_self()); #endif @@ -931,7 +931,7 @@ long Cache_read(Cache *cf, char *output_buf, off_t len, off_t offset) "Cache_read(): received %ld, possible network error.\n", recv); } free(recv_buf); -#ifdef LOCK_DEBUG +#ifdef CACHE_LOCK_DEBUG fprintf(stderr, "Cache_read(): thread %lu: unlocking rw_lock;\n", pthread_self()); #endif @@ -945,8 +945,10 @@ long Cache_read(Cache *cf, char *output_buf, off_t len, off_t offset) cf->next_offset < cf->content_length ){ /* Stop the spawning of multiple background pthreads */ if(!pthread_mutex_trylock(&cf->bgt_lock)) { +#ifdef CACHE_LOCK_DEBUG fprintf(stderr, "Cache_read(): thread %lu: trylocked bgt_lock;\n", pthread_self()); +#endif if (pthread_create(&cf->bgt, NULL, Cache_bgdl, cf)) { fprintf(stderr, "Cache_read(): Error creating background download thread\n" diff --git a/src/link.c b/src/link.c index 6ebc08d..5eb6eee 100644 --- a/src/link.c +++ b/src/link.c @@ -15,6 +15,23 @@ LinkTable *ROOT_LINK_TBL = NULL; int ROOT_LINK_OFFSET = 0; +/* ----------------- Static variable ----------------------- */ +/** + * \brief LinkTable generation priority lock + * \details This allows LinkTable generation to be run exclusively. This + * effectively gives LinkTable generation priority over file transfer. + */ +static pthread_mutex_t link_lock; + +void link_system_init() +{ + if (pthread_mutex_init(&link_lock, NULL) != 0) { + fprintf(stderr, + "link_system_init(): link_lock initialisation failed!\n"); + exit(EXIT_FAILURE); + } +} + static void LinkTable_add(LinkTable *linktbl, Link *link) { linktbl->num++; @@ -266,6 +283,12 @@ static void LinkTable_print(LinkTable *linktbl) LinkTable *LinkTable_new(const char *url) { +#ifdef LINK_LOCK_DEBUG + fprintf(stderr, + "LinkTable_new(): thread %lu: locking link_lock;\n", + pthread_self()); +#endif + pthread_mutex_lock(&link_lock); LinkTable *linktbl = calloc(1, sizeof(LinkTable)); if (!linktbl) { fprintf(stderr, "LinkTable_new(): calloc failure!\n"); @@ -349,6 +372,12 @@ HTTP %ld\n", url, http_resp); curl_easy_cleanup(c); LinkTable_print(linktbl); +#ifdef LINK_LOCK_DEBUG + fprintf(stderr, + "LinkTable_new(): thread %lu: unlocking link_lock;\n", + pthread_self()); +#endif + pthread_mutex_unlock(&link_lock); return linktbl; } @@ -553,6 +582,18 @@ long path_download(const char *path, char *output_buf, size_t size, curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&buf); curl_easy_setopt(curl, CURLOPT_RANGE, range_str); +#ifdef LINK_LOCK_DEBUG + fprintf(stderr, + "path_download(): thread %lu: locking link_lock;\n", + pthread_self()); +#endif + pthread_mutex_lock(&link_lock); +#ifdef LINK_LOCK_DEBUG + fprintf(stderr, + "path_download(): thread %lu: unlocking link_lock;\n", + pthread_self()); +#endif + pthread_mutex_unlock(&link_lock); transfer_blocking(curl); long http_resp; diff --git a/src/link.h b/src/link.h index ac8d8ce..5cee891 100644 --- a/src/link.h +++ b/src/link.h @@ -50,6 +50,11 @@ extern LinkTable *ROOT_LINK_TBL; */ extern int ROOT_LINK_OFFSET; +/** + * \brief initialise link sub-system. + */ +void link_system_init(); + /** * \brief */ diff --git a/src/main.c b/src/main.c index 328ae57..1f5fdb7 100644 --- a/src/main.c +++ b/src/main.c @@ -36,6 +36,9 @@ int main(int argc, char **argv) /*--- FUSE expects the first initialisation to be the program's name ---*/ add_arg(&fuse_argv, &fuse_argc, argv[0]); + /* initialise link subsystem */ + link_system_init(); + /* initialise network configuration struct */ network_config_init(); diff --git a/src/network.c b/src/network.c index 5e646cd..4d4d900 100644 --- a/src/network.c +++ b/src/network.c @@ -160,6 +160,11 @@ static void curl_process_msgs(CURLMsg *curl_msg, int n_running_curl, */ int curl_multi_perform_once() { +#ifdef NETWORK_LOCK_DEBUG + fprintf(stderr, + "curl_multi_perform_once(): thread %lu: locking transfer_lock;\n", + pthread_self()); +#endif pthread_mutex_lock(&transfer_lock); /* Get curl multi interface to perform pending tasks */ int n_running_curl; @@ -217,6 +222,11 @@ int curl_multi_perform_once() while((curl_msg = curl_multi_info_read(curl_multi, &n_mesgs))) { curl_process_msgs(curl_msg, n_running_curl, n_mesgs); } +#ifdef NETWORK_LOCK_DEBUG + fprintf(stderr, + "curl_multi_perform_once(): thread %lu: unlocking transfer_lock;\n", + pthread_self()); +#endif pthread_mutex_unlock(&transfer_lock); return n_running_curl; } @@ -254,8 +264,7 @@ LinkTable *network_init(const char *url) curl_share_setopt(CURL_SHARE, CURLSHOPT_SHARE, CURL_LOCK_DATA_SSL_SESSION); if (pthread_mutex_init(&curl_lock, NULL) != 0) { - printf( - "network_init(): curl_lock initialisation failed!\n"); + fprintf(stderr, "network_init(): curl_lock initialisation failed!\n"); exit(EXIT_FAILURE); } curl_share_setopt(CURL_SHARE, CURLSHOPT_LOCKFUNC, curl_callback_lock); @@ -327,9 +336,18 @@ void transfer_blocking(CURL *curl) transfer.type = DATA; transfer.transferring = 1; curl_easy_setopt(curl, CURLOPT_PRIVATE, &transfer); - +#ifdef NETWORK_LOCK_DEBUG + fprintf(stderr, + "transfer_blocking(): thread %lu: locking transfer_lock;\n", + pthread_self()); +#endif pthread_mutex_lock(&transfer_lock); CURLMcode res = curl_multi_add_handle(curl_multi, curl); +#ifdef NETWORK_LOCK_DEBUG + fprintf(stderr, + "transfer_blocking(): thread %lu: unlocking transfer_lock;\n", + pthread_self()); +#endif pthread_mutex_unlock(&transfer_lock); if(res > 0) { @@ -345,8 +363,18 @@ void transfer_blocking(CURL *curl) void transfer_nonblocking(CURL *curl) { +#ifdef NETWORK_LOCK_DEBUG + fprintf(stderr, + "transfer_nonblocking(): thread %lu: locking transfer_lock;\n", + pthread_self()); +#endif pthread_mutex_lock(&transfer_lock); CURLMcode res = curl_multi_add_handle(curl_multi, curl); +#ifdef NETWORK_LOCK_DEBUG + fprintf(stderr, + "transfer_nonblocking(): thread %lu: unlocking transfer_lock;\n", + pthread_self()); +#endif pthread_mutex_unlock(&transfer_lock); if(res > 0) {