[Freeipa-devel] [PATCHES] First step to make DNA more useful and configurable

Simo Sorce ssorce at redhat.com
Sat May 10 18:05:03 UTC 2008


These first three patches are the starting point for making DNA much more useful
in a dynamic environment where masters can come and go and where you do not want
to reconfigure all of them at the same time just because you are adding a new
one.
See details here: http://directory.fedoraproject.org/wiki/DNA_Plugin

These first patches only make it possible to add a maxvalue and check that the
value allocate is actually free before assigning it, skipping until the first
free is found otherwise.

This patchset currently works and is backwards compatible.

The next step will be to implement the housekeeping functions that allows
multiple masters to actually split and transfer ranges of values between them.
This is necessary for 2 reasons:
1. to allow new masters to be added and automatically assign them some space
to alloc from.
2. To allow space to be shifted to masters that are more hungry than others.

Simo.
-------------- next part --------------
>From a7ffe4ee2960eb71cff33f4d4d60f29904d8bf75 Mon Sep 17 00:00:00 2001
From: Simo Sorce <ssorce at redhat.com>
Date: Thu, 1 May 2008 18:03:57 -0400
Subject: [PATCH] Implement checks to make sure we are not assigning a number that is in use.
 Change config to support a maximum value so that ranges can be defined.
 Add stubs to reach out and ask to swap in new ranges and notify that new
 chuncks are needed/used.

---
 ipa-server/ipa-slapi-plugins/dna/dna.c |  636 +++++++++++++++++++++++---------
 1 files changed, 455 insertions(+), 181 deletions(-)

diff --git a/ipa-server/ipa-slapi-plugins/dna/dna.c b/ipa-server/ipa-slapi-plugins/dna/dna.c
index 169edb8..3df6dbb 100644
--- a/ipa-server/ipa-slapi-plugins/dna/dna.c
+++ b/ipa-server/ipa-slapi-plugins/dna/dna.c
@@ -51,6 +51,7 @@
 #include <stdio.h>
 #include <ctype.h>
 #include <string.h>
+#include <errno.h>
 /*#include "portable.h"*/
 #include "nspr.h"
 /*#include "slapi-private.h"*/
@@ -66,7 +67,7 @@
 #endif
 
 #define DNA_PLUGIN_SUBSYSTEM "ipa-dna-plugin"
-#define DNA_PLUGIN_VERSION 0x00010000
+#define DNA_PLUGIN_VERSION 0x00020000
 
 /* temporary */
 #define DNA_DN "cn=ipa-dna,cn=plugins,cn=config"
@@ -77,16 +78,28 @@
 /**
  * DNA config types
  */
-#define DNA_TYPE	"dnaType"
-#define DNA_PREFIX	"dnaPrefix"
-#define DNA_NEXTVAL	"dnaNextValue"
-#define DNA_INTERVAL	"dnaInterval"
-#define DNA_GENERATE	"dnaMagicRegen"
-#define DNA_FILTER	"dnaFilter"
-#define DNA_SCOPE	"dnaScope"
+#define DNA_TYPE            "dnaType"
+#define DNA_PREFIX          "dnaPrefix"
+#define DNA_NEXTVAL         "dnaNextValue"
+#define DNA_INTERVAL        "dnaInterval"
+#define DNA_GENERATE        "dnaMagicRegen"
+#define DNA_FILTER          "dnaFilter"
+#define DNA_SCOPE           "dnaScope"
 
