ldap/servers/plugins/schema_reload/schema_reload.c | 7 ldap/servers/slapd/attr.c | 8 ldap/servers/slapd/attrsyntax.c | 249 ++++++++++++++------- ldap/servers/slapd/opshared.c | 2 ldap/servers/slapd/proto-slap.h | 13 - ldap/servers/slapd/schema.c | 116 +++++---- 6 files changed, 254 insertions(+), 141 deletions(-)
New commits: commit 3fafcbe0a2ada038f02efdfdce77c1768f0e1819 Author: Mark Reynolds mreynolds@redhat.com Date: Fri Jan 9 13:53:20 2015 -0500
Ticket 47973 - During schema reload sometimes the search returns no results
Bug Description: During a schema reload operation the search of an existing entry may randomly report no results. This is because during the schema reload all existing attribute syntaxes are removed, and there is a small window where ldap operations can be performed before the new schema is loaded. During this window, attribute values are normalized to NULL which causes operation to unexpectedly fail.
Fix Description: Instead of wiping out the existing attribute syntax hastables in the middle of the task, instead load the new schema into temporary hash tables. Once the reload is complete, then take the asi write lock, remove the old hash tables, and swap in the new ones.
https://fedorahosted.org/389/ticket/47973
valgrind: PASSED
Reviewed by: nhosoi(Thanks!)
diff --git a/ldap/servers/plugins/schema_reload/schema_reload.c b/ldap/servers/plugins/schema_reload/schema_reload.c index efc0de2..4e5c7f0 100644 --- a/ldap/servers/plugins/schema_reload/schema_reload.c +++ b/ldap/servers/plugins/schema_reload/schema_reload.c @@ -170,13 +170,6 @@ schemareload_thread(void *arg) slapi_task_log_notice(task, "Schema reload task finished."); slapi_task_log_status(task, "Schema reload task finished."); slapi_log_error(SLAPI_LOG_FATAL, "schemareload", "Schema reload task finished.\n"); - - slapi_log_error(SLAPI_LOG_FATAL, "schemareload", - "Register internal schema.\n"); - rv = slapi_reload_internal_attr_syntax(); - slapi_log_error(SLAPI_LOG_FATAL, "schemareload", - "Register internal schema finished.\n"); - } else { slapi_task_log_notice(task, "Schema reload task failed."); slapi_task_log_status(task, "Schema reload task failed."); diff --git a/ldap/servers/slapd/attr.c b/ldap/servers/slapd/attr.c index 9fa07be..28a4247 100644 --- a/ldap/servers/slapd/attr.c +++ b/ldap/servers/slapd/attr.c @@ -175,8 +175,8 @@ slapi_attr_types_equivalent(const char *t1, const char *t2) return 0; }
- asi1 = attr_syntax_get_by_name(t1); - asi2 = attr_syntax_get_by_name(t2); + asi1 = attr_syntax_get_by_name(t1, 0); + asi2 = attr_syntax_get_by_name(t2, 0); if (NULL != asi1) { if (NULL != asi2) { /* Both found - compare normalized names */ @@ -277,7 +277,7 @@ slapi_attr_init_locking_optional(Slapi_Attr *a, const char *type, PRBool use_loc { basetype = tmp; /* basetype was malloc'd */ } - asi = attr_syntax_get_by_name_locking_optional(basetype, use_lock); + asi = attr_syntax_get_by_name_locking_optional(basetype, use_lock, 0); } if(NULL == asi) { @@ -288,7 +288,7 @@ slapi_attr_init_locking_optional(Slapi_Attr *a, const char *type, PRBool use_loc * attribute type that has that syntax. */ asi = attr_syntax_get_by_name_locking_optional( - ATTR_WITH_OCTETSTRING_SYNTAX, use_lock); + ATTR_WITH_OCTETSTRING_SYNTAX, use_lock, 0); } else { diff --git a/ldap/servers/slapd/attrsyntax.c b/ldap/servers/slapd/attrsyntax.c index 18d0c52..673a903 100644 --- a/ldap/servers/slapd/attrsyntax.c +++ b/ldap/servers/slapd/attrsyntax.c @@ -67,8 +67,14 @@ static PLHashTable *internalasi = NULL; static PLHashTable *name2asi = NULL; /* read/write lock to protect table */ static Slapi_RWLock *name2asi_lock = NULL; -static int asi_locking = 1;
+/* + * For the schema reload task, we need to use separate temporary hashtables & linked lists + */ +static PLHashTable *oid2asi_tmp = NULL; +static PLHashTable *name2asi_tmp = NULL; + +static int asi_locking = 1; #define AS_LOCK_READ(l) if (asi_locking) { slapi_rwlock_rdlock(l); } #define AS_LOCK_WRITE(l) if (asi_locking) { slapi_rwlock_wrlock(l); } #define AS_UNLOCK_READ(l) if (asi_locking) { slapi_rwlock_unlock(l); } @@ -79,9 +85,9 @@ static struct asyntaxinfo *default_asi = NULL;
static void *attr_syntax_get_plugin_by_name_with_default( const char *type ); static void attr_syntax_delete_no_lock( struct asyntaxinfo *asip, - PRBool remove_from_oid_table ); + PRBool remove_from_oid_table, PRUint32 schema_flags ); static struct asyntaxinfo *attr_syntax_get_by_oid_locking_optional( const - char *oid, PRBool use_lock); + char *oid, PRBool use_lock, PRUint32 schema_flags);
#ifdef ATTR_LDAP_DEBUG static void attr_syntax_print(); @@ -199,8 +205,6 @@ attr_syntax_check_oids() void attr_syntax_free( struct asyntaxinfo *a ) { - PR_ASSERT( a->asi_refcnt == 0 ); - cool_charray_free( a->asi_aliases ); slapi_ch_free( (void**)&a->asi_name ); slapi_ch_free( (void **)&a->asi_desc ); @@ -229,9 +233,9 @@ attr_syntax_new() * be returned by calling to attr_syntax_return(). */ struct asyntaxinfo * -attr_syntax_get_by_oid(const char *oid) +attr_syntax_get_by_oid(const char *oid, PRUint32 schema_flags) { - return attr_syntax_get_by_oid_locking_optional( oid, PR_TRUE); + return attr_syntax_get_by_oid_locking_optional( oid, PR_TRUE, schema_flags); }
@@ -244,15 +248,30 @@ attr_syntax_get_by_oid(const char *oid) * same use_lock parameter. */ static struct asyntaxinfo * -attr_syntax_get_by_oid_locking_optional( const char *oid, PRBool use_lock ) +attr_syntax_get_by_oid_locking_optional( const char *oid, PRBool use_lock, PRUint32 schema_flags ) { struct asyntaxinfo *asi = 0; - if (oid2asi) + PLHashTable *ht = oid2asi; + int using_tmp_ht = 0; + + if (schema_flags & DSE_SCHEMA_LOCKED){ + ht = oid2asi_tmp; + using_tmp_ht = 1; + use_lock = 0; + } + if (ht) { if ( use_lock ) { AS_LOCK_READ(oid2asi_lock); } - asi = (struct asyntaxinfo *)PL_HashTableLookup_const(oid2asi, oid); + if (!using_tmp_ht){ + /* + * The oid2asi pointer could have been rewritten by the schema_reload task + * while waiting on the lock, so grab it again. + */ + ht = oid2asi; + } + asi = (struct asyntaxinfo *)PL_HashTableLookup_const(ht, oid); if (asi) { PR_AtomicIncrement( &asi->asi_refcnt ); @@ -273,18 +292,22 @@ attr_syntax_get_by_oid_locking_optional( const char *oid, PRBool use_lock ) * to worry about resource contention. */ static void -attr_syntax_add_by_oid(const char *oid, struct asyntaxinfo *a, int lock) +attr_syntax_add_by_oid(const char *oid, struct asyntaxinfo *a, PRUint32 schema_flags, int lock) { if (0 != attr_syntax_init()) return;
- if (lock) { - AS_LOCK_WRITE(oid2asi_lock); - } + if(schema_flags & DSE_SCHEMA_LOCKED){ + PL_HashTableAdd(oid2asi_tmp, oid, a); + } else { + if (lock) { + AS_LOCK_WRITE(oid2asi_lock); + }
- PL_HashTableAdd(oid2asi, oid, a); + PL_HashTableAdd(oid2asi, oid, a);
- if (lock) { - AS_UNLOCK_WRITE(oid2asi_lock); + if (lock) { + AS_UNLOCK_WRITE(oid2asi_lock); + } } }
@@ -297,18 +320,18 @@ attr_syntax_add_by_oid(const char *oid, struct asyntaxinfo *a, int lock) * be returned by calling to attr_syntax_return(). */ struct asyntaxinfo * -attr_syntax_get_by_name(const char *name) +attr_syntax_get_by_name(const char *name, PRUint32 schema_flags) { - return attr_syntax_get_by_name_locking_optional(name, PR_TRUE); + return attr_syntax_get_by_name_locking_optional(name, PR_TRUE, schema_flags); }
struct asyntaxinfo * attr_syntax_get_by_name_with_default(const char *name) { struct asyntaxinfo *asi = NULL; - asi = attr_syntax_get_by_name_locking_optional(name, PR_TRUE); + asi = attr_syntax_get_by_name_locking_optional(name, PR_TRUE, 0); if (asi == NULL) - asi = attr_syntax_get_by_name(ATTR_WITH_OCTETSTRING_SYNTAX); + asi = attr_syntax_get_by_name(ATTR_WITH_OCTETSTRING_SYNTAX, 0); if ( asi == NULL ) asi = default_asi; return asi; @@ -323,15 +346,30 @@ struct asyntaxinfo *asi = NULL; * same use_lock parameter. */ struct asyntaxinfo * -attr_syntax_get_by_name_locking_optional(const char *name, PRBool use_lock) +attr_syntax_get_by_name_locking_optional(const char *name, PRBool use_lock, PRUint32 schema_flags) { struct asyntaxinfo *asi = 0; - if (name2asi) + PLHashTable *ht = name2asi; + int using_tmp_ht = 0; + + if (schema_flags & DSE_SCHEMA_LOCKED){ + ht = name2asi_tmp; + using_tmp_ht = 1; + use_lock = 0; + } + if (ht) { if ( use_lock ) { AS_LOCK_READ(name2asi_lock); } - asi = (struct asyntaxinfo *)PL_HashTableLookup_const(name2asi, name); + if(!using_tmp_ht){ + /* + * The name2asi pointer could have been rewritten by the schema_reload task + * while waiting on the lock, so grab it again. + */ + ht = name2asi; + } + asi = (struct asyntaxinfo *)PL_HashTableLookup_const(ht, name); if ( NULL != asi ) { PR_AtomicIncrement( &asi->asi_refcnt ); } @@ -340,7 +378,7 @@ attr_syntax_get_by_name_locking_optional(const char *name, PRBool use_lock) } } if (!asi) /* given name may be an OID */ - asi = attr_syntax_get_by_oid_locking_optional(name, use_lock); + asi = attr_syntax_get_by_oid_locking_optional(name, use_lock, schema_flags);
return asi; } @@ -403,26 +441,37 @@ attr_syntax_return_locking_optional(struct asyntaxinfo *asi, PRBool use_lock) * to worry about resource contention. */ static void -attr_syntax_add_by_name(struct asyntaxinfo *a, int lock) +attr_syntax_add_by_name(struct asyntaxinfo *a, PRUint32 schema_flags, int lock) { if (0 != attr_syntax_init()) return;
- if (lock) { - AS_LOCK_WRITE(name2asi_lock); - } + if (schema_flags & DSE_SCHEMA_LOCKED ){ + PL_HashTableAdd(name2asi_tmp, a->asi_name, a); + if ( a->asi_aliases != NULL ) { + int i; + + for ( i = 0; a->asi_aliases[i] != NULL; ++i ) { + PL_HashTableAdd(name2asi_tmp, a->asi_aliases[i], a); + } + } + } else { + if (lock) { + AS_LOCK_WRITE(name2asi_lock); + }
- PL_HashTableAdd(name2asi, a->asi_name, a); - if ( a->asi_aliases != NULL ) { - int i; + PL_HashTableAdd(name2asi, a->asi_name, a); + if ( a->asi_aliases != NULL ) { + int i;
- for ( i = 0; a->asi_aliases[i] != NULL; ++i ) { - PL_HashTableAdd(name2asi, a->asi_aliases[i], a); + for ( i = 0; a->asi_aliases[i] != NULL; ++i ) { + PL_HashTableAdd(name2asi, a->asi_aliases[i], a); + } + } + if (lock) { + AS_UNLOCK_WRITE(name2asi_lock); } }
- if (lock) { - AS_UNLOCK_WRITE(name2asi_lock); - } }
@@ -431,7 +480,7 @@ attr_syntax_add_by_name(struct asyntaxinfo *a, int lock) * and oids. */ void -attr_syntax_delete( struct asyntaxinfo *asi ) +attr_syntax_delete( struct asyntaxinfo *asi, PRUint32 schema_flags ) { PR_ASSERT( asi );
@@ -439,7 +488,7 @@ attr_syntax_delete( struct asyntaxinfo *asi ) AS_LOCK_WRITE(oid2asi_lock); AS_LOCK_WRITE(name2asi_lock);
- attr_syntax_delete_no_lock( asi, PR_TRUE ); + attr_syntax_delete_no_lock( asi, PR_TRUE, schema_flags );
AS_UNLOCK_WRITE(name2asi_lock); AS_UNLOCK_WRITE(oid2asi_lock); @@ -453,19 +502,34 @@ attr_syntax_delete( struct asyntaxinfo *asi ) */ static void attr_syntax_delete_no_lock( struct asyntaxinfo *asi, - PRBool remove_from_oidtable ) + PRBool remove_from_oidtable, PRUint32 schema_flags ) { - int i; + PLHashTable *ht = NULL; + int using_tmp_ht = 0; + int i;
+ if (schema_flags & DSE_SCHEMA_LOCKED){ + using_tmp_ht = 1; + } if (oid2asi && remove_from_oidtable ) { - PL_HashTableRemove(oid2asi, asi->asi_oid); + if (using_tmp_ht){ + ht = oid2asi_tmp; + } else { + ht = oid2asi; + } + PL_HashTableRemove(ht, asi->asi_oid); }
if(name2asi) { - PL_HashTableRemove(name2asi, asi->asi_name); + if (using_tmp_ht){ + ht = name2asi_tmp; + } else { + ht = name2asi; + } + PL_HashTableRemove(ht, asi->asi_name); if ( asi->asi_aliases != NULL ) { for ( i = 0; asi->asi_aliases[i] != NULL; ++i ) { - PL_HashTableRemove(name2asi, asi->asi_aliases[i]); + PL_HashTableRemove(ht, asi->asi_aliases[i]); } } if ( asi->asi_refcnt > 0 ) { @@ -494,7 +558,7 @@ slapi_attr_syntax_normalize( const char *s ) struct asyntaxinfo *asi = NULL; char *r = NULL;
- if((asi=attr_syntax_get_by_name(s)) != NULL ) { + if((asi=attr_syntax_get_by_name(s, 0)) != NULL ) { r = slapi_ch_strdup(asi->asi_name); attr_syntax_return( asi ); } @@ -518,7 +582,7 @@ slapi_attr_syntax_normalize_ext( char *s, int flags ) struct asyntaxinfo *asi = NULL; char *r = NULL;
- if((asi=attr_syntax_get_by_name(s)) != NULL ) { + if((asi=attr_syntax_get_by_name(s, flags)) != NULL ) { r = slapi_ch_strdup(asi->asi_name); attr_syntax_return( asi ); } @@ -538,7 +602,8 @@ attr_syntax_exists(const char *attr_name) { struct asyntaxinfo *asi;
- asi = attr_syntax_get_by_name(attr_name); + + asi = attr_syntax_get_by_name(attr_name, 0); attr_syntax_return( asi );
if ( asi != NULL ) @@ -707,13 +772,13 @@ attr_syntax_get_plugin_by_name_with_default( const char *type ) /* * first we look for this attribute type explictly */ - if ( (asi = attr_syntax_get_by_name(type)) == NULL ) { + if ( (asi = attr_syntax_get_by_name(type, 0)) == NULL ) { /* * no syntax for this type... return Octet String * syntax. we accomplish this by looking up a well known * attribute type that has that syntax. */ - asi = attr_syntax_get_by_name(ATTR_WITH_OCTETSTRING_SYNTAX); + asi = attr_syntax_get_by_name(ATTR_WITH_OCTETSTRING_SYNTAX, 0); if (asi == NULL) asi = default_asi; } @@ -750,14 +815,13 @@ attr_syntax_dup( struct asyntaxinfo *a ) return( newas ); }
- /* * Add a new attribute type to the schema. * * Returns an LDAP error code (LDAP_SUCCESS if all goes well). */ int -attr_syntax_add( struct asyntaxinfo *asip ) +attr_syntax_add( struct asyntaxinfo *asip, PRUint32 schema_flags ) { int i, rc = LDAP_SUCCESS; int nolock = asip->asi_flags & SLAPI_ATTR_FLAG_NOLOCKING; @@ -769,7 +833,7 @@ attr_syntax_add( struct asyntaxinfo *asip )
/* make sure the oid is unique */ if ( NULL != ( oldas_from_oid = attr_syntax_get_by_oid_locking_optional( - asip->asi_oid, !nolock))) { + asip->asi_oid, !nolock, schema_flags))) { if ( 0 == (asip->asi_flags & SLAPI_ATTR_FLAG_OVERRIDE)) { /* failure - OID is in use; no override flag */ rc = LDAP_TYPE_OR_VALUE_EXISTS; @@ -781,7 +845,7 @@ attr_syntax_add( struct asyntaxinfo *asip ) * the primary name and OID point to the same schema definition. */ if ( NULL != ( oldas_from_name = attr_syntax_get_by_name_locking_optional( - asip->asi_name, !nolock))) { + asip->asi_name, !nolock, schema_flags))) { if ( 0 == (asip->asi_flags & SLAPI_ATTR_FLAG_OVERRIDE) || ( oldas_from_oid != oldas_from_name )) { /* failure; no override flag OR OID and name don't match */ @@ -789,7 +853,7 @@ attr_syntax_add( struct asyntaxinfo *asip ) goto cleanup_and_return; } /* Flag for deletion. We are going to override this attr */ - attr_syntax_delete(oldas_from_name); + attr_syntax_delete(oldas_from_name, schema_flags); } else if ( NULL != oldas_from_oid ) { /* failure - OID is in use but name does not exist */ rc = LDAP_TYPE_OR_VALUE_EXISTS; @@ -803,11 +867,11 @@ attr_syntax_add( struct asyntaxinfo *asip )
if ( NULL != ( tmpasi = attr_syntax_get_by_name_locking_optional( - asip->asi_aliases[i], !nolock))) { + asip->asi_aliases[i], !nolock, schema_flags))) { if (asip->asi_flags & SLAPI_ATTR_FLAG_OVERRIDE) { /* Flag for tmpasi for deletion. It will be free'd * when attr_syntax_return is called. */ - attr_syntax_delete(tmpasi); + attr_syntax_delete(tmpasi, schema_flags); } else { /* failure - one of the aliases is already in use */ rc = LDAP_TYPE_OR_VALUE_EXISTS; @@ -826,8 +890,8 @@ attr_syntax_add( struct asyntaxinfo *asip ) /* ditto for the override one */ asip->asi_flags &= ~SLAPI_ATTR_FLAG_OVERRIDE; - attr_syntax_add_by_oid( asip->asi_oid, asip, !nolock); - attr_syntax_add_by_name( asip, !nolock); + attr_syntax_add_by_oid( asip->asi_oid, asip, schema_flags, !nolock); + attr_syntax_add_by_name( asip, schema_flags, !nolock);
cleanup_and_return: attr_syntax_return_locking_optional( oldas_from_oid, !nolock ); @@ -1000,7 +1064,7 @@ slapi_attr_type2plugin( const char *type, void **pi ) int slapi_attr_get_oid( const Slapi_Attr *a, char **oid ) { - struct asyntaxinfo *asi = attr_syntax_get_by_name(a->a_type); + struct asyntaxinfo *asi = attr_syntax_get_by_name(a->a_type, 0); if (asi) { *oid = asi->asi_oid; attr_syntax_return(asi); @@ -1016,7 +1080,7 @@ slapi_attr_get_oid( const Slapi_Attr *a, char **oid ) int slapi_attr_get_oid_copy( const Slapi_Attr *a, char **oidp ) { - struct asyntaxinfo *asi = attr_syntax_get_by_name(a->a_type); + struct asyntaxinfo *asi = attr_syntax_get_by_name(a->a_type, 0); if (asi) { *oidp = slapi_ch_strdup( asi->asi_oid ); attr_syntax_return(asi); @@ -1073,7 +1137,7 @@ slapi_attr_is_dn_syntax_type(char *type) int dn_syntax = 0; /* not DN, by default */ struct asyntaxinfo * asi;
- asi = attr_syntax_get_by_name(type); + asi = attr_syntax_get_by_name(type, 0);
if (asi && asi->asi_plugin) { /* If not set, there is no way to get the info */ if ((syntaxoid = asi->asi_plugin->plg_syntax_oid)) { @@ -1249,7 +1313,7 @@ attr_syntax_delete_if_not_flagged(struct asyntaxinfo *asip, void *arg) PR_ASSERT( fi != NULL );
if ( 0 == ( asip->asi_flags & fi->asef_flag )) { - attr_syntax_delete_no_lock( asip, PR_FALSE ); + attr_syntax_delete_no_lock( asip, PR_FALSE, 0 ); return ATTR_SYNTAX_ENUM_REMOVE; } else { return ATTR_SYNTAX_ENUM_NEXT; @@ -1265,7 +1329,7 @@ attr_syntax_force_to_delete(struct asyntaxinfo *asip, void *arg) fi = (struct attr_syntax_enum_flaginfo *)arg; PR_ASSERT( fi != NULL );
- attr_syntax_delete_no_lock( asip, PR_FALSE ); + attr_syntax_delete_no_lock( asip, PR_FALSE, 0 ); return ATTR_SYNTAX_ENUM_REMOVE; }
@@ -1330,6 +1394,7 @@ attr_syntax_delete_all_for_schemareload(unsigned long flag)
#define ATTR_DEFAULT_SYNTAX_OID "1.1" #define ATTR_DEFAULT_SYNTAX "defaultdirstringsyntax" + static int attr_syntax_init(void) { @@ -1339,8 +1404,8 @@ attr_syntax_init(void) if (!oid2asi) { oid2asi = PL_NewHashTable(2047, hashNocaseString, - hashNocaseCompare, - PL_CompareValues, 0, 0); + hashNocaseCompare, + PL_CompareValues, 0, 0); if ( asi_locking && NULL == ( oid2asi_lock = slapi_new_rwlock())) { if(oid2asi) PL_HashTableDestroy(oid2asi); oid2asi = NULL; @@ -1351,11 +1416,19 @@ attr_syntax_init(void) } }
+ if (!oid2asi_tmp) + { + /* temporary hash table for schema reload */ + oid2asi_tmp = PL_NewHashTable(2047, hashNocaseString, + hashNocaseCompare, + PL_CompareValues, 0, 0); + } + if (!name2asi) { name2asi = PL_NewHashTable(2047, hashNocaseString, - hashNocaseCompare, - PL_CompareValues, 0, 0); + hashNocaseCompare, + PL_CompareValues, 0, 0); if ( asi_locking && NULL == ( name2asi_lock = slapi_new_rwlock())) { if(name2asi) PL_HashTableDestroy(name2asi); name2asi = NULL; @@ -1367,10 +1440,18 @@ attr_syntax_init(void) /* add a default syntax plugin as fallback, required during startup */ attr_syntax_create_default( ATTR_DEFAULT_SYNTAX, - ATTR_DEFAULT_SYNTAX_OID, - DIRSTRING_SYNTAX_OID, - SLAPI_ATTR_FLAG_NOUSERMOD| SLAPI_ATTR_FLAG_NOEXPOSE); + ATTR_DEFAULT_SYNTAX_OID, + DIRSTRING_SYNTAX_OID, + SLAPI_ATTR_FLAG_NOUSERMOD| SLAPI_ATTR_FLAG_NOEXPOSE); } + if (!name2asi_tmp) + { + /* temporary hash table for schema reload */ + name2asi_tmp = PL_NewHashTable(2047, hashNocaseString, + hashNocaseCompare, + PL_CompareValues, 0, 0); + } + return 0; }
@@ -1440,7 +1521,7 @@ slapi_add_internal_attr_syntax( const char *name, const char *oid, &asip );
if ( rc == LDAP_SUCCESS ) { - rc = attr_syntax_add( asip ); + rc = attr_syntax_add( asip, 0 ); if ( rc == LDAP_SUCCESS ) { if (attr_syntax_internal_asi_add_ht(asip)) { slapi_log_error(SLAPI_LOG_FATAL, @@ -1448,6 +1529,8 @@ slapi_add_internal_attr_syntax( const char *name, const char *oid, "Failed to stash internal asyntaxinfo: %s.\n", asip->asi_name); } + } else { + attr_syntax_free(asip); } }
@@ -1467,7 +1550,7 @@ attr_syntax_internal_asi_add(struct asyntaxinfo *asip, void *arg) /* Copy is needed since when reloading the schema, * existing syntax info is cleaned up. */ asip_copy = attr_syntax_dup(asip); - rc = attr_syntax_add(asip_copy); + rc = attr_syntax_add(asip_copy, 0); if (LDAP_SUCCESS != rc) { attr_syntax_free(asip_copy); } @@ -1487,3 +1570,25 @@ slapi_reload_internal_attr_syntax() attr_syntax_enumerate_attrs_ext(internalasi, attr_syntax_internal_asi_add, NULL); return rc; } + +/* + * schema reload - now that we have loaded the schema into temporary + * hash tables, swap out the old for the new. + */ +void +attr_syntax_swap_ht() +{ + /* Remove the old hash tables */ + PL_HashTableDestroy(name2asi); + PL_HashTableDestroy(oid2asi); + + /* + * Swap the hash table/linked list pointers, and set the + * temporary pointers to NULL + */ + name2asi = name2asi_tmp; + name2asi_tmp = NULL; + oid2asi = oid2asi_tmp; + oid2asi_tmp = NULL; +} + diff --git a/ldap/servers/slapd/opshared.c b/ldap/servers/slapd/opshared.c index eb890b0..9e13d86 100644 --- a/ldap/servers/slapd/opshared.c +++ b/ldap/servers/slapd/opshared.c @@ -86,7 +86,7 @@ int op_shared_is_allowed_attr (const char *attr_name, int replicated_op) * check to see if attribute is marked as one clients can't modify */
- asi = attr_syntax_get_by_name( attr_name ); + asi = attr_syntax_get_by_name( attr_name, 0 ); if ( NULL != asi && 0 != ( asi->asi_flags & SLAPI_ATTR_FLAG_NOUSERMOD )) { /* this attribute is not allowed */ diff --git a/ldap/servers/slapd/proto-slap.h b/ldap/servers/slapd/proto-slap.h index d854d0a..7fde382 100644 --- a/ldap/servers/slapd/proto-slap.h +++ b/ldap/servers/slapd/proto-slap.h @@ -118,7 +118,7 @@ void attr_syntax_write_lock(void); void attr_syntax_unlock_read(void); void attr_syntax_unlock_write(void); int attr_syntax_exists (const char *attr_name); -void attr_syntax_delete ( struct asyntaxinfo *asip ); +void attr_syntax_delete ( struct asyntaxinfo *asip, PRUint32 schema_flags ); #define SLAPI_SYNTAXLENGTH_NONE (-1) /* for syntaxlength parameter */ int attr_syntax_create( const char *attr_oid, char *const*attr_names, int num_names, const char *attr_desc, const char *attr_superior, @@ -127,16 +127,19 @@ int attr_syntax_create( const char *attr_oid, char *const*attr_names, const char *attr_syntax, int syntaxlength, unsigned long flags, struct asyntaxinfo **asip ); void attr_syntax_free( struct asyntaxinfo *a ); -int attr_syntax_add( struct asyntaxinfo *asip ); +int attr_syntax_add( struct asyntaxinfo *asip, PRUint32 schema_flags ); char *attr_syntax_normalize_no_lookup( const char *s ); char *attr_syntax_normalize_no_lookup_ext( char *s, int flags ); void attr_syntax_enumerate_attrs(AttrEnumFunc aef, void *arg, PRBool writelock); void attr_syntax_all_clear_flag( unsigned long flag ); void attr_syntax_delete_all_not_flagged( unsigned long flag ); -struct asyntaxinfo *attr_syntax_get_by_oid ( const char *oid ); -struct asyntaxinfo *attr_syntax_get_by_name ( const char *name ); +struct asyntaxinfo *attr_syntax_get_by_oid ( const char *oid, PRUint32 schema_flags ); +struct asyntaxinfo *attr_syntax_get_by_name ( const char *name, PRUint32 schema_flags ); struct asyntaxinfo *attr_syntax_get_by_name_with_default ( const char *name ); -struct asyntaxinfo *attr_syntax_get_by_name_locking_optional ( const char *name, PRBool use_lock ); +struct asyntaxinfo *attr_syntax_get_by_name_locking_optional ( const char *name, PRBool use_lock, PRUint32 schema_flags ); +struct asyntaxinfo *attr_syntax_get_global_at(); +struct asyntaxinfo *attr_syntax_find(struct asyntaxinfo *at1, struct asyntaxinfo *at2); +void attr_syntax_swap_ht(void); /* * Call attr_syntax_return() when you are done using a value returned * by attr_syntax_get_by_oid() or attr_syntax_get_by_name(). diff --git a/ldap/servers/slapd/schema.c b/ldap/servers/slapd/schema.c index 98d5e17..5399d00 100644 --- a/ldap/servers/slapd/schema.c +++ b/ldap/servers/slapd/schema.c @@ -154,6 +154,8 @@ static int schema_strcmp( const char *s1, const char *s2 ); static int schema_strcmp_array( char **sa1, char **sa2, const char *ignorestr ); static PRBool schema_type_is_interesting( const char *type ); +static void reload_schemafile_lock(void); +static void reload_schemafile_unlock(void); static void schema_create_errormsg( char *errorbuf, size_t errorbufsize, const char *prefix, const char *name, const char *fmt, ... ) #ifdef __GNUC__ @@ -2138,7 +2140,7 @@ schema_delete_attributes ( Slapi_Entry *entryBefore, LDAPMod *mod, sscanf (attr_ldif, "%s name %s syntax %s", psbAttrOid->buffer, psbAttrName->buffer, psbAttrSyntax->buffer); - if ((a = attr_syntax_get_by_name ( psbAttrName->buffer)) != NULL ) { + if ((a = attr_syntax_get_by_name ( psbAttrName->buffer, 0 )) != NULL ) { /* only modify attrs which were user defined */ if (a->asi_flags & SLAPI_ATTR_FLAG_STD_ATTR) { schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_at, @@ -2190,7 +2192,7 @@ schema_delete_attributes ( Slapi_Entry *entryBefore, LDAPMod *mod, }
/* Delete it. */ - attr_syntax_delete( a ); + attr_syntax_delete( a, 0 ); attr_syntax_return( a ); } else { @@ -2313,7 +2315,7 @@ add_oc_internal(struct objclass *pnew_oc, char *errorbuf, size_t errorbufsize, }
/* check to see if the oid is already in use by an attribute */ - if (!rc && (pasyntaxinfo = attr_syntax_get_by_oid(pnew_oc->oc_oid))) { + if (!rc && (pasyntaxinfo = attr_syntax_get_by_oid(pnew_oc->oc_oid, flags))) { schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_oc, pnew_oc->oc_name, "The OID "%s" is also used by the attribute type "%s"", @@ -2432,7 +2434,7 @@ schema_replace_attributes ( Slapi_PBlock *pb, LDAPMod *mod, char *errorbuf, * handle the various cases. */ if ( NULL == ( oldasip = - attr_syntax_get_by_oid( newasip->asi_oid ))) { + attr_syntax_get_by_oid( newasip->asi_oid, 0 ))) { /* new attribute type */ LDAPDebug( LDAP_DEBUG_TRACE, "schema_replace_attributes:" " new type %s (OID %s)\n", @@ -2450,14 +2452,14 @@ schema_replace_attributes ( Slapi_PBlock *pb, LDAPMod *mod, char *errorbuf, " replacing type %s (OID %s)\n", newasip->asi_name, newasip->asi_oid, 0 ); /* flag for deletion */ - attr_syntax_delete( oldasip ); + attr_syntax_delete( oldasip, 0 ); }
attr_syntax_return( oldasip ); }
if ( NULL != newasip ) { /* add new or replacement definition */ - rc = attr_syntax_add( newasip ); + rc = attr_syntax_add( newasip, 0 ); if ( LDAP_SUCCESS != rc ) { schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_at, newasip->asi_name, @@ -3368,7 +3370,7 @@ read_at_ldif(const char *input, struct asyntaxinfo **asipp, char *errorbuf, if (!status && (NULL != pSuperior)) { struct asyntaxinfo *asi_parent;
- asi_parent = attr_syntax_get_by_name(pSuperior); + asi_parent = attr_syntax_get_by_name(pSuperior, schema_flags); /* if we find no match then server won't start or add the attribute type */ if (asi_parent == NULL) { LDAPDebug (LDAP_DEBUG_PARSE, @@ -3480,7 +3482,7 @@ read_at_ldif(const char *input, struct asyntaxinfo **asipp, char *errorbuf, struct asyntaxinfo *tmpasi;
if (!(flags & SLAPI_ATTR_FLAG_OVERRIDE) && - ( NULL != ( tmpasi = attr_syntax_get_by_oid(pOid)))) { + ( NULL != ( tmpasi = attr_syntax_get_by_oid(pOid, schema_flags)))) { schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_at, first_attr_name, "Could not be added because the OID "%s" is already in use", @@ -3503,7 +3505,7 @@ read_at_ldif(const char *input, struct asyntaxinfo **asipp, char *errorbuf, if ( NULL != asipp ) { *asipp = tmpasip; /* just return it */ } else { /* add the new attribute to the global store */ - status = attr_syntax_add( tmpasip ); + status = attr_syntax_add( tmpasip, schema_flags ); if ( LDAP_SUCCESS != status ) { if ( 0 != (flags & SLAPI_ATTR_FLAG_OVERRIDE) && LDAP_TYPE_OR_VALUE_EXISTS == status ) { @@ -4320,6 +4322,59 @@ get_tagged_oid( const char *tag, const char **inputp, return( oid ); }
+/* + * Reload the schema files + * + * This is only called from the schema_reload task. The flag DSE_SCHEMA_LOCKED + * is also only set been called from this function. To not interrupt clients + * we will rebuild the schema in separate hash tables, and then swap the + * hash tables once the schema is completely reloaded. We use the DSE_SCHEMA_LOCKED + * flag to tell the attribute syntax functions to use the temporary hashtables. + */ +int +slapi_reload_schema_files(char *schemadir) +{ + int rc = LDAP_SUCCESS; + struct dse *my_pschemadse = NULL; + /* get be to lock */ + Slapi_Backend *be = slapi_be_select_by_instance_name( DSE_SCHEMA ); + + if (NULL == be) + { + slapi_log_error( SLAPI_LOG_FATAL, "schema_reload", + "schema file reload failed\n" ); + return LDAP_LOCAL_ERROR; + } + slapi_be_Wlock(be); /* be lock must be outer of schemafile lock */ + reload_schemafile_lock(); + oc_delete_all_nolock(); + rc = init_schema_dse_ext(schemadir, be, &my_pschemadse, + DSE_SCHEMA_NO_CHECK | DSE_SCHEMA_LOCKED); + if (rc) { + /* + * The schema has been reloaded into the temporary hash tables. + * Take the write lock, wipe out the existing hash tables, and + * swap in the new ones. + */ + attr_syntax_write_lock(); + attr_syntax_delete_all_for_schemareload(SLAPI_ATTR_FLAG_KEEP); + attr_syntax_swap_ht(); + attr_syntax_unlock_write(); + slapi_reload_internal_attr_syntax(); + + dse_destroy(pschemadse); + pschemadse = my_pschemadse; + reload_schemafile_unlock(); + slapi_be_Unlock(be); + return LDAP_SUCCESS; + } else { + reload_schemafile_unlock(); + slapi_be_Unlock(be); + slapi_log_error( SLAPI_LOG_FATAL, "schema_reload", + "schema file reload failed\n" ); + return LDAP_LOCAL_ERROR; + } +}
/* * sprintf to `outp' the contents of `tag' followed by `oid' followed by a @@ -4833,49 +4888,6 @@ slapi_validate_schema_files(char *schemadir) }
/* - * API to reload the schema files. - * Rule: this function is called when slapi_validate_schema_files is passed. - * Schema checking is skipped in this function. - */ -int -slapi_reload_schema_files(char *schemadir) -{ - int rc = LDAP_SUCCESS; - struct dse *my_pschemadse = NULL; - /* get be to lock */ - Slapi_Backend *be = slapi_be_select_by_instance_name( DSE_SCHEMA ); - - if (NULL == be) - { - slapi_log_error( SLAPI_LOG_FATAL, "schema_reload", - "schema file reload failed\n" ); - return LDAP_LOCAL_ERROR; - } - slapi_be_Wlock(be); /* be lock must be outer of schemafile lock */ - reload_schemafile_lock(); - /* Exclude attr_syntax not to grab from the hash table while cleaning up */ - attr_syntax_write_lock(); - attr_syntax_delete_all_for_schemareload(SLAPI_ATTR_FLAG_KEEP); - oc_delete_all_nolock(); - attr_syntax_unlock_write(); - rc = init_schema_dse_ext(schemadir, be, &my_pschemadse, - DSE_SCHEMA_NO_CHECK | DSE_SCHEMA_LOCKED); - if (rc) { - dse_destroy(pschemadse); - pschemadse = my_pschemadse; - reload_schemafile_unlock(); - slapi_be_Unlock(be); - return LDAP_SUCCESS; - } else { - reload_schemafile_unlock(); - slapi_be_Unlock(be); - slapi_log_error( SLAPI_LOG_FATAL, "schema_reload", - "schema file reload failed\n" ); - return LDAP_LOCAL_ERROR; - } -} - -/* * slapi_schema_list_objectclass_attributes: * Return the list of attributes belonging to the objectclass *
389-commits@lists.fedoraproject.org