diff --git a/include/dqlite.h b/include/dqlite.h index 0b24b399f..f0aa28608 100644 --- a/include/dqlite.h +++ b/include/dqlite.h @@ -217,7 +217,8 @@ DQLITE_API DQLITE_EXPERIMENTAL void dqlite_server_destroy( enum { DQLITE_ERROR = 1, /* Generic error */ DQLITE_MISUSE, /* Library used incorrectly */ - DQLITE_NOMEM /* A malloc() failed */ + DQLITE_NOMEM, /* A malloc() failed */ + DQLITE_AGAIN /* Retryable error */ }; /** diff --git a/src/raft.h b/src/raft.h index 7f8496c58..8b76f49a3 100644 --- a/src/raft.h +++ b/src/raft.h @@ -55,7 +55,8 @@ enum { RAFT_INVALID, /* Invalid parameter */ RAFT_UNAUTHORIZED, /* No access to a resource */ RAFT_NOSPACE, /* Not enough space on disk */ - RAFT_TOOMANY /* Some system or raft limit was hit */ + RAFT_TOOMANY, /* Some system or raft limit was hit */ + RAFT_AGAIN /* Retryable error */ }; /** diff --git a/src/raft/uv_fs.c b/src/raft/uv_fs.c index d28ac9eec..5cf78083b 100644 --- a/src/raft/uv_fs.c +++ b/src/raft/uv_fs.c @@ -774,8 +774,11 @@ static int probeAsyncIO(int fd, size_t size, bool *ok, char *errmsg) rv = UvOsIoSetup(1, &ctx); if (rv != 0) { UvOsErrMsg(errmsg, "io_setup", rv); - /* UNTESTED: in practice this should fail only with ENOMEM */ - return RAFT_IOERR; + if (rv == -EAGAIN) { + return RAFT_AGAIN; + } else { + return RAFT_IOERR; + } } /* Allocate the write buffer */ diff --git a/src/server.c b/src/server.c index 72fd40e2c..1aa52308c 100644 --- a/src/server.c +++ b/src/server.c @@ -110,7 +110,7 @@ int dqlite__init(struct dqlite_node *d, if (rv != 0) { snprintf(d->errmsg, DQLITE_ERRMSG_BUF_SIZE, "raft_init(): %s", raft_errmsg(&d->raft)); - return DQLITE_ERROR; + return (rv == RAFT_AGAIN) ? DQLITE_AGAIN : DQLITE_ERROR; } /* TODO: expose these values through some API */ raft_set_election_timeout(&d->raft, 3000); diff --git a/test/lib/server.c b/test/lib/server.c index d16fa076b..84c79dcea 100644 --- a/test/lib/server.c +++ b/test/lib/server.c @@ -61,7 +61,18 @@ void test_server_start(struct test_server *s, const MunitParameter params[]) { int rv; - rv = dqlite_node_create(s->id, s->address, s->dir, &s->dqlite); + struct timespec ts = {.tv_sec = 0, .tv_nsec = 1000000}; + do { + rv = dqlite_node_create(s->id, s->address, s->dir, &s->dqlite); + if (rv != 0) { + dqlite_node_destroy(s->dqlite); + } + if (rv != DQLITE_AGAIN) { + break; + } + nanosleep(&ts, NULL); + ts.tv_nsec *= 2; + } while (ts.tv_nsec < 1000000000); munit_assert_int(rv, ==, 0); rv = dqlite_node_set_bind_address(s->dqlite, s->address);