-#define FEATURE_DESC	"IPA Distributed Numeric Assignment"
-#define PLUGIN_DESC	"IPA Distributed Numeric Assignment plugin"
+/* since v2 */
+#define DNA_MAXVAL          "dnaMaxValue"
+#define DNA_SHARED_CFG_DN   "dnaSharedCfgDN"
+
+/* Shared Config */
+#define DNA_GLOBAL_RANGE    "dnaGlobalRange"
+#define DNA_RANGE           "dnaRange"
+#define DNA_MAX_RANGE_SIZE  "dnaMaxRangeSize"
+#define DNA_CHUNK_SIZE      "dnaChunkSize"
+
+
+
+#define FEATURE_DESC    "IPA Distributed Numeric Assignment"
+#define PLUGIN_DESC     "IPA Distributed Numeric Assignment plugin"
 
 static Slapi_PluginDesc pdesc = { FEATURE_DESC,
     "FreeIPA project", "FreeIPA/1.0",
@@ -98,19 +111,21 @@ static Slapi_PluginDesc pdesc = { FEATURE_DESC,
  * linked list of config entries
  */
 
-struct _defs {
+struct configEntry {
     PRCList list;
     char *dn;
     char *type;
     char *prefix;
     unsigned long nextval;
     unsigned long interval;
-    struct slapi_filter *filter;
+    unsigned long maxval;
+    char *filter;
+    struct slapi_filter *slapi_filter;
     char *generate;
     char *scope;
-} dna_anchor;
-typedef struct _defs configEntry;
-static PRCList *config;
+};
+
+static PRCList *dna_global_config = NULL;
 static PRRWLock *g_dna_cache_lock;
 
 static void *_PluginID = NULL;
@@ -140,7 +155,7 @@ static int dna_postop_init(Slapi_PBlock * pb);
 static int loadPluginConfig();
 static int parseConfigEntry(Slapi_Entry * e);
 static void deleteConfig();
-static void freeConfigEntry(configEntry ** entry);
+static void freeConfigEntry(struct configEntry ** entry);
 
 /**
  *
@@ -149,8 +164,8 @@ static void freeConfigEntry(configEntry ** entry);
  */
 static char *dna_get_dn(Slapi_PBlock * pb);
 static int dna_dn_is_config(char *dn);
-static int dna_get_next_value(configEntry * config_entry,
-                              char **next_value_ret);
+static int dna_get_next_value(struct configEntry * config_entry,
+                                 char **next_value_ret);
 
 /**
  *
@@ -166,7 +181,7 @@ static int dna_add_pre_op(Slapi_PBlock * pb);
  * debug functions - global, for the debugger
  */
 void dnaDumpConfig();
-void dnaDumpConfigEntry(configEntry *);
+void dnaDumpConfigEntry(struct configEntry *);
 
 /**
  * set the debug level
@@ -325,7 +340,6 @@ static int dna_start(Slapi_PBlock * pb)
     slapi_log_error(SLAPI_LOG_TRACE, DNA_PLUGIN_SUBSYSTEM,
                     "--> dna_start\n");
 
-    config = &dna_anchor.list;
     g_dna_cache_lock = PR_NewRWLock(PR_RWLOCK_RANK_NONE, "dna");
     g_new_value_lock = slapi_new_mutex();
 
@@ -336,13 +350,13 @@ static int dna_start(Slapi_PBlock * pb)
         return DNA_FAILURE;
     }
 
-        /**
+    /**
 	 *	Get the plug-in target dn from the system
 	 *	and store it for future use. This should avoid
 	 *	hardcoding of DN's in the code.
 	 */
     slapi_pblock_get(pb, SLAPI_TARGET_DN, &plugindn);
-    if (plugindn == NULL || strlen(plugindn) == 0) {
+    if (NULL == plugindn || 0 == strlen(plugindn)) {
         slapi_log_error(SLAPI_LOG_PLUGIN, DNA_PLUGIN_SUBSYSTEM,
                         "dna_start: had to use hard coded config dn\n");
         plugindn = DNA_DN;
@@ -357,7 +371,10 @@ static int dna_start(Slapi_PBlock * pb)
         /**
 	 * Load the config for our plug-in
 	 */
-    PR_INIT_CLIST(config);
+    dna_global_config = (struct configEntry *)
+        slapi_ch_calloc(1, sizeof(struct configEntry));
+    PR_INIT_CLIST(dna_global_config);
+
     if (loadPluginConfig() != DNA_SUCCESS) {
         slapi_log_error(SLAPI_LOG_FATAL, DNA_PLUGIN_SUBSYSTEM,
                         "dna_start: unable to load plug-in configuration\n");
@@ -384,6 +401,8 @@ static int dna_close(Slapi_PBlock * pb)
 
     deleteConfig();
 
+    slapi_sh_free((void **)dna_global_config);
+
     slapi_log_error(SLAPI_LOG_TRACE, DNA_PLUGIN_SUBSYSTEM,
                     "<-- dna_close\n");
 
@@ -393,7 +412,7 @@ static int dna_close(Slapi_PBlock * pb)
 /*
  * config looks like this
  * - cn=myplugin
- * --- ou=posix
+ * --- cn=posix
  * ------ cn=accounts
  * ------ cn=groups
  * --- cn=samba
@@ -416,26 +435,28 @@ static int loadPluginConfig()
 
     search_pb = slapi_pblock_new();
 
-    slapi_search_internal_set_pb(search_pb, DNA_DN, LDAP_SCOPE_SUBTREE,
-                                 "objectclass=*", NULL, 0, NULL, NULL,
-                                 getPluginID(), 0);
+    slapi_search_internal_set_pb(search_pb, getPluginDN(),
+                                 LDAP_SCOPE_SUBTREE, "objectclass=*",
+                                 NULL, 0, NULL, NULL, getPluginID(), 0);
     slapi_search_internal_pb(search_pb);
     slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_RESULT, &result);
 
-    if (status != DNA_SUCCESS) {
-        status = DNA_SUCCESS;
+    if (LDAP_SUCCESS != result) {
+        status = DNA_FAILURE;
         goto cleanup;
     }
 
     slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES,
                      &entries);
-    if (NULL == entries || entries[0] == NULL) {
+    if (NULL == entries || NULL == entries[0]) {
         status = DNA_SUCCESS;
         goto cleanup;
     }
 
     for (i = 0; (entries[i] != NULL); i++) {
         status = parseConfigEntry(entries[i]);
+        if (DNA_SUCCESS != status)
+            break;
     }
 
   cleanup:
@@ -450,17 +471,18 @@ static int loadPluginConfig()
 
 static int parseConfigEntry(Slapi_Entry * e)
 {
-    char *value = NULL;
-    configEntry *entry = NULL;
-    configEntry *config_entry = NULL;
-    PRCList *list = NULL;
+    char *value;
+    struct configEntry *entry;
+    struct configEntry *config_entry;
+    PRCList *list;
     int entry_added = 0;
 
     slapi_log_error(SLAPI_LOG_TRACE, DNA_PLUGIN_SUBSYSTEM,
                     "--> parseConfigEntry\n");
 
-    entry = (configEntry *) slapi_ch_calloc(1, sizeof(configEntry));
-    if (0 == entry)
+    entry = (struct configEntry *)
+	slapi_ch_calloc(1, sizeof(struct configEntry));
+    if (NULL == entry)
         goto bail;
 
     value = slapi_entry_get_ndn(e);
@@ -469,7 +491,7 @@ static int parseConfigEntry(Slapi_Entry * e)
     }
 
     slapi_log_error(SLAPI_LOG_CONFIG, DNA_PLUGIN_SUBSYSTEM,
-                    "----------> dn [%s] \n", entry->dn, 0, 0);
+                    "----------> dn [%s]\n", entry->dn, 0, 0);
 
     value = slapi_entry_attr_get_charptr(e, DNA_TYPE);
     if (value) {
@@ -478,38 +500,41 @@ static int parseConfigEntry(Slapi_Entry * e)
         goto bail;
 
     slapi_log_error(SLAPI_LOG_CONFIG, DNA_PLUGIN_SUBSYSTEM,
-                    "----------> dnaType [%s] \n", entry->type, 0, 0);
+                    "----------> dnaType [%s]\n", entry->type, 0, 0);
+
+    /* FIXME: check the attribute type, it must suport matching rules and be
+     * indexed, these are requirements and failure to meet them should result in
+     * the configuration to be disarded and an ERROR logged prominently */
 
     value = slapi_entry_attr_get_charptr(e, DNA_NEXTVAL);
     if (value) {
         entry->nextval = strtoul(value, 0, 0);
         slapi_ch_free_string(&value);
-        value = 0;
     } else
         goto bail;
 
     slapi_log_error(SLAPI_LOG_CONFIG, DNA_PLUGIN_SUBSYSTEM,
-                    "----------> dnaNextValue [%d] \n", entry->nextval, 0,
+                    "----------> dnaNextValue [%d]\n", entry->nextval, 0,
                     0);
 
     value = slapi_entry_attr_get_charptr(e, DNA_PREFIX);
-    if (value) {
+    if (value && value[0]) {
         entry->prefix = value;
     }
 
     slapi_log_error(SLAPI_LOG_CONFIG, DNA_PLUGIN_SUBSYSTEM,
-                    "----------> dnaPrefix [%s] \n", entry->prefix, 0, 0);
+                    "----------> dnaPrefix [%s]\n", entry->prefix, 0, 0);
 
     value = slapi_entry_attr_get_charptr(e, DNA_INTERVAL);
     if (value) {
         entry->interval = strtoul(value, 0, 0);
-        slapi_ch_free_string(&value);
-        value = 0;
     } else
         goto bail;
 
     slapi_log_error(SLAPI_LOG_CONFIG, DNA_PLUGIN_SUBSYSTEM,
-                    "----------> dnaInterval [%s] \n", value, 0, 0);
+                    "----------> dnaInterval [%s]\n", value, 0, 0);
+
+    slapi_ch_free_string(&value);
 
     value = slapi_entry_attr_get_charptr(e, DNA_GENERATE);
     if (value) {
@@ -517,48 +542,59 @@ static int parseConfigEntry(Slapi_Entry * e)
     }
 
     slapi_log_error(SLAPI_LOG_CONFIG, DNA_PLUGIN_SUBSYSTEM,
-                    "----------> dnaMagicRegen [%s] \n", entry->generate,
+                    "----------> dnaMagicRegen [%s]\n", entry->generate,
                     0, 0);
 
     value = slapi_entry_attr_get_charptr(e, DNA_FILTER);
     if (value) {
-        entry->filter = slapi_str2filter(value);
+        entry->filter = value;
+        entry->slapi_filter = slapi_str2filter(value);
     } else
         goto bail;
 
     slapi_log_error(SLAPI_LOG_CONFIG, DNA_PLUGIN_SUBSYSTEM,
-                    "----------> dnaFilter [%s] \n", value, 0, 0);
-
-    slapi_ch_free_string(&value);
-    value = 0;
+                    "----------> dnaFilter [%s]\n", value, 0, 0);
 
     value = slapi_entry_attr_get_charptr(e, DNA_SCOPE);
     if (value) {
-        char *canonical_dn = slapi_dn_normalize(value);
-        entry->scope = canonical_dn;
+        entry->scope = slapi_dn_normalize(value);
     }
 
     slapi_log_error(SLAPI_LOG_CONFIG, DNA_PLUGIN_SUBSYSTEM,
-                    "----------> dnaScope [%s] \n", entry->scope, 0, 0);
+                    "----------> dnaScope [%s]\n", entry->scope, 0, 0);
 
+    /* optional, if not specified set -1  which is converted to the max unisgnee
+     * value */
+    value = slapi_entry_attr_get_charptr(e, DNA_MAXVAL);
+    if (value) {
+            entry->maxval = strtoul(value, 0, 0);
 
-        /**
-	 * Finally add the entry to the list
-	 * we group by type then by filter
-	 * and finally sort by dn length with longer dn's
-	 * first - this allows the scope checking
-	 * code to be simple and quick and
-	 * cunningly linear
-	 */
-    if (!PR_CLIST_IS_EMPTY(config)) {
-        list = PR_LIST_HEAD(config);
-        while (list != config) {
-            config_entry = (configEntry *) list;
+            slapi_log_error(SLAPI_LOG_CONFIG, DNA_PLUGIN_SUBSYSTEM,
+                        "----------> dnaMaxValue [%ld]\n", value, 0, 0);
+
+            slapi_ch_free_string(&value);
+    } else
+        entry->maxval = -1;
+
+
+    /**
+     * Finally add the entry to the list
+     * we group by type then by filter
+     * and finally sort by dn length with longer dn's
+     * first - this allows the scope checking
+     * code to be simple and quick and
+     * cunningly linear
+     */
+    if (!PR_CLIST_IS_EMPTY(dna_global_config)) {
+        list = PR_LIST_HEAD(dna_global_config);
+        while (list != dna_global_config) {
+            config_entry = (struct configEntry *) list;
 
             if (slapi_attr_type_cmp(config_entry->type, entry->type, 1))
                 goto next;
 
-            if (slapi_filter_compare(config_entry->filter, entry->filter))
+            if (slapi_filter_compare(config_entry->slapi_filter,
+                                     entry->slapi_filter))
                 goto next;
 
             if (slapi_dn_issuffix(entry->scope, config_entry->scope)) {
@@ -574,7 +610,7 @@ static int parseConfigEntry(Slapi_Entry * e)
           next:
             list = PR_NEXT_LINK(list);
 
-            if (config == list) {
+            if (dna_global_config == list) {
                 /* add to tail */
                 PR_INSERT_BEFORE(&(entry->list), list);
                 slapi_log_error(SLAPI_LOG_CONFIG, DNA_PLUGIN_SUBSYSTEM,
@@ -586,7 +622,7 @@ static int parseConfigEntry(Slapi_Entry * e)
         }
     } else {
         /* first entry */
-        PR_INSERT_LINK(&(entry->list), config);
+        PR_INSERT_LINK(&(entry->list), dna_global_config);
         slapi_log_error(SLAPI_LOG_CONFIG, DNA_PLUGIN_SUBSYSTEM,
                         "store [%s] at head \n", entry->scope, 0, 0);
         entry_added = 1;
@@ -605,9 +641,9 @@ static int parseConfigEntry(Slapi_Entry * e)
     return DNA_SUCCESS;
 }
 
-static void freeConfigEntry(configEntry ** entry)
+static void freeConfigEntry(struct configEntry ** entry)
 {
-    configEntry *e = *entry;
+    struct configEntry *e = *entry;
 
     if (e->dn) {
         slapi_log_error(SLAPI_LOG_CONFIG, DNA_PLUGIN_SUBSYSTEM,
@@ -622,7 +658,10 @@ static void freeConfigEntry(configEntry ** entry)
         slapi_ch_free_string(&e->prefix);
 
     if (e->filter)
-        slapi_filter_free(e->filter, 1);
+        slapi_ch_free_string(&e->filter);
+
+    if (e->slapi_filter)
+        slapi_filter_free(e->slapi_filter, 1);
 
     if (e->generate)
         slapi_ch_free_string(&e->generate);
@@ -636,21 +675,45 @@ static void freeConfigEntry(configEntry ** entry)
 static void deleteConfigEntry(PRCList * entry)
 {
     PR_REMOVE_LINK(entry);
-    freeConfigEntry((configEntry **) & entry);
+    freeConfigEntry((struct configEntry **) & entry);
 }
 
 static void deleteConfig()
 {
     PRCList *list;
 
-    while (!PR_CLIST_IS_EMPTY(config)) {
-        list = PR_LIST_HEAD(config);
+    while (!PR_CLIST_IS_EMPTY(dna_global_config)) {
+        list = PR_LIST_HEAD(dna_global_config);
         deleteConfigEntry(list);
     }
 
     return;
 }
 
+/****************************************************
+    Distributed ranges Helpers
+****************************************************/
+
+static int dna_fix_maxval(Slapi_DN *dn, unsigned long *cur, unsigned long *max)
+{
+    /* TODO: check the main partition to see if another range
+     * is available, and set the new local configuration
+     * accordingly.
+     * If a new range is not available run the retrieval task
+     * and simply return error
+     */
+
+    return LDAP_OPERATIONS_ERROR;
+}
+
+static void dna_notice_allocation(Slapi_DN *dn, unsigned long new)
+{
+    /* TODO: check if we passed a new chunk threshold and update
+     * the shared configuration on the public partition.
+     */
+
+    return;
+}
 
 /****************************************************
 	Helpers
@@ -697,29 +760,183 @@ static int dna_dn_is_config(char *dn)
     return ret;
 }
 
+static LDAPControl *dna_build_sort_control(const char *attr)
+{
+    LDAPControl *ctrl;
+    BerElement *ber;
+    int rc;
+
+    ber = ber_alloc();
+    if (NULL == ber)
+        return NULL;
+
+    rc = ber_printf(ber, "{{s}}", attr);
+    if (-1 == rc) {
+        ber_free(ber, 1);
+        return NULL;
+    }
+
+    rc = slapi_build_control(LDAP_CONTROL_SORTREQUEST, ber, 1, &ctrl);
+
+    ber_free(ber, 1);
+
+    if (LDAP_SUCCESS != rc)
+         return NULL;
+
+    return ctrl;
+}
 
 /****************************************************
         Functions that actually do things other
         than config and startup
 ****************************************************/
 
+/* we do search all values between newval and maxval asking the
+ * server to sort them, then we check the first free spot and
+ * use it as newval */
+static int dna_first_free_value(struct configEntry *config_entry,
+                                unsigned long *newval,
+                                unsigned long maxval,
+				unsigned long increment)
+{
+    Slapi_Entry **entries = NULL;
+    Slapi_PBlock *pb = NULL;
+    LDAPControl **ctrls;
+    char *attrs[2];
+    char *filter;
+    char *prefix;
+    char *type;
+    int preflen;
+    int result, status;
+    unsigned long tmpval, sval, i;
+    char *strval = NULL;
+
+    prefix = config_entry->prefix;
+    type = config_entry->type;
+    tmpval = *newval;
+
+    attrs[0] = type;
+    attrs[1] = NULL;
+
+    ctrls = (LDAPControl **)slapi_ch_calloc(2, sizeof(LDAPControl));
+    if (NULL == ctrls)
+        return LDAP_OPERATIONS_ERROR;
+
+    ctrls[0] = dna_build_sort_control(config_entry->type);
+    if (NULL == ctrls[0]) {
+        slapi_ch_free((void **)&ctrls);
+        return LDAP_OPERATIONS_ERROR;
+    }
+
+    filter = slapi_ch_smprintf("(&%s(&(%s>=%s%llu)(%s<=%s%llu)))",
+                               config_entry->filter,
+                               type, prefix?prefix:"", tmpval,
+                               type, prefix?prefix:"", maxval);
+    if (NULL == filter) {
+        ldap_control_free(ctrls[0]);
+        slapi_ch_free((void **)&ctrls);
+        return LDAP_OPERATIONS_ERROR;
+    }
+
+    pb = slapi_pblock_new();
+    if (NULL == pb) {
+        ldap_control_free(ctrls[0]);
+        slapi_ch_free((void **)&ctrls);
+        slapi_ch_free_string(&filter);
+        return LDAP_OPERATIONS_ERROR;
+    }
+
+    slapi_search_internal_set_pb(pb, config_entry->scope,
+                                 LDAP_SCOPE_SUBTREE, filter,
+                                 attrs, 0, ctrls,
+                                 NULL, getPluginID(), 0);
+    slapi_search_internal_pb(pb);
+/*
+    ldap_control_free(ctrls[0]);
+*/
+    slapi_ch_free_string(&filter);
+
+    slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &result);
+    if (LDAP_SUCCESS != result) {
+        status = LDAP_OPERATIONS_ERROR;
+        goto cleanup;
+    }
+
+    slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES,
+                     &entries);
+
+    if (NULL == entries || NULL == entries[0]) {
+        /* no values means we already have a good value */
+        status = LDAP_SUCCESS;
+        goto cleanup;
+    }
+
+    /* entries are sorted and filtered for value >= tval therefore if the
+     * first one does not match tval it means that the value is free,
+     * otherwise we need to cycle through values until we find a mismatch,
+     * the first mismatch is the first free pit */
+
+    preflen = prefix?strlen(prefix):0;
+    sval = 0;
+    for (i = 0; NULL != entries[i]; i++) {
+        strval = slapi_entry_attr_get_charptr(entries[i], type);
+        if (preflen) {
+            if (strlen(strval) <= preflen) {
+                /* something very wrong here ... */
+                status = LDAP_OPERATIONS_ERROR;
+                goto cleanup;
+            }
+            strval = &strval[preflen-1];
+        }
+
+        errno = 0;
+        sval = strtoul(strval, 0, 0);
+        if (errno) {
+            /* something very wrong here ... */
+            status = LDAP_OPERATIONS_ERROR;
+            goto cleanup;
+        }
+        slapi_ch_free_string(&strval);
+
+        if (tmpval != sval)
+            break;
+
+        if (maxval < sval)
+            break;
+
+        tmpval += increment;
+    }
+
+    *newval = tmpval;
+    status = LDAP_SUCCESS;
+
+cleanup:
+    slapi_ch_free_string(&strval);
+    slapi_free_search_results_internal(pb);
+    slapi_pblock_destroy(pb);
+
+    return status;
+}
 
 /*
  * Perform ldap operationally atomic increment
  * Return the next value to be assigned
  * Method:
  * 1. retrieve entry
- * 2. remove current value, add new value in one operation
- * 3. if failed, and less than 3 times, goto 1
+ * 2. do increment operations
+ * 3. remove current value, add new value in one operation
+ * 4. if failed, and less than 3 times, goto 1
  */
-static int dna_get_next_value(configEntry * config_entry,
-                              char **next_value_ret)
+static int dna_get_next_value(struct configEntry *config_entry,
+                                 char **next_value_ret)
 {
-    int ret = LDAP_SUCCESS;
-    Slapi_DN *dn = 0;
-    char *attrlist[3];
-    Slapi_Entry *e = 0;
-    int attempts = 0;
+    Slapi_PBlock *pb = NULL;
+    char *old_value = NULL;
+    Slapi_Entry *e = NULL;
+    Slapi_DN *dn = NULL;
+    char *attrlist[4];
+    int attempts;
+    int ret;
 
     slapi_log_error(SLAPI_LOG_TRACE, DNA_PLUGIN_SUBSYSTEM,
                     "--> dna_get_next_value\n");
@@ -727,8 +944,9 @@ static int dna_get_next_value(configEntry * config_entry,
     /* get pre-requisites to search */
     dn = slapi_sdn_new_dn_byref(config_entry->dn);
     attrlist[0] = DNA_NEXTVAL;
-    attrlist[1] = DNA_INTERVAL;
-    attrlist[2] = 0;
+    attrlist[1] = DNA_MAXVAL;
+    attrlist[2] = DNA_INTERVAL;
+    attrlist[3] = NULL;
 
 
     /* the operation is constructed such that race conditions
@@ -739,113 +957,169 @@ static int dna_get_next_value(configEntry * config_entry,
 
     slapi_lock_mutex(g_new_value_lock);
 
-    while (attempts < 3 && LDAP_SUCCESS == ret) {
-        attempts++;
+    for (attempts = 0; attempts < 3; attempts++) {
+
+        LDAPMod mod_add;
+        LDAPMod mod_delete;
+        LDAPMod *mods[3];
+        char *delete_val[2];
+        char *add_val[2];
+        char new_value[16];
+        char *interval;
+        char *max_value;
+        unsigned long increment = 1; /* default increment */
+        unsigned long setval = 0;
+        unsigned long newval = 0;
+        unsigned long maxval = -1;
+        int result;
 
         /* do update */
-        if (e) {
-            slapi_entry_free(e);
-            e = 0;
+        ret = slapi_search_internal_get_entry(dn, attrlist, &e,
+                                              getPluginID());
+        if (LDAP_SUCCESS != ret) {
+            ret = LDAP_OPERATIONS_ERROR;
+            goto done;
         }
 
-        ret =
-            slapi_search_internal_get_entry(dn, attrlist, &e,
-                                            getPluginID());
-        if (LDAP_SUCCESS == ret) {
-            char *old_value;
-
-            old_value = slapi_entry_attr_get_charptr(e, DNA_NEXTVAL);
-            if (old_value) {
-                LDAPMod mod_add;
-                LDAPMod mod_delete;
-                LDAPMod *mods[3];
-                Slapi_PBlock *pb = slapi_pblock_new();
-                char *delete_val[2];
-                char *add_val[2];
-                char new_value[16];
-                char *interval = 0;
-
-                mods[0] = &mod_delete;
-                mods[1] = &mod_add;
-                mods[2] = 0;
-
-                if (0 == pb)
-                    goto bail;
-
-                interval = slapi_entry_attr_get_charptr(e, DNA_INTERVAL);
-                if (0 == interval) {
-                    slapi_pblock_destroy(pb);
-                    slapi_ch_free_string(&old_value);
-                    goto bail;
-                }
+        old_value = slapi_entry_attr_get_charptr(e, DNA_NEXTVAL);
+        if (NULL == old_value) {
+            ret = LDAP_OPERATIONS_ERROR;
+            goto done;
+        }
+
+        setval = strtoul(old_value, 0, 0);
+
+        max_value = slapi_entry_attr_get_charptr(e, DNA_MAXVAL);
+        if (max_value) {
+            maxval = strtoul(max_value, 0, 0);
+            slapi_ch_free_string(&max_value);
+        }
 
-                /* perform increment */
+        /* if not present the default is 1 */
+        interval = slapi_entry_attr_get_charptr(e, DNA_INTERVAL);
+        if (NULL != interval) {
+            increment = strtoul(interval, 0, 0);
+        }
 
-                sprintf(new_value, "%lu",
-                        strtoul(interval, 0, 0) +
-                        strtoul(old_value, 0, 0));
+        slapi_entry_free(e);
+        e = NULL;
+
+        /* check the value is actually in range */
+
+        /* verify the new value is actually free and get the first
+         * one free if not*/
+        ret = dna_first_free_value(config_entry, &setval, maxval, increment);
+        if (LDAP_SUCCESS != ret)
+            goto done;
+
+        /* try for a new range or fail */
+        if (setval > maxval) {
+            ret = dna_fix_maxval(dn, &setval, &maxval);
+            if (LDAP_SUCCESS != ret) {
+                slapi_log_error(SLAPI_LOG_FATAL, DNA_PLUGIN_SUBSYSTEM,
+                                "dna_get_next_value: no more IDs available!!\n");
+                goto done;
+            }
 
-                delete_val[0] = old_value;
-                delete_val[1] = 0;
+            /* verify the new value is actually free and get the first
+             * one free if not */
+            ret = dna_first_free_value(config_entry, &setval, maxval, increment);
+            if (LDAP_SUCCESS != ret)
+                goto done;
+        }
 
-                mod_delete.mod_op = LDAP_MOD_DELETE;
-                mod_delete.mod_type = DNA_NEXTVAL;
-                mod_delete.mod_values = delete_val;
+        if (setval > maxval) {
+            ret = LDAP_OPERATIONS_ERROR;
+            goto done;
+        }
 
-                add_val[0] = new_value;
-                add_val[1] = 0;
+        newval = setval + increment;
 
-                mod_add.mod_op = LDAP_MOD_ADD;
-                mod_add.mod_type = DNA_NEXTVAL;
-                mod_add.mod_values = add_val;
+        /* try for a new range or fail */
+        if (newval > maxval) {
+            ret = dna_fix_maxval(dn, &newval, &maxval);
+            if (LDAP_SUCCESS != ret) {
+                slapi_log_error(SLAPI_LOG_FATAL, DNA_PLUGIN_SUBSYSTEM,
+                                "dna_get_next_value: no more IDs available!!\n");
+                goto done;
+            }
+        }
 
+        /* try to set the new value */
 
-                mods[0] = &mod_delete;
-                mods[1] = &mod_add;
-                mods[2] = 0;
+        sprintf(new_value, "%llu", newval);
 
-                slapi_modify_internal_set_pb(pb, config_entry->dn,
-                                             mods, 0, 0, getPluginID(), 0);
+        delete_val[0] = old_value;
+        delete_val[1] = 0;
 
-                slapi_modify_internal_pb(pb);
+        mod_delete.mod_op = LDAP_MOD_DELETE;
+        mod_delete.mod_type = DNA_NEXTVAL;
+        mod_delete.mod_values = delete_val;
 
-                slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &ret);
+        add_val[0] = new_value;
+        add_val[1] = 0;
 
-                slapi_pblock_destroy(pb);
-                slapi_ch_free_string(&interval);
+        mod_add.mod_op = LDAP_MOD_ADD;
+        mod_add.mod_type = DNA_NEXTVAL;
+        mod_add.mod_values = add_val;
 
-                if (LDAP_SUCCESS == ret) {
-                    *next_value_ret = old_value;
-                    break;
-                } else {
-                    slapi_ch_free_string(&old_value);
-                    if (LDAP_NO_SUCH_ATTRIBUTE != ret) {
-                        /* not the result of a race
-                           to change the value
-                         */
-                        break;
-                    } else
-                        /* we lost the race to mod
-                           try again
-                         */
-                        ret = LDAP_SUCCESS;
-                }
-            } else
-                break;
-        } else
-            break;
+        mods[0] = &mod_delete;
+        mods[1] = &mod_add;
+        mods[2] = 0;
+
+        pb = slapi_pblock_new();
+        if (NULL == pb) {
+            ret = LDAP_OPERATIONS_ERROR;
+            goto done;
+        }
+
+        slapi_modify_internal_set_pb(pb, config_entry->dn,
+                                     mods, 0, 0, getPluginID(), 0);
+
+        slapi_modify_internal_pb(pb);
+
+        slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &ret);
+
+        slapi_pblock_destroy(pb);
+        pb = NULL;
+        slapi_ch_free_string(&interval);
+        slapi_ch_free_string(&old_value);
+
+        if (LDAP_SUCCESS == ret) {
+            *next_value_ret = slapi_ch_smprintf("%llu", setval);
+            if (NULL == *next_value_ret) {
+                ret = LDAP_OPERATIONS_ERROR;
+                goto done;
+            }
+
+            dna_notice_allocation(dn, newval);
+            goto done;
+        }
+
+        if (LDAP_NO_SUCH_ATTRIBUTE != ret) {
+            /* not the result of a race
+               to change the value
+             */
+            goto done;
+        }
     }
 
-  bail:
+  done:
 
     slapi_unlock_mutex(g_new_value_lock);
 
+    if (LDAP_SUCCESS != ret)
+        slapi_ch_free_string(&old_value);
+
     if (dn)
         slapi_sdn_free(&dn);
 
     if (e)
         slapi_entry_free(e);
 
+    if (pb)
+        slapi_pblock_destroy(pb);
+
     slapi_log_error(SLAPI_LOG_TRACE, DNA_PLUGIN_SUBSYSTEM,
                     "<-- dna_get_next_value\n");
 
@@ -862,7 +1136,7 @@ static int dna_pre_op(Slapi_PBlock * pb, int modtype)
 {
     char *dn = 0;
     PRCList *list = 0;
-    configEntry *config_entry = 0;
+    struct configEntry *config_entry = 0;
     struct slapi_entry *e = 0;
     char *last_type = 0;
     char *value = 0;
@@ -916,11 +1190,11 @@ static int dna_pre_op(Slapi_PBlock * pb, int modtype)
 
     dna_read_lock();
 
-    if (!PR_CLIST_IS_EMPTY(config)) {
-        list = PR_LIST_HEAD(config);
+    if (!PR_CLIST_IS_EMPTY(dna_global_config)) {
+        list = PR_LIST_HEAD(dna_global_config);
 
-        while (list != config && LDAP_SUCCESS == ret) {
-            config_entry = (configEntry *) list;
+        while (list != dna_global_config && LDAP_SUCCESS == ret) {
+            config_entry = (struct configEntry *) list;
 
             /* did we already service this type? */
             if (last_type) {
@@ -935,11 +1209,11 @@ static int dna_pre_op(Slapi_PBlock * pb, int modtype)
             }
 
             /* does the entry match the filter? */
-            if (config_entry->filter) {
+            if (config_entry->slapi_filter) {
                 if (LDAP_SUCCESS != slapi_vattr_filter_test(pb,
                                                             e,
                                                             config_entry->
-                                                            filter, 0))
+                                                            slapi_filter, 0))
                     goto next;
             }
 
@@ -972,8 +1246,8 @@ static int dna_pre_op(Slapi_PBlock * pb, int modtype)
 
                         if (len == bv->bv_len) {
                             if (!slapi_UTF8NCASECMP(bv->bv_val,
-                                                    config_entry->
-                                                    generate, len))
+                                                    config_entry->generate,
+                                                    len))
 
                                 generate = 1;
                             break;
@@ -992,7 +1266,8 @@ static int dna_pre_op(Slapi_PBlock * pb, int modtype)
                 int len;
 
                 /* create the value to add */
-                if ((ret = dna_get_next_value(config_entry, &value)))
+                ret = dna_get_next_value(config_entry, &value);
+		if (DNA_SUCCESS != ret)
                     break;
 
                 len = strlen(value) + 1;
@@ -1066,7 +1341,6 @@ static int dna_pre_op(Slapi_PBlock * pb, int modtype)
     return ret;
 }
 
-
 static int dna_add_pre_op(Slapi_PBlock * pb)
 {
     return dna_pre_op(pb, LDAP_CHANGETYPE_ADD);
@@ -1110,10 +1384,10 @@ void dnaDumpConfig()
 
     dna_read_lock();
 
-    if (!PR_CLIST_IS_EMPTY(config)) {
-        list = PR_LIST_HEAD(config);
-        while (list != config) {
-            dnaDumpConfigEntry((configEntry *) list);
+    if (!PR_CLIST_IS_EMPTY(dna_global_config)) {
+        list = PR_LIST_HEAD(dna_global_config);
+        while (list != dna_global_config) {
+            dnaDumpConfigEntry((struct configEntry *) list);
             list = PR_NEXT_LINK(list);
         }
     }
@@ -1122,7 +1396,7 @@ void dnaDumpConfig()
 }
 
 
-void dnaDumpConfigEntry(configEntry * entry)
+void dnaDumpConfigEntry(struct configEntry * entry)
 {
     printf("<- type --------------> %s\n", entry->type);
     printf("<---- prefix ---------> %s\n", entry->prefix);
-- 
1.5.4.1

-------------- next part --------------
>From aad496178d5cc419eb607a2e4b64fa6261473ed8 Mon Sep 17 00:00:00 2001
From: Simo Sorce <ssorce at redhat.com>
Date: Fri, 9 May 2008 12:52:17 -0400
Subject: [PATCH] For some unknown reason the sort control returns values sorted in reverse.
 Ask for inverse order to get them straight ...

---
 ipa-server/ipa-slapi-plugins/dna/dna.c |    4 +++-
 1 files changed, 3 insertions(+), 1 deletions(-)

diff --git a/ipa-server/ipa-slapi-plugins/dna/dna.c b/ipa-server/ipa-slapi-plugins/dna/dna.c
index 3df6dbb..1f67dc9 100644
--- a/ipa-server/ipa-slapi-plugins/dna/dna.c
+++ b/ipa-server/ipa-slapi-plugins/dna/dna.c
@@ -760,6 +760,8 @@ static int dna_dn_is_config(char *dn)
     return ret;
 }
 
+#define DNA_LDAP_TAG_SK_REVERSE 0x81L
+
 static LDAPControl *dna_build_sort_control(const char *attr)
 {
     LDAPControl *ctrl;
@@ -770,7 +772,7 @@ static LDAPControl *dna_build_sort_control(const char *attr)
     if (NULL == ber)
         return NULL;
 
-    rc = ber_printf(ber, "{{s}}", attr);
+    rc = ber_printf(ber, "{{stb}}", attr, DNA_LDAP_TAG_SK_REVERSE, 1);
     if (-1 == rc) {
         ber_free(ber, 1);
         return NULL;
-- 
1.5.4.1

-------------- next part --------------
>From b03ef4250a2bdd7a9d66c13ef4a52f852504273e Mon Sep 17 00:00:00 2001
From: Simo Sorce <ssorce at redhat.com>
Date: Fri, 9 May 2008 20:58:02 -0400
Subject: [PATCH] If there is an error we need to send back a reply ourselves.
 Return also an intelligible error message.

---
 ipa-server/ipa-slapi-plugins/dna/dna.c |   13 +++++++++++--
 1 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/ipa-server/ipa-slapi-plugins/dna/dna.c b/ipa-server/ipa-slapi-plugins/dna/dna.c
index 1f67dc9..fdcd96d 100644
--- a/ipa-server/ipa-slapi-plugins/dna/dna.c
+++ b/ipa-server/ipa-slapi-plugins/dna/dna.c
@@ -1147,6 +1147,7 @@ static int dna_pre_op(Slapi_PBlock * pb, int modtype)
     Slapi_Mod *smod = 0;
     LDAPMod **mods;
     int free_entry = 0;
+    char *errstr = NULL;
     int ret = 0;
 
     slapi_log_error(SLAPI_LOG_TRACE, DNA_PLUGIN_SUBSYSTEM,
@@ -1269,8 +1270,12 @@ static int dna_pre_op(Slapi_PBlock * pb, int modtype)
 
                 /* create the value to add */
                 ret = dna_get_next_value(config_entry, &value);
-		if (DNA_SUCCESS != ret)
+                if (DNA_SUCCESS != ret) {
+                    errstr = slapi_ch_smprintf("Allocation of a new value for"
+                                               " %s failed! Unable to proceed.",
+                                               config_entry->type);
                     break;
+                }
 
                 len = strlen(value) + 1;
                 if (config_entry->prefix) {
@@ -1333,9 +1338,13 @@ static int dna_pre_op(Slapi_PBlock * pb, int modtype)
     if (free_entry && e)
         slapi_entry_free(e);
 
-    if (ret)
+    if (ret) {
         slapi_log_error(SLAPI_LOG_PLUGIN, DNA_PLUGIN_SUBSYSTEM,
                         "dna_pre_op: operation failure [%d]\n", ret);
+        slapi_send_ldap_result(pb, ret, NULL, errstr, 0, NULL);
+        slapi_ch_free(&errstr);
+        ret = DNA_FAILURE;
+    }
 
     slapi_log_error(SLAPI_LOG_TRACE, DNA_PLUGIN_SUBSYSTEM,
                     "<-- dna_pre_op\n");
-- 
1.5.4.1



More information about the Freeipa-devel mailing list