>From a5f945a9107c7d0c89a9ad591ff6802878e16e57 Mon Sep 17 00:00:00 2001 From: Jakub Hrozek Date: Wed, 21 Aug 2013 01:41:16 +0200 Subject: [PATCH 04/11] LDAP: Convert enumeration to the ptask API https://fedorahosted.org/sssd/ticket/1942 Identity providers other than LDAP need to customize the enumeration in different ways while sharing the way the task is scheduled etc. The easiest way to accomplish it is to leverage the recently introduced ptask framework. --- src/providers/ldap/ldap_common.c | 30 +--- src/providers/ldap/ldap_common.h | 4 +- src/providers/ldap/ldap_id_enum.c | 279 +++++++++++++++++++++----------------- src/providers/ldap/sdap.h | 1 + 4 files changed, 157 insertions(+), 157 deletions(-) diff --git a/src/providers/ldap/ldap_common.c b/src/providers/ldap/ldap_common.c index 9aa98173c865d0b032f02bd6a0ec80b93682af6d..05e487a1e8f57da338c9949b9f1a75688a6595e7 100644 --- a/src/providers/ldap/ldap_common.c +++ b/src/providers/ldap/ldap_common.c @@ -941,37 +941,11 @@ int sdap_id_setup_tasks(struct sdap_id_ctx *ctx) struct timeval tv; int ret = EOK; int delay; - bool has_enumerated; /* set up enumeration task */ if (ctx->be->domain->enumerate) { - /* If this is the first startup, we need to kick off - * an enumeration immediately, to close a window where - * clients requesting get*ent information won't get an - * immediate reply with no entries - */ - ret = sysdb_has_enumerated(ctx->be->domain->sysdb, ctx->be->domain, - &has_enumerated); - if (ret != EOK) { - return ret; - } - if (has_enumerated) { - /* At least one enumeration has previously run, - * so clients will get cached data. We will delay - * starting to enumerate by 10s so we don't slow - * down the startup process if this is happening - * during system boot. - */ - tv = tevent_timeval_current_ofs(10, 0); - } else { - /* This is our first startup. Schedule the - * enumeration to start immediately once we - * enter the mainloop. - */ - tv = tevent_timeval_current(); - } - - ret = ldap_id_enumerate_set_timer(ctx, tv); + DEBUG(SSSDBG_TRACE_FUNC, ("Setting up enumeration for %s\n", ctx->be->domain->name)); + ret = ldap_setup_enumeration(ctx, ctx->conn, ctx->opts->sdom); } else { /* the enumeration task, runs the cleanup process by itself, * but if enumeration is not running we need to schedule it */ diff --git a/src/providers/ldap/ldap_common.h b/src/providers/ldap/ldap_common.h index c9b2f663b72658c9cdcd4d54ec32b1dd74f31326..7ba8e95571854dfbb2e1eb4faf24c992f41b68f4 100644 --- a/src/providers/ldap/ldap_common.h +++ b/src/providers/ldap/ldap_common.h @@ -165,7 +165,9 @@ int ldap_get_autofs_options(TALLOC_CTX *memctx, const char *conf_path, struct sdap_options *opts); -int ldap_id_enumerate_set_timer(struct sdap_id_ctx *ctx, struct timeval tv); +errno_t ldap_setup_enumeration(struct sdap_id_ctx *ctx, + struct sdap_id_conn_ctx *conn, + struct sdap_domain *sdom); int ldap_id_cleanup_set_timer(struct sdap_id_ctx *ctx, struct timeval tv); void sdap_mark_offline(struct sdap_id_ctx *ctx); diff --git a/src/providers/ldap/ldap_id_enum.c b/src/providers/ldap/ldap_id_enum.c index 4e0e1d06eb4e1fe8b93b9d6e35f5843c0861d5ba..98f35504db6ae33f29d861308a7a1bfe2b20f780 100644 --- a/src/providers/ldap/ldap_id_enum.c +++ b/src/providers/ldap/ldap_id_enum.c @@ -22,153 +22,176 @@ along with this program. If not, see . */ -#include -#include -#include - #include "util/util.h" #include "db/sysdb.h" #include "providers/ldap/ldap_common.h" -#include "providers/ldap/sdap_async.h" -#include "providers/ldap/sdap_idmap.h" #include "providers/ldap/sdap_async_enum.h" -extern struct tevent_req *ldap_id_cleanup_send(TALLOC_CTX *memctx, - struct tevent_context *ev, - struct sdap_id_ctx *ctx); - -/* ==Enumeration-Task===================================================== */ - -static void ldap_id_enumerate_reschedule(struct tevent_req *req); - -static void ldap_id_enumerate_timeout(struct tevent_context *ev, - struct tevent_timer *te, - struct timeval tv, void *pvt); - -static void ldap_id_enumerate_timer(struct tevent_context *ev, - struct tevent_timer *tt, - struct timeval tv, void *pvt) -{ - struct sdap_id_ctx *ctx = talloc_get_type(pvt, struct sdap_id_ctx); - struct tevent_timer *timeout; - struct tevent_req *req; - int delay; - errno_t ret; - - if (be_is_offline(ctx->be)) { - DEBUG(4, ("Backend is marked offline, retry later!\n")); - /* schedule starting from now, not the last run */ - delay = dp_opt_get_int(ctx->opts->basic, SDAP_ENUM_REFRESH_TIMEOUT); - tv = tevent_timeval_current_ofs(delay, 0); - ldap_id_enumerate_set_timer(ctx, tv); - return; - } - - req = sdap_dom_enum_send(ctx, ev, ctx, ctx->opts->sdom, ctx->conn); - if (!req) { - DEBUG(1, ("Failed to schedule enumeration, retrying later!\n")); - /* schedule starting from now, not the last run */ - delay = dp_opt_get_int(ctx->opts->basic, SDAP_ENUM_REFRESH_TIMEOUT); - tv = tevent_timeval_current_ofs(delay, 0); - ret = ldap_id_enumerate_set_timer(ctx, tv); - if (ret != EOK) { - DEBUG(1, ("Error setting up enumerate timer\n")); - } - return; - } - tevent_req_set_callback(req, ldap_id_enumerate_reschedule, ctx); - - /* if enumeration takes so long, either we try to enumerate too - * frequently, or something went seriously wrong */ - delay = dp_opt_get_int(ctx->opts->basic, SDAP_ENUM_REFRESH_TIMEOUT); - tv = tevent_timeval_current_ofs(delay, 0); - timeout = tevent_add_timer(ctx->be->ev, req, tv, - ldap_id_enumerate_timeout, req); - if (timeout == NULL) { - /* If we can't guarantee a timeout, we - * need to cancel the request, to avoid - * the possibility of starting another - * concurrently - */ - talloc_zfree(req); - - DEBUG(1, ("Failed to schedule enumeration, retrying later!\n")); - /* schedule starting from now, not the last run */ - delay = dp_opt_get_int(ctx->opts->basic, SDAP_ENUM_REFRESH_TIMEOUT); - tv = tevent_timeval_current_ofs(delay, 0); - ret = ldap_id_enumerate_set_timer(ctx, tv); - if (ret != EOK) { - DEBUG(1, ("Error setting up enumerate timer\n")); - } - return; - } - return; -} - -static void ldap_id_enumerate_timeout(struct tevent_context *ev, - struct tevent_timer *te, - struct timeval tv, void *pvt) -{ - struct tevent_req *req = talloc_get_type(pvt, struct tevent_req); - struct sdap_id_ctx *ctx = tevent_req_callback_data(req, - struct sdap_id_ctx); - int delay; - - delay = dp_opt_get_int(ctx->opts->basic, SDAP_ENUM_REFRESH_TIMEOUT); - DEBUG(1, ("Enumeration timed out! Timeout too small? (%ds)!\n", delay)); - - tv = tevent_timeval_current_ofs(delay, 0); - ldap_id_enumerate_set_timer(ctx, tv); - - talloc_zfree(req); -} - -static void ldap_id_enumerate_reschedule(struct tevent_req *req) +static struct tevent_req * +ldap_enumeration_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct be_ctx *be_ctx, + struct be_ptask *be_ptask, + void *pvt); +errno_t ldap_enumeration_recv(struct tevent_req *req); + +struct ldap_enum_ctx { + struct sdap_id_ctx *ctx; + struct sdap_domain *sdom; + struct sdap_id_conn_ctx *conn; +}; + +errno_t ldap_setup_enumeration(struct sdap_id_ctx *ctx, + struct sdap_id_conn_ctx *conn, + struct sdap_domain *sdom) { - struct sdap_id_ctx *ctx = tevent_req_callback_data(req, - struct sdap_id_ctx); - struct timeval tv; - int delay; errno_t ret; + time_t first_delay; + time_t period; + bool has_enumerated; + struct ldap_enum_ctx *ectx; - ret = sdap_dom_enum_recv(req); - talloc_zfree(req); + ret = sysdb_has_enumerated(sdom->dom->sysdb, sdom->dom, &has_enumerated); if (ret != EOK) { - /* On error schedule starting from now, not the last run */ - tv = tevent_timeval_current(); + return ret; + } + + if (has_enumerated) { + /* At least one enumeration has previously run, + * so clients will get cached data. We will delay + * starting to enumerate by 10s so we don't slow + * down the startup process if this is happening + * during system boot. + */ + first_delay = 10; } else { - tv = ctx->opts->sdom->last_enum; - - /* Ok, we've completed an enumeration. Save this to the - * sysdb so we can postpone starting up the enumeration - * process on the next SSSD service restart (to avoid - * slowing down system boot-up + /* This is our first startup. Schedule the + * enumeration to start immediately once we + * enter the mainloop. */ - ret = sysdb_set_enumerated(ctx->be->domain->sysdb, ctx->be->domain, true); - if (ret != EOK) { - DEBUG(1, ("Could not mark domain as having enumerated.\n")); - /* This error is non-fatal, so continue */ - } + first_delay = 0; } - delay = dp_opt_get_int(ctx->opts->basic, SDAP_ENUM_REFRESH_TIMEOUT); - tv = tevent_timeval_add(&tv, delay, 0); - ldap_id_enumerate_set_timer(ctx, tv); + period = dp_opt_get_int(ctx->opts->basic, SDAP_ENUM_REFRESH_TIMEOUT); + + ectx = talloc(sdom, struct ldap_enum_ctx); + if (ectx == NULL) { + return ENOMEM; + } + ectx->ctx = ctx; + ectx->sdom = sdom; + + ret = be_ptask_create(sdom, ctx->be, + period, /* period */ + first_delay, /* first_delay */ + 5, /* enabled delay */ + period, /* timeout */ + BE_PTASK_OFFLINE_SKIP, + ldap_enumeration_send, ldap_enumeration_recv, + ectx, "enumeration", &sdom->enum_task); + if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, + ("Unable to initialize enumeration periodic task\n")); + talloc_free(ectx); + return ret; + } + + talloc_steal(sdom->enum_task, ectx); + return EOK; } -int ldap_id_enumerate_set_timer(struct sdap_id_ctx *ctx, struct timeval tv) + +struct ldap_enumeration_state { + struct ldap_enum_ctx *ectx; + struct sss_domain_info *dom; +}; + +static void ldap_enumeration_done(struct tevent_req *subreq); + +static struct tevent_req * +ldap_enumeration_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct be_ctx *be_ctx, + struct be_ptask *be_ptask, + void *pvt) { - struct tevent_timer *enum_task; + struct ldap_enumeration_state *state; + struct tevent_req *req; + struct tevent_req *subreq; + struct ldap_enum_ctx *ectx; + errno_t ret; + + req = tevent_req_create(mem_ctx, &state, + struct ldap_enumeration_state); + if (req == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, ("tevent_req_create() failed\n")); + return NULL; + } - DEBUG(6, ("Scheduling next enumeration at %ld.%ld\n", - (long)tv.tv_sec, (long)tv.tv_usec)); + ectx = talloc_get_type(pvt, struct ldap_enum_ctx); + if (ectx == NULL) { + ret = EFAULT; + goto fail; + } + state->ectx = ectx; + state->dom = ectx->sdom->dom; - enum_task = tevent_add_timer(ctx->be->ev, ctx, - tv, ldap_id_enumerate_timer, ctx); - if (!enum_task) { - DEBUG(0, ("FATAL: failed to setup enumeration task!\n")); - return EFAULT; + subreq = sdap_dom_enum_send(ectx, ev, ectx->ctx, ectx->sdom, + ectx->conn); + if (subreq == NULL) { + /* The ptask API will reschedule the enumeration on its own on + * failure */ + DEBUG(SSSDBG_OP_FAILURE, + ("Failed to schedule enumeration, retrying later!\n")); + ret = EIO; + goto fail; } + tevent_req_set_callback(subreq, ldap_enumeration_done, req); + return req; + +fail: + tevent_req_error(req, ret); + tevent_req_post(req, ev); + return req; +} + +static void +ldap_enumeration_done(struct tevent_req *subreq) +{ + errno_t ret; + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct ldap_enumeration_state *state = tevent_req_data(req, + struct ldap_enumeration_state); + + ret = sdap_dom_enum_recv(subreq); + talloc_zfree(subreq); + if (ret != EOK) { + /* FIXME - On error schedule starting from now, not the last run */ + tevent_req_error(req, ret); + } + + /* Ok, we've completed an enumeration. Save this to the + * sysdb so we can postpone starting up the enumeration + * process on the next SSSD service restart (to avoid + * slowing down system boot-up + */ + ret = sysdb_set_enumerated(state->dom->sysdb, + state->dom, true); + if (ret != EOK) { + DEBUG(SSSDBG_MINOR_FAILURE, + ("Could not mark domain as having enumerated.\n")); + /* This error is non-fatal, so continue */ + } + + tevent_req_done(req); +} + +errno_t +ldap_enumeration_recv(struct tevent_req *req) +{ + TEVENT_REQ_RETURN_ON_ERROR(req); + return EOK; } diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h index f5f6d90aa075b5e7cffa4445cda87b1757dd3ca3..5da27fe87ff5900857ec89e6084ab4d766944327 100644 --- a/src/providers/ldap/sdap.h +++ b/src/providers/ldap/sdap.h @@ -384,6 +384,7 @@ struct sdap_domain { /* Need to modify the list from a talloc destructor */ struct sdap_domain **head; + struct be_ptask *enum_task; /* enumeration loop timer */ struct timeval last_enum; }; -- 1.8.3.1