From d9cb9a69a8efb6209f4dc3a4a81367f2f848d652 Mon Sep 17 00:00:00 2001
From: Ludwig Krispenz <lkrispen@redhat.com>
Date: Mon, 17 Dec 2012 19:45:11 +0100
Subject: [PATCH] Ticket 505 - use lock-free access name2asi and oid2asi table

Bug Description: there is a high contention on the attr syntax locks
		 triggered by syntax lookups for attribute types

Fix Description: this fix does not provide a lock free hash table or change
		 in the hash table implemenmtation. It addresses the issue by
		 reducing the syntax lookups as far as possible.
		 syntax lookups are either done at attribute initialization
		 or during dn normalization when is_dn_syntax is checked.
		 The areas changed are:
		 - attribute initialization from str2entry_fast. The syntax fields
		   are not initialized, this is done on demand when a_*plugin or a_flags
		   is used.
		   This allows the removal of the hashtable lookups and the global lock
		   in str2entry_fast
		 - reduce dn normalization. When reading an entry from the database
		   all attributes with dn syntax are already normalized. No check cor
		   dn syntax and dn normalization required
		 - reuse srdn. In entryrdn_lookup_dn a Slapi_RDN is built from the entryrdn
		   index, this can be reused to initialize the rdn of the entry, no
		   further dn explode or normalize required.

https://fedorahosted.org/389/ticket/505

Reviewed by: ?
---
 ldap/servers/slapd/attr.c                      | 57 ++++++++++++++++++++++++++
 ldap/servers/slapd/attrlist.c                  | 17 ++++++++
 ldap/servers/slapd/attrsyntax.c                | 12 ++++++
 ldap/servers/slapd/back-ldbm/id2entry.c        |  6 ++-
 ldap/servers/slapd/back-ldbm/import-threads.c  | 12 +++---
 ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c   |  8 +++-
 ldap/servers/slapd/back-ldbm/ldif2ldbm.c       | 12 +++---
 ldap/servers/slapd/back-ldbm/proto-back-ldbm.h |  2 +-
 ldap/servers/slapd/entry.c                     | 32 ++++++++++-----
 ldap/servers/slapd/plugin_syntax.c             | 36 +++++++++++++++-
 ldap/servers/slapd/proto-slap.h                |  2 +
 ldap/servers/slapd/slapi-plugin.h              |  4 +-
 ldap/servers/slapd/slapi-private.h             |  2 +
 13 files changed, 172 insertions(+), 30 deletions(-)

diff --git a/ldap/servers/slapd/attr.c b/ldap/servers/slapd/attr.c
index 73892bf..63142f5 100644
--- a/ldap/servers/slapd/attr.c
+++ b/ldap/servers/slapd/attr.c
@@ -229,6 +229,34 @@ slapi_attr_init(Slapi_Attr *a, const char *type)
 	return slapi_attr_init_locking_optional(a, type, PR_TRUE);
 }
 
