diff options
Diffstat (limited to 'ldap/servers/slapd/back-ldbm/import-threads.c')
-rw-r--r-- | ldap/servers/slapd/back-ldbm/import-threads.c | 780 |
1 files changed, 747 insertions, 33 deletions
diff --git a/ldap/servers/slapd/back-ldbm/import-threads.c b/ldap/servers/slapd/back-ldbm/import-threads.c index 264eb90b..dcc44517 100644 --- a/ldap/servers/slapd/back-ldbm/import-threads.c +++ b/ldap/servers/slapd/back-ldbm/import-threads.c @@ -378,6 +378,7 @@ import_producer(void *param) ldif_context c; int my_version = 0; size_t newesize = 0; + Slapi_Attr *attr = NULL; PR_ASSERT(info != NULL); PR_ASSERT(inst != NULL); @@ -405,7 +406,6 @@ import_producer(void *param) * as we read it. */ while (! finished) { - Slapi_Attr *attr = NULL; int flags = 0; int prev_lineno = 0; int lines_in_entry = 0; @@ -586,7 +586,6 @@ import_producer(void *param) /* If we are importing pre-encrypted attributes, we need * to skip syntax checks for the encrypted values. */ if (!(job->encrypt) && inst->attrcrypt_configured) { - Slapi_Attr *attr = NULL; Slapi_Entry *e_copy = NULL; /* Scan through the entry to see if any present @@ -1042,6 +1041,7 @@ index_producer(void *param) rc = 0; /* assume this is a suffix */ } else { ID pid = (ID)strtol(pid_str, (char **)NULL, 10); + slapi_ch_free_string(&pid_str); /* if pid is larger than the current pid temp_id, * the parent entry hasn't */ rc = import_get_and_add_parent_rdns(info, inst, db, @@ -1123,6 +1123,593 @@ error: info->state = ABORTED; } +struct upgradedn_attr { + char *ud_type; + char *ud_value; + struct upgradedn_attr *ud_next; + int ud_flags; +#define OLD_DN_NORMALIZE 0x1 +}; + +static void +upgradedn_free_list(struct upgradedn_attr **ud_list) +{ + struct upgradedn_attr *ptr = *ud_list; + + while (ptr) { + struct upgradedn_attr *next = ptr->ud_next; + slapi_ch_free_string(&ptr->ud_type); + slapi_ch_free_string(&ptr->ud_value); + slapi_ch_free((void **)&ptr); + ptr = next; + } + *ud_list = NULL; + return; +} + +static void +upgradedn_add_to_list(struct upgradedn_attr **ud_list, + char *type, char *value, int flag) +{ + struct upgradedn_attr *elem = + (struct upgradedn_attr *) slapi_ch_malloc(sizeof(struct upgradedn_attr)); + elem->ud_type = type; + elem->ud_value = value; + elem->ud_flags = flag; + elem->ud_next = *ud_list; + *ud_list = elem; + return; +} + +/* + * Producer thread for upgrading dn format + * FLAG_UPGRADEDNFORMAT | FLAG_DRYRUN -- check the necessity of dn upgrade + * FLAG_UPGRADEDNFORMAT -- execute dn upgrade + * + * Read id2entry, + * Check the DN syntax attributes if it contains '\' or not AND + * Check the RDNs of the attributes if the value is surrounded by + * double-quotes or not. + * If both are false, skip the entry and go to next + * If either is true, create an entry which contains a correctly normalized + * DN attribute values in e_attr list and the original entrydn in the + * deleted attribute list e_deleted_attrs. + * + * If FLAG_UPGRADEDNFORMAT is set, worker_threads for indexing DN syntax + * attributes are brought up. Foreman thread updates entrydn index + * as well as the entry itself in the id2entry.db#. + * + * Note: QUIT state for info->state is introduced for DRYRUN mode to + * distinguish the intentional QUIT (found the dn upgrade candidate) + * from ABORTED (aborted or error) and FINISHED (scan all the entries + * and found no candidate to upgrade) + */ +void +upgradedn_producer(void *param) +{ + ImportWorkerInfo *info = (ImportWorkerInfo *)param; + ImportJob *job = info->job; + ID id = job->first_ID; + Slapi_Entry *e = NULL; + struct backentry *ep = NULL, *old_ep = NULL; + ldbm_instance *inst = job->inst; + PRIntervalTime sleeptime; + int finished = 0; + int idx; + int rc = 0; + Slapi_Attr *a = NULL; + Slapi_DN *sdn = NULL; + char *workdn = NULL; + int doit = 0; + int skipit = 0; + int isentrydn = 0; + Slapi_Value *value = NULL; + struct upgradedn_attr *ud_list = NULL; + char **ud_vals = NULL; + char **ud_valp = NULL; + struct upgradedn_attr *ud_ptr = NULL; + Slapi_Attr *ud_attr = NULL; + char *ecopy = NULL; + + /* vars for Berkeley DB */ + DB_ENV *env = NULL; + DB *db = NULL; + DBC *dbc = NULL; + DBT key = {0}; + DBT data = {0}; + int db_rval = -1; + backend *be = inst->inst_be; + int isfirst = 1; + int curr_entry = 0; + size_t newesize = 0; + + PR_ASSERT(info != NULL); + PR_ASSERT(inst != NULL); + PR_ASSERT(be != NULL); + + if ( job->flags & FLAG_ABORT ) + goto error; + + sleeptime = PR_MillisecondsToInterval(import_sleep_time); + + /* pause until we're told to run */ + while ((info->command == PAUSE) && !(job->flags & FLAG_ABORT)) { + info->state = WAITING; + DS_Sleep(sleeptime); + } + info->state = RUNNING; + + /* open id2entry with dedicated db env and db handler */ + if ( dblayer_get_aux_id2entry( be, &db, &env ) != 0 || db == NULL || + env == NULL) { + LDAPDebug( LDAP_DEBUG_ANY, "Could not open id2entry\n", 0, 0, 0 ); + goto error; + } + + /* get a cursor to we can walk over the table */ + db_rval = db->cursor(db, NULL, &dbc, 0); + if ( 0 != db_rval ) { + LDAPDebug( LDAP_DEBUG_ANY, + "Failed to get cursor for reindexing\n", 0, 0, 0 ); + dblayer_release_id2entry(be, db); + goto error; + } + + /* we loop around reading the input files and processing each entry + * as we read it. + */ + finished = 0; + while (!finished) { + ID temp_id; + + if (job->flags & FLAG_ABORT) { + goto error; + } + while ((info->command == PAUSE) && !(job->flags & FLAG_ABORT)){ + info->state = WAITING; + DS_Sleep(sleeptime); + } + info->state = RUNNING; + + key.flags = DB_DBT_MALLOC; + data.flags = DB_DBT_MALLOC; + if (isfirst) + { + db_rval = dbc->c_get(dbc, &key, &data, DB_FIRST); + isfirst = 0; + } + else + { + db_rval = dbc->c_get(dbc, &key, &data, DB_NEXT); + } + + if (0 != db_rval) { + if (DB_NOTFOUND != db_rval) { + LDAPDebug(LDAP_DEBUG_ANY, "%s: Failed to read database, " + "errno=%d (%s)\n", inst->inst_name, db_rval, + dblayer_strerror(db_rval)); + if (job->task) { + slapi_task_log_notice(job->task, + "%s: Failed to read database, err %d (%s)", + inst->inst_name, db_rval, + dblayer_strerror(db_rval)); + } + } + finished = 1; + break; /* error or done */ + } + curr_entry++; + temp_id = id_stored_to_internal((char *)key.data); + slapi_ch_free(&(key.data)); + + /* call post-entry plugin */ + plugin_call_entryfetch_plugins((char **)&data.dptr, &data.dsize); + ecopy = (char *)slapi_ch_malloc(data.dsize + 1); + memcpy(ecopy, data.dptr, data.dsize); + *(ecopy + data.dsize) = '\0'; + if (entryrdn_get_switch()) { + char *rdn = NULL; + + /* rdn is allocated in get_value_from_string */ + rc = get_value_from_string((const char *)data.dptr, "rdn", &rdn); + if (rc) { + /* data.dptr may not include rdn: ..., try "dn: ..." */ + e = slapi_str2entry( data.dptr, 0 ); + } else { + char *dn = NULL; + struct backdn *bdn = + dncache_find_id(&inst->inst_dncache, temp_id); + if (bdn) { + /* don't free dn */ + dn = (char *)slapi_sdn_get_dn(bdn->dn_sdn); + CACHE_RETURN(&inst->inst_dncache, &bdn); + } else { + Slapi_DN *sdn = NULL; + rc = entryrdn_lookup_dn(be, rdn, temp_id, &dn, NULL); + if (rc) { + /* We cannot use the entryrdn index; + * Compose dn from the entries in id2entry */ + Slapi_RDN psrdn = {0}; + char *pid_str = NULL; + char *pdn = NULL; + + LDAPDebug2Args( LDAP_DEBUG_TRACE, + "index_producer: entryrdn is not available; " + "composing dn (rdn: %s, ID: %d)\n", + rdn, temp_id); + rc = get_value_from_string((const char *)data.dptr, + LDBM_PARENTID_STR, &pid_str); + if (rc) { + rc = 0; /* assume this is a suffix */ + } else { + ID pid = (ID)strtol(pid_str, (char **)NULL, 10); + slapi_ch_free_string(&pid_str); + /* if pid is larger than the current pid temp_id, + * the parent entry hasn't */ + rc = import_get_and_add_parent_rdns(info, inst, db, + pid, &id, &psrdn, &curr_entry); + if (rc) { + LDAPDebug2Args( LDAP_DEBUG_ANY, + "ldbm2index: Failed to compose dn for " + "(rdn: %s, ID: %d)\n", rdn, temp_id); + slapi_ch_free_string(&rdn); + slapi_rdn_done(&psrdn); + continue; + } + /* Generate DN string from Slapi_RDN */ + rc = slapi_rdn_get_dn(&psrdn, &pdn); + slapi_rdn_done(&psrdn); + if (rc) { + LDAPDebug2Args( LDAP_DEBUG_ANY, + "ldbm2index: Failed to compose dn for " + "(rdn: %s, ID: %d) from Slapi_RDN\n", + rdn, temp_id); + slapi_ch_free_string(&rdn); + continue; + } + } + dn = slapi_ch_smprintf("%s%s%s", + rdn, pdn?",":"", pdn?pdn:""); + slapi_ch_free_string(&pdn); + } + /* dn is not dup'ed in slapi_sdn_new_dn_byref. + * It's set to bdn and put in the dn cache. */ + sdn = slapi_sdn_new_dn_byref(dn); + bdn = backdn_init(sdn, temp_id, 0); + CACHE_ADD( &inst->inst_dncache, bdn, NULL ); + CACHE_RETURN(&inst->inst_dncache, &bdn); + slapi_log_error(SLAPI_LOG_CACHE, "ldbm2index", + "entryrdn_lookup_dn returned: %s, " + "and set to dn cache\n", dn); + } + e = slapi_str2entry_ext( dn, data.dptr, 0 ); + slapi_ch_free_string(&rdn); + } + } else { + e = slapi_str2entry(data.data, 0); + } + slapi_ch_free(&(data.data)); + if ( NULL == e ) { + if (job->task) { + slapi_task_log_notice(job->task, + "%s: WARNING: skipping badly formatted entry (id %lu)", + inst->inst_name, (u_long)temp_id); + } + LDAPDebug(LDAP_DEBUG_ANY, + "%s: WARNING: skipping badly formatted entry (id %lu)\n", + inst->inst_name, (u_long)temp_id, 0); + continue; + } + + /* Check DN syntax attr values if it contains '\\' or not */ + /* Start from the rdn */ + if (entryrdn_get_switch()) { /* subtree-rename: on */ + char *rdn = NULL; + size_t rdnlen = 0; + rc = get_value_from_string((const char *)ecopy, "rdn", &rdn); + if (rc || (NULL == rdn)) { + LDAPDebug2Args(LDAP_DEBUG_ANY, + "%s: WARNING: skipping an entry with no RDN (id %lu)\n", + inst->inst_name, (u_long)temp_id); + continue; + } + + /* rdn contains '\\'. We have to update the value */ + if (PL_strchr(rdn, '\\')) { + upgradedn_add_to_list(&ud_list, + slapi_ch_strdup(LDBM_ENTRYRDN_STR), + slapi_ch_strdup(rdn), 0); + LDAPDebug(LDAP_DEBUG_TRACE, + "%s: Found upgradedn candidate: %s (id %lu)\n", + inst->inst_name, *ud_valp, (u_long)temp_id); + doit = 1; + } else { + rdnlen = strlen(rdn); + /* DN contains an RDN <type>="<value>" ? */ + if (('"' == *rdn) && + ('"' == *(rdn + rdnlen - 1))) { + upgradedn_add_to_list(&ud_list, + slapi_ch_strdup(LDBM_ENTRYRDN_STR), + slapi_ch_strdup(rdn), 0); + LDAPDebug(LDAP_DEBUG_TRACE, + "%s: Found upgradedn candidate: %s (id %lu)\n", + inst->inst_name, rdn, (u_long)temp_id); + doit = 1; + } + } + slapi_ch_free_string(&rdn); + } + for (a = e->e_attrs; a; a = a->a_next) { + if (slapi_attr_is_dn_syntax_attr(a)) { /* is dn syntax attr? */ + rc = get_values_from_string((const char *)ecopy, + a->a_type, &ud_vals); + if (rc || (NULL == ud_vals)) { + continue; /* empty; ignore it */ + } + + for (ud_valp = ud_vals; ud_valp && *ud_valp; ud_valp++) { + char **rdns = NULL; + char **rdnsp = NULL; + char *valueptr = NULL; + int valuelen; + + /* ud_valp contains '\\'. We have to update the value */ + if (PL_strchr(*ud_valp, '\\')) { + upgradedn_add_to_list(&ud_list, + slapi_ch_strdup(a->a_type), + slapi_ch_strdup(*ud_valp), + 0); + LDAPDebug(LDAP_DEBUG_TRACE, + "%s: Found upgradedn candidate: %s (id %lu)\n", + inst->inst_name, *ud_valp, (u_long)temp_id); + doit = 1; + continue; + } + /* Also check RDN contains double quoted values */ + if (strcasecmp(a->a_type, "entrydn")) { + /* except entrydn */ + workdn = slapi_ch_strdup(*ud_valp); + isentrydn = 0; + } else { + /* entrydn: Get Slapi DN */ + sdn = slapi_entry_get_sdn(e); + workdn = slapi_ch_strdup(slapi_sdn_get_dn(sdn)); + isentrydn = 1; + } + rdns = ldap_explode_dn(workdn, 0); + skipit = 0; + for (rdnsp = rdns; rdnsp && *rdnsp; rdnsp++) { + valueptr = PL_strchr(*rdnsp, '='); + if (NULL == valueptr) { + skipit = 1; + break; + } + valueptr++; + while ((' ' == *valueptr) || ('\t' == *valueptr)) { + valueptr++; + } + valuelen = strlen(valueptr); + if (0 == valuelen) { + skipit = 1; + break; + } + /* DN contains an RDN <type>="<value>" ? */ + if (('"' == *valueptr) && + ('"' == *(valueptr + valuelen - 1))) { + upgradedn_add_to_list(&ud_list, + slapi_ch_strdup(a->a_type), + slapi_ch_strdup(*ud_valp), + isentrydn?0:OLD_DN_NORMALIZE); + LDAPDebug(LDAP_DEBUG_TRACE, + "%s: Found upgradedn candidate: %s (id %lu)\n", + inst->inst_name, valueptr, (u_long)temp_id); + doit = 1; + break; + } + } + if (rdns) { + slapi_ldap_value_free(rdns); + } else { + skipit = 1; + } + if (skipit) { + break; + } + slapi_ch_free_string(&workdn); + } /* for (ud_valp = ud_vals; ud_valp && *ud_valp; ud_valp++) */ + charray_free(ud_vals); + ud_vals = NULL; + if (skipit) { + LDAPDebug(LDAP_DEBUG_ANY, "%s: WARNING: skipping an entry " + "with a corrupted dn (syntax value): %s " + "(id %lu)\n", + inst->inst_name, + workdn?workdn:"unknown", (u_long)temp_id); + slapi_ch_free_string(&workdn); + upgradedn_free_list(&ud_list); + break; + } + } /* if (slapi_attr_is_dn_syntax_attr(a)) */ + } /* for (a = e->e_attrs; a; a = a->a_next) */ + slapi_ch_free_string(&ecopy); + if (skipit) { + upgradedn_free_list(&ud_list); + slapi_entry_free(e); e = NULL; + continue; + } + + if (!doit) { + /* We don't have to update dn syntax values. */ + upgradedn_free_list(&ud_list); + slapi_entry_free(e); e = NULL; + continue; + } + + /* doit */ + if (job->flags & FLAG_DRYRUN) { + /* We can return SUCCESS (== found upgrade dn candidates) */ + finished = 0; /* make it sure ... */ + upgradedn_free_list(&ud_list); + slapi_entry_free(e); e = NULL; + goto bail; + } + + skipit = 0; + for (ud_ptr = ud_list; ud_ptr; ud_ptr = ud_ptr->ud_next) { + /* Move the current value to e_deleted_attrs. */ + /* entryrdn is special since it does not have an attribute in db */ + if (0 == strcmp(ud_ptr->ud_type, LDBM_ENTRYRDN_STR)) { + /* entrydn contains half normalized value in id2entry, + thus we have to replace it in id2entry. + The other DN syntax attribute values store + the originals. They are taken care by the normalizer. + */ + a = slapi_attr_new(); + slapi_attr_init(a, ud_ptr->ud_type); + value = slapi_value_new_string(ud_ptr->ud_value); + slapi_attr_add_value(a, value); + slapi_value_free(&value); + attrlist_add(&e->e_deleted_attrs, a); + } else { /* except "entryrdn" */ + ud_attr = attrlist_find(e->e_attrs, ud_ptr->ud_type); + if (ud_attr) { + /* We have to normalize the orignal string to generate + the key in the index. + */ + a = attrlist_find(e->e_deleted_attrs, ud_ptr->ud_type); + if (!a) { + a = slapi_attr_new(); + slapi_attr_init(a, ud_ptr->ud_type); + } else { + a = attrlist_remove(&e->e_deleted_attrs, + ud_ptr->ud_type); + } + slapi_dn_normalize_case_original(ud_ptr->ud_value); + value = slapi_value_new_string(ud_ptr->ud_value); + slapi_attr_add_value(a, value); + slapi_value_free(&value); + attrlist_add(&e->e_deleted_attrs, a); + } + } + } + upgradedn_free_list(&ud_list); + if (skipit) { + slapi_entry_free(e); e = NULL; + continue; + } + + ep = import_make_backentry(e, temp_id); + if (!ep) { + slapi_entry_free(e); e = NULL; + goto error; + } + + /* Add the newly case-normalized dn to entrydn in the e_attrs list. */ + add_update_entrydn_operational_attributes(ep); + + if (job->flags & FLAG_ABORT) + goto error; + + /* Now we have this new entry, all decoded + * Next thing we need to do is: + * (1) see if the appropriate fifo location contains an + * entry which had been processed by the indexers. + * If so, proceed. + * If not, spin waiting for it to become free. + * (2) free the old entry and store the new one there. + * (3) Update the job progress indicators so the indexers + * can use the new entry. + */ + idx = id % job->fifo.size; + old_ep = job->fifo.item[idx].entry; + if (old_ep) { + /* for the slot to be recycled, it needs to be already absorbed + * by the foreman (id >= ready_EID), and all the workers need to + * be finished with it (refcount = 0). + */ + while (((old_ep->ep_refcnt > 0) || + (old_ep->ep_id >= job->ready_EID)) + && (info->command != ABORT) && !(job->flags & FLAG_ABORT)) { + info->state = WAITING; + DS_Sleep(sleeptime); + } + if (job->flags & FLAG_ABORT) + goto error; + + info->state = RUNNING; + PR_ASSERT(old_ep == job->fifo.item[idx].entry); + job->fifo.item[idx].entry = NULL; + if (job->fifo.c_bsize > job->fifo.item[idx].esize) + job->fifo.c_bsize -= job->fifo.item[idx].esize; + else + job->fifo.c_bsize = 0; + backentry_free(&old_ep); + } + + newesize = (slapi_entry_size(ep->ep_entry) + sizeof(struct backentry)); + if (newesize > job->fifo.bsize) { /* entry too big */ + char ebuf[BUFSIZ]; + import_log_notice(job, "WARNING: skipping entry \"%s\"", + escape_string(slapi_entry_get_dn(e), ebuf)); + import_log_notice(job, "REASON: entry too large (%lu bytes) for " + "the buffer size (%lu bytes)", newesize, job->fifo.bsize); + backentry_free(&ep); + job->skipped++; + continue; + } + /* Now check if fifo has enough space for the new entry */ + if ((job->fifo.c_bsize + newesize) > job->fifo.bsize) { + import_wait_for_space_in_fifo( job, newesize ); + } + + /* We have enough space */ + job->fifo.item[idx].filename = ID2ENTRY LDBM_FILENAME_SUFFIX; + job->fifo.item[idx].line = curr_entry; + job->fifo.item[idx].entry = ep; + job->fifo.item[idx].bad = 0; + job->fifo.item[idx].esize = newesize; + + /* Add the entry size to total fifo size */ + job->fifo.c_bsize += ep->ep_entry? job->fifo.item[idx].esize : 0; + + /* Update the job to show our progress */ + job->lead_ID = id; + if ((id - info->first_ID) <= job->fifo.size) { + job->trailing_ID = info->first_ID; + } else { + job->trailing_ID = id - job->fifo.size; + } + + /* Update our progress meter too */ + info->last_ID_processed = id; + id++; + if (job->flags & FLAG_ABORT) + goto error; + if (info->command == STOP) + { + finished = 1; + } + } +bail: + dbc->c_close(dbc); + dblayer_release_aux_id2entry( be, db, env ); + if (job->flags & FLAG_DRYRUN) { + if (finished) { /* Set if dn upgrade candidates are not found */ + info->state = FINISHED; + } else { /* At least one dn upgrade candidate is found */ + info->state = QUIT; + } + } else { + info->state = FINISHED; + } + return; + +error: + dbc->c_close(dbc); + dblayer_release_aux_id2entry( be, db, env ); + info->state = ABORTED; +} + static void import_wait_for_space_in_fifo(ImportJob *job, size_t new_esize) { @@ -1198,6 +1785,39 @@ foreman_do_entrydn(ImportJob *job, FifoItem *fi) int err = 0, ret = 0; IDList *IDL; + if (job->flags & FLAG_UPGRADEDNFORMAT) { + /* Get the entrydn attribute value from deleted attr list */ + Slapi_Value *value = NULL; + Slapi_Attr *entrydn_to_del = + attrlist_remove(&fi->entry->ep_entry->e_deleted_attrs, "entrydn"); + + if (entrydn_to_del) { + /* Delete it. */ + ret = slapi_attr_first_value(entrydn_to_del, &value); + if (ret < 0) { + import_log_notice(job, + "Error: retrieving entrydn value (error %d)", + ret); + } else { + const struct berval *bval = + slapi_value_get_berval((const Slapi_Value *)value); + ret = index_addordel_string(be, "entrydn", + bval->bv_val, + fi->entry->ep_id, + BE_INDEX_DEL|BE_INDEX_EQUALITY|BE_INDEX_NORMALIZED, + NULL); + if (ret) { + import_log_notice(job, + "Error: deleting %s from entrydn index " + "(error %d: %s)", + bval->bv_val, ret, dblayer_strerror(ret)); + return ret; + } + } + slapi_attr_free(&entrydn_to_del); + } + } + /* insert into the entrydn index */ bv.bv_val = (void*)backentry_get_ndn(fi->entry); /* jcm - Had to cast away const */ bv.bv_len = strlen(bv.bv_val); @@ -1210,29 +1830,49 @@ foreman_do_entrydn(ImportJob *job, FifoItem *fi) /* So, we do an index read first */ err = 0; IDL = index_read(be, LDBM_ENTRYDN_STR, indextype_EQUALITY, &bv, NULL, &err); - - /* Did this work ? */ - if (NULL != IDL) { - /* IMPOSTER ! Get thee hence... */ - import_log_notice(job, "WARNING: Skipping duplicate entry " - "\"%s\" found at line %d of file \"%s\"", - slapi_entry_get_dn(fi->entry->ep_entry), - fi->line, fi->filename); - idl_free(IDL); - /* skip this one */ - fi->bad = 1; - job->skipped++; - return -1; /* skip to next entry */ - } - if ((ret = index_addordel_string(be, LDBM_ENTRYDN_STR, - bv.bv_val, - fi->entry->ep_id, - BE_INDEX_ADD|BE_INDEX_NORMALIZED, NULL)) != 0) { - import_log_notice(job, "Error writing entrydn index " - "(error %d: %s)", - ret, dblayer_strerror(ret)); - return ret; + if (job->flags & FLAG_UPGRADEDNFORMAT) { + /* + * In the UPGRADEDNFORMAT case, if entrydn value exists, + * that means entrydn is not upgraded. And it is normal. + * We could add entrydn only when the value is not found in the db. + */ + if (IDL) { + idl_free(IDL); + } else { + ret = index_addordel_string(be, "entrydn", + bv.bv_val, fi->entry->ep_id, + BE_INDEX_ADD|BE_INDEX_NORMALIZED, NULL); + if (ret) { + import_log_notice(job, "Error writing entrydn index " + "(error %d: %s)", + ret, dblayer_strerror(ret)); + return ret; + } + } + } else { + /* Did this work ? */ + if (IDL) { + /* IMPOSTER ! Get thee hence... */ + import_log_notice(job, "WARNING: Skipping duplicate entry " + "\"%s\" found at line %d of file \"%s\"", + slapi_entry_get_dn(fi->entry->ep_entry), + fi->line, fi->filename); + idl_free(IDL); + /* skip this one */ + fi->bad = 1; + job->skipped++; + return -1; /* skip to next entry */ + } + ret = index_addordel_string(be, "entrydn", bv.bv_val, fi->entry->ep_id, + BE_INDEX_ADD|BE_INDEX_NORMALIZED, NULL); + if (ret) { + import_log_notice(job, "Error writing entrydn index " + "(error %d: %s)", + ret, dblayer_strerror(ret)); + return ret; + } } + return 0; } @@ -1243,6 +1883,34 @@ foreman_do_entryrdn(ImportJob *job, FifoItem *fi) backend *be = job->inst->inst_be; int ret = 0; + if (job->flags & FLAG_UPGRADEDNFORMAT) { + /* Get the entrydn attribute value from deleted attr list */ + Slapi_Value *value = NULL; + Slapi_Attr *entryrdn_to_del = NULL; + entryrdn_to_del = attrlist_remove(&fi->entry->ep_entry->e_deleted_attrs, + LDBM_ENTRYRDN_STR); + if (entryrdn_to_del) { + /* Delete it. */ + ret = slapi_attr_first_value(entryrdn_to_del, &value); + if (ret < 0) { + import_log_notice(job, + "Error: retrieving entryrdn value (error %d)", + ret); + } else { + const struct berval *bval = + slapi_value_get_berval((const Slapi_Value *)value); + ret = entryrdn_index_entry(be, fi->entry, BE_INDEX_DEL, NULL); + if (ret) { + import_log_notice(job, + "Error: deleting %s from entrydn index " + "(error %d: %s)", + bval->bv_val, ret, dblayer_strerror(ret)); + return ret; + } + } + slapi_attr_free(&entryrdn_to_del); + } + } if ((ret = entryrdn_index_entry(be, fi->entry, BE_INDEX_ADD, NULL)) != 0) { import_log_notice(job, "Error writing entryrdn index " "(error %d: %s)", @@ -1294,7 +1962,8 @@ import_foreman(void *param) } while ( ((info->command == PAUSE) || (id > job->lead_ID)) && - (info->command != STOP) && (info->command != ABORT) && !(job->flags & FLAG_ABORT)) { + (info->command != STOP) && (info->command != ABORT) && + !(job->flags & FLAG_ABORT) ) { /* Check to see if we've been told to stop */ info->state = WAITING; DS_Sleep(sleeptime); @@ -1335,9 +2004,9 @@ import_foreman(void *param) * Only check for a parent and add to the entry2dn index if * the entry is not a tombstone. */ - if (job->flags & FLAG_ABORT) { - goto error; - } + if (job->flags & FLAG_ABORT) { + goto error; + } if (parent_status == IMPORT_ADD_OP_ATTRS_NO_PARENT) { /* If this entry is a suffix entry, this is not a problem */ @@ -1386,6 +2055,9 @@ import_foreman(void *param) * (that isn't really an index -- it's the storehouse of the entries * themselves.) */ + /* id2entry_add_ext replaces an entry if it already exists. + * therefore, the Entry ID stays the same. + */ ret = id2entry_add_ext(be, fi->entry, NULL, job->encrypt); if (ret) { /* DB_RUNRECOVERY usually occurs if disk fills */ @@ -1412,7 +2084,10 @@ import_foreman(void *param) goto error; } - if (! slapi_entry_flag_is_set(fi->entry->ep_entry, + if (!(job->flags & FLAG_UPGRADEDNFORMAT) && /* Upgrade dn format mode + does not need to update + parentid index */ + !slapi_entry_flag_is_set(fi->entry->ep_entry, SLAPI_ENTRY_FLAG_TOMBSTONE)) { /* parentid index * (we have to do this here, because the parentID is dependent on @@ -1427,9 +2102,9 @@ import_foreman(void *param) vlv code to see whether it's within the scope a VLV index. */ vlv_grok_new_import_entry(fi->entry, be); } - if (job->flags & FLAG_ABORT) { - goto error; - } + if (job->flags & FLAG_ABORT) { + goto error; + } /* Remove the entry from the cache (Put in the cache in id2entry_add) */ @@ -1547,7 +2222,8 @@ import_worker(void *param) * thread, and the state is neither STOP nor ABORT */ while (((info->command == PAUSE) || (id > job->ready_ID)) && - (info->command != STOP) && (info->command != ABORT) && !(job->flags & FLAG_ABORT)) { + (info->command != STOP) && (info->command != ABORT) && + !(job->flags & FLAG_ABORT)) { /* Check to see if we've been told to stop */ info->state = WAITING; DS_Sleep(sleeptime); @@ -1594,6 +2270,43 @@ import_worker(void *param) slapi_pblock_destroy(pb); } else { /* No, process regular index */ + if (job->flags & FLAG_UPGRADEDNFORMAT) { + /* Get the attribute value from deleted attr list */ + Slapi_Value *value = NULL; + const struct berval *bval = NULL; + Slapi_Attr *key_to_del = + attrlist_remove(&fi->entry->ep_entry->e_deleted_attrs, + info->index_info->name); + + if (key_to_del) { + int idx = 0; + /* Delete it. */ + for (idx = slapi_attr_first_value(key_to_del, &value); + idx >= 0; + idx = slapi_attr_next_value(key_to_del, idx, + &value)) { + bval = + slapi_value_get_berval((const Slapi_Value *)value); + ret = index_addordel_string(be, + info->index_info->name, + bval->bv_val, + fi->entry->ep_id, + BE_INDEX_DEL|BE_INDEX_EQUALITY| + BE_INDEX_NORMALIZED, + NULL); + if (ret) { + import_log_notice(job, + "Error deleting %s from %s index " + "(error %d: %s)", + bval->bv_val, info->index_info->name, + ret, dblayer_strerror(ret)); + goto error; + } + } + slapi_attr_free(&key_to_del); + } + } + /* Look for the attribute we're indexing and its subtypes */ /* For each attr write to the index */ attrlist_cursor = NULL; @@ -2488,6 +3201,7 @@ import_get_and_add_parent_rdns(ImportWorkerInfo *info, rc = 0; /* assume this is a suffix */ } else { ID pid = (ID)strtol(pid_str, (char **)NULL, 10); + slapi_ch_free_string(&pid_str); rc = import_get_and_add_parent_rdns(info, inst, db, pid, total_id, &mysrdn, curr_entry); if (rc) { |