From 54577e54d1b6300aeb348087372c14ed72530f88 Mon Sep 17 00:00:00 2001 From: eindenbom Date: Fri, 2 Jul 2010 18:46:53 +0400 Subject: Add an interface to try next fail-over server after connection to the active server was unexpectedly dropped. --- src/providers/data_provider_fo.c | 90 ++++++++++++++++++++-------------------- src/providers/dp_backend.h | 6 +++ src/providers/fail_over.c | 21 ++++++++++ src/providers/fail_over.h | 6 +++ src/providers/ldap/sdap_id_op.c | 3 ++ 5 files changed, 81 insertions(+), 45 deletions(-) diff --git a/src/providers/data_provider_fo.c b/src/providers/data_provider_fo.c index 21059d394..dff0aef24 100644 --- a/src/providers/data_provider_fo.c +++ b/src/providers/data_provider_fo.c @@ -155,22 +155,42 @@ static int be_svc_data_destroy(void *memptr) return 0; } -int be_fo_add_service(struct be_ctx *ctx, const char *service_name) +/* + * Find registered be_svc_data by service name. + */ +static struct be_svc_data *be_fo_find_svc_data(struct be_ctx *ctx, + const char *service_name) { - struct fo_service *service; struct be_svc_data *svc; - int ret; + + if (!ctx || !ctx->be_fo) { + return 0; + } DLIST_FOR_EACH(svc, ctx->be_fo->svcs) { if (strcmp(svc->name, service_name) == 0) { - DEBUG(6, ("Failover service already initialized!\n")); - /* we already have a service up and configured, - * can happen when using both id and auth provider - */ - return EOK; + return svc; } } + return 0; +} + +int be_fo_add_service(struct be_ctx *ctx, const char *service_name) +{ + struct fo_service *service; + struct be_svc_data *svc; + int ret; + + svc = be_fo_find_svc_data(ctx, service_name); + if (svc) { + DEBUG(6, ("Failover service already initialized!\n")); + /* we already have a service up and configured, + * can happen when using both id and auth provider + */ + return EOK; + } + /* if not in the be service list, try to create new one */ ret = fo_new_service(ctx->be_fo->fo_ctx, service_name, &service); @@ -217,11 +237,7 @@ int be_fo_service_add_callback(TALLOC_CTX *memctx, struct be_svc_callback *callback; struct be_svc_data *svc; - DLIST_FOR_EACH(svc, ctx->be_fo->svcs) { - if (strcmp(svc->name, service_name) == 0) { - break; - } - } + svc = be_fo_find_svc_data(ctx, service_name); if (NULL == svc) { return ENOENT; } @@ -249,11 +265,7 @@ int be_fo_add_srv_server(struct be_ctx *ctx, const char *service_name, char *domain; int ret; - DLIST_FOR_EACH(svc, ctx->be_fo->svcs) { - if (strcmp(svc->name, service_name) == 0) { - break; - } - } + svc = be_fo_find_svc_data(ctx, service_name); if (NULL == svc) { return ENOENT; } @@ -281,16 +293,7 @@ int be_fo_get_server_count(struct be_ctx *ctx, const char *service_name) { struct be_svc_data *svc_data; - if (!ctx->be_fo) { - return 0; - } - - DLIST_FOR_EACH(svc_data, ctx->be_fo->svcs) { - if (strcmp(svc_data->name, service_name) == 0) { - break; - } - } - + svc_data = be_fo_find_svc_data(ctx, service_name); if (!svc_data) { return 0; } @@ -304,11 +307,7 @@ int be_fo_add_server(struct be_ctx *ctx, const char *service_name, struct be_svc_data *svc; int ret; - DLIST_FOR_EACH(svc, ctx->be_fo->svcs) { - if (strcmp(svc->name, service_name) == 0) { - break; - } - } + svc = be_fo_find_svc_data(ctx, service_name); if (NULL == svc) { return ENOENT; } @@ -349,19 +348,14 @@ struct tevent_req *be_resolve_server_send(TALLOC_CTX *memctx, state->ev = ev; state->ctx = ctx; - DLIST_FOR_EACH(svc, ctx->be_fo->svcs) { - if (strcmp(svc->name, service_name) == 0) { - state->svc = svc; - break; - } - } - + svc = be_fo_find_svc_data(ctx, service_name); if (NULL == svc) { tevent_req_error(req, EINVAL); tevent_req_post(req, ev); return req; } + state->svc = svc; state->attempts = 0; subreq = fo_resolve_service_send(state, ev, @@ -474,16 +468,22 @@ int be_resolve_server_recv(struct tevent_req *req, struct fo_server **srv) return EOK; } +void be_fo_try_next_server(struct be_ctx *ctx, const char *service_name) +{ + struct be_svc_data *svc; + + svc = be_fo_find_svc_data(ctx, service_name); + if (svc) { + fo_try_next_server(svc->fo_service); + } +} + int be_fo_run_callbacks_at_next_request(struct be_ctx *ctx, const char *service_name) { struct be_svc_data *svc; - DLIST_FOR_EACH(svc, ctx->be_fo->svcs) { - if (strcmp(svc->name, service_name) == 0) { - break; - } - } + svc = be_fo_find_svc_data(ctx, service_name); if (NULL == svc) { return ENOENT; } diff --git a/src/providers/dp_backend.h b/src/providers/dp_backend.h index 69872b6c4..a31e458f7 100644 --- a/src/providers/dp_backend.h +++ b/src/providers/dp_backend.h @@ -177,6 +177,12 @@ struct tevent_req *be_resolve_server_send(TALLOC_CTX *memctx, struct be_ctx *ctx, const char *service_name); int be_resolve_server_recv(struct tevent_req *req, struct fo_server **srv); +/* + * Instruct fail-over to try next server on the next connect attempt. + * Should be used after connection to service was unexpectedly dropped + * but there is no authoritative information on whether active server is down. + */ +void be_fo_try_next_server(struct be_ctx *ctx, const char *service_name); int be_fo_run_callbacks_at_next_request(struct be_ctx *ctx, const char *service_name); diff --git a/src/providers/fail_over.c b/src/providers/fail_over.c index f364a8c5f..3dab38a34 100644 --- a/src/providers/fail_over.c +++ b/src/providers/fail_over.c @@ -1275,6 +1275,27 @@ fo_set_port_status(struct fo_server *server, enum port_status status) } } +void fo_try_next_server(struct fo_service *service) +{ + struct fo_server *server; + + if (!service) { + DEBUG(1, ("Bug: No service supplied\n")); + return; + } + + server = service->active_server; + if (!server) { + return; + } + + service->active_server = 0; + + if (server->port_status == PORT_WORKING) { + server->port_status = PORT_NEUTRAL; + } +} + void * fo_get_server_user_data(struct fo_server *server) { diff --git a/src/providers/fail_over.h b/src/providers/fail_over.h index 24b2c1f5f..f1a071da9 100644 --- a/src/providers/fail_over.h +++ b/src/providers/fail_over.h @@ -155,6 +155,12 @@ void fo_set_server_status(struct fo_server *server, void fo_set_port_status(struct fo_server *server, enum port_status status); +/* + * Instruct fail-over to try next server on the next connect attempt. + * Should be used after connection to service was unexpectedly dropped + * but there is no authoritative information on whether active server is down. + */ +void fo_try_next_server(struct fo_service *service); void *fo_get_server_user_data(struct fo_server *server); diff --git a/src/providers/ldap/sdap_id_op.c b/src/providers/ldap/sdap_id_op.c index de498bd77..1e20c75e1 100644 --- a/src/providers/ldap/sdap_id_op.c +++ b/src/providers/ldap/sdap_id_op.c @@ -703,6 +703,9 @@ int sdap_id_op_done(struct sdap_id_op *op, int retval, int *dp_err_out) && op->conn_data == op->conn_cache->cached_connection) { /* do not reuse failed connection */ op->conn_cache->cached_connection = NULL; + + DEBUG(5, ("communication error on cached connection, moving to next server\n")); + be_fo_try_next_server(op->conn_cache->be, op->conn_cache->service->name); } int dp_err; -- cgit