+int
+slapi_attr_init_syntax(Slapi_Attr    *a)
+{
+	int rc = 1;
+	struct asyntaxinfo *asi = NULL;
+	char *tmp = 0;
+	const char *basetype= NULL;
+	char buf[SLAPD_TYPICAL_ATTRIBUTE_NAME_MAX_LENGTH];
+
+	basetype = buf;
+	tmp = slapi_attr_basetype(a->a_type, buf, sizeof(buf));
+	if (tmp) {
+		basetype = buf;
+	}
+	asi = attr_syntax_get_by_name_with_default (basetype);
+	if (asi) {
+		rc = 0;
+		a->a_plugin = asi->asi_plugin;
+		a->a_flags = asi->asi_flags;
+		a->a_mr_eq_plugin = asi->asi_mr_eq_plugin;
+		a->a_mr_ord_plugin = asi->asi_mr_ord_plugin;
+		a->a_mr_sub_plugin = asi->asi_mr_sub_plugin;
+	} 
+	if (tmp)
+		slapi_ch_free_string(&tmp);
+	return rc;
+}
+
 Slapi_Attr *
 slapi_attr_init_locking_optional(Slapi_Attr *a, const char *type, PRBool use_lock)
 {
@@ -320,6 +348,20 @@ slapi_attr_init_locking_optional(Slapi_Attr *a, const char *type, PRBool use_loc
 }
 
 Slapi_Attr *
+slapi_attr_init_nosyntax(Slapi_Attr *a, const char *type)
+{
+
+	a->a_type = slapi_ch_strdup(type);
+	slapi_valueset_init(&a->a_present_values);
+	slapi_valueset_init(&a->a_deleted_values);
+	a->a_listtofree= NULL;
+	a->a_deletioncsn= NULL;
+	a->a_next= NULL;
+
+	return a;
+}
+
+Slapi_Attr *
 slapi_attr_dup(const Slapi_Attr *attr)
 {
 	Slapi_Attr *newattr= slapi_attr_new();
@@ -410,6 +452,9 @@ slapi_attr_value_find( const Slapi_Attr *a, const struct berval *v )
 		return( -1 );
 	}
 
+	if ( a->a_flags == 0 && a->a_plugin == NULL ) { 
+	    slapi_attr_init_syntax (a);
+	}
 	ava.ava_type = a->a_type;
 	ava.ava_value = *v;
 	if (a->a_flags & SLAPI_ATTR_FLAG_NORMALIZED) {
@@ -521,6 +566,9 @@ attr_get_present_values(const Slapi_Attr *a)
 int
 slapi_attr_get_flags( const Slapi_Attr *a, unsigned long *flags )
 {
+	if ( a->a_flags == 0 && a->a_plugin == NULL ) { 
+	    slapi_attr_init_syntax (a);
+	}
 	*flags = a->a_flags;
 	return( 0 );
 }
@@ -528,6 +576,9 @@ slapi_attr_get_flags( const Slapi_Attr *a, unsigned long *flags )
 int
 slapi_attr_flag_is_set( const Slapi_Attr *a, unsigned long flag )
 {
+	if ( a->a_flags == 0 && a->a_plugin == NULL ) { 
+	    slapi_attr_init_syntax (a);
+	}
 	return( a->a_flags & flag );
 }
 
@@ -536,6 +587,9 @@ slapi_attr_value_cmp( const Slapi_Attr *a, const struct berval *v1, const struct
 {
 	int retVal;
 
+	if ( a->a_flags == 0 && a->a_plugin == NULL ) { 
+	    slapi_attr_init_syntax (a);
+	}
 	if ( a->a_flags & SLAPI_ATTR_FLAG_CMP_BITBYBIT )
 	{
 		int cmplen = ( v1->bv_len <= v2->bv_len ? v1->bv_len : v2->bv_len );
@@ -577,6 +631,9 @@ slapi_attr_value_cmp_ext(const Slapi_Attr *a, Slapi_Value *v1, Slapi_Value *v2)
         int retVal;
         const struct berval *bv2 = slapi_value_get_berval(v2);
 
+	if ( a->a_flags == 0 && a->a_plugin == NULL ) { 
+	    slapi_attr_init_syntax (a);
+	}
         if ( a->a_flags & SLAPI_ATTR_FLAG_CMP_BITBYBIT )
         {
                 const struct berval *bv1 = slapi_value_get_berval(v1);
diff --git a/ldap/servers/slapd/attrlist.c b/ldap/servers/slapd/attrlist.c
index e365f3d..1f52bb8 100644
--- a/ldap/servers/slapd/attrlist.c
+++ b/ldap/servers/slapd/attrlist.c
@@ -87,6 +87,23 @@ attrlist_find_or_create_locking_optional(Slapi_Attr **alist, const char *type, S
 	}
 	return rc;
 }
+int
+attrlist_append_nosyntax_init(Slapi_Attr **alist, const char *type, Slapi_Attr ***a)
+{
+	int rc= 0; /* found */
+	if ( *a==NULL )
+	{
+		for ( *a = alist; **a != NULL; *a = &(**a)->a_next );
+	}
+
+	if( **a==NULL )
+	{
+		**a = slapi_attr_new();
+		slapi_attr_init_nosyntax(**a, type);
+		rc= 1; /* created */
+	}
+	return rc;
+}
 
 /*
  * attrlist_merge - merge the given type and value with the list of
diff --git a/ldap/servers/slapd/attrsyntax.c b/ldap/servers/slapd/attrsyntax.c
index d7e4d04..8f360d3 100644
--- a/ldap/servers/slapd/attrsyntax.c
+++ b/ldap/servers/slapd/attrsyntax.c
@@ -280,6 +280,15 @@ attr_syntax_get_by_name(const char *name)
 	return attr_syntax_get_by_name_locking_optional(name, PR_TRUE);
 }
 
+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);
+	if (asi == NULL)
+		asi = attr_syntax_get_by_name(ATTR_WITH_OCTETSTRING_SYNTAX);
+	return asi;
+}
 
 /*
  * A version of attr_syntax_get_by_name() that allows you to bypass using
@@ -804,6 +813,9 @@ slapi_attr_is_dn_syntax_attr(Slapi_Attr *attr)
 	const char *syntaxoid = NULL;
 	int dn_syntax = 0; /* not DN, by default */
 
+	if ( attr->a_plugin == NULL ) { 
+ 	    slapi_attr_init_syntax (attr);
+ 	}
 	if (attr && attr->a_plugin) { /* If not set, there is no way to get the info */
 		if ((syntaxoid = attr_get_syntax_oid(attr))) {
 			dn_syntax = ((0 == strcmp(syntaxoid, NAMEANDOPTIONALUID_SYNTAX_OID))
diff --git a/ldap/servers/slapd/back-ldbm/id2entry.c b/ldap/servers/slapd/back-ldbm/id2entry.c
index 4d9c111..dae558c 100644
--- a/ldap/servers/slapd/back-ldbm/id2entry.c
+++ b/ldap/servers/slapd/back-ldbm/id2entry.c
@@ -367,6 +367,7 @@ id2entry( backend *be, ID id, back_txn *txn, int *err  )
             ee = slapi_str2entry( data.dptr, SLAPI_STR2ENTRY_NO_ENTRYDN );
         } else {
             char *normdn = NULL;
+	    Slapi_RDN * srdn = NULL;
             struct backdn *bdn = dncache_find_id(&inst->inst_dncache, id);
             if (bdn) {
                 normdn = slapi_ch_strdup(slapi_sdn_get_dn(bdn->dn_sdn));
@@ -375,7 +376,7 @@ id2entry( backend *be, ID id, back_txn *txn, int *err  )
                 CACHE_RETURN(&inst->inst_dncache, &bdn);
             } else {
                 Slapi_DN *sdn = NULL;
-                rc = entryrdn_lookup_dn(be, rdn, id, &normdn, txn);
+                rc = entryrdn_lookup_dn(be, rdn, id, &normdn, &srdn, txn);
                 if (rc) {
                     slapi_log_error(SLAPI_LOG_TRACE, ID2ENTRY,
                                     "id2entry: entryrdn look up failed "
@@ -402,10 +403,11 @@ id2entry( backend *be, ID id, back_txn *txn, int *err  )
                                     "and set to dn cache (id %d)\n", normdn, id);
                 }
             }
-            ee = slapi_str2entry_ext( (const char *)normdn, data.dptr, 
+            ee = slapi_str2entry_ext( (const char *)normdn, (const Slapi_RDN *)srdn, data.dptr, 
                                       SLAPI_STR2ENTRY_NO_ENTRYDN );
             slapi_ch_free_string(&rdn);
             slapi_ch_free_string(&normdn);
+	    slapi_rdn_free(&srdn);
         }
     } else {
         ee = slapi_str2entry( data.dptr, 0 );
diff --git a/ldap/servers/slapd/back-ldbm/import-threads.c b/ldap/servers/slapd/back-ldbm/import-threads.c
index 60dbb5f..54f8159 100644
--- a/ldap/servers/slapd/back-ldbm/import-threads.c
+++ b/ldap/servers/slapd/back-ldbm/import-threads.c
@@ -543,7 +543,7 @@ import_producer(void *param)
             }
             normdn = slapi_create_dn_string("%s", dn);
             slapi_ch_free_string(&dn);
-            e = slapi_str2entry_ext(normdn, estr, 
+            e = slapi_str2entry_ext(normdn, NULL, estr, 
                                     flags|SLAPI_STR2ENTRY_NO_ENTRYDN);
             slapi_ch_free_string(&normdn);
         } else {
@@ -1046,7 +1046,7 @@ index_producer(void *param)
                     CACHE_RETURN(&inst->inst_dncache, &bdn);
                 } else {
                     Slapi_DN *sdn = NULL;
-                    rc = entryrdn_lookup_dn(be, rdn, temp_id, &normdn, NULL);
+                    rc = entryrdn_lookup_dn(be, rdn, temp_id, &normdn, NULL, NULL);
                     if (rc) {
                         /* We cannot use the entryrdn index;
                          * Compose dn from the entries in id2entry */
@@ -1103,7 +1103,7 @@ index_producer(void *param)
                                     "entryrdn_lookup_dn returned: %s, "
                                     "and set to dn cache\n", normdn);
                 }
-                e = slapi_str2entry_ext(normdn, data.dptr, 
+                e = slapi_str2entry_ext(normdn, NULL, data.dptr, 
                                         SLAPI_STR2ENTRY_NO_ENTRYDN);
                 slapi_ch_free_string(&rdn);
             }
@@ -1408,7 +1408,7 @@ upgradedn_producer(void *param)
                     CACHE_RETURN(&inst->inst_dncache, &bdn);
                 } else {
                     rc = entryrdn_lookup_dn(be, rdn, temp_id,
-                                            (char **)&normdn, NULL);
+                                            (char **)&normdn, NULL, NULL);
                     if (rc) {
                         /* We cannot use the entryrdn index;
                          * Compose dn from the entries in id2entry */
@@ -1465,7 +1465,7 @@ upgradedn_producer(void *param)
                                     "entryrdn_lookup_dn returned: %s, "
                                     "and set to dn cache\n", normdn);
                 }
-                e = slapi_str2entry_ext(normdn, data.dptr, 
+                e = slapi_str2entry_ext(normdn, NULL, data.dptr, 
                                         SLAPI_STR2ENTRY_USE_OBSOLETE_DNFORMAT);
                 slapi_ch_free_string(&rdn);
             }
@@ -3567,7 +3567,7 @@ import_get_and_add_parent_rdns(ImportWorkerInfo *info,
                                 "from Slapi_RDN\n", rdn, id);
             goto bail;
         }
-        e = slapi_str2entry_ext(normdn, data.dptr, SLAPI_STR2ENTRY_NO_ENTRYDN);
+        e = slapi_str2entry_ext(normdn, NULL, data.dptr, SLAPI_STR2ENTRY_NO_ENTRYDN);
         (*curr_entry)++;
         rc = index_set_entry_to_fifo(info, e, id, total_id, *curr_entry);
         if (rc) {
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c b/ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c
index 82806db..d54d2a8 100644
--- a/ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c
+++ b/ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c
@@ -1162,6 +1162,7 @@ entryrdn_lookup_dn(backend *be,
                    const char *rdn,
                    ID id,
                    char **dn,
+		   Slapi_RDN **psrdn,
                    back_txn *txn)
 {
     int rc = -1;
@@ -1192,6 +1193,7 @@ entryrdn_lookup_dn(backend *be,
     }
 
     *dn = NULL;
+    if (psrdn) *psrdn = NULL;
     /* Open the entryrdn index */
     rc = _entryrdn_open_index(be, &ai, &db);
     if (rc || (NULL == db)) {
@@ -1348,7 +1350,11 @@ bail:
     }
     /* it is guaranteed that db is not NULL. */
     dblayer_release_index_file(be, ai, db);
-    slapi_rdn_free(&srdn);
+    if (psrdn) {
+	*psrdn = srdn;
+    } else {
+    	slapi_rdn_free(&srdn);
+    }
     slapi_ch_free_string(&nrdn);
     slapi_ch_free_string(&keybuf);
     slapi_log_error(SLAPI_LOG_TRACE, ENTRYRDN_TAG,
diff --git a/ldap/servers/slapd/back-ldbm/ldif2ldbm.c b/ldap/servers/slapd/back-ldbm/ldif2ldbm.c
index 957ebf5..8ef1d57 100644
--- a/ldap/servers/slapd/back-ldbm/ldif2ldbm.c
+++ b/ldap/servers/slapd/back-ldbm/ldif2ldbm.c
@@ -1484,7 +1484,7 @@ ldbm_back_ldbm2ldif( Slapi_PBlock *pb )
                 } else {
                     int myrc = 0;
                     Slapi_DN *sdn = NULL;
-                    rc = entryrdn_lookup_dn(be, rdn, temp_id, &dn, NULL);
+                    rc = entryrdn_lookup_dn(be, rdn, temp_id, &dn, NULL, NULL);
                     if (rc) {
                         /* We cannot use the entryrdn index;
                          * Compose dn from the entries in id2entry */
@@ -1544,7 +1544,7 @@ ldbm_back_ldbm2ldif( Slapi_PBlock *pb )
                                         "and set to dn cache\n", dn);
                     }
                 }
-                ep->ep_entry = slapi_str2entry_ext( dn, data.dptr, 
+                ep->ep_entry = slapi_str2entry_ext( dn, NULL, data.dptr, 
                                str2entry_options | SLAPI_STR2ENTRY_NO_ENTRYDN );
                 slapi_ch_free_string(&rdn);
             }
@@ -2065,7 +2065,7 @@ ldbm_back_ldbm2index(Slapi_PBlock *pb)
                 } else {
                     int myrc = 0;
                     Slapi_DN *sdn = NULL;
-                    rc = entryrdn_lookup_dn(be, rdn, temp_id, &dn, NULL);
+                    rc = entryrdn_lookup_dn(be, rdn, temp_id, &dn, NULL, NULL);
                     if (rc) {
                         /* We cannot use the entryrdn index;
                          * Compose dn from the entries in id2entry */
@@ -2133,7 +2133,7 @@ ldbm_back_ldbm2index(Slapi_PBlock *pb)
                     }
                 }
                 slapi_rdn_done(&psrdn);
-                ep->ep_entry = slapi_str2entry_ext( dn, data.dptr, 
+                ep->ep_entry = slapi_str2entry_ext( dn, NULL, data.dptr, 
                                                    SLAPI_STR2ENTRY_NO_ENTRYDN );
                 slapi_ch_free_string(&rdn);
             }
@@ -3307,7 +3307,7 @@ _get_and_add_parent_rdns(backend *be,
                            "(rdn: %s, ID: %d) from Slapi_RDN\n", rdn, id);
             goto bail;
         }
-        ep->ep_entry = slapi_str2entry_ext( dn, data.dptr, 
+        ep->ep_entry = slapi_str2entry_ext( dn, NULL, data.dptr, 
                                             SLAPI_STR2ENTRY_NO_ENTRYDN );
         ep->ep_id = id;
         slapi_ch_free_string(&dn);
@@ -3437,7 +3437,7 @@ _export_or_index_parents(ldbm_instance *inst,
             if (!bdn) {
                 /* we put pdn to dn cache, which could be used
                  * in _get_and_add_parent_rdns */
-                rc = entryrdn_lookup_dn(be, prdn, pid, &pdn, NULL);
+                rc = entryrdn_lookup_dn(be, prdn, pid, &pdn, NULL, NULL);
                 if (0 == rc) {
                     int myrc = 0;
                     /* pdn is put in DN cache.  No need to free it here,
diff --git a/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h b/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h
index 7cbaff7..f9c2c05 100644
--- a/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h
+++ b/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h
@@ -704,6 +704,6 @@ int
 entryrdn_index_read_ext(backend *be, const Slapi_DN *sdn, ID *id, int flags, back_txn *txn);
 int entryrdn_rename_subtree(backend *be, const Slapi_DN *oldsdn, Slapi_RDN *newsrdn, const Slapi_DN *newsupsdn, ID id, back_txn *txn);
 int entryrdn_get_subordinates(backend *be, const Slapi_DN *sdn, ID id, IDList **subordinates, back_txn *txn);
-int entryrdn_lookup_dn(backend *be, const char *rdn, ID id, char **dn, back_txn *txn);
+int entryrdn_lookup_dn(backend *be, const char *rdn, ID id, char **dn, Slapi_RDN **psrdn, back_txn *txn);
 int entryrdn_get_parent(backend *be, const char *rdn, ID id, char **prdn, ID *pid, back_txn *txn);
 #endif
diff --git a/ldap/servers/slapd/entry.c b/ldap/servers/slapd/entry.c
index 675f323..e30f03b 100644
--- a/ldap/servers/slapd/entry.c
+++ b/ldap/servers/slapd/entry.c
@@ -178,7 +178,7 @@ str2entry_state_information_from_type(char *s,CSNSet **csnset,CSN **attributedel
 
 /* rawdn is not consumed.  Caller needs to free it. */
 static Slapi_Entry *
-str2entry_fast( const char *rawdn, char *s, int flags, int read_stateinfo )
+str2entry_fast( const char *rawdn, const Slapi_RDN *srdn, char *s, int flags, int read_stateinfo )
 {
 	Slapi_Entry	*e;
 	char		*next, *ptype=NULL;
@@ -227,7 +227,9 @@ str2entry_fast( const char *rawdn, char *s, int flags, int read_stateinfo )
 	/* get the read lock of name2asi for performance purpose.
 	   It reduces read locking by per-entry lock, instead of per-attribute.
 	*/
-	attr_syntax_read_lock();
+	/* attr_syntax_read_lock();
+ 	 * no longer needed since attr syntax is not initialized
+ 	 */     
 
 	while ( (s = ldif_getline( &next )) != NULL &&
 	         attr_val_cnt < ENTRY_MAX_ATTRIBUTE_VALUE_COUNT )
@@ -310,7 +312,10 @@ str2entry_fast( const char *rawdn, char *s, int flags, int read_stateinfo )
 				slapi_entry_set_normdn(e, normdn);
 			}
 			if ( NULL == slapi_entry_get_rdn_const( e )) {
-				if (normdn) {
+				if (srdn) {
+					/* we can use the rdn generated in entryrdn_lookup_dn */
+					slapi_entry_set_srdn ( e, srdn );
+				}else if (normdn) {
 					/* normdn is just referred in slapi_entry_set_rdn. */
 					slapi_entry_set_rdn(e, normdn);
 				} else {
@@ -403,9 +408,9 @@ str2entry_fast( const char *rawdn, char *s, int flags, int read_stateinfo )
 						   e->e_uniqueid, value.bv_val, 0);
 			}else{
 				/* name2asi will be locked in slapi_entry_set_uniqueid */
-				attr_syntax_unlock_read(); 
+				/* attr_syntax_unlock_read(); */
 				slapi_entry_set_uniqueid (e, PL_strndup(value.bv_val, value.bv_len));
-				attr_syntax_read_lock();
+				/* attr_syntax_read_lock();*/
 			}
 			/* the memory below was not allocated by the slapi_ch_ functions */
 			if (freeval) slapi_ch_free_string(&value.bv_val);
@@ -426,7 +431,7 @@ str2entry_fast( const char *rawdn, char *s, int flags, int read_stateinfo )
 				switch(attr_state)
 				{
 				case ATTRIBUTE_PRESENT:
-					if(attrlist_find_or_create_locking_optional(&e->e_attrs, type.bv_val, &a, PR_FALSE)==0 /* Found */)
+					if(attrlist_append_nosyntax_init(&e->e_attrs, type.bv_val, &a)==0 /* Found */)
 					{
 						LDAPDebug (LDAP_DEBUG_ANY, "str2entry_fast: Error. Non-contiguous attribute values for %s\n", type.bv_val, 0, 0);
 						PR_ASSERT(0);
@@ -434,7 +439,7 @@ str2entry_fast( const char *rawdn, char *s, int flags, int read_stateinfo )
 					}
 					break;
 				case ATTRIBUTE_DELETED:
-					if(attrlist_find_or_create_locking_optional(&e->e_deleted_attrs, type.bv_val, &a, PR_FALSE)==0 /* Found */)
+					if(attrlist_append_nosyntax_init(&e->e_deleted_attrs, type.bv_val, &a)==0 /* Found */)
 					{
 						LDAPDebug (LDAP_DEBUG_ANY, "str2entry_fast: Error. Non-contiguous deleted attribute values for %s\n", type.bv_val, 0, 0);
 						PR_ASSERT(0);
@@ -451,6 +456,7 @@ str2entry_fast( const char *rawdn, char *s, int flags, int read_stateinfo )
 			/* moved the value setting code here to check Slapi_Attr 'a'
 			 * to retrieve the attribute syntax info */
 			svalue = value_new(NULL, CSN_TYPE_NONE, NULL);
+#if 0
 			if (slapi_attr_is_dn_syntax_attr(*a)) {
 				int rc = 0;
 				char *dn_aval = NULL;
@@ -483,6 +489,8 @@ str2entry_fast( const char *rawdn, char *s, int flags, int read_stateinfo )
 			} else {
 				slapi_value_set_berval(svalue, &value);
 			}
+#endif
+			slapi_value_set_berval(svalue, &value);
 			/* the memory below was not allocated by the slapi_ch_ functions */	
 			if (freeval) slapi_ch_free_string(&value.bv_val);
 			svalue->v_csnset = valuecsnset;
@@ -542,7 +550,9 @@ str2entry_fast( const char *rawdn, char *s, int flags, int read_stateinfo )
 	}
 
 	/* release read lock of name2asi, per-entry lock */
-	attr_syntax_unlock_read();
+	/* attr_syntax_unlock_read();
+ 	 * no longer locked since attr syntax is not initialized
+ 	 */     
 
 	/* If this is a tombstone, it requires a special treatment for rdn. */
 	if (e->e_flags & SLAPI_ENTRY_FLAG_TOMBSTONE) {
@@ -1369,7 +1379,7 @@ slapi_str2entry( char *s, int flags )
 	}
 	else
 	{
-	    e= str2entry_fast( NULL/*dn*/, s, flags, read_stateinfo );
+	    e= str2entry_fast( NULL/*dn*/, NULL/*rdn*/, s, flags, read_stateinfo );
 	}
 	if (!e)
 	   return e;	/* e == NULL */
@@ -1404,7 +1414,7 @@ slapi_str2entry( char *s, int flags )
  * NOTE: the first arg "dn" should have been normalized before passing.
  */
 Slapi_Entry *
-slapi_str2entry_ext( const char *normdn, char *s, int flags )
+slapi_str2entry_ext( const char *normdn, const Slapi_RDN *srdn, char *s, int flags )
 {
 	Slapi_Entry *e;
 	int read_stateinfo= ~( flags & SLAPI_STR2ENTRY_IGNORE_STATE );
@@ -1431,7 +1441,7 @@ slapi_str2entry_ext( const char *normdn, char *s, int flags )
 	}
 	else
 	{
-	    e = str2entry_fast( normdn, s, 
+	    e = str2entry_fast( normdn, srdn, s, 
 	                    flags|SLAPI_STR2ENTRY_DN_NORMALIZED, read_stateinfo );
 	}
 	if (!e)
diff --git a/ldap/servers/slapd/plugin_syntax.c b/ldap/servers/slapd/plugin_syntax.c
index 840fa7a..5d1d6cc 100644
--- a/ldap/servers/slapd/plugin_syntax.c
+++ b/ldap/servers/slapd/plugin_syntax.c
@@ -135,6 +135,12 @@ plugin_call_syntax_filter_ava_sv(
 	    ava->ava_value.bv_val, 0 );
 
 	if ( ( a->a_mr_eq_plugin == NULL ) && ( a->a_mr_ord_plugin == NULL ) && ( a->a_plugin == NULL ) ) {
+		/* could be lazy plugin initialization, get it now */
+		Slapi_Attr *t = a;
+		slapi_attr_init_syntax(t);
+	}
+
+	if ( ( a->a_mr_eq_plugin == NULL ) && ( a->a_mr_ord_plugin == NULL ) && ( a->a_plugin == NULL ) ) {
 		LDAPDebug( LDAP_DEBUG_FILTER,
 		    "<= plugin_call_syntax_filter_ava no plugin for attr (%s)\n",
 		    a->a_type, 0, 0 );
@@ -243,6 +249,10 @@ plugin_call_syntax_filter_sub_sv(
 	    "=> plugin_call_syntax_filter_sub_sv\n", 0, 0, 0 );
 
 	if ( ( a->a_mr_sub_plugin == NULL ) && ( a->a_plugin == NULL ) ) {
+		/* could be lazy plugin initialization, get it now */
+		slapi_attr_init_syntax(a);
+	}
+	if ( ( a->a_mr_sub_plugin == NULL ) && ( a->a_plugin == NULL ) ) {
 		LDAPDebug( LDAP_DEBUG_FILTER,
 				   "<= plugin_call_syntax_filter_sub_sv attribute (%s) has no substring matching rule or syntax plugin\n",
 				   a->a_type, 0, 0 );
@@ -397,7 +407,11 @@ slapi_entry_syntax_check(
 	}
 
 	i = slapi_entry_first_attr(e, &a);
-
+  
+	if ( a && ( a->a_plugin == NULL ) ) {
+		/* could be lazy plugin initialization, get it now */
+		slapi_attr_init_syntax(a);
+	}
 	while ((-1 != i) && a && (a->a_plugin != NULL)) {
 		/* If no validate function is available for this type, just
 		 * assume that the value is valid. */
@@ -438,6 +452,10 @@ slapi_entry_syntax_check(
 
 		prevattr = a;
 		i = slapi_entry_next_attr(e, prevattr, &a);
+		if ( a && ( a->a_plugin == NULL ) ) {
+			/* could be lazy plugin initialization, get it now */
+			slapi_attr_init_syntax(a);
+		}	
 	}
 
 	/* See if we need to set the error text in the pblock. */
@@ -605,6 +623,10 @@ slapi_attr_values2keys_sv_pb(
 
 	LDAPDebug( LDAP_DEBUG_FILTER, "=> slapi_attr_values2keys_sv\n",
 	    0, 0, 0 );
+	if ( ( sattr->a_plugin == NULL ) ) {
+		/* could be lazy plugin initialization, get it now */
+		slapi_attr_init_syntax(sattr);
+	}
 
 	switch (ftype) {
 	case LDAP_FILTER_EQUALITY:
@@ -773,6 +795,10 @@ slapi_attr_assertion2keys_ava_sv(
 
 	LDAPDebug( LDAP_DEBUG_FILTER,
 	    "=> slapi_attr_assertion2keys_ava_sv\n", 0, 0, 0 );
+	if ( ( sattr->a_plugin == NULL ) ) {
+		/* could be lazy plugin initialization, get it now */
+		slapi_attr_init_syntax(sattr);
+	}
 
 	switch (ftype) {
 	case LDAP_FILTER_EQUALITY:
@@ -889,6 +915,10 @@ slapi_attr_assertion2keys_sub_sv(
 
 	LDAPDebug( LDAP_DEBUG_FILTER,
 	    "=> slapi_attr_assertion2keys_sub_sv\n", 0, 0, 0 );
+	if ( ( sattr->a_plugin == NULL ) ) {
+		/* could be lazy plugin initialization, get it now */
+		slapi_attr_init_syntax(sattr);
+	}
 
 	if (sattr->a_mr_sub_plugin) {
 		pi = sattr->a_mr_sub_plugin;
@@ -945,6 +975,10 @@ slapi_attr_value_normalize_ext(
 	if (!sattr) {
 		sattr = slapi_attr_init(&myattr, type);
 	}
+	if ( ( sattr->a_plugin == NULL ) ) {
+		/* could be lazy plugin initialization, get it now */
+		slapi_attr_init_syntax(sattr);
+	}
 
 	/* use the filter type to determine which matching rule to use */
 	switch (filter_type) {
diff --git a/ldap/servers/slapd/proto-slap.h b/ldap/servers/slapd/proto-slap.h
index 3c83e30..778b916 100644
--- a/ldap/servers/slapd/proto-slap.h
+++ b/ldap/servers/slapd/proto-slap.h
@@ -98,6 +98,7 @@ const char *attr_get_syntax_oid(const Slapi_Attr *attr);
 void attrlist_free(Slapi_Attr *alist);
 int attrlist_find_or_create(Slapi_Attr **alist, const char *type, Slapi_Attr ***a);
 int attrlist_find_or_create_locking_optional(Slapi_Attr **alist, const char *type, Slapi_Attr ***a, PRBool use_lock);
+int attrlist_append_nosyntax_init(Slapi_Attr **alist, const char *type, Slapi_Attr ***a);
 void attrlist_merge( Slapi_Attr **alist, const char *type, struct berval **vals );
 void attrlist_merge_valuearray( Slapi_Attr **alist, const char *type, Slapi_Value **vals );
 int attrlist_delete( Slapi_Attr **attrs, const char *type );
@@ -131,6 +132,7 @@ 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_name_with_default ( const char *name );
 struct asyntaxinfo *attr_syntax_get_by_name_locking_optional ( const char *name, PRBool use_lock );
 /*
  * Call attr_syntax_return() when you are done using a value returned
diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h
index cc1d292..73ae477 100644
--- a/ldap/servers/slapd/slapi-plugin.h
+++ b/ldap/servers/slapd/slapi-plugin.h
@@ -844,9 +844,9 @@ void slapi_pblock_destroy( Slapi_PBlock *pb );
 Slapi_Entry *slapi_str2entry( char *s, int flags );
 
 /*
- * Same as slapi_str2entry except passing dn as an argument
+ * Same as slapi_str2entry except passing optional dn and rdn structure as argument
  */
-Slapi_Entry *slapi_str2entry_ext( const char *dn, char *s, int flags );
+Slapi_Entry *slapi_str2entry_ext( const char *dn, const Slapi_RDN *srdn, char *s, int flags );
 
 
 /*-----------------------------
diff --git a/ldap/servers/slapd/slapi-private.h b/ldap/servers/slapd/slapi-private.h
index 7bd7f3e..b3888ef 100644
--- a/ldap/servers/slapd/slapi-private.h
+++ b/ldap/servers/slapd/slapi-private.h
@@ -350,6 +350,8 @@ int entry_add_dncsn_ext(Slapi_Entry *entry, const CSN *csn, PRUint32 flags);
 
 /* attr.c */
 Slapi_Attr *slapi_attr_init_locking_optional(Slapi_Attr *a, const char *type, PRBool use_lock);
+Slapi_Attr *slapi_attr_init_nosyntax(Slapi_Attr *a, const char *type);
+int slapi_attr_init_syntax(Slapi_Attr *a);
 int attr_set_csn( Slapi_Attr *a, const CSN *csn);
 int attr_set_deletion_csn( Slapi_Attr *a, const CSN *csn);
 const CSN *attr_get_deletion_csn(const Slapi_Attr *a);
-- 
1.7.11.7

