Cache system bug fix
- Now keep track of the number of times a file has been opened. The on-disk cache file no longer gets opened multiple times, if a file is opened multiple times.
This commit is contained in:
parent
ef7630f9a8
commit
92a9658c66
98
src/cache.c
98
src/cache.c
|
@ -37,11 +37,21 @@ typedef enum {
|
||||||
EMEM = -4 /**< Memory allocation failure */
|
EMEM = -4 /**< Memory allocation failure */
|
||||||
} MetaError;
|
} MetaError;
|
||||||
|
|
||||||
|
/* ---------------- External variables -----------------------*/
|
||||||
|
|
||||||
int CACHE_SYSTEM_INIT = 0;
|
int CACHE_SYSTEM_INIT = 0;
|
||||||
int DATA_BLK_SZ = 0;
|
int DATA_BLK_SZ = 0;
|
||||||
int MAX_SEGBC = DEFAULT_MAX_SEGBC;
|
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
|
* \brief The metadata directory
|
||||||
*/
|
*/
|
||||||
|
@ -111,6 +121,12 @@ static char *CacheSystem_calc_dir(const char *url)
|
||||||
|
|
||||||
void CacheSystem_init(const char *path, int url_supplied)
|
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) {
|
if (url_supplied) {
|
||||||
path = CacheSystem_calc_dir(path);
|
path = CacheSystem_calc_dir(path);
|
||||||
}
|
}
|
||||||
|
@ -696,16 +712,43 @@ Cache *Cache_open(const char *fn)
|
||||||
return NULL;
|
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 */
|
/* Create the cache in-memory data structure */
|
||||||
Cache *cf = Cache_alloc();
|
Cache *cf = Cache_alloc();
|
||||||
cf->path = strndup(fn, MAX_PATH_LEN);
|
cf->path = strndup(fn, MAX_PATH_LEN);
|
||||||
|
|
||||||
/* Associate the cache structure with a link */
|
/* Associate the cache structure with a link */
|
||||||
cf->link = path_to_Link(fn);
|
cf->link = link;
|
||||||
if (!cf->link) {
|
|
||||||
Cache_free(cf);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Meta_open(cf)) {
|
if (Meta_open(cf)) {
|
||||||
Cache_free(cf);
|
Cache_free(cf);
|
||||||
|
@ -750,22 +793,41 @@ cf->content_length: %ld, Data_size(fn): %ld.\n", fn, cf->content_length,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cf->link->cache_opened = 1;
|
||||||
|
/* Yup, we just created a circular loop. ;) */
|
||||||
|
cf->link->cache_ptr = cf;
|
||||||
|
|
||||||
return cf;
|
return cf;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cache_close(Cache *cf)
|
void Cache_close(Cache *cf)
|
||||||
{
|
{
|
||||||
|
/*--------------- Cache_close() critical section -----------------*/
|
||||||
|
|
||||||
#ifdef CACHE_LOCK_DEBUG
|
#ifdef CACHE_LOCK_DEBUG
|
||||||
/* Must wait for the background download thread to stop */
|
fprintf(stderr, "Cache_close(): thread %lu: locking cf_lock;\n",
|
||||||
fprintf(stderr, "Cache_close(): locking bgt_lock;\n");
|
pthread_self());
|
||||||
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);
|
|
||||||
#endif
|
#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)) {
|
if (Meta_write(cf)) {
|
||||||
fprintf(stderr, "Cache_close(): Meta_write() error.");
|
fprintf(stderr, "Cache_close(): Meta_write() error.");
|
||||||
|
@ -876,15 +938,13 @@ long Cache_read(Cache *cf, char *output_buf, off_t len, off_t offset)
|
||||||
|
|
||||||
#ifdef CACHE_LOCK_DEBUG
|
#ifdef CACHE_LOCK_DEBUG
|
||||||
/* Wait for the background download thread to finish */
|
/* 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());
|
pthread_self());
|
||||||
#endif
|
#endif
|
||||||
pthread_mutex_lock(&cf->bgt_lock);
|
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);
|
pthread_mutex_unlock(&cf->bgt_lock);
|
||||||
|
|
||||||
#ifdef CACHE_LOCK_DEBUG
|
#ifdef CACHE_LOCK_DEBUG
|
||||||
/* Wait for any other download thread to finish*/
|
/* Wait for any other download thread to finish*/
|
||||||
fprintf(stderr, "Cache_read(): thread %lu: locking rw_lock;\n",
|
fprintf(stderr, "Cache_read(): thread %lu: locking rw_lock;\n",
|
||||||
|
|
15
src/cache.h
15
src/cache.h
|
@ -1,10 +1,15 @@
|
||||||
#ifndef CACHE_H
|
#ifndef CACHE_H
|
||||||
#define CACHE_H
|
#define CACHE_H
|
||||||
|
|
||||||
#include "link.h"
|
|
||||||
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief cache data type
|
||||||
|
*/
|
||||||
|
typedef struct Cache Cache;
|
||||||
|
|
||||||
|
#include "link.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \file cache.h
|
* \file cache.h
|
||||||
* \brief cache related structures and functions
|
* \brief cache related structures and functions
|
||||||
|
@ -19,9 +24,9 @@
|
||||||
typedef uint8_t Seg;
|
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 */
|
char *path; /**< the path to the file on the web server */
|
||||||
Link *link; /**< the Link associated with this cache data set */
|
Link *link; /**< the Link associated with this cache data set */
|
||||||
long time; /**<the modified time of the file */
|
long time; /**<the modified time of the file */
|
||||||
|
@ -41,7 +46,7 @@ typedef struct {
|
||||||
int blksz; /**<the block size of the data file */
|
int blksz; /**<the block size of the data file */
|
||||||
long segbc; /**<segment array byte count */
|
long segbc; /**<segment array byte count */
|
||||||
Seg *seg; /**< the detail of each segment */
|
Seg *seg; /**< the detail of each segment */
|
||||||
} Cache;
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief whether the cache system is enabled
|
* \brief whether the cache system is enabled
|
||||||
|
|
12
src/link.c
12
src/link.c
|
@ -15,7 +15,8 @@
|
||||||
LinkTable *ROOT_LINK_TBL = NULL;
|
LinkTable *ROOT_LINK_TBL = NULL;
|
||||||
int ROOT_LINK_OFFSET = 0;
|
int ROOT_LINK_OFFSET = 0;
|
||||||
|
|
||||||
/* ----------------- Static variable ----------------------- */
|
/* ----------------- Static variables ----------------------- */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief LinkTable generation priority lock
|
* \brief LinkTable generation priority lock
|
||||||
* \details This allows LinkTable generation to be run exclusively. This
|
* \details This allows LinkTable generation to be run exclusively. This
|
||||||
|
@ -584,16 +585,13 @@ long path_download(const char *path, char *output_buf, size_t size,
|
||||||
|
|
||||||
#ifdef LINK_LOCK_DEBUG
|
#ifdef LINK_LOCK_DEBUG
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"path_download(): thread %lu: locking link_lock;\n",
|
"path_download(): thread %lu: locking and unlocking link_lock;\n",
|
||||||
pthread_self());
|
pthread_self());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
pthread_mutex_lock(&link_lock);
|
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);
|
pthread_mutex_unlock(&link_lock);
|
||||||
|
|
||||||
transfer_blocking(curl);
|
transfer_blocking(curl);
|
||||||
|
|
||||||
long http_resp;
|
long http_resp;
|
||||||
|
|
12
src/link.h
12
src/link.h
|
@ -5,6 +5,11 @@
|
||||||
|
|
||||||
#include <curl/curl.h>
|
#include <curl/curl.h>
|
||||||
|
|
||||||
|
/** \brief Link type */
|
||||||
|
typedef struct Link Link;
|
||||||
|
|
||||||
|
#include "cache.h"
|
||||||
|
|
||||||
/** \brief the link type */
|
/** \brief the link type */
|
||||||
typedef enum {
|
typedef enum {
|
||||||
LINK_HEAD = 'H',
|
LINK_HEAD = 'H',
|
||||||
|
@ -19,11 +24,8 @@ typedef enum {
|
||||||
*/
|
*/
|
||||||
typedef struct LinkTable LinkTable;
|
typedef struct LinkTable LinkTable;
|
||||||
|
|
||||||
/** \brief link data type */
|
|
||||||
typedef struct Link Link;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Link data structure
|
* \brief Link type data structure
|
||||||
*/
|
*/
|
||||||
struct Link {
|
struct Link {
|
||||||
char linkname[MAX_FILENAME_LEN+1]; /**< The link name in the last level of
|
char linkname[MAX_FILENAME_LEN+1]; /**< The link name in the last level of
|
||||||
|
@ -33,6 +35,8 @@ struct Link {
|
||||||
size_t content_length; /**< CURLINFO_CONTENT_LENGTH_DOWNLOAD of the file */
|
size_t content_length; /**< CURLINFO_CONTENT_LENGTH_DOWNLOAD of the file */
|
||||||
LinkTable *next_table; /**< The next LinkTable level, if it is a LINK_DIR */
|
LinkTable *next_table; /**< The next LinkTable level, if it is a LINK_DIR */
|
||||||
long time; /**< CURLINFO_FILETIME obtained from the server */
|
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 {
|
struct LinkTable {
|
||||||
|
|
Loading…
Reference in New Issue