static void gncCustomerFree (GncCustomer *cust) { if (!cust) return; qof_event_gen (&cust->inst, QOF_EVENT_DESTROY, NULL); CACHE_REMOVE (cust->id); CACHE_REMOVE (cust->name); CACHE_REMOVE (cust->notes); gncAddressBeginEdit (cust->addr); gncAddressDestroy (cust->addr); gncAddressBeginEdit (cust->shipaddr); gncAddressDestroy (cust->shipaddr); g_list_free (cust->jobs); if (cust->terms) gncBillTermDecRef (cust->terms); if (cust->taxtable) { gncTaxTableDecRef (cust->taxtable); } /* qof_instance_release (&cust->inst); */ g_object_unref (cust); }
static void gncJobFree (GncJob *job) { if (!job) return; qof_event_gen (&job->inst, QOF_EVENT_DESTROY, NULL); CACHE_REMOVE (job->id); CACHE_REMOVE (job->name); CACHE_REMOVE (job->desc); switch (gncOwnerGetType (&(job->owner))) { case GNC_OWNER_CUSTOMER: gncCustomerRemoveJob (gncOwnerGetCustomer(&job->owner), job); break; case GNC_OWNER_VENDOR: gncVendorRemoveJob (gncOwnerGetVendor(&job->owner), job); break; default: break; } /* qof_instance_release (&job->inst); */ g_object_unref (job); }
static void gncBillTermFree (GncBillTerm *term) { GncBillTerm *child; GList *list; if (!term) return; qof_event_gen (&term->inst, QOF_EVENT_DESTROY, NULL); CACHE_REMOVE (term->name); CACHE_REMOVE (term->desc); remObj (term); if (!qof_instance_get_destroying(term)) PERR("free a billterm without do_free set!"); /* disconnect from parent */ if (term->parent) gncBillTermRemoveChild(term->parent, term); /* disconnect from the children */ for (list = term->children; list; list = list->next) { child = list->data; gncBillTermSetParent(child, NULL); } g_list_free(term->children); /* qof_instance_release(&term->inst); */ g_object_unref (term); }
static void gncEmployeeFree (GncEmployee *employee) { if (!employee) return; qof_event_gen (&employee->inst, QOF_EVENT_DESTROY, NULL); CACHE_REMOVE (employee->id); CACHE_REMOVE (employee->username); CACHE_REMOVE (employee->language); CACHE_REMOVE (employee->acl); gncAddressBeginEdit (employee->addr); gncAddressDestroy (employee->addr); /* qof_instance_release (&employee->inst); */ g_object_unref (employee); }
static void gncTaxTableFree (GncTaxTable *table) { GList *list; GncTaxTable *child; if (!table) return; qof_event_gen (&table->inst, QOF_EVENT_DESTROY, NULL); CACHE_REMOVE (table->name); remObj (table); /* destroy the list of entries */ for (list = table->entries; list; list = list->next) gncTaxTableEntryDestroy (list->data); g_list_free (table->entries); if (!qof_instance_get_destroying(table)) PERR("free a taxtable without do_free set!"); /* disconnect from parent */ if (table->parent) gncTaxTableRemoveChild(table->parent, table); /* disconnect from the children */ for (list = table->children; list; list = list->next) { child = list->data; gncTaxTableSetParent(child, NULL); } g_list_free(table->children); /* qof_instance_release (&table->inst); */ g_object_unref (table); }
int main(){ struct cache_manager *lru_manager; int i; lru_init(&lru_manager,"LRU", 500, 500, 1, 0); for(i =0;i < 1000000;i++){ struct lru_node *ln = NULL; unsigned int blkno = RND(10000); ln = CACHE_SEARCH(lru_manager, blkno); if(!ln){ ln = CACHE_REPLACE(lru_manager, 0, FCL_REPLACE_ANY); ln = CACHE_ALLOC(lru_manager, ln, blkno); CACHE_INSERT(lru_manager, ln); }else{ ln = CACHE_REMOVE(lru_manager, ln); CACHE_INSERT(lru_manager, ln); } } CACHE_PRINT(lru_manager, stdout); CACHE_CLOSE(lru_manager); return 0; }
static void gncEntryFree (GncEntry *entry) { if (!entry) return; qof_event_gen (&entry->inst, QOF_EVENT_DESTROY, NULL); CACHE_REMOVE (entry->desc); CACHE_REMOVE (entry->action); CACHE_REMOVE (entry->notes); if (entry->i_tax_values) gncAccountValueDestroy (entry->i_tax_values); if (entry->b_tax_values) gncAccountValueDestroy (entry->b_tax_values); if (entry->i_tax_table) gncTaxTableDecRef (entry->i_tax_table); if (entry->b_tax_table) gncTaxTableDecRef (entry->b_tax_table); /* qof_instance_release (&entry->inst); */ g_object_unref (entry); }
void gnc_quickfill_purge (QuickFill *qf) { if (qf == NULL) return; g_hash_table_foreach_remove (qf->matches, destroy_helper, NULL); if (qf->text) CACHE_REMOVE (qf->text); qf->text = NULL; qf->len = 0; }
static void qof_instance_dispose (GObject *instp) { QofInstancePrivate *priv; QofInstance* inst = QOF_INSTANCE(instp); priv = GET_PRIVATE(instp); if (!priv->collection) return; qof_collection_remove_entity(inst); CACHE_REMOVE(inst->e_type); inst->e_type = NULL; G_OBJECT_CLASS(qof_instance_parent_class)->dispose(instp); }
void gnc_quickfill_destroy (QuickFill *qf) { if (qf == NULL) return; g_hash_table_foreach (qf->matches, (GHFunc)destroy_helper, NULL); g_hash_table_destroy (qf->matches); qf->matches = NULL; if (qf->text) CACHE_REMOVE(qf->text); qf->text = NULL; qf->len = 0; g_free (qf); }
static void gncAddressFree (GncAddress *addr) { if (!addr) return; qof_event_gen (&addr->inst, QOF_EVENT_DESTROY, NULL); CACHE_REMOVE (addr->name); CACHE_REMOVE (addr->addr1); CACHE_REMOVE (addr->addr2); CACHE_REMOVE (addr->addr3); CACHE_REMOVE (addr->addr4); CACHE_REMOVE (addr->phone); CACHE_REMOVE (addr->fax); CACHE_REMOVE (addr->email); /* qof_instance_release (&addr->inst); */ g_object_unref (addr); }
static void gnc_quickfill_remove_recursive (QuickFill *qf, const gchar *text, gint depth, QuickFillSort sort) { QuickFill *match_qf; gchar *child_text; gint child_len; child_text = NULL; child_len = 0; if (depth < g_utf8_strlen (text, -1)) { /* process next letter */ gchar *key_char; gunichar key_char_uc; guint key; key_char = g_utf8_offset_to_pointer (text, depth); key_char_uc = g_utf8_get_char (key_char); key = g_unichar_toupper (key_char_uc); match_qf = g_hash_table_lookup (qf->matches, GUINT_TO_POINTER (key)); if (match_qf) { /* remove text from child qf */ gnc_quickfill_remove_recursive (match_qf, text, depth + 1, sort); if (match_qf->text == NULL) { /* text was the only word with a prefix up to match_qf */ g_hash_table_remove (qf->matches, GUINT_TO_POINTER (key)); gnc_quickfill_destroy (match_qf); } else { /* remember remaining best child string */ child_text = match_qf->text; child_len = match_qf->len; } } } if (qf->text == NULL) return; if (strcmp (text, qf->text) == 0) { /* the currently best text is about to be removed */ gchar *best_text = NULL; gint best_len = 0; if (child_text != NULL) { /* other children are pretty good as well */ best_text = child_text; best_len = child_len; } else { if (g_hash_table_size (qf->matches) != 0) { /* otherwise search for another good text */ struct _BestText bts; bts.text = NULL; bts.sort = sort; g_hash_table_foreach (qf->matches, (GHFunc) best_text_helper, &bts); best_text = bts.text; best_len = (best_text == NULL) ? 0 : g_utf8_strlen (best_text, -1); } } /* now replace or clear text */ CACHE_REMOVE(qf->text); if (best_text != NULL) { qf->text = CACHE_INSERT((gpointer) best_text); qf->len = best_len; } else { qf->text = NULL; qf->len = 0; } } }
static void quickfill_insert_recursive (QuickFill *qf, const char *text, int depth, QuickFillSort sort) { guint key; char *old_text; QuickFill *match_qf; int len; char *key_char; gunichar key_char_uc; if (qf == NULL) return; if ((text == NULL) || (g_utf8_strlen (text, -1) <= depth)) return; key_char = g_utf8_offset_to_pointer (text, depth); key_char_uc = g_utf8_get_char (key_char); key = g_unichar_toupper (key_char_uc); match_qf = g_hash_table_lookup (qf->matches, GUINT_TO_POINTER (key)); if (match_qf == NULL) { match_qf = gnc_quickfill_new (); g_hash_table_insert (qf->matches, GUINT_TO_POINTER (key), match_qf); } old_text = match_qf->text; switch (sort) { case QUICKFILL_ALPHA: if (old_text && (g_utf8_collate (text, old_text) >= 0)) break; /* fall through */ case QUICKFILL_LIFO: default: len = g_utf8_strlen (text, -1); /* If there's no string there already, just put the new one in. */ if (old_text == NULL) { match_qf->text = CACHE_INSERT((gpointer) text); match_qf->len = len; break; } /* Leave prefixes in place */ if ((len > match_qf->len) && (strncmp(text, old_text, strlen(old_text)) == 0)) break; CACHE_REMOVE(old_text); match_qf->text = CACHE_INSERT((gpointer) text); match_qf->len = len; break; } quickfill_insert_recursive (match_qf, text, ++depth, sort); }
int ldbm_back_modify( Slapi_PBlock *pb ) { backend *be; ldbm_instance *inst = NULL; struct ldbminfo *li; struct backentry *e = NULL, *ec = NULL; struct backentry *original_entry = NULL, *tmpentry = NULL; Slapi_Entry *postentry = NULL; LDAPMod **mods = NULL; LDAPMod **mods_original = NULL; Slapi_Mods smods = {0}; back_txn txn; back_txnid parent_txn; modify_context ruv_c = {0}; int ruv_c_init = 0; int retval = -1; char *msg; char *errbuf = NULL; int retry_count = 0; int disk_full = 0; int ldap_result_code= LDAP_SUCCESS; char *ldap_result_message= NULL; int rc = 0; Slapi_Operation *operation; entry_address *addr; int is_fixup_operation= 0; int is_ruv = 0; /* True if the current entry is RUV */ CSN *opcsn = NULL; int repl_op; int opreturn = 0; int mod_count = 0; int not_an_error = 0; int fixup_tombstone = 0; int ec_locked = 0; int result_sent = 0; slapi_pblock_get( pb, SLAPI_BACKEND, &be); slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &li ); slapi_pblock_get( pb, SLAPI_TARGET_ADDRESS, &addr ); slapi_pblock_get( pb, SLAPI_MODIFY_MODS, &mods ); slapi_pblock_get( pb, SLAPI_TXN, (void**)&parent_txn ); slapi_pblock_get( pb, SLAPI_IS_REPLICATED_OPERATION, &repl_op); slapi_pblock_get( pb, SLAPI_OPERATION, &operation ); fixup_tombstone = operation_is_flag_set(operation, OP_FLAG_TOMBSTONE_FIXUP); dblayer_txn_init(li,&txn); /* must do this before first goto error_return */ /* the calls to perform searches require the parent txn if any so set txn to the parent_txn until we begin the child transaction */ if (parent_txn) { txn.back_txn_txn = parent_txn; } else { parent_txn = txn.back_txn_txn; slapi_pblock_set( pb, SLAPI_TXN, parent_txn ); } if (NULL == operation) { ldap_result_code = LDAP_OPERATIONS_ERROR; goto error_return; } is_fixup_operation = operation_is_flag_set(operation, OP_FLAG_REPL_FIXUP); is_ruv = operation_is_flag_set(operation, OP_FLAG_REPL_RUV); inst = (ldbm_instance *) be->be_instance_info; if (NULL == addr) { goto error_return; } if (inst && inst->inst_ref_count) { slapi_counter_increment(inst->inst_ref_count); } else { slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_modify", "Instance \"%s\" does not exist.\n", inst ? inst->inst_name : "null instance"); goto error_return; } /* no need to check the dn syntax as this is a replicated op */ if(!repl_op){ ldap_result_code = slapi_dn_syntax_check(pb, slapi_sdn_get_dn(addr->sdn), 1); if (ldap_result_code) { ldap_result_code = LDAP_INVALID_DN_SYNTAX; slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, &ldap_result_message); goto error_return; } } /* The dblock serializes writes to the database, * which reduces deadlocking in the db code, * which means that we run faster. * * But, this lock is re-enterant for the fixup * operations that the URP code in the Replication * plugin generates. * * SERIALLOCK is moved to dblayer_txn_begin along with exposing be * transaction to plugins (see slapi_back_transaction_* APIs). * if(SERIALLOCK(li) && !operation_is_flag_set(operation,OP_FLAG_REPL_FIXUP)) { dblayer_lock_backend(be); dblock_acquired= 1; } */ if ( MANAGE_ENTRY_BEFORE_DBLOCK(li)) { /* find and lock the entry we are about to modify */ if (fixup_tombstone) { e = find_entry2modify_only_ext( pb, be, addr, TOMBSTONE_INCLUDED, &txn, &result_sent ); } else { e = find_entry2modify( pb, be, addr, &txn, &result_sent ); } if (e == NULL) { ldap_result_code = -1; goto error_return; /* error result sent by find_entry2modify() */ } } txn.back_txn_txn = NULL; /* ready to create the child transaction */ for (retry_count = 0; retry_count < RETRY_TIMES; retry_count++) { int cache_rc = 0; int new_mod_count = 0; if (txn.back_txn_txn && (txn.back_txn_txn != parent_txn)) { /* don't release SERIAL LOCK */ dblayer_txn_abort_ext(li, &txn, PR_FALSE); slapi_pblock_set(pb, SLAPI_TXN, parent_txn); /* * Since be_txn_preop functions could have modified the entry/mods, * We need to grab the current mods, free them, and restore the * originals. Same thing for the entry. */ slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &mods); ldap_mods_free(mods, 1); slapi_pblock_set(pb, SLAPI_MODIFY_MODS, copy_mods(mods_original)); /* reset ec set cache in id2entry_add_ext */ if (ec) { /* must duplicate ec before returning it to cache, * which could free the entry. */ if ((tmpentry = backentry_dup(original_entry?original_entry:ec)) == NULL) { ldap_result_code= LDAP_OPERATIONS_ERROR; goto error_return; } if (cache_is_in_cache(&inst->inst_cache, ec)) { CACHE_REMOVE(&inst->inst_cache, ec); } CACHE_RETURN(&inst->inst_cache, &ec); slapi_pblock_set( pb, SLAPI_MODIFY_EXISTING_ENTRY, original_entry->ep_entry ); ec = original_entry; original_entry = tmpentry; tmpentry = NULL; } if (ruv_c_init) { /* reset the ruv txn stuff */ modify_term(&ruv_c, be); ruv_c_init = 0; } slapi_log_err(SLAPI_LOG_BACKLDBM, "ldbm_back_modify", "Modify Retrying Transaction\n"); #ifndef LDBM_NO_BACKOFF_DELAY { PRIntervalTime interval; interval = PR_MillisecondsToInterval(slapi_rand() % 100); DS_Sleep(interval); } #endif } /* Nothing above here modifies persistent store, everything after here is subject to the transaction */ /* dblayer_txn_begin holds SERIAL lock, * which should be outside of locking the entry (find_entry2modify) */ if (0 == retry_count) { /* First time, hold SERIAL LOCK */ retval = dblayer_txn_begin(be, parent_txn, &txn); } else { /* Otherwise, no SERIAL LOCK */ retval = dblayer_txn_begin_ext(li, parent_txn, &txn, PR_FALSE); } if (0 != retval) { if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1; ldap_result_code= LDAP_OPERATIONS_ERROR; goto error_return; } /* stash the transaction for plugins */ slapi_pblock_set(pb, SLAPI_TXN, txn.back_txn_txn); if (0 == retry_count) { /* just once */ if ( !MANAGE_ENTRY_BEFORE_DBLOCK(li)) { /* find and lock the entry we are about to modify */ if (fixup_tombstone) { e = find_entry2modify_only_ext( pb, be, addr, TOMBSTONE_INCLUDED, &txn, &result_sent ); } else { e = find_entry2modify( pb, be, addr, &txn, &result_sent ); } if (e == NULL) { ldap_result_code = -1; goto error_return; /* error result sent by find_entry2modify() */ } } if ( !is_fixup_operation && !fixup_tombstone) { if (!repl_op && slapi_entry_flag_is_set(e->ep_entry, SLAPI_ENTRY_FLAG_TOMBSTONE)) { ldap_result_code = LDAP_UNWILLING_TO_PERFORM; ldap_result_message = "Operation not allowed on tombstone entry."; slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_modify", "Attempt to modify a tombstone entry %s\n", slapi_sdn_get_dn(slapi_entry_get_sdn_const( e->ep_entry ))); goto error_return; } opcsn = operation_get_csn (operation); if (NULL == opcsn && operation->o_csngen_handler) { /* * Current op is a user request. Opcsn will be assigned * if the dn is in an updatable replica. */ opcsn = entry_assign_operation_csn ( pb, e->ep_entry, NULL ); } if (opcsn) { entry_set_maxcsn (e->ep_entry, opcsn); } } /* Save away a copy of the entry, before modifications */ slapi_pblock_set( pb, SLAPI_ENTRY_PRE_OP, slapi_entry_dup( e->ep_entry )); if ( (ldap_result_code = plugin_call_acl_mods_access( pb, e->ep_entry, mods, &errbuf)) != LDAP_SUCCESS ) { ldap_result_message= errbuf; goto error_return; } /* create a copy of the entry and apply the changes to it */ if ( (ec = backentry_dup( e )) == NULL ) { ldap_result_code= LDAP_OPERATIONS_ERROR; goto error_return; } if(!repl_op){ remove_illegal_mods(mods); } /* ec is the entry that our bepreop should get to mess with */ slapi_pblock_set( pb, SLAPI_MODIFY_EXISTING_ENTRY, ec->ep_entry ); slapi_pblock_set(pb, SLAPI_RESULT_CODE, &ldap_result_code); opreturn = plugin_call_plugins(pb, SLAPI_PLUGIN_BE_PRE_MODIFY_FN); if (opreturn || (slapi_pblock_get(pb, SLAPI_RESULT_CODE, &ldap_result_code) && ldap_result_code) || (slapi_pblock_get(pb, SLAPI_PLUGIN_OPRETURN, &opreturn) && opreturn)) { slapi_pblock_get(pb, SLAPI_RESULT_CODE, &ldap_result_code); slapi_pblock_get(pb, SLAPI_PLUGIN_OPRETURN, &opreturn); if (!ldap_result_code) { slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_modify", "SLAPI_PLUGIN_BE_PRE_MODIFY_FN " "returned error but did not set SLAPI_RESULT_CODE\n"); ldap_result_code = LDAP_OPERATIONS_ERROR; } if (SLAPI_PLUGIN_NOOP == opreturn) { not_an_error = 1; rc = opreturn = LDAP_SUCCESS; } else if (!opreturn) { opreturn = SLAPI_PLUGIN_FAILURE; slapi_pblock_set(pb, SLAPI_PLUGIN_OPRETURN, &opreturn); } slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, &ldap_result_message); goto error_return; } /* The Plugin may have messed about with some of the PBlock parameters... ie. mods */ slapi_pblock_get( pb, SLAPI_MODIFY_MODS, &mods ); /* apply the mods, check for syntax, schema problems, etc. */ if (modify_apply_check_expand(pb, operation, mods, e, ec, &postentry, &ldap_result_code, &ldap_result_message)) { goto error_return; } /* the schema check could have added a repl conflict mod * get the mods again */ slapi_pblock_get( pb, SLAPI_MODIFY_MODS, &mods ); slapi_mods_init_byref(&smods,mods); mod_count = slapi_mods_get_num_mods(&smods); /* * Grab a copy of the mods and the entry in case the be_txn_preop changes * the them. If we have a failure, then we need to reset the mods to their * their original state; */ mods_original = copy_mods(mods); if ( (original_entry = backentry_dup( ec )) == NULL ) { ldap_result_code= LDAP_OPERATIONS_ERROR; goto error_return; } } /* if (0 == retry_count) just once */ /* call the transaction pre modify plugins just after creating the transaction */ retval = plugin_call_plugins(pb, SLAPI_PLUGIN_BE_TXN_PRE_MODIFY_FN); if (retval) { slapi_log_err(SLAPI_LOG_TRACE, "ldbm_back_modify", "SLAPI_PLUGIN_BE_TXN_PRE_MODIFY_FN plugin " "returned error code %d\n", retval ); slapi_pblock_get(pb, SLAPI_RESULT_CODE, &ldap_result_code); slapi_pblock_get(pb, SLAPI_PLUGIN_OPRETURN, &opreturn); if (SLAPI_PLUGIN_NOOP == retval) { not_an_error = 1; rc = retval = LDAP_SUCCESS; } if (!opreturn) { slapi_pblock_set(pb, SLAPI_PLUGIN_OPRETURN, ldap_result_code ? &ldap_result_code : &retval); } slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, &ldap_result_message); goto error_return; } /* the mods might have been changed, so get the latest */ slapi_pblock_get( pb, SLAPI_MODIFY_MODS, &mods ); /* make sure the betxnpreop did not alter any of the mods that had already previously been applied */ slapi_mods_done(&smods); slapi_mods_init_byref(&smods,mods); new_mod_count = slapi_mods_get_num_mods(&smods); if (new_mod_count < mod_count) { slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_modify", "Error: BE_TXN_PRE_MODIFY plugin has removed " "mods from the original list - mod count was [%d] now [%d] " "mods will not be applied - mods list changes must be done " "in the BE_PRE_MODIFY plugin, not the BE_TXN_PRE_MODIFY\n", mod_count, new_mod_count ); } else if (new_mod_count > mod_count) { /* apply the new betxnpremod mods */ /* apply the mods, check for syntax, schema problems, etc. */ if (modify_apply_check_expand(pb, operation, &mods[mod_count], e, ec, &postentry, &ldap_result_code, &ldap_result_message)) { goto error_return; } } /* else if new_mod_count == mod_count then betxnpremod plugin did nothing */ /* * Update the ID to Entry index. * Note that id2entry_add replaces the entry, so the Entry ID * stays the same. */ retval = id2entry_add_ext( be, ec, &txn, 1, &cache_rc ); if (DB_LOCK_DEADLOCK == retval) { /* Abort and re-try */ continue; } if (0 != retval) { slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_modify", "id2entry_add failed, err=%d %s\n", retval, (msg = dblayer_strerror( retval )) ? msg : ""); if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1; MOD_SET_ERROR(ldap_result_code, LDAP_OPERATIONS_ERROR, retry_count); goto error_return; } retval = index_add_mods( be, mods, e, ec, &txn ); if (DB_LOCK_DEADLOCK == retval) { /* Abort and re-try */ continue; } if (0 != retval) { slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_modify", "index_add_mods failed, err=%d %s\n", retval, (msg = dblayer_strerror( retval )) ? msg : ""); if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1; MOD_SET_ERROR(ldap_result_code, LDAP_OPERATIONS_ERROR, retry_count); goto error_return; } /* * Remove the old entry from the Virtual List View indexes. * Add the new entry to the Virtual List View indexes. * If the entry is ruv, no need to update vlv. */ if (!is_ruv) { retval= vlv_update_all_indexes(&txn, be, pb, e, ec); if (DB_LOCK_DEADLOCK == retval) { /* Abort and re-try */ continue; } if (0 != retval) { slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_modify", "vlv_update_index failed, err=%d %s\n", retval, (msg = dblayer_strerror( retval )) ? msg : ""); if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1; MOD_SET_ERROR(ldap_result_code, LDAP_OPERATIONS_ERROR, retry_count); goto error_return; } } if (!is_ruv && !is_fixup_operation && !NO_RUV_UPDATE(li)) { ruv_c_init = ldbm_txn_ruv_modify_context( pb, &ruv_c ); if (-1 == ruv_c_init) { slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_modify", "ldbm_txn_ruv_modify_context failed to construct RUV modify context\n"); ldap_result_code= LDAP_OPERATIONS_ERROR; retval = 0; goto error_return; } } if (ruv_c_init) { retval = modify_update_all( be, pb, &ruv_c, &txn ); if (DB_LOCK_DEADLOCK == retval) { /* Abort and re-try */ continue; } if (0 != retval) { slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_modify", "modify_update_all failed, err=%d %s\n", retval, (msg = dblayer_strerror( retval )) ? msg : ""); if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1; ldap_result_code= LDAP_OPERATIONS_ERROR; goto error_return; } } if (0 == retval) { break; } } if (retry_count == RETRY_TIMES) { slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_modify", "Retry count exceeded in modify\n"); ldap_result_code= LDAP_BUSY; goto error_return; } if (ruv_c_init) { if (modify_switch_entries(&ruv_c, be) != 0 ) { ldap_result_code= LDAP_OPERATIONS_ERROR; slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_modify", "modify_switch_entries failed\n"); goto error_return; } } if (cache_replace( &inst->inst_cache, e, ec ) != 0 ) { MOD_SET_ERROR(ldap_result_code, LDAP_OPERATIONS_ERROR, retry_count); goto error_return; } /* e uncached */ /* we must return both e (which has been deleted) and new entry ec to cache */ /* cache_replace removes e from the cache hash tables */ cache_unlock_entry( &inst->inst_cache, e ); CACHE_RETURN( &inst->inst_cache, &e ); /* lock new entry in cache to prevent usage until we are complete */ cache_lock_entry( &inst->inst_cache, ec ); ec_locked = 1; postentry = slapi_entry_dup( ec->ep_entry ); slapi_pblock_set( pb, SLAPI_ENTRY_POST_OP, postentry ); /* invalidate virtual cache */ ec->ep_entry->e_virtual_watermark = 0; /* * LP Fix of crash when the commit will fail: * If the commit fail, the common error path will * try to unlock the entry again and crash (PR_ASSERT * in debug mode. * By just setting e to NULL, we avoid this. It's OK since * we don't use e after that in the normal case. */ e = NULL; /* call the transaction post modify plugins just before the commit */ if ((retval = plugin_call_plugins(pb, SLAPI_PLUGIN_BE_TXN_POST_MODIFY_FN))) { slapi_log_err(SLAPI_LOG_TRACE, "ldbm_back_modify", "SLAPI_PLUGIN_BE_TXN_POST_MODIFY_FN plugin " "returned error code %d\n", retval ); if (!ldap_result_code) { slapi_pblock_get(pb, SLAPI_RESULT_CODE, &ldap_result_code); } if (!opreturn) { slapi_pblock_get(pb, SLAPI_PLUGIN_OPRETURN, &opreturn); } if (!opreturn) { slapi_pblock_set(pb, SLAPI_PLUGIN_OPRETURN, ldap_result_code ? &ldap_result_code : &retval); } slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, &ldap_result_message); goto error_return; } /* Release SERIAL LOCK */ retval = dblayer_txn_commit(be, &txn); /* after commit - txn is no longer valid - replace SLAPI_TXN with parent */ slapi_pblock_set(pb, SLAPI_TXN, parent_txn); if (0 != retval) { if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1; ldap_result_code= LDAP_OPERATIONS_ERROR; goto error_return; } rc= 0; goto common_return; error_return: if ( postentry != NULL ) { slapi_entry_free( postentry ); postentry = NULL; slapi_pblock_set( pb, SLAPI_ENTRY_POST_OP, NULL ); } if (retval == DB_RUNRECOVERY) { dblayer_remember_disk_filled(li); ldbm_nasty("ldbm_back_modify","Modify",81,retval); disk_full = 1; } if (disk_full) { rc= return_on_disk_full(li); } else { if (txn.back_txn_txn && (txn.back_txn_txn != parent_txn)) { /* make sure SLAPI_RESULT_CODE and SLAPI_PLUGIN_OPRETURN are set */ int val = 0; slapi_pblock_get(pb, SLAPI_RESULT_CODE, &val); if (!val) { if (!ldap_result_code) { ldap_result_code = LDAP_OPERATIONS_ERROR; } slapi_pblock_set(pb, SLAPI_RESULT_CODE, &ldap_result_code); } slapi_pblock_get( pb, SLAPI_PLUGIN_OPRETURN, &val ); if (!val) { opreturn = -1; slapi_pblock_set( pb, SLAPI_PLUGIN_OPRETURN, &opreturn ); } /* call the transaction post modify plugins just before the abort */ /* plugins called before abort should check for the OPRETURN or RESULT_CODE and skip processing if they don't want do anything - some plugins that keep track of a counter (usn, dna) may want to "rollback" the counter in this case */ if ((retval = plugin_call_plugins(pb, SLAPI_PLUGIN_BE_TXN_POST_MODIFY_FN))) { slapi_log_err(SLAPI_LOG_TRACE, "ldbm_back_modify", "SLAPI_PLUGIN_BE_TXN_POST_MODIFY_FN plugin returned error code %d\n", retval ); slapi_pblock_get(pb, SLAPI_RESULT_CODE, &ldap_result_code); slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, &ldap_result_message); slapi_pblock_get(pb, SLAPI_PLUGIN_OPRETURN, &opreturn); if (!opreturn) { slapi_pblock_set(pb, SLAPI_PLUGIN_OPRETURN, ldap_result_code ? &ldap_result_code : &retval); } } /* It is safer not to abort when the transaction is not started. */ /* Release SERIAL LOCK */ dblayer_txn_abort(be, &txn); /* abort crashes in case disk full */ /* txn is no longer valid - reset the txn pointer to the parent */ slapi_pblock_set(pb, SLAPI_TXN, parent_txn); } if (!not_an_error) { rc = SLAPI_FAIL_GENERAL; } } /* if ec is in cache, remove it, then add back e if we still have it */ if (inst && cache_is_in_cache(&inst->inst_cache, ec)) { CACHE_REMOVE( &inst->inst_cache, ec ); /* if ec was in cache, e was not - add back e */ if (e) { if (CACHE_ADD( &inst->inst_cache, e, NULL ) < 0) { slapi_log_err(SLAPI_LOG_CACHE, "ldbm_back_modify", "CACHE_ADD %s failed\n", slapi_entry_get_dn(e->ep_entry)); } } } common_return: slapi_mods_done(&smods); if (inst) { if (ec_locked || cache_is_in_cache(&inst->inst_cache, ec)) { cache_unlock_entry(&inst->inst_cache, ec); } else if (e) { /* if ec was not in cache, cache_replace was not done. * i.e., e was not unlocked. */ cache_unlock_entry(&inst->inst_cache, e); CACHE_RETURN(&inst->inst_cache, &e); } CACHE_RETURN(&inst->inst_cache, &ec); if (inst->inst_ref_count) { slapi_counter_decrement(inst->inst_ref_count); } } /* result code could be used in the bepost plugin functions. */ slapi_pblock_set(pb, SLAPI_RESULT_CODE, &ldap_result_code); /* The bepostop is called even if the operation fails. */ if (!disk_full) plugin_call_plugins (pb, SLAPI_PLUGIN_BE_POST_MODIFY_FN); if (ruv_c_init) { modify_term(&ruv_c, be); } if (ldap_result_code == -1) { /* Reset to LDAP_NO_SUCH_OBJECT*/ ldap_result_code = LDAP_NO_SUCH_OBJECT; slapi_pblock_set(pb, SLAPI_RESULT_CODE, &ldap_result_code); } else { if (not_an_error) { /* This is mainly used by urp. Solved conflict is not an error. * And we don't want the supplier to halt sending the updates. */ ldap_result_code = LDAP_SUCCESS; } if (!result_sent) { /* result is already sent in find_entry. */ slapi_send_ldap_result( pb, ldap_result_code, NULL, ldap_result_message, 0, NULL ); } } /* free our backups */ ldap_mods_free(mods_original, 1); backentry_free(&original_entry); backentry_free(&tmpentry); slapi_ch_free_string(&errbuf); return rc; }