Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cache system bug fix #42

Merged
merged 1 commit into from
Aug 31, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 79 additions & 19 deletions src/cache.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,21 @@ typedef enum {
EMEM = -4 /**< Memory allocation failure */
} MetaError;

/* ---------------- External variables -----------------------*/

int CACHE_SYSTEM_INIT = 0;
int DATA_BLK_SZ = 0;
int MAX_SEGBC = DEFAULT_MAX_SEGBC;

/* ----------------- Static variables ----------------------- */

/**
* \brief Cache file locking
* \details Ensure cache opening and cache closing is an atomic operation
*/
static pthread_mutex_t cf_lock;


/**
* \brief The metadata directory
*/
Expand Down Expand Up @@ -111,6 +121,12 @@ static char *CacheSystem_calc_dir(const char *url)

void CacheSystem_init(const char *path, int url_supplied)
{
if (pthread_mutex_init(&cf_lock, NULL) != 0) {
fprintf(stderr,
"CacheSystem_init(): cf_lock initialisation failed!\n");
exit(EXIT_FAILURE);
}

if (url_supplied) {
path = CacheSystem_calc_dir(path);
}
Expand Down Expand Up @@ -696,16 +712,43 @@ Cache *Cache_open(const char *fn)
return NULL;
}

/* Obtain the link structure memory pointer */
Link *link = path_to_Link(fn);
if (!link) {
return NULL;
}

/*---------------- Cache_open() critical section -----------------*/

#ifdef CACHE_LOCK_DEBUG
fprintf(stderr, "Cache_open(): thread %lu: locking cf_lock;\n",
pthread_self());
#endif
pthread_mutex_lock(&cf_lock);

if (link->cache_opened) {
link->cache_opened++;
#ifdef CACHE_LOCK_DEBUG
fprintf(stderr, "Cache_open(): thread %lu: unlocking cf_lock;\n",
pthread_self());
#endif
pthread_mutex_unlock(&cf_lock);
return link->cache_ptr;
}

#ifdef CACHE_LOCK_DEBUG
fprintf(stderr, "Cache_open(): thread %lu: unlocking cf_lock;\n",
pthread_self());
#endif
pthread_mutex_unlock(&cf_lock);
/*----------------------------------------------------------------*/

/* Create the cache in-memory data structure */
Cache *cf = Cache_alloc();
cf->path = strndup(fn, MAX_PATH_LEN);

/* Associate the cache structure with a link */
cf->link = path_to_Link(fn);
if (!cf->link) {
Cache_free(cf);
return NULL;
}
cf->link = link;

if (Meta_open(cf)) {
Cache_free(cf);
Expand Down Expand Up @@ -750,22 +793,41 @@ cf->content_length: %ld, Data_size(fn): %ld.\n", fn, cf->content_length,
return NULL;
}

cf->link->cache_opened = 1;
/* Yup, we just created a circular loop. ;) */
cf->link->cache_ptr = cf;

return cf;
}

