Bugfix: partially fixed the cache lock
- now when the same file is opened twice, the fread() output is consistent.
This commit is contained in:
parent
20f30a0e38
commit
ed5457c76f
95
src/cache.c
95
src/cache.c
|
@ -354,9 +354,22 @@ static long Data_read(Cache *cf, uint8_t *buf, off_t len, off_t offset)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
#ifdef CACHE_LOCK_DEBUG
|
||||
fprintf(stderr, "Data_read(): thread %lu: locking seek_lock;\n",
|
||||
pthread_self());
|
||||
#endif
|
||||
PTHREAD_MUTEX_LOCK(&cf->seek_lock);
|
||||
|
||||
if (fseeko(cf->dfp, offset, SEEK_SET)) {
|
||||
/* fseeko failed */
|
||||
fprintf(stderr, "Data_read(): fseeko(): %s\n", strerror(errno));
|
||||
|
||||
#ifdef CACHE_LOCK_DEBUG
|
||||
fprintf(stderr, "Data_read(): thread %lu: unlocking seek_lock;\n",
|
||||
pthread_self());
|
||||
#endif
|
||||
PTHREAD_MUTEX_UNLOCK(&cf->seek_lock);
|
||||
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
|
@ -377,6 +390,12 @@ static long Data_read(Cache *cf, uint8_t *buf, off_t len, off_t offset)
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef CACHE_LOCK_DEBUG
|
||||
fprintf(stderr, "Data_read(): thread %lu: unlocking seek_lock;\n",
|
||||
pthread_self());
|
||||
#endif
|
||||
PTHREAD_MUTEX_UNLOCK(&cf->seek_lock);
|
||||
|
||||
return byte_read;
|
||||
}
|
||||
|
||||
|
@ -399,10 +418,21 @@ static long Data_write(Cache *cf, const uint8_t *buf, off_t len,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
#ifdef CACHE_LOCK_DEBUG
|
||||
fprintf(stderr, "Data_write(): thread %lu: locking seek_lock;\n",
|
||||
pthread_self());
|
||||
#endif
|
||||
PTHREAD_MUTEX_LOCK(&cf->seek_lock);
|
||||
|
||||
if (fseeko(cf->dfp, offset, SEEK_SET)) {
|
||||
/* fseeko failed */
|
||||
fprintf(stderr, "Data_write(): fseeko(): %s\n", strerror(errno));
|
||||
|
||||
#ifdef CACHE_LOCK_DEBUG
|
||||
fprintf(stderr, "Data_write(): thread %lu: unlocking seek_lock;\n",
|
||||
pthread_self());
|
||||
#endif
|
||||
PTHREAD_MUTEX_UNLOCK(&cf->seek_lock);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
|
@ -417,7 +447,11 @@ static long Data_write(Cache *cf, const uint8_t *buf, off_t len,
|
|||
"Data_write(): fwrite(): encountered error!\n");
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CACHE_LOCK_DEBUG
|
||||
fprintf(stderr, "Data_write(): thread %lu: unlocking seek_lock;\n",
|
||||
pthread_self());
|
||||
#endif
|
||||
PTHREAD_MUTEX_UNLOCK(&cf->seek_lock);
|
||||
return byte_written;
|
||||
}
|
||||
|
||||
|
@ -450,18 +484,12 @@ static Cache *Cache_alloc()
|
|||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (pthread_mutexattr_init(&cf->rw_lock_attr)) {
|
||||
fprintf(stderr,
|
||||
"Cache_alloc(): rw_lock_attr initialisation failed!\n");
|
||||
if (pthread_mutex_init(&cf->seek_lock, NULL)) {
|
||||
fprintf(stderr, "Cache_alloc(): seek_lock initialisation failed!\n");
|
||||
}
|
||||
|
||||
if (pthread_mutexattr_setpshared(&cf->rw_lock_attr,
|
||||
PTHREAD_PROCESS_SHARED)) {
|
||||
fprintf(stderr, "Cache_alloc(): could not set rw_lock_attr!\n");
|
||||
}
|
||||
|
||||
if (pthread_mutex_init(&cf->rw_lock, &cf->rw_lock_attr)) {
|
||||
fprintf(stderr, "Cache_alloc(): rw_lock initialisation failed!\n");
|
||||
if (pthread_mutex_init(&cf->w_lock, NULL)) {
|
||||
fprintf(stderr, "Cache_alloc(): w_lock initialisation failed!\n");
|
||||
}
|
||||
|
||||
if (pthread_mutexattr_init(&cf->bgt_lock_attr)) {
|
||||
|
@ -486,12 +514,12 @@ static Cache *Cache_alloc()
|
|||
*/
|
||||
static void Cache_free(Cache *cf)
|
||||
{
|
||||
if (pthread_mutex_destroy(&cf->rw_lock)) {
|
||||
fprintf(stderr, "Cache_free(): could not destroy rw_lock!\n");
|
||||
if (pthread_mutex_destroy(&cf->seek_lock)) {
|
||||
fprintf(stderr, "Cache_free(): could not destroy seek_lock!\n");
|
||||
}
|
||||
|
||||
if (pthread_mutexattr_destroy(&cf->rw_lock_attr)) {
|
||||
fprintf(stderr, "Cache_alloc(): could not destroy rw_lock_attr!\n");
|
||||
if (pthread_mutex_destroy(&cf->w_lock)) {
|
||||
fprintf(stderr, "Cache_free(): could not destroy w_lock!\n");
|
||||
}
|
||||
|
||||
if (pthread_mutex_destroy(&cf->bgt_lock)) {
|
||||
|
@ -878,10 +906,10 @@ static void *Cache_bgdl(void *arg)
|
|||
{
|
||||
Cache *cf = (Cache *) arg;
|
||||
#ifdef CACHE_LOCK_DEBUG
|
||||
fprintf(stderr, "Cache_bgdl(): thread %lu: locking rw_lock;\n",
|
||||
fprintf(stderr, "Cache_bgdl(): thread %lu: locking w_lock;\n",
|
||||
pthread_self());
|
||||
#endif
|
||||
PTHREAD_MUTEX_LOCK(&cf->rw_lock);
|
||||
PTHREAD_MUTEX_LOCK(&cf->w_lock);
|
||||
uint8_t *recv_buf = calloc(cf->blksz, sizeof(uint8_t));
|
||||
fprintf(stderr, "Cache_bgdl(): thread %lu:", pthread_self());
|
||||
long recv = path_download(cf->path, (char *) recv_buf, cf->blksz,
|
||||
|
@ -902,10 +930,10 @@ static void *Cache_bgdl(void *arg)
|
|||
#endif
|
||||
PTHREAD_MUTEX_UNLOCK(&cf->bgt_lock);
|
||||
#ifdef CACHE_LOCK_DEBUG
|
||||
fprintf(stderr, "Cache_bgdl(): thread %lu: unlocking rw_lock;\n",
|
||||
fprintf(stderr, "Cache_bgdl(): thread %lu: unlocking w_lock;\n",
|
||||
pthread_self());
|
||||
#endif
|
||||
PTHREAD_MUTEX_UNLOCK(&cf->rw_lock);
|
||||
PTHREAD_MUTEX_UNLOCK(&cf->w_lock);
|
||||
pthread_detach(pthread_self());
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
@ -919,14 +947,6 @@ long Cache_read(Cache *cf, char *output_buf, off_t len, off_t offset)
|
|||
fprintf(stderr, "Cache_read(): thread %lu: %s, %s;\n", pthread_self(),
|
||||
cf->path, range_str);
|
||||
|
||||
/* SIGFPE prevention, although this shouldn't happen in the first place! */
|
||||
if (!cf->blksz) {
|
||||
fprintf(stderr,
|
||||
"Cache_read(): Warning: cf->blksz: %d, directly downloading",
|
||||
cf->blksz);
|
||||
return path_download(cf->path, output_buf, len, offset);
|
||||
}
|
||||
|
||||
long send;
|
||||
off_t dl_offset = offset / cf->blksz * cf->blksz;
|
||||
|
||||
|
@ -937,29 +957,20 @@ long Cache_read(Cache *cf, char *output_buf, off_t len, off_t offset)
|
|||
} else {
|
||||
|
||||
#ifdef CACHE_LOCK_DEBUG
|
||||
fprintf(stderr,
|
||||
"Cache_read(): thread %lu: locking and unlocking bgt_lock;\n",
|
||||
pthread_self());
|
||||
#endif
|
||||
/* Wait for the background download thread to finish */
|
||||
PTHREAD_MUTEX_LOCK(&cf->bgt_lock);
|
||||
PTHREAD_MUTEX_UNLOCK(&cf->bgt_lock);
|
||||
|
||||
#ifdef CACHE_LOCK_DEBUG
|
||||
fprintf(stderr, "Cache_read(): thread %lu: locking rw_lock;\n",
|
||||
fprintf(stderr, "Cache_read(): thread %lu: locking w_lock;\n",
|
||||
pthread_self());
|
||||
#endif
|
||||
/* Wait for any other download thread to finish*/
|
||||
PTHREAD_MUTEX_LOCK(&cf->rw_lock);
|
||||
PTHREAD_MUTEX_LOCK(&cf->w_lock);
|
||||
if (Seg_exist(cf, offset)) {
|
||||
/* The segment now exists - it was downloaded by another
|
||||
* download thread. Send it off and unlock the I/O */
|
||||
send = Data_read(cf, (uint8_t *) output_buf, len, offset);
|
||||
#ifdef CACHE_LOCK_DEBUG
|
||||
fprintf(stderr, "Cache_read(): thread %lu: unlocking rw_lock;\n",
|
||||
fprintf(stderr, "Cache_read(): thread %lu: unlocking w_lock;\n",
|
||||
pthread_self());
|
||||
#endif
|
||||
PTHREAD_MUTEX_UNLOCK(&cf->rw_lock);
|
||||
PTHREAD_MUTEX_UNLOCK(&cf->w_lock);
|
||||
goto bgdl;
|
||||
}
|
||||
}
|
||||
|
@ -992,10 +1003,10 @@ long Cache_read(Cache *cf, char *output_buf, off_t len, off_t offset)
|
|||
}
|
||||
free(recv_buf);
|
||||
#ifdef CACHE_LOCK_DEBUG
|
||||
fprintf(stderr, "Cache_read(): thread %lu: unlocking rw_lock;\n",
|
||||
fprintf(stderr, "Cache_read(): thread %lu: unlocking w_lock;\n",
|
||||
pthread_self());
|
||||
#endif
|
||||
PTHREAD_MUTEX_UNLOCK(&cf->rw_lock);
|
||||
PTHREAD_MUTEX_UNLOCK(&cf->w_lock);
|
||||
|
||||
/* -----------Download the next segment in background -------------------*/
|
||||
bgdl:
|
||||
|
|
51
src/cache.h
51
src/cache.h
|
@ -27,25 +27,42 @@ typedef uint8_t Seg;
|
|||
* \brief cache data type in-memory data structure
|
||||
*/
|
||||
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 */
|
||||
off_t content_length; /**<the size of the file */
|
||||
/** \brief The FILE pointer for the data file*/
|
||||
FILE *dfp;
|
||||
/** \brief The FILE pointer for the metadata */
|
||||
FILE *mfp;
|
||||
/** \brief the path to the file on the web server */
|
||||
char *path;
|
||||
/** \brief the Link associated with this cache data set */
|
||||
Link *link;
|
||||
/** \brief the modified time of the file */
|
||||
long time;
|
||||
/** \brief the size of the file */
|
||||
off_t content_length;
|
||||
/** \brief the block size of the data file */
|
||||
int blksz;
|
||||
/** \brief segment array byte count */
|
||||
long segbc;
|
||||
/** \brief the detail of each segment */
|
||||
Seg *seg;
|
||||
|
||||
pthread_t bgt; /**< background download pthread */
|
||||
pthread_mutex_t bgt_lock; /**< mutex for the background download thread */
|
||||
pthread_mutexattr_t bgt_lock_attr; /**< attributes for bgt_lock */
|
||||
off_t next_offset; /**<the offset of the next segment to be
|
||||
downloaded in background*/
|
||||
/** \brief mutex lock for seek operation */
|
||||
pthread_mutex_t seek_lock;
|
||||
/** \brief mutex lock for write operation */
|
||||
pthread_mutex_t w_lock;
|
||||
|
||||
pthread_mutex_t rw_lock; /**< mutex for read/write operation */
|
||||
pthread_mutexattr_t rw_lock_attr; /**< attributes for rw_lock */
|
||||
|
||||
FILE *dfp; /**< The FILE pointer for the data file*/
|
||||
FILE *mfp; /**< The FILE pointer for the metadata */
|
||||
int blksz; /**<the block size of the data file */
|
||||
long segbc; /**<segment array byte count */
|
||||
Seg *seg; /**< the detail of each segment */
|
||||
/** \brief background download pthread */
|
||||
pthread_t bgt;
|
||||
/**
|
||||
* \brief mutex lock for the background download thread
|
||||
* \note This lock is locked by the foreground thread, but unlocked by the
|
||||
* background thread!
|
||||
*/
|
||||
pthread_mutex_t bgt_lock;
|
||||
/** \brief mutex attributes for bgt_lock */
|
||||
pthread_mutexattr_t bgt_lock_attr;
|
||||
/** \brief the offset of the next segment to be downloaded in background*/
|
||||
off_t next_offset;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
25
src/link.h
25
src/link.h
|
@ -33,15 +33,22 @@ typedef struct LinkTable LinkTable;
|
|||
* \brief Link type data structure
|
||||
*/
|
||||
struct Link {
|
||||
char linkname[MAX_FILENAME_LEN+1]; /**< The link name in the last level of
|
||||
the URL */
|
||||
char f_url[MAX_PATH_LEN+1]; /**< The full URL of the file */
|
||||
LinkType type; /**< The type of the 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 */
|
||||
/** \brief The link name in the last level of the URL */
|
||||
char linkname[MAX_FILENAME_LEN+1];
|
||||
/** \brief The full URL of the file */
|
||||
char f_url[MAX_PATH_LEN+1];
|
||||
/** \brief The type of the link */
|
||||
LinkType type;
|
||||
/** \brief CURLINFO_CONTENT_LENGTH_DOWNLOAD of the file */
|
||||
size_t content_length;
|
||||
/** \brief The next LinkTable level, if it is a LINK_DIR */
|
||||
LinkTable *next_table;
|
||||
/** \brief CURLINFO_FILETIME obtained from the server */
|
||||
long time;
|
||||
/** \brief How many times associated cache has been opened */
|
||||
int cache_opened;
|
||||
/** \brief The pointer associated with the cache file */
|
||||
Cache *cache_ptr;
|
||||
};
|
||||
|
||||
struct LinkTable {
|
||||
|
|
Loading…
Reference in New Issue