summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDavid Young <dyoung@hdfgroup.org>2019-09-10 20:27:38 (GMT)
committerDavid Young <dyoung@hdfgroup.org>2019-09-10 20:27:38 (GMT)
commit9e2d4344de72a5e69e28629a11d918675877dfe4 (patch)
tree844461958cd2620cad2b32d140e548eef0d33ae9 /src
parent508cfab552d844c1ea313af99b5e815e87053c7c (diff)
downloadhdf5-9e2d4344de72a5e69e28629a11d918675877dfe4.zip
hdf5-9e2d4344de72a5e69e28629a11d918675877dfe4.tar.gz
hdf5-9e2d4344de72a5e69e28629a11d918675877dfe4.tar.bz2
Merge the latest h5_retry_t code from my `sleepy` branch.
Diffstat (limited to 'src')
-rw-r--r--src/H5C.c25
-rw-r--r--src/H5private.h2
-rw-r--r--src/H5retry_private.h100
-rw-r--r--src/H5system.c25
4 files changed, 132 insertions, 20 deletions
diff --git a/src/H5C.c b/src/H5C.c
index 038f103..028affe 100644
--- a/src/H5C.c
+++ b/src/H5C.c
@@ -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() */