void Cache_close(Cache *cf)
{
/*--------------- Cache_close() critical section -----------------*/

#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);
fprintf(stderr, "Cache_close(): unlocking bgt_lock;\n");
pthread_mutex_unlock(&cf->bgt_lock);
fprintf(stderr, "Cache_close(): locking rw_lock;\n");
pthread_mutex_lock(&cf->rw_lock);
fprintf(stderr, "Cache_close(): unlocking rw_lock;\n");
pthread_mutex_unlock(&cf->rw_lock);
fprintf(stderr, "Cache_close(): thread %lu: locking cf_lock;\n",
pthread_self());
#endif
pthread_mutex_lock(&cf_lock);

cf->link->cache_opened--;

if (cf->link->cache_opened > 0) {
#ifdef CACHE_LOCK_DEBUG
fprintf(stderr, "Cache_close(): thread %lu: unlocking cf_lock;\n",
pthread_self());
#endif
pthread_mutex_unlock(&cf_lock);
return;
}

#ifdef CACHE_LOCK_DEBUG
fprintf(stderr, "Cache_close(): thread %lu: unlocking cf_lock;\n",
pthread_self());
#endif
pthread_mutex_unlock(&cf_lock);

/*----------------------------------------------------------------*/

if (Meta_write(cf)) {
fprintf(stderr, "Cache_close(): Meta_write() error.");
Expand Down Expand Up @@ -876,15 +938,13 @@ long Cache_read(Cache *cf, char *output_buf, off_t len, off_t offset)

#ifdef CACHE_LOCK_DEBUG
/* Wait for the background download thread to finish */
fprintf(stderr, "Cache_read(): thread %lu: locking bgt_lock;\n",
fprintf(stderr,
"Cache_read(): thread %lu: locking and unlocking bgt_lock;\n",
pthread_self());
#endif
pthread_mutex_lock(&cf->bgt_lock);
#ifdef CACHE_LOCK_DEBUG
fprintf(stderr, "Cache_read(): thread %lu: unlocking bgt_lock;\n",
pthread_self());
#endif
pthread_mutex_unlock(&cf->bgt_lock);

#ifdef CACHE_LOCK_DEBUG
/* Wait for any other download thread to finish*/
fprintf(stderr, "Cache_read(): thread %lu: locking rw_lock;\n",
Expand Down
15 changes: 10 additions & 5 deletions src/cache.h
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
#ifndef CACHE_H
#define CACHE_H

#include "link.h"

#include <pthread.h>

/**
* \brief cache data type
*/
typedef struct Cache Cache;

#include "link.h"

/**
* \file cache.h
* \brief cache related structures and functions
Expand All @@ -19,9 +24,9 @@
typedef uint8_t Seg;

/**
* \brief cache in-memory data structure
* \brief cache data type in-memory data structure
*/
typedef struct {
struct Cache {
char *path; /**< the path to the file on the web server */
Link *link; /**< the Link associated with this cache data set */
long time; /**<the modified time of the file */
Expand All @@ -41,7 +46,7 @@ typedef struct {
int blksz; /**<the block size of the data file */
long segbc; /**<segment array byte count */
Seg *seg; /**< the detail of each segment */
} Cache;
};

/**
* \brief whether the cache system is enabled
Expand Down
12 changes: 5 additions & 7 deletions src/link.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
LinkTable *ROOT_LINK_TBL = NULL;
int ROOT_LINK_OFFSET = 0;

/* ----------------- Static variable ----------------------- */
/* ----------------- Static variables ----------------------- */

/**
* \brief LinkTable generation priority lock
* \details This allows LinkTable generation to be run exclusively. This
Expand Down Expand Up @@ -584,16 +585,13 @@ long path_download(const char *path, char *output_buf, size_t size,

#ifdef LINK_LOCK_DEBUG
fprintf(stderr,
"path_download(): thread %lu: locking link_lock;\n",
"path_download(): thread %lu: locking and unlocking 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;
Expand Down
12 changes: 8 additions & 4 deletions src/link.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@

#include <curl/curl.h>

/** \brief Link type */
typedef struct Link Link;

#include "cache.h"

/** \brief the link type */
typedef enum {
LINK_HEAD = 'H',
Expand All @@ -19,11 +24,8 @@ typedef enum {
*/
typedef struct LinkTable LinkTable;

/** \brief link data type */
typedef struct Link Link;

/**
* \brief Link data structure
* \brief Link type data structure
*/
struct Link {
char linkname[MAX_FILENAME_LEN+1]; /**< The link name in the last level of
Expand All @@ -33,6 +35,8 @@ struct Link {
size_t content_length; /**< CURLINFO_CONTENT_LENGTH_DOWNLOAD of the file */
LinkTable *next_table; /**< The next LinkTable level, if it is a LINK_DIR */
long time; /**< CURLINFO_FILETIME obtained from the server */
int cache_opened; /**< How many times associated cache has been opened */
Cache *cache_ptr; /**< The pointer associated with the cache file */
};

struct LinkTable {
Expand Down