|
@@ -244,6 +244,8 @@ typedef struct _completion_list {
|
|
} completion_list_t;
|
|
} completion_list_t;
|
|
|
|
|
|
const char*err2string(int err);
|
|
const char*err2string(int err);
|
|
|
|
+static inline int calculate_interval(const struct timeval *start,
|
|
|
|
+ const struct timeval *end);
|
|
static int queue_session_event(zhandle_t *zh, int state);
|
|
static int queue_session_event(zhandle_t *zh, int state);
|
|
static const char* format_endpoint_info(const struct sockaddr_storage* ep);
|
|
static const char* format_endpoint_info(const struct sockaddr_storage* ep);
|
|
|
|
|
|
@@ -984,10 +986,14 @@ fail:
|
|
*
|
|
*
|
|
* See zoo_cycle_next_server for the selection logic.
|
|
* See zoo_cycle_next_server for the selection logic.
|
|
*
|
|
*
|
|
|
|
+ * \param ref_time an optional "reference time," used to determine if
|
|
|
|
+ * resolution can be skipped in accordance to the delay set by \ref
|
|
|
|
+ * zoo_set_servers_resolution_delay. Passing NULL prevents skipping.
|
|
|
|
+ *
|
|
* See {@link https://issues.apache.org/jira/browse/ZOOKEEPER-1355} for the
|
|
* See {@link https://issues.apache.org/jira/browse/ZOOKEEPER-1355} for the
|
|
* protocol and its evaluation,
|
|
* protocol and its evaluation,
|
|
*/
|
|
*/
|
|
-int update_addrs(zhandle_t *zh)
|
|
|
|
|
|
+int update_addrs(zhandle_t *zh, const struct timeval *ref_time)
|
|
{
|
|
{
|
|
int rc = ZOK;
|
|
int rc = ZOK;
|
|
char *hosts = NULL;
|
|
char *hosts = NULL;
|
|
@@ -1008,26 +1014,54 @@ int update_addrs(zhandle_t *zh)
|
|
return ZSYSTEMERROR;
|
|
return ZSYSTEMERROR;
|
|
}
|
|
}
|
|
|
|
|
|
- // NOTE: guard access to {hostname, addr_cur, addrs, addrs_old, addrs_new}
|
|
|
|
|
|
+ // NOTE: guard access to {hostname, addr_cur, addrs, addrs_old, addrs_new, last_resolve, resolve_delay_ms}
|
|
lock_reconfig(zh);
|
|
lock_reconfig(zh);
|
|
|
|
|
|
|
|
+ // Check if we are due for a host name resolution. (See
|
|
|
|
+ // zoo_set_servers_resolution_delay. The answer is always "yes"
|
|
|
|
+ // if no reference is provided or the file descriptor is invalid.)
|
|
|
|
+ if (ref_time && zh->fd->sock != -1) {
|
|
|
|
+ int do_resolve;
|
|
|
|
+
|
|
|
|
+ if (zh->resolve_delay_ms <= 0) {
|
|
|
|
+ // -1 disables, 0 means unconditional. Fail safe.
|
|
|
|
+ do_resolve = zh->resolve_delay_ms != -1;
|
|
|
|
+ } else {
|
|
|
|
+ int elapsed_ms = calculate_interval(&zh->last_resolve, ref_time);
|
|
|
|
+ // Include < 0 in case of overflow, or if we are not
|
|
|
|
+ // backed by a monotonic clock.
|
|
|
|
+ do_resolve = elapsed_ms > zh->resolve_delay_ms || elapsed_ms < 0;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (!do_resolve) {
|
|
|
|
+ goto finish;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
// Copy zh->hostname for local use
|
|
// Copy zh->hostname for local use
|
|
hosts = strdup(zh->hostname);
|
|
hosts = strdup(zh->hostname);
|
|
if (hosts == NULL) {
|
|
if (hosts == NULL) {
|
|
rc = ZSYSTEMERROR;
|
|
rc = ZSYSTEMERROR;
|
|
- goto fail;
|
|
|
|
|
|
+ goto finish;
|
|
}
|
|
}
|
|
|
|
|
|
rc = resolve_hosts(zh, hosts, &resolved);
|
|
rc = resolve_hosts(zh, hosts, &resolved);
|
|
if (rc != ZOK)
|
|
if (rc != ZOK)
|
|
{
|
|
{
|
|
- goto fail;
|
|
|
|
|
|
+ goto finish;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // Unconditionally note last resolution time.
|
|
|
|
+ if (ref_time) {
|
|
|
|
+ zh->last_resolve = *ref_time;
|
|
|
|
+ } else {
|
|
|
|
+ get_system_time(&zh->last_resolve);
|
|
}
|
|
}
|
|
|
|
|
|
// If the addrvec list is identical to last time we ran don't do anything
|
|
// If the addrvec list is identical to last time we ran don't do anything
|
|
if (addrvec_eq(&zh->addrs, &resolved))
|
|
if (addrvec_eq(&zh->addrs, &resolved))
|
|
{
|
|
{
|
|
- goto fail;
|
|
|
|
|
|
+ goto finish;
|
|
}
|
|
}
|
|
|
|
|
|
// Is the server we're connected to in the new resolved list?
|
|
// Is the server we're connected to in the new resolved list?
|
|
@@ -1047,14 +1081,14 @@ int update_addrs(zhandle_t *zh)
|
|
rc = addrvec_append(&zh->addrs_old, resolved_address);
|
|
rc = addrvec_append(&zh->addrs_old, resolved_address);
|
|
if (rc != ZOK)
|
|
if (rc != ZOK)
|
|
{
|
|
{
|
|
- goto fail;
|
|
|
|
|
|
+ goto finish;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
else {
|
|
rc = addrvec_append(&zh->addrs_new, resolved_address);
|
|
rc = addrvec_append(&zh->addrs_new, resolved_address);
|
|
if (rc != ZOK)
|
|
if (rc != ZOK)
|
|
{
|
|
{
|
|
- goto fail;
|
|
|
|
|
|
+ goto finish;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -1107,13 +1141,13 @@ int update_addrs(zhandle_t *zh)
|
|
zh->state = ZOO_NOTCONNECTED_STATE;
|
|
zh->state = ZOO_NOTCONNECTED_STATE;
|
|
}
|
|
}
|
|
|
|
|
|
-fail:
|
|
|
|
|
|
+finish:
|
|
|
|
|
|
unlock_reconfig(zh);
|
|
unlock_reconfig(zh);
|
|
|
|
|
|
// If we short-circuited out and never assigned resolved to zh->addrs then we
|
|
// If we short-circuited out and never assigned resolved to zh->addrs then we
|
|
// need to free resolved to avoid a memleak.
|
|
// need to free resolved to avoid a memleak.
|
|
- if (zh->addrs.data != resolved.data)
|
|
|
|
|
|
+ if (resolved.data && zh->addrs.data != resolved.data)
|
|
{
|
|
{
|
|
addrvec_free(&resolved);
|
|
addrvec_free(&resolved);
|
|
}
|
|
}
|
|
@@ -1310,7 +1344,7 @@ static zhandle_t *zookeeper_init_internal(const char *host, watcher_fn watcher,
|
|
if (zh->hostname == 0) {
|
|
if (zh->hostname == 0) {
|
|
goto abort;
|
|
goto abort;
|
|
}
|
|
}
|
|
- if(update_addrs(zh) != 0) {
|
|
|
|
|
|
+ if(update_addrs(zh, NULL) != 0) {
|
|
goto abort;
|
|
goto abort;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1404,7 +1438,7 @@ int zoo_set_servers(zhandle_t *zh, const char *hosts)
|
|
return ZBADARGUMENTS;
|
|
return ZBADARGUMENTS;
|
|
}
|
|
}
|
|
|
|
|
|
- // NOTE: guard access to {hostname, addr_cur, addrs, addrs_old, addrs_new}
|
|
|
|
|
|
+ // NOTE: guard access to {hostname, addr_cur, addrs, addrs_old, addrs_new, last_resolve, resolve_delay_ms}
|
|
lock_reconfig(zh);
|
|
lock_reconfig(zh);
|
|
|
|
|
|
// Reset hostname to new set of hosts to connect to
|
|
// Reset hostname to new set of hosts to connect to
|
|
@@ -1416,7 +1450,27 @@ int zoo_set_servers(zhandle_t *zh, const char *hosts)
|
|
|
|
|
|
unlock_reconfig(zh);
|
|
unlock_reconfig(zh);
|
|
|
|
|
|
- return update_addrs(zh);
|
|
|
|
|
|
+ return update_addrs(zh, NULL);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+ * Sets a minimum delay to observe between "routine" host name
|
|
|
|
+ * resolutions. See prototype for full documentation.
|
|
|
|
+ */
|
|
|
|
+int zoo_set_servers_resolution_delay(zhandle_t *zh, int delay_ms) {
|
|
|
|
+ if (delay_ms < -1) {
|
|
|
|
+ LOG_ERROR(LOGCALLBACK(zh), "Resolution delay cannot be %d", delay_ms);
|
|
|
|
+ return ZBADARGUMENTS;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // NOTE: guard access to {hostname, addr_cur, addrs, addrs_old, addrs_new, last_resolve, resolve_delay_ms}
|
|
|
|
+ lock_reconfig(zh);
|
|
|
|
+
|
|
|
|
+ zh->resolve_delay_ms = delay_ms;
|
|
|
|
+
|
|
|
|
+ unlock_reconfig(zh);
|
|
|
|
+
|
|
|
|
+ return ZOK;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -1481,7 +1535,7 @@ static int get_next_server_in_reconfig(zhandle_t *zh)
|
|
*/
|
|
*/
|
|
void zoo_cycle_next_server(zhandle_t *zh)
|
|
void zoo_cycle_next_server(zhandle_t *zh)
|
|
{
|
|
{
|
|
- // NOTE: guard access to {hostname, addr_cur, addrs, addrs_old, addrs_new}
|
|
|
|
|
|
+ // NOTE: guard access to {hostname, addr_cur, addrs, addrs_old, addrs_new, last_resolve, resolve_delay_ms}
|
|
lock_reconfig(zh);
|
|
lock_reconfig(zh);
|
|
|
|
|
|
memset(&zh->addr_cur, 0, sizeof(zh->addr_cur));
|
|
memset(&zh->addr_cur, 0, sizeof(zh->addr_cur));
|
|
@@ -1513,7 +1567,7 @@ const char* zoo_get_current_server(zhandle_t* zh)
|
|
{
|
|
{
|
|
const char *endpoint_info = NULL;
|
|
const char *endpoint_info = NULL;
|
|
|
|
|
|
- // NOTE: guard access to {hostname, addr_cur, addrs, addrs_old, addrs_new}
|
|
|
|
|
|
+ // NOTE: guard access to {hostname, addr_cur, addrs, addrs_old, addrs_new, last_resolve, resolve_delay_ms}
|
|
// Need the lock here as it is changed in update_addrs()
|
|
// Need the lock here as it is changed in update_addrs()
|
|
lock_reconfig(zh);
|
|
lock_reconfig(zh);
|
|
|
|
|
|
@@ -2415,7 +2469,7 @@ int zookeeper_interest(zhandle_t *zh, socket_t *fd, int *interest,
|
|
}
|
|
}
|
|
api_prolog(zh);
|
|
api_prolog(zh);
|
|
|
|
|
|
- rc = update_addrs(zh);
|
|
|
|
|
|
+ rc = update_addrs(zh, &now);
|
|
if (rc != ZOK) {
|
|
if (rc != ZOK) {
|
|
return api_epilog(zh, rc);
|
|
return api_epilog(zh, rc);
|
|
}
|
|
}
|