]> git.ipfire.org Git - thirdparty/openldap.git/commitdiff
ITS#9264 add an optional lock to slapo-unique
authorHoward Chu <hyc@openldap.org>
Fri, 22 May 2020 14:08:20 +0000 (15:08 +0100)
committerHoward Chu <hyc@openldap.org>
Fri, 22 May 2020 14:08:20 +0000 (15:08 +0100)
doc/man/man5/slapo-unique.5
servers/slapd/overlays/unique.c

index 869fb97dbecbabe74782f3e0bf3e8a7921a779c7..742fe3192528c83684d024d1c0b3d8beb1cb92c9 100644 (file)
@@ -39,7 +39,7 @@ They should appear after the
 .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
@@ -50,9 +50,10 @@ attributes will create independent domains, each with their own
 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
@@ -119,6 +120,17 @@ mode extends the concept of uniqueness to include null values, such
 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
index a398ac9b75127101afcb47c524787b5d41572e1d..69e026a7b0c28952c1a7ad2bfa3154b6c2b678e5 100644 (file)
@@ -58,12 +58,14 @@ typedef struct unique_domain_s {
        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 {
@@ -76,7 +78,7 @@ enum {
        UNIQUE_IGNORE,
        UNIQUE_ATTR,
        UNIQUE_STRICT,
-       UNIQUE_URI
+       UNIQUE_URI,
 };
 
 static ConfigDriver unique_cf_base;
@@ -315,7 +317,7 @@ unique_new_domain_uri_basic ( unique_domain_uri **urip,
  *
  * 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
@@ -346,6 +348,11 @@ unique_new_domain ( unique_domain **domainp,
                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;
@@ -644,11 +651,7 @@ unique_cf_strict( ConfigArgs *c )
                 * 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;
@@ -789,11 +792,13 @@ unique_db_init(
 )
 {
        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;
 }
@@ -805,8 +810,7 @@ unique_db_destroy(
 )
 {
        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" );
 
@@ -816,8 +820,9 @@ unique_db_destroy(
 
                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;
@@ -1025,6 +1030,21 @@ unique_search(
        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,
@@ -1041,6 +1061,7 @@ unique_add(
        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 );
@@ -1100,6 +1121,9 @@ unique_add(
                        /* 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("(|)");
 
@@ -1150,6 +1174,17 @@ unique_add(
                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;
 }
 
@@ -1171,6 +1206,7 @@ unique_modify(
        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 );
@@ -1223,6 +1259,9 @@ unique_modify(
                        /* 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("(|)");
 
@@ -1275,6 +1314,17 @@ unique_modify(
                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;
 }
 
@@ -1297,6 +1347,7 @@ unique_modrdn(
        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 );
@@ -1374,6 +1425,9 @@ unique_modrdn(
                        /* 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("(|)");
 
@@ -1426,6 +1480,17 @@ unique_modrdn(
                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;
 }