diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/H5C.c | 25 | ||||
-rw-r--r-- | src/H5private.h | 2 | ||||
-rw-r--r-- | src/H5retry_private.h | 100 | ||||
-rw-r--r-- | src/H5system.c | 25 |
4 files changed, 132 insertions, 20 deletions
@@ -7189,19 +7189,15 @@ H5C_load_entry(H5F_t * f, /* Get the on-disk entry image */ if ( 0 == (type->flags & H5C__CLASS_SKIP_READS) ) { - unsigned tries, max_tries; /* The # of read attempts */ unsigned retries; /* The # of retries */ htri_t chk_ret; /* return from verify_chksum callback */ size_t actual_len = len; /* The actual length, after speculative */ /* reads have been resolved */ - uint64_t nanosec = 1; /* # of nanoseconds to sleep between */ - /* retries */ void *new_image; /* Pointer to image */ hbool_t len_changed = TRUE; /* Whether to re-check speculative */ /* entries */ - - /* Get the # of read attempts */ - max_tries = tries = H5F_GET_READ_ATTEMPTS(f); + bool do_try; + h5_retry_t retry; /* * This do/while loop performs the following till the metadata checksum @@ -7210,7 +7206,10 @@ H5C_load_entry(H5F_t * f, * --determine the actual size of the metadata * --perform checksum verification */ - do { + for (do_try = h5_retry_init(&retry, H5F_GET_READ_ATTEMPTS(f), + 1, H5_RETRY_ONE_HOUR); + do_try; + do_try = h5_retry_next(&retry)) { if ( actual_len != len ) { if ( NULL == (new_image = H5MM_realloc(image, @@ -7354,15 +7353,10 @@ H5C_load_entry(H5F_t * f, if(chk_ret == TRUE) break; - - /* Sleep for some time */ - H5_nanosleep(nanosec); - nanosec *= 2; /* Double the sleep time next time */ - - } while(--tries); + } /* Check for too many tries */ - if ( tries == 0 ) { + if (!do_try) { #if 0 /* JRM */ haddr_t eoa; int64_t page = (int64_t)(addr / f->shared->cache->page_size); @@ -7382,8 +7376,7 @@ H5C_load_entry(H5F_t * f, } /* Calculate and track the # of retries */ - retries = max_tries - tries; - if ( retries ) { /* Does not track 0 retry */ + if ((retries = h5_retry_retries(&retry)) != 0) /* Does not track 0 retry */ if ( H5F_track_metadata_read_retries(f, (unsigned)type->mem_type, retries) < 0) diff --git a/src/H5private.h b/src/H5private.h index f96188f..6614ea9 100644 --- a/src/H5private.h +++ b/src/H5private.h @@ -2697,5 +2697,7 @@ H5_DLL herr_t H5_combine_path(const char *path1, const char *path2, char **ful H5_DLL herr_t H5_buffer_dump(FILE *stream, int indent, const uint8_t *buf, const uint8_t *marker, size_t buf_offset, size_t buf_size); +#include "H5retry_private.h" + #endif /* _H5private_H */ diff --git a/src/H5retry_private.h b/src/H5retry_private.h new file mode 100644 index 0000000..03568ef --- /dev/null +++ b/src/H5retry_private.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2019 The HDF Group. All rights reserved. + * + * This file is part of HDF5. The full HDF5 copyright notice, including + * terms governing use, modification, and redistribution, is contained in + * the COPYING file, which can be found at the root of the source code + * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. + * If you do not have access to either file, you may request a copy from + * help@hdfgroup.org. + */ + +#ifndef _H5retry_private_H +#define _H5retry_private_H + +/* + * Data types and functions for retry loops. + */ + +/* State for a retry loop. No user-serviceable parts inside. */ +typedef struct h5_retry_t { + uint64_t maxival; /* maximum sleep interval (nanoseconds) */ + unsigned maxtries; /* maximum permissible tries */ + unsigned tries; /* remaining tries */ + uint64_t ival; /* nanoseconds sleep interval before clamping to + * maxival + */ +} h5_retry_t; + +/* Default minimum/maximum retry intervals: 1/10s minimum, 1s maximum. */ +#define H5_RETRY_DEFAULT_MINIVAL ( 100ULL * 1000ULL * 1000ULL) +#define H5_RETRY_DEFAULT_MAXIVAL ( 1000ULL * 1000ULL * 1000ULL) +/* One hour: */ +#define H5_RETRY_ONE_HOUR (3600ULL * 1000ULL * 1000ULL * 1000ULL) + +/* Establish state for a retry loop in `r`. The loop will retry no + * more than `maxtries` times, sleeping for no fewer than `minival` + * nanoseconds between tries. After each try, the sleep time will + * increase to `maxival` nanoseconds or twice the previous sleep time, + * whichever is less. + * + * `h5_retry_init` always returns true. This is to help one use + * it in a loop like this: + * + * for (do_try = h5_retry_init(&r, 100, H5_RETRY_DEFAULT_MINIVAL, + * H5_RETRY_DEFAULT_MAXIVAL); + * do_try; + * do_try = h5_retry_next(&r)) { + * . + * . + * . + * } + * + * Note well: the program will enter the body of the loop, above, no more + * than 101 times: once for an initial try, and then 100 times for retries. + */ +static inline bool +h5_retry_init(struct h5_retry_t *r, unsigned int maxtries, uint64_t minival, + uint64_t maxival) +{ + memset(r, '\0', sizeof(*r)); + assert(0 < maxtries); + assert(0 < minival && minival <= maxival); + r->tries = r->maxtries = maxtries; + r->ival = minival; + r->maxival = maxival; + return true; +} + +/* If any tries remain, sleep for the mininum interval, or twice the + * previous sleep time, and return true. If no tries remain, return false. + */ +static inline bool +h5_retry_next(struct h5_retry_t *r) +{ + uint64_t ival; + + if (r->tries == 0) + return false; + --r->tries; + ival = r->ival; + if (r->maxival < ival) + ival = r->maxival; + else if (UINT64_MAX - ival >= ival) + r->ival += ival; + + H5_nanosleep(ival); + + return true; +} + +/* Return the number of retries performed since `h5_retry_init()` + * was called on `r`. + */ +static inline unsigned +h5_retry_retries(struct h5_retry_t *r) +{ + return r->maxtries - r->tries; +} + +#endif /* _H5retry_private_H */ diff --git a/src/H5system.c b/src/H5system.c index 2d29650..55cac8d 100644 --- a/src/H5system.c +++ b/src/H5system.c @@ -1192,15 +1192,32 @@ done: void H5_nanosleep(uint64_t nanosec) { + const uint64_t nanosec_per_sec = 1000 * 1000 * 1000; struct timespec sleeptime; /* Struct to hold time to sleep */ FUNC_ENTER_NOAPI_NOINIT_NOERR - /* Set up time to sleep */ - sleeptime.tv_sec = 0; - sleeptime.tv_nsec = (long)nanosec; + /* Set up time to sleep + * + * Assuming ILP32 or LP64 or wider architecture, (long)operand + * satisfies 0 <= operand < nanosec_per_sec < LONG_MAX. + * + * It's harder to be sure that we don't overflow time_t. + */ + sleeptime.tv_sec = (time_t)(nanosec / nanosec_per_sec); + sleeptime.tv_nsec = (long)(nanosec % nanosec_per_sec); - HDnanosleep(&sleeptime, NULL); + /* Sleep for up to `sleeptime` and, in the event of an interruption, + * save the unslept time back to `sleeptime`. + */ + while (HDnanosleep(&sleeptime, &sleeptime) == -1) { + /* If we were just interrupted, sleep for the remaining time. + * Otherwise, the error was essentially impossible, so just stop + * sleeping. + */ + if (errno != EINTR) + break; + } FUNC_LEAVE_NOAPI_VOID } /* end H5_nanosleep() */ |