diff options
-rw-r--r-- | source4/dsdb/samdb/ldb_modules/samldb.c | 3 | ||||
-rw-r--r-- | source4/dsdb/samdb/ldb_modules/schema_load.c | 39 | ||||
-rw-r--r-- | source4/dsdb/samdb/samdb.h | 1 | ||||
-rw-r--r-- | source4/dsdb/schema/schema.h | 1 | ||||
-rw-r--r-- | source4/ldap_server/ldap_backend.c | 25 |
5 files changed, 65 insertions, 4 deletions
diff --git a/source4/dsdb/samdb/ldb_modules/samldb.c b/source4/dsdb/samdb/ldb_modules/samldb.c index 41c97bf32a..7b98dd62c1 100644 --- a/source4/dsdb/samdb/ldb_modules/samldb.c +++ b/source4/dsdb/samdb/ldb_modules/samldb.c @@ -4,6 +4,7 @@ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005 Copyright (C) Simo Sorce 2004-2008 Copyright (C) Matthias Dieter Wallnöfer 2009-2011 + Copyright (C) Matthieu Patou 2012 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -428,6 +429,8 @@ static int samldb_add_handle_msDS_IntId(struct samldb_ctx *ac) struct ldb_context *ldb; struct ldb_result *ldb_res; struct ldb_dn *schema_dn; + struct samldb_msds_intid_persistant *msds_intid_struct; + struct dsdb_schema *schema; ldb = ldb_module_get_ctx(ac->module); schema_dn = ldb_get_schema_basedn(ldb); diff --git a/source4/dsdb/samdb/ldb_modules/schema_load.c b/source4/dsdb/samdb/ldb_modules/schema_load.c index 4c166d51ce..f922aabba9 100644 --- a/source4/dsdb/samdb/ldb_modules/schema_load.c +++ b/source4/dsdb/samdb/ldb_modules/schema_load.c @@ -49,6 +49,10 @@ static struct dsdb_schema *dsdb_schema_refresh(struct ldb_module *module, struct struct dsdb_control_current_partition *ctrl; struct ldb_context *ldb = ldb_module_get_ctx(module); struct dsdb_schema *new_schema; + int interval; + time_t ts, lastts; + struct loadparm_context *lp_ctx = + (struct loadparm_context *)ldb_get_opaque(ldb, "loadparm"); struct schema_load_private_data *private_data = talloc_get_type(ldb_module_get_private(module), struct schema_load_private_data); if (!private_data) { @@ -61,6 +65,14 @@ static struct dsdb_schema *dsdb_schema_refresh(struct ldb_module *module, struct return schema; } + lastts = schema->last_refresh; + ts = time(NULL); + interval = lpcfg_parm_int(lp_ctx, NULL, "dsdb", "schema_reload_interval", 120); + if (lastts > (ts - interval)) { + DEBUG(11, ("Less than %d seconds since last reload, returning cached version ts = %d\n", interval, (int)lastts)); + return schema; + } + res = talloc_zero(schema, struct ldb_result); if (res == NULL) { return NULL; @@ -84,7 +96,16 @@ static struct dsdb_schema *dsdb_schema_refresh(struct ldb_module *module, struct talloc_free(res); return NULL; } - + + /* + * We update right now the last refresh timestamp so that if + * the schema partition hasn't change we don't keep on retrying. + * Otherwise if the timestamp was update only when the schema has + * actually changed (and therefor completely reloaded) we would + * continue to hit the database to get the highest USN. + */ + schema->last_refresh = ts; + ctrl = talloc(treq, struct dsdb_control_current_partition); if (!ctrl) { talloc_free(res); @@ -130,7 +151,7 @@ static struct dsdb_schema *dsdb_schema_refresh(struct ldb_module *module, struct if (ret != LDB_SUCCESS) { return schema; } - + if (is_global_schema) { dsdb_make_schema_global(ldb, new_schema); } @@ -226,6 +247,7 @@ static int dsdb_schema_from_db(struct ldb_module *module, struct ldb_dn *schema_ ret = dsdb_set_schema(ldb, (*schema)); (*schema)->refresh_in_progress = false; + (*schema)->last_refresh = time(NULL); if (ret != LDB_SUCCESS) { ldb_debug_set(ldb, LDB_DEBUG_FATAL, @@ -324,9 +346,22 @@ static int schema_load_del_transaction(struct ldb_module *module) static int schema_load_extended(struct ldb_module *module, struct ldb_request *req) { + time_t *lastts; + struct ldb_context *ldb = ldb_module_get_ctx(module); + struct dsdb_schema *schema; + if (strcmp(req->op.extended.oid, DSDB_EXTENDED_SCHEMA_UPDATE_NOW_OID) != 0) { return ldb_next_request(module, req); } + lastts = (time_t *)ldb_get_opaque(ldb, DSDB_OPAQUE_LAST_SCHEMA_UPDATE_MSG_OPAQUE_NAME); + if (!lastts) { + lastts = talloc(ldb, time_t); + } + schema = dsdb_get_schema(ldb, NULL); + /* Force a refresh */ + schema->last_refresh = 0; + *lastts = 0; + ldb_set_opaque(ldb, DSDB_OPAQUE_LAST_SCHEMA_UPDATE_MSG_OPAQUE_NAME, lastts); /* This is a no-op. We reload as soon as we can */ return ldb_module_done(req, NULL, NULL, LDB_SUCCESS); diff --git a/source4/dsdb/samdb/samdb.h b/source4/dsdb/samdb/samdb.h index 50f7bf7d13..2a4bd355eb 100644 --- a/source4/dsdb/samdb/samdb.h +++ b/source4/dsdb/samdb/samdb.h @@ -199,6 +199,7 @@ struct dsdb_extended_dn_store_format { bool store_extended_dn_in_ldb; }; +#define DSDB_OPAQUE_LAST_SCHEMA_UPDATE_MSG_OPAQUE_NAME "DSDB_OPAQUE_LAST_SCHEMA_UPDATE" #define DSDB_OPAQUE_PARTITION_MODULE_MSG_OPAQUE_NAME "DSDB_OPAQUE_PARTITION_MODULE_MSG" /* this takes a struct dsdb_fsmo_extended_op */ diff --git a/source4/dsdb/schema/schema.h b/source4/dsdb/schema/schema.h index b1ae76882a..d3dd035e01 100644 --- a/source4/dsdb/schema/schema.h +++ b/source4/dsdb/schema/schema.h @@ -245,6 +245,7 @@ struct dsdb_schema { struct ldb_module *loaded_from_module; struct dsdb_schema *(*refresh_fn)(struct ldb_module *module, struct dsdb_schema *schema, bool is_global_schema); bool refresh_in_progress; + time_t last_refresh; /* an 'opaque' sequence number that the reload function may also wish to use */ uint64_t reload_seq_number; diff --git a/source4/ldap_server/ldap_backend.c b/source4/ldap_server/ldap_backend.c index afeb3500d0..000d7e28f8 100644 --- a/source4/ldap_server/ldap_backend.c +++ b/source4/ldap_server/ldap_backend.c @@ -1162,6 +1162,9 @@ NTSTATUS ldapsrv_do_call(struct ldapsrv_call *call) { unsigned int i; struct ldap_message *msg = call->request; + struct ldb_context *samdb = call->conn->ldb; + NTSTATUS status; + time_t *lastts; /* Check for undecoded critical extensions */ for (i=0; msg->controls && msg->controls[i]; i++) { if (!msg->controls_decoded[i] && @@ -1180,9 +1183,11 @@ NTSTATUS ldapsrv_do_call(struct ldapsrv_call *call) case LDAP_TAG_SearchRequest: return ldapsrv_SearchRequest(call); case LDAP_TAG_ModifyRequest: - return ldapsrv_ModifyRequest(call); + status = ldapsrv_ModifyRequest(call); + break; case LDAP_TAG_AddRequest: - return ldapsrv_AddRequest(call); + status = ldapsrv_AddRequest(call); + break; case LDAP_TAG_DelRequest: return ldapsrv_DelRequest(call); case LDAP_TAG_ModifyDNRequest: @@ -1196,4 +1201,20 @@ NTSTATUS ldapsrv_do_call(struct ldapsrv_call *call) default: return ldapsrv_unwilling(call, LDAP_PROTOCOL_ERROR); } + + if (NT_STATUS_IS_OK(status)) { + lastts = (time_t *)ldb_get_opaque(samdb, DSDB_OPAQUE_LAST_SCHEMA_UPDATE_MSG_OPAQUE_NAME); + if (lastts && !*lastts) { + DEBUG(10, ("Schema update now was requested, fullfilling the request ts = %d\n", lastts)); + /* + * Just requesting the schema will do the trick + * as the delay for reload is experied, we will have a reload + * from the schema as expected as we are not yet in a transaction! + */ + dsdb_get_schema(samdb, NULL); + *lastts = time(NULL); + ldb_set_opaque(samdb, DSDB_OPAQUE_LAST_SCHEMA_UPDATE_MSG_OPAQUE_NAME, lastts); + } + } + return status; } |