]> git.sur5r.net Git - openldap/commitdiff
Back out giant lock code, needs more work
authorKurt Zeilenga <kurt@openldap.org>
Tue, 29 Jan 2002 17:49:37 +0000 (17:49 +0000)
committerKurt Zeilenga <kurt@openldap.org>
Tue, 29 Jan 2002 17:49:37 +0000 (17:49 +0000)
13 files changed:
servers/slapd/back-ldbm/add.c
servers/slapd/back-ldbm/back-ldbm.h
servers/slapd/back-ldbm/bind.c
servers/slapd/back-ldbm/compare.c
servers/slapd/back-ldbm/delete.c
servers/slapd/back-ldbm/entry.c
servers/slapd/back-ldbm/init.c
servers/slapd/back-ldbm/modify.c
servers/slapd/back-ldbm/modrdn.c
servers/slapd/back-ldbm/nextid.c
servers/slapd/back-ldbm/passwd.c
servers/slapd/back-ldbm/referral.c
servers/slapd/back-ldbm/search.c

index 9baac8106575f52ee31ab38f91161e8bc8120eed..997e969f1de3ba5718af6134ea264e45f62dd6f5 100644 (file)
@@ -27,6 +27,7 @@ ldbm_back_add(
        struct ldbminfo *li = (struct ldbminfo *) be->be_private;
        struct berval   pdn;
        Entry           *p = NULL;
+       int                     rootlock = 0;
        int                     rc;
        ID               id = NOID;
        const char      *text = NULL;
@@ -41,12 +42,12 @@ ldbm_back_add(
        Debug(LDAP_DEBUG_ARGS, "==> ldbm_back_add: %s\n", e->e_dn, 0, 0);
 #endif
 
-       /* grab giant lock for writing */
-       ldap_pvt_thread_rdwr_wlock(&li->li_giant_rwlock);
+       /* nobody else can add until we lock our parent */
+       ldap_pvt_thread_mutex_lock(&li->li_add_mutex);
 
        if ( ( rc = dn2id( be, &e->e_nname, &id ) ) || id != NOID ) {
                /* if (rc) something bad happened to ldbm cache */
-               ldap_pvt_thread_rdwr_wunlock(&li->li_giant_rwlock);
+               ldap_pvt_thread_mutex_unlock(&li->li_add_mutex);
                send_ldap_result( conn, op, 
                        rc ? LDAP_OPERATIONS_ERROR : LDAP_ALREADY_EXISTS,
                        NULL, NULL, NULL, NULL );
@@ -56,7 +57,7 @@ ldbm_back_add(
        rc = entry_schema_check( be, e, NULL, &text, textbuf, textlen );
 
        if ( rc != LDAP_SUCCESS ) {
-               ldap_pvt_thread_rdwr_wunlock(&li->li_giant_rwlock);
+               ldap_pvt_thread_mutex_unlock(&li->li_add_mutex);
 
 #ifdef NEW_LOGGING
                LDAP_LOG(( "backend", LDAP_LEVEL_ERR,
@@ -67,6 +68,7 @@ ldbm_back_add(
                        text, 0, 0 );
 #endif
 
+
                send_ldap_result( conn, op, rc,
                        NULL, text, NULL, NULL );
                return( -1 );
@@ -92,6 +94,8 @@ ldbm_back_add(
                        char *matched_dn = NULL;
                        BerVarray refs;
 
+                       ldap_pvt_thread_mutex_unlock(&li->li_add_mutex);
+
                        if ( matched != NULL ) {
                                matched_dn = ch_strdup( matched->e_dn );
                                refs = is_entry_referral( matched )
@@ -104,8 +108,6 @@ ldbm_back_add(
                                        NULL, &e->e_name, LDAP_SCOPE_DEFAULT );
                        }
 
-                       ldap_pvt_thread_rdwr_wunlock(&li->li_giant_rwlock);
-
 #ifdef NEW_LOGGING
                        LDAP_LOG(( "backend", LDAP_LEVEL_ERR,
                                "ldbm_back_add: Parent of (%s) does not exist.\n",
@@ -125,12 +127,14 @@ ldbm_back_add(
                        return -1;
                }
 
+               /* don't need the add lock anymore */
+               ldap_pvt_thread_mutex_unlock(&li->li_add_mutex);
+
                if ( ! access_allowed( be, conn, op, p,
                        children, NULL, ACL_WRITE ) )
                {
                        /* free parent and writer lock */
                        cache_return_entry_w( &li->li_cache, p ); 
-                       ldap_pvt_thread_rdwr_wunlock(&li->li_giant_rwlock);
 
 #ifdef NEW_LOGGING
                        LDAP_LOG(( "backend", LDAP_LEVEL_ERR,
@@ -144,6 +148,7 @@ ldbm_back_add(
                        send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
                            NULL, "no write access to parent", NULL, NULL );
 
+
                        return -1;
                }
 
@@ -152,7 +157,6 @@ ldbm_back_add(
 
                        /* free parent and writer lock */
                        cache_return_entry_w( &li->li_cache, p );
-                       ldap_pvt_thread_rdwr_wunlock(&li->li_giant_rwlock);
 
 #ifdef NEW_LOGGING
                        LDAP_LOG(( "backend", LDAP_LEVEL_ERR,
@@ -178,7 +182,6 @@ ldbm_back_add(
 
                        /* free parent and writer lock */
                        cache_return_entry_w( &li->li_cache, p );
-                       ldap_pvt_thread_rdwr_wunlock(&li->li_giant_rwlock);
 
 #ifdef NEW_LOGGING
                        LDAP_LOG(( "backend", LDAP_LEVEL_ERR,
@@ -211,7 +214,7 @@ ldbm_back_add(
                                p = NULL;
                                
                                if ( ! rc ) {
-                                       ldap_pvt_thread_rdwr_wunlock(&li->li_giant_rwlock);
+                                       ldap_pvt_thread_mutex_unlock(&li->li_add_mutex);
 
 #ifdef NEW_LOGGING
                                        LDAP_LOG(( "backend", LDAP_LEVEL_ERR,
@@ -233,7 +236,7 @@ ldbm_back_add(
                                }
 
                        } else {
-                               ldap_pvt_thread_rdwr_wunlock(&li->li_giant_rwlock);
+                               ldap_pvt_thread_mutex_unlock(&li->li_add_mutex);
 
 #ifdef NEW_LOGGING
                                LDAP_LOG(( "backend", LDAP_LEVEL_ERR,
@@ -253,6 +256,14 @@ ldbm_back_add(
                                return -1;
                        }
                }
+
+               /*
+                * no parent, acquire the root write lock
+                * and release the add lock.
+                */
+               ldap_pvt_thread_mutex_lock(&li->li_root_mutex);
+               rootlock = 1;
+               ldap_pvt_thread_mutex_unlock(&li->li_add_mutex);
        }
 
        if ( next_id( be, &e->e_id ) ) {
@@ -261,16 +272,20 @@ ldbm_back_add(
                        cache_return_entry_w( &li->li_cache, p ); 
                }
 
-               ldap_pvt_thread_rdwr_wunlock(&li->li_giant_rwlock);
+               if ( rootlock ) {
+                       /* release root lock */
+                       ldap_pvt_thread_mutex_unlock(&li->li_root_mutex);
+               }
 
 #ifdef NEW_LOGGING
                LDAP_LOG(( "backend", LDAP_LEVEL_ERR,
-                       "ldbm_back_add: next_id failed.\n" ));
+                          "ldbm_back_add: next_id failed.\n" ));
 #else
                Debug( LDAP_DEBUG_ANY, "ldbm_add: next_id failed\n",
                        0, 0, 0 );
 #endif
 
+
                send_ldap_result( conn, op, LDAP_OTHER,
                        NULL, "next_id add failed", NULL, NULL );
 
@@ -288,7 +303,10 @@ ldbm_back_add(
                        cache_return_entry_w( &li->li_cache, p ); 
                }
 
-               ldap_pvt_thread_rdwr_wunlock(&li->li_giant_rwlock);
+               if ( rootlock ) {
+                       /* release root lock */
+                       ldap_pvt_thread_mutex_unlock(&li->li_root_mutex);
+               }
 
 #ifdef NEW_LOGGING
                LDAP_LOG(( "backend", LDAP_LEVEL_ERR,
@@ -374,13 +392,16 @@ return_results:;
                cache_return_entry_w( &li->li_cache, p ); 
        }
 
+       if ( rootlock ) {
+               /* release root lock */
+               ldap_pvt_thread_mutex_unlock(&li->li_root_mutex);
+       }
+
        if ( rc ) {
                /* in case of error, writer lock is freed 
                 * and entry's private data is destroyed */
                cache_return_entry_w( &li->li_cache, e );
        }
 
-       ldap_pvt_thread_rdwr_wunlock(&li->li_giant_rwlock);
-
        return( rc );
 }
index c74d84c40864aa7c791a61e5fb3130182680ca56..a1072adc745446e60726a06da0a797a4e7b2fe14 100644 (file)
@@ -125,8 +125,10 @@ typedef struct ldbm_dbcache {
 #define MAXDBCACHE     128
 
 struct ldbminfo {
-       ldap_pvt_thread_rdwr_t          li_giant_rwlock;
        ID                      li_nextid;
+       ldap_pvt_thread_mutex_t         li_nextid_mutex;
+       ldap_pvt_thread_mutex_t         li_root_mutex;
+       ldap_pvt_thread_mutex_t         li_add_mutex;
        int                     li_mode;
        slap_mask_t     li_defaultmask;
        char                    *li_directory;
index ddadbad7b16a3b1db2eb334d7e834fb86e3f5a3b..a6ab1c5e2940830e1b5c70ba9254e65488016026 100644 (file)
@@ -50,10 +50,8 @@ ldbm_back_bind(
        Debug(LDAP_DEBUG_ARGS, "==> ldbm_back_bind: dn: %s\n", dn->bv_val, 0, 0);
 #endif
 
-       dn = ndn;
 
-       /* grab giant lock for reading */
-       ldap_pvt_thread_rdwr_rlock(&li->li_giant_rwlock);
+       dn = ndn;
 
        /* get entry with reader lock */
        if ( (e = dn2entry_r( be, dn, &matched )) == NULL ) {
@@ -74,8 +72,6 @@ ldbm_back_bind(
                                NULL, dn, LDAP_SCOPE_DEFAULT );
                }
 
-               ldap_pvt_thread_rdwr_runlock(&li->li_giant_rwlock);
-
                /* allow noauth binds */
                rc = 1;
                if ( method == LDAP_AUTH_SIMPLE ) {
@@ -267,7 +263,6 @@ ldbm_back_bind(
 return_results:;
        /* free entry and reader lock */
        cache_return_entry_r( &li->li_cache, e );
-       ldap_pvt_thread_rdwr_runlock(&li->li_giant_rwlock);
 
        /* front end with send result on success (rc==0) */
        return( rc );
index b5ca4f66186297bfba422f7d4e5cb24aa1ee18ea..b3494b4964fba9a26cb590330beb9d862e362005 100644 (file)
@@ -33,9 +33,6 @@ ldbm_back_compare(
        int             rc;
        int             manageDSAit = get_manageDSAit( op );
 
-       /* grab giant lock for reading */
-       ldap_pvt_thread_rdwr_rlock(&li->li_giant_rwlock);
-
        /* get entry with reader lock */
        if ( (e = dn2entry_r( be, ndn, &matched )) == NULL ) {
                char *matched_dn = NULL;
@@ -52,8 +49,6 @@ ldbm_back_compare(
                                NULL, dn, LDAP_SCOPE_DEFAULT );
                }
 
-               ldap_pvt_thread_rdwr_runlock(&li->li_giant_rwlock);
-
                send_ldap_result( conn, op, LDAP_REFERRAL,
                        matched_dn, NULL, refs, NULL );
 
@@ -120,6 +115,5 @@ ldbm_back_compare(
 
 return_results:;
        cache_return_entry_r( &li->li_cache, e );
-       ldap_pvt_thread_rdwr_runlock(&li->li_giant_rwlock);
        return( rc );
 }
index 874fe4f156775266ec034f63f02d6340dca56794..a3b5ebe902da0c235f43e810acdab39f74f43296 100644 (file)
@@ -29,6 +29,7 @@ ldbm_back_delete(
        Entry   *matched;
        struct berval   pdn;
        Entry   *e, *p = NULL;
+       int rootlock = 0;
        int     rc = -1;
        int             manageDSAit = get_manageDSAit( op );
        AttributeDescription *children = slap_schema.si_ad_children;
@@ -40,9 +41,6 @@ ldbm_back_delete(
        Debug(LDAP_DEBUG_ARGS, "==> ldbm_back_delete: %s\n", dn->bv_val, 0, 0);
 #endif
 
-       /* grab giant lock for writing */
-       ldap_pvt_thread_rdwr_wlock(&li->li_giant_rwlock);
-
        /* get entry with writer lock */
        if ( (e = dn2entry_w( be, ndn, &matched )) == NULL ) {
                char *matched_dn = NULL;
@@ -68,8 +66,6 @@ ldbm_back_delete(
                                NULL, dn, LDAP_SCOPE_DEFAULT );
                }
 
-               ldap_pvt_thread_rdwr_wunlock(&li->li_giant_rwlock);
-
                send_ldap_result( conn, op, LDAP_REFERRAL,
                        matched_dn, NULL, refs, NULL );
 
@@ -200,6 +196,9 @@ ldbm_back_delete(
                                goto return_results;
                        }
                }
+
+               ldap_pvt_thread_mutex_lock(&li->li_root_mutex);
+               rootlock = 1;
        }
 
        /* delete from dn2id mapping */
@@ -249,10 +248,13 @@ return_results:;
                cache_return_entry_w( &li->li_cache, p );
        }
 
+       if ( rootlock ) {
+               /* release root lock */
+               ldap_pvt_thread_mutex_unlock(&li->li_root_mutex);
+       }
+
        /* free entry and writer lock */
        cache_return_entry_w( &li->li_cache, e );
 
-       ldap_pvt_thread_rdwr_wunlock(&li->li_giant_rwlock);
-
        return rc;
 }
index f018d2b1299914b19202c46b3b838f02f503be48..28267e39fb658ccaa8d804c4e308461326954b22 100644 (file)
@@ -31,8 +31,8 @@ ldbm_back_entry_release_rw(
        if ( slapMode == SLAP_SERVER_MODE ) {
                /* free entry and reader or writer lock */
                cache_return_entry_rw( &li->li_cache, e, rw ); 
-
        } else {
+               
                entry_free( e );
        }
 
index 1c1af991f85eb234d1c2daf7ba0c8290c88322d1..1fe1335666f1de3fcd9f0662710ded8a981b3aca 100644 (file)
@@ -172,8 +172,10 @@ ldbm_back_db_init(
        li->li_dbshutdown = 0;
 
        /* initialize various mutex locks & condition variables */
-       ldap_pvt_thread_rdwr_init( &li->li_giant_rwlock );
+       ldap_pvt_thread_mutex_init( &li->li_root_mutex );
+       ldap_pvt_thread_mutex_init( &li->li_add_mutex );
        ldap_pvt_thread_mutex_init( &li->li_cache.c_mutex );
+       ldap_pvt_thread_mutex_init( &li->li_nextid_mutex );
        ldap_pvt_thread_mutex_init( &li->li_dbcache_mutex );
        ldap_pvt_thread_cond_init( &li->li_dbcache_cv );
 
@@ -223,8 +225,10 @@ ldbm_back_db_destroy(
        free( li->li_directory );
        attr_index_destroy( li->li_attrs );
 
-       ldap_pvt_thread_rdwr_destroy( &li->li_giant_rwlock );
+       ldap_pvt_thread_mutex_destroy( &li->li_root_mutex );
+       ldap_pvt_thread_mutex_destroy( &li->li_add_mutex );
        ldap_pvt_thread_mutex_destroy( &li->li_cache.c_mutex );
+       ldap_pvt_thread_mutex_destroy( &li->li_nextid_mutex );
        ldap_pvt_thread_mutex_destroy( &li->li_dbcache_mutex );
        ldap_pvt_thread_cond_destroy( &li->li_dbcache_cv );
 
index 6948d2ffd8d088e8e9a56fab030b90d9e2f0a88d..c7978238a2ee8575acb0b551345d6a6281121548 100644 (file)
@@ -297,8 +297,6 @@ ldbm_back_modify(
        Debug(LDAP_DEBUG_ARGS, "ldbm_back_modify:\n", 0, 0, 0);
 #endif
 
-       /* grab giant lock for writing */
-       ldap_pvt_thread_rdwr_wlock(&li->li_giant_rwlock);
 
        /* acquire and lock entry */
        if ( (e = dn2entry_w( be, ndn, &matched )) == NULL ) {
@@ -316,7 +314,6 @@ ldbm_back_modify(
                                NULL, dn, LDAP_SCOPE_DEFAULT );
                }
 
-               ldap_pvt_thread_rdwr_wunlock(&li->li_giant_rwlock);
                send_ldap_result( conn, op, LDAP_REFERRAL,
                        matched_dn, NULL, refs, NULL );
 
@@ -373,11 +370,9 @@ ldbm_back_modify(
                NULL, NULL, NULL, NULL );
 
        cache_return_entry_w( &li->li_cache, e );
-       ldap_pvt_thread_rdwr_wunlock(&li->li_giant_rwlock);
        return( 0 );
 
 error_return:;
        cache_return_entry_w( &li->li_cache, e );
-       ldap_pvt_thread_rdwr_wunlock(&li->li_giant_rwlock);
        return( -1 );
 }
index f2e2dfb6d6c603ecfc049b72d76a675ebc7bb2ed..195fa4d434f575c5e86171d73b6224481e492146 100644 (file)
@@ -88,9 +88,6 @@ ldbm_back_modrdn(
                        ? newSuperior->bv_val : "NULL", 0 );
 #endif
 
-       /* grab giant lock for writing */
-       ldap_pvt_thread_rdwr_wlock(&li->li_giant_rwlock);
-
        /* get entry with writer lock */
        if ( (e = dn2entry_w( be, ndn, &matched )) == NULL ) {
                char* matched_dn = NULL;
@@ -107,8 +104,6 @@ ldbm_back_modrdn(
                                NULL, dn, LDAP_SCOPE_DEFAULT );
                }
 
-               ldap_pvt_thread_rdwr_wunlock(&li->li_giant_rwlock);
-
                send_ldap_result( conn, op, LDAP_REFERRAL,
                        matched_dn, NULL, refs, NULL );
 
@@ -267,6 +262,9 @@ ldbm_back_modrdn(
                        }
                }
 
+               ldap_pvt_thread_mutex_lock(&li->li_root_mutex);
+               rootlock = 1;
+               
 #ifdef NEW_LOGGING
                LDAP_LOG(( "backend", LDAP_LEVEL_INFO,
                           "ldbm_back_modrdn: (%s) no parent, locked root.\n", e->e_dn ));
@@ -806,6 +804,11 @@ return_results:
                cache_return_entry_w( &li->li_cache, p );
        }
 
+       if ( rootlock ) {
+               /* release root writer lock */
+               ldap_pvt_thread_mutex_unlock(&li->li_root_mutex);
+       }
+
        /* free entry and writer lock */
        cache_return_entry_w( &li->li_cache, e );
        if ( rc == MUST_DESTROY ) {
@@ -814,6 +817,5 @@ return_results:
                 * the entry must be freed */
                entry_free( e );
        }
-       ldap_pvt_thread_rdwr_wunlock(&li->li_giant_rwlock);
        return( rc );
 }
index 80f6f0f61f89c022dde08a1817909b95dd57b94c..2bdcde3871fbde8ed402ec143a27e87f18f82bf6 100644 (file)
@@ -102,8 +102,11 @@ next_id_get( Backend *be, ID *idp )
 
        *idp = NOID;
 
+       ldap_pvt_thread_mutex_lock( &li->li_nextid_mutex );
+
        if ( li->li_nextid == NOID ) {
                if ( ( rc = next_id_read( be, idp ) ) ) {
+                       ldap_pvt_thread_mutex_unlock( &li->li_nextid_mutex );
                        return( rc );
                }
                li->li_nextid = *idp;
@@ -111,6 +114,7 @@ next_id_get( Backend *be, ID *idp )
 
        *idp = li->li_nextid;
 
+       ldap_pvt_thread_mutex_unlock( &li->li_nextid_mutex );
        return( rc );
 }
 
@@ -120,8 +124,11 @@ next_id( Backend *be, ID *idp )
        struct ldbminfo *li = (struct ldbminfo *) be->be_private;
        int rc = 0;
 
+       ldap_pvt_thread_mutex_lock( &li->li_nextid_mutex );
+
        if ( li->li_nextid == NOID ) {
                if ( ( rc = next_id_read( be, idp ) ) ) {
+                       ldap_pvt_thread_mutex_unlock( &li->li_nextid_mutex );
                        return( rc );
                }
                li->li_nextid = *idp;
@@ -132,5 +139,6 @@ next_id( Backend *be, ID *idp )
                rc = -1;
        }
 
+       ldap_pvt_thread_mutex_unlock( &li->li_nextid_mutex );
        return( rc );
 }
index 8ad0948f09fe06cf33e52c8dbf5b25eaa306db2a..1f04c48555825478fc4a93f205a8989bc5e9242f 100644 (file)
@@ -31,7 +31,7 @@ ldbm_back_exop_passwd(
 )
 {
        struct ldbminfo *li = (struct ldbminfo *) be->be_private;
-       int rc, locked=0;
+       int rc;
        Entry *e = NULL;
        struct berval hash = { 0, NULL };
 
@@ -108,12 +108,8 @@ ldbm_back_exop_passwd(
                goto done;
        }
 
-       /* grab giant lock for writing */
-       ldap_pvt_thread_rdwr_wlock(&li->li_giant_rwlock);
-
        e = dn2entry_w( be, &ndn, NULL );
        if( e == NULL ) {
-               ldap_pvt_thread_rdwr_wunlock(&li->li_giant_rwlock);
                *text = "could not locate authorization entry";
                rc = LDAP_NO_SUCH_OBJECT;
                goto done;
@@ -177,7 +173,6 @@ ldbm_back_exop_passwd(
 done:
        if( e != NULL ) {
                cache_return_entry_w( &li->li_cache, e );
-               ldap_pvt_thread_rdwr_wunlock(&li->li_giant_rwlock);
        }
 
        if( hash.bv_val != NULL ) {
index 48bb7886cc53017d2b837fb7d9d9a152cff52b2c..05d51e0919b2500f1afea47fb1601a944306d1d1 100644 (file)
@@ -38,9 +38,6 @@ ldbm_back_referrals(
                return rc;
        } 
 
-       /* grab giant lock for reading */
-       ldap_pvt_thread_rdwr_rlock(&li->li_giant_rwlock);
-
        /* get entry with reader lock */
        e = dn2entry_r( be, ndn, &matched );
        if ( e == NULL ) {
@@ -73,8 +70,6 @@ ldbm_back_referrals(
                                NULL, dn, LDAP_SCOPE_DEFAULT );
                }
 
-               ldap_pvt_thread_rdwr_runlock(&li->li_giant_rwlock);
-
                if( refs != NULL ) {
                        /* send referrals */
                        send_ldap_result( conn, op, rc = LDAP_REFERRAL,
@@ -122,7 +117,5 @@ ldbm_back_referrals(
        }
 
        cache_return_entry_r( &li->li_cache, e );
-       ldap_pvt_thread_rdwr_runlock(&li->li_giant_rwlock);
-
        return rc;
 }
index c61b921ac6e01982298ec4986d666f1b6171c1eb..c80359f8c6ecb6dcc141727faf659e340e6d1d7b 100644 (file)
@@ -64,8 +64,6 @@ ldbm_back_search(
        Debug(LDAP_DEBUG_TRACE, "=> ldbm_back_search\n", 0, 0, 0);
 #endif
 
-       /* grab giant lock for reading */
-       ldap_pvt_thread_rdwr_rlock(&li->li_giant_rwlock);
 
        if ( nbase->bv_len == 0 ) {
                /* DIT root special case */
@@ -118,8 +116,6 @@ ldbm_back_search(
                                NULL, base, scope );
                }
 
-               ldap_pvt_thread_rdwr_runlock(&li->li_giant_rwlock);
-
                send_ldap_result( conn, op, err, matched_dn.bv_val, 
                        text, refs, NULL );
 
@@ -139,7 +135,6 @@ ldbm_back_search(
                refs = NULL;
 
                cache_return_entry_r( &li->li_cache, e );
-               ldap_pvt_thread_rdwr_runlock(&li->li_giant_rwlock);
 
 #ifdef NEW_LOGGING
                LDAP_LOG(( "backend", LDAP_LEVEL_INFO,
@@ -511,8 +506,6 @@ loop_continue:
        rc = 0;
 
 done:
-       ldap_pvt_thread_rdwr_runlock(&li->li_giant_rwlock);
-
        if( candidates != NULL )
                idl_free( candidates );