.B overlay
directive.
.TP
-.B unique_uri <[strict ][ignore ]URI[URI...]...>
+.B unique_uri <[strict ][ignore ][serialize ]URI[URI...]...>
Configure the base, attributes, scope, and filter for uniqueness
checking. Multiple URIs may be specified within a domain,
allowing complex selections of objects. Multiple
independent lists of URIs and ignore/strict settings.
Keywords
-.B strict
+.BR strict ,
+.BR ignore ,
and
-.B ignore
+.B serialize
have to be enclosed in quotes (") together with the URI.
The LDAP URI syntax is a subset of
that only one attribute within a subtree will be allowed to have a
null value. Strictness applies to all URIs within a uniqueness
domain, but some domains may be strict while others are not.
+
+It is possible to enforce strict serialization of modifications by
+prepending the keyword
+.B serialize.
+By default, no serialization is performed, so multiple modifications
+occurring nearly simultaneously may see incomplete uniqueness results.
+Using
+.B serialize
+will force individual write operations to fully complete before allowing
+any others to proceed, to ensure that each operation's uniqueness checks
+are consistent.
.LP
It is not possible to set both URIs and legacy slapo\-unique configuration
parameters simultaneously. In general, the legacy configuration options
struct unique_domain_uri_s *uri;
char ignore; /* polarity of attributes */
char strict; /* null considered unique too */
+ char serial; /* serialize execution */
} unique_domain;
typedef struct unique_data_s {
struct unique_domain_s *domains;
struct unique_domain_s *legacy;
char legacy_strict_set;
+ ldap_pvt_thread_mutex_t serial_mutex;
} unique_data;
typedef struct unique_counter_s {
UNIQUE_IGNORE,
UNIQUE_ATTR,
UNIQUE_STRICT,
- UNIQUE_URI
+ UNIQUE_URI,
};
static ConfigDriver unique_cf_base;
*
* domain_specs look like
*
- * [strict ][ignore ]uri[[ uri]...]
+ * [strict ][ignore ][serialize ]uri[[ uri]...]
* e.g. "ldap:///ou=foo,o=bar?uid?sub ldap:///ou=baz,o=bar?uid?sub"
* "strict ldap:///ou=accounts,o=bar?uid,uidNumber?one"
* etc
domain->ignore = 1;
uri_start += STRLENOF( "ignore " );
}
+ if ( strncasecmp ( uri_start, "serialize ",
+ STRLENOF( "serialize " ) ) == 0 ) {
+ domain->serial = 1;
+ uri_start += STRLENOF( "serialize " );
+ }
if ( strncasecmp ( uri_start, "strict ",
STRLENOF( "strict " ) ) == 0 ) {
domain->strict = 1;
* and missing is necessary to add olcUniqueURIs...
*/
if ( private->legacy_strict_set ) {
- struct berval bv;
- bv.bv_val = legacy->strict ? "TRUE" : "FALSE";
- bv.bv_len = legacy->strict ?
- STRLENOF("TRUE") :
- STRLENOF("FALSE");
+ struct berval bv = legacy->strict ? slap_true_bv : slap_false_bv;
value_add_one ( &c->rvalue_vals, &bv );
}
rc = 0;
)
{
slap_overinst *on = (slap_overinst *)be->bd_info;
- unique_data **privatep = (unique_data **) &on->on_bi.bi_private;
+ unique_data *private;
Debug(LDAP_DEBUG_TRACE, "==> unique_db_init\n" );
- *privatep = ch_calloc ( 1, sizeof ( unique_data ) );
+ private = ch_calloc ( 1, sizeof ( unique_data ) );
+ ldap_pvt_thread_mutex_init( &private->serial_mutex );
+ on->on_bi.bi_private = private;
return 0;
}
)
{
slap_overinst *on = (slap_overinst *)be->bd_info;
- unique_data **privatep = (unique_data **) &on->on_bi.bi_private;
- unique_data *private = *privatep;
+ unique_data *private = on->on_bi.bi_private;
Debug(LDAP_DEBUG_TRACE, "==> unique_db_destroy\n" );
unique_free_domain ( domains );
unique_free_domain ( legacy );
+ ldap_pvt_thread_mutex_destroy( &private->serial_mutex );
ch_free ( private );
- *privatep = NULL;
+ on->on_bi.bi_private = NULL;
}
return 0;
return(rc);
}
+static int
+unique_unlock(
+ Operation *op,
+ SlapReply *rs
+)
+{
+ slap_callback *sc = op->o_callback;
+ unique_data *private = sc->sc_private;
+
+ ldap_pvt_thread_mutex_unlock( &private->serial_mutex );
+ op->o_callback = sc->sc_next;
+ op->o_tmpfree( sc, op->o_tmpmemctx );
+ return 0;
+}
+
static int
unique_add(
Operation *op,
char *key, *kp;
struct berval bvkey;
int rc = SLAP_CB_CONTINUE;
+ int locked = 0;
Debug(LDAP_DEBUG_TRACE, "==> unique_add <%s>\n",
op->o_req_dn.bv_val );
/* skip this domain-uri if it isn't involved */
if ( !ks ) continue;
+ if ( domain->serial && !locked )
+ ldap_pvt_thread_mutex_lock( &private->serial_mutex );
+
/* terminating NUL */
ks += sizeof("(|)");
if ( rc != SLAP_CB_CONTINUE ) break;
}
+ if ( locked ) {
+ if ( rc != SLAP_CB_CONTINUE ) {
+ ldap_pvt_thread_mutex_unlock( &private->serial_mutex );
+ } else {
+ slap_callback *cb = op->o_tmpcalloc( 1, sizeof(slap_callback), op->o_tmpmemctx );
+ cb->sc_cleanup = unique_unlock;
+ cb->sc_private = private;
+ cb->sc_next = op->o_callback;
+ op->o_callback = cb;
+ }
+ }
return rc;
}
char *key, *kp;
struct berval bvkey;
int rc = SLAP_CB_CONTINUE;
+ int locked = 0;
Debug(LDAP_DEBUG_TRACE, "==> unique_modify <%s>\n",
op->o_req_dn.bv_val );
/* skip this domain-uri if it isn't involved */
if ( !ks ) continue;
+ if ( domain->serial && !locked )
+ ldap_pvt_thread_mutex_lock( &private->serial_mutex );
+
/* terminating NUL */
ks += sizeof("(|)");
if ( rc != SLAP_CB_CONTINUE ) break;
}
+ if ( locked ) {
+ if ( rc != SLAP_CB_CONTINUE ) {
+ ldap_pvt_thread_mutex_unlock( &private->serial_mutex );
+ } else {
+ slap_callback *cb = op->o_tmpcalloc( 1, sizeof(slap_callback), op->o_tmpmemctx );
+ cb->sc_cleanup = unique_unlock;
+ cb->sc_private = private;
+ cb->sc_next = op->o_callback;
+ op->o_callback = cb;
+ }
+ }
return rc;
}
LDAPRDN newrdn;
struct berval bv[2];
int rc = SLAP_CB_CONTINUE;
+ int locked = 0;
Debug(LDAP_DEBUG_TRACE, "==> unique_modrdn <%s> <%s>\n",
op->o_req_dn.bv_val, op->orr_newrdn.bv_val );
/* skip this domain if it isn't involved */
if ( !ks ) continue;
+ if ( domain->serial && !locked )
+ ldap_pvt_thread_mutex_lock( &private->serial_mutex );
+
/* terminating NUL */
ks += sizeof("(|)");
if ( rc != SLAP_CB_CONTINUE ) break;
}
+ if ( locked ) {
+ if ( rc != SLAP_CB_CONTINUE ) {
+ ldap_pvt_thread_mutex_unlock( &private->serial_mutex );
+ } else {
+ slap_callback *cb = op->o_tmpcalloc( 1, sizeof(slap_callback), op->o_tmpmemctx );
+ cb->sc_cleanup = unique_unlock;
+ cb->sc_private = private;
+ cb->sc_next = op->o_callback;
+ op->o_callback = cb;
+ }
+ }
return rc;
}