@@ -45,11 +45,6 @@ typedef enum {
4545
4646int CACHE_SYSTEM_INIT = 0 ;
4747
48- /**
49- * \brief the receive buffer
50- */
51- static uint8_t RECV_BUF [DATA_BLK_SZ ];
52-
5348/**
5449 * \brief The metadata directory
5550 */
@@ -280,19 +275,13 @@ static long Data_size(const char *fn)
280275 * - negative values on error,
281276 * - otherwise, the number of bytes read.
282277 */
283- static long Data_read (const Cache * cf , uint8_t * buf , off_t len , off_t offset )
278+ static long Data_read (Cache * cf , uint8_t * buf , off_t len , off_t offset )
284279{
285280 if (len == 0 ) {
286281 fprintf (stderr , "Data_read(): requested to read 0 byte!\n" );
287282 return - EINVAL ;
288283 }
289284
290- size_t start = offset ;
291- size_t end = start + len ;
292- char range_str [64 ];
293- snprintf (range_str , sizeof (range_str ), "%lu-%lu" , start , end );
294- fprintf (stderr , "Data_read(%s, %s);\n" , cf -> path , range_str );
295-
296285 long byte_read = - EIO ;
297286
298287 if (fseeko (cf -> dfp , offset , SEEK_SET )) {
@@ -332,20 +321,14 @@ static long Data_read(const Cache *cf, uint8_t *buf, off_t len, off_t offset)
332321 * - otherwise, the number of bytes written.
333322 */
334323
335- static long Data_write (const Cache * cf , const uint8_t * buf , off_t len ,
324+ static long Data_write (Cache * cf , const uint8_t * buf , off_t len ,
336325 off_t offset )
337326{
338327 if (len == 0 ) {
339328 fprintf (stderr , "Data_write(): requested to write 0 byte!\n" );
340329 return - EINVAL ;
341330 }
342331
343- size_t start = offset ;
344- size_t end = start + len ;
345- char range_str [64 ];
346- snprintf (range_str , sizeof (range_str ), "%lu-%lu" , start , end );
347- fprintf (stderr , "Data_write(%s, %s);\n" , cf -> path , range_str );
348-
349332 long byte_written = - EIO ;
350333
351334 if (fseeko (cf -> dfp , offset , SEEK_SET )) {
@@ -404,8 +387,26 @@ static Cache *Cache_alloc()
404387 }
405388
406389 if (pthread_mutex_init (& cf -> rw_lock , NULL )) {
407- printf (
408- "Cache_alloc(): rw_lock initialisation failed!\n" );
390+ fprintf (stderr , "Cache_alloc(): rw_lock initialisation failed!\n" );
391+ }
392+
393+ if (pthread_mutex_init (& cf -> bgt_lock , NULL )) {
394+ fprintf (stderr , "Cache_alloc(): seg_lock initialisation failed!\n" );
395+ }
396+
397+
398+ if (pthread_mutexattr_init (& cf -> bgt_lock_attr )) {
399+ fprintf (stderr ,
400+ "Cache_alloc(): bgt_lock_attr initialisation failed!\n" );
401+ }
402+
403+ if (pthread_mutexattr_setpshared (& cf -> bgt_lock_attr ,
404+ PTHREAD_PROCESS_SHARED )) {
405+ fprintf (stderr , "Cache_alloc(): could not set bgt_lock_attr!\n" );
406+ }
407+
408+ if (pthread_mutex_init (& cf -> bgt_lock , NULL )) {
409+ fprintf (stderr , "Cache_alloc(): bgt_lock initialisation failed!\n" );
409410 }
410411
411412 return cf ;
@@ -420,12 +421,21 @@ static void Cache_free(Cache *cf)
420421 fprintf (stderr , "Cache_free(): could not destroy rw_lock!\n" );
421422 }
422423
424+ if (pthread_mutex_destroy (& cf -> bgt_lock )) {
425+ fprintf (stderr , "Cache_free(): could not destroy bgt_lock!\n" );
426+ }
427+
428+ if (pthread_mutexattr_destroy (& cf -> bgt_lock_attr )) {
429+ fprintf (stderr , "Cache_alloc(): could not destroy bgt_lock_attr!\n" );
430+ }
431+
423432 if (cf -> path ) {
424433 free (cf -> path );
425434 }
426435 if (cf -> seg ) {
427436 free (cf -> seg );
428437 }
438+
429439 free (cf );
430440}
431441
@@ -626,7 +636,6 @@ Cache *Cache_open(const char *fn)
626636{
627637 /* Check if both metadata and data file exist */
628638 if (!Cache_exist (fn )) {
629- // fprintf(stderr, "dataset does not exist!\n");
630639 return NULL ;
631640 }
632641
@@ -689,6 +698,10 @@ cf->content_length: %ld, Data_size(fn): %ld.\n", fn, cf->content_length,
689698
690699void Cache_close (Cache * cf )
691700{
701+ /* Must wait for the background download thread to stop */
702+ pthread_mutex_lock (& cf -> bgt_lock );
703+ pthread_mutex_unlock (& cf -> bgt_lock );
704+
692705 if (Meta_write (cf )) {
693706 fprintf (stderr , "Cache_close(): Meta_write() error." );
694707 }
@@ -728,9 +741,41 @@ static void Seg_set(Cache *cf, off_t offset, int i)
728741 cf -> seg [byte ] = i ;
729742}
730743
744+ /**
745+ * \brief Background download function
746+ * \details If we are requesting the data from the second half of the current
747+ * segment, we can spawn a pthread using this function to download the next
748+ * segment.
749+ */
750+ static void * Cache_background_download (void * arg )
751+ {
752+ fprintf (stderr , "Starting Cache_background_download in its own thread.\n" );
753+ Cache * cf = (Cache * ) arg ;
754+ uint8_t recv_buf [DATA_BLK_SZ ];
755+
756+ long recv = path_download (cf -> path , (char * ) recv_buf , cf -> blksz ,
757+ cf -> next_offset );
758+ if ( (recv == cf -> blksz ) ||
759+ (cf -> next_offset == (cf -> content_length / cf -> blksz * cf -> blksz )) )
760+ {
761+ Data_write (cf , recv_buf , cf -> blksz , cf -> next_offset );
762+ Seg_set (cf , cf -> next_offset , 1 );
763+ } else {
764+ fprintf (stderr ,
765+ "Cache_background_download(): recv (%ld) < cf->blksz! \
766+ Possible network error?\n" ,
767+ recv );
768+ }
769+
770+ pthread_mutex_unlock (& cf -> bgt_lock );
771+ fprintf (stderr , "Exiting Cache_background_download thread.\n" );
772+ pthread_exit (NULL );
773+ }
774+
731775long Cache_read (Cache * cf , char * output_buf , off_t len , off_t offset )
732776{
733777 long send ;
778+ uint8_t recv_buf [DATA_BLK_SZ ];
734779 /*
735780 * Quick fix for SIGFPE,
736781 * this shouldn't happen in the first place!
@@ -741,18 +786,19 @@ long Cache_read(Cache *cf, char *output_buf, off_t len, off_t offset)
741786 cf -> blksz );
742787 return path_download (cf -> path , output_buf , len , offset );
743788 }
789+
744790 pthread_mutex_lock (& cf -> rw_lock );
791+ /* Calculate the aligned offset */
792+ off_t dl_offset = offset / cf -> blksz * cf -> blksz ;
745793 if (Seg_exist (cf , offset )) {
746794 /*
747795 * The metadata shows the segment already exists. This part is easy,
748796 * as you don't have to worry about alignment
749797 */
750798 send = Data_read (cf , (uint8_t * ) output_buf , len , offset );
751799 } else {
752- /* Calculate the aligned offset */
753- off_t dl_offset = offset / cf -> blksz * cf -> blksz ;
754800 /* Download the segment */
755- long recv = path_download (cf -> path , (char * ) RECV_BUF , cf -> blksz ,
801+ long recv = path_download (cf -> path , (char * ) recv_buf , cf -> blksz ,
756802 dl_offset );
757803 /*
758804 * check if we have received enough data
@@ -762,19 +808,34 @@ long Cache_read(Cache *cf, char *output_buf, off_t len, off_t offset)
762808 * Condition 2: offset is the last segment
763809 */
764810 if ( (recv == cf -> blksz ) ||
765- (dl_offset == (cf -> content_length / cf -> blksz * cf -> blksz )) ) {
766- memmove (output_buf , RECV_BUF + (offset - dl_offset ), len );
811+ (dl_offset == (cf -> content_length / cf -> blksz * cf -> blksz )) )
812+ {
813+ memmove (output_buf , recv_buf + (offset - dl_offset ), len );
767814 send = len ;
768- Data_write (cf , RECV_BUF , cf -> blksz , dl_offset );
815+ Data_write (cf , recv_buf , cf -> blksz , dl_offset );
769816 Seg_set (cf , dl_offset , 1 );
770817 } else {
771- memmove (output_buf , RECV_BUF + (offset - dl_offset ), recv );
818+ memmove (output_buf , recv_buf + (offset - dl_offset ), recv );
772819 send = recv ;
773820 fprintf (stderr ,
774821 "Cache_read(): recv (%ld) < cf->blksz! Possible network error?\n" ,
775822 recv );
776823 }
777824 }
778825 pthread_mutex_unlock (& cf -> rw_lock );
826+
827+ /* Download the next segment in background */
828+ cf -> next_offset = round_div (offset , cf -> blksz ) * cf -> blksz ;
829+ if ( (cf -> next_offset > dl_offset ) && !Seg_exist (cf , cf -> next_offset ) ) {
830+ /* Stop the spawning of multiple background pthreads */
831+ if (!pthread_mutex_trylock (& cf -> bgt_lock )) {
832+ if (pthread_create (& cf -> bgt , NULL , Cache_background_download , cf )) {
833+ fprintf (stderr ,
834+ "Cache_read(): Error creating background download thread\n"
835+ );
836+ }
837+ }
838+ }
839+
779840 return send ;
780841}
0 commit comments