The branch, master has been updated via 3d85d2cf669686f89cacdc481eaa97aef1ba62c0 (commit) via 7fb6cf549de1b5e9ac5a3e4483c7591850ea2464 (commit) from 2908e092710d7fa2245161b3315747e17e4226c0 (commit)
http://gitweb.samba.org/?p=sahlberg/ctdb.git;a=shortlog;h=master - Log ----------------------------------------------------------------- commit 3d85d2cf669686f89cacdc481eaa97aef1ba62c0 Author: Ronnie Sahlberg <[EMAIL PROTECTED]> Date: Thu May 22 13:12:53 2008 +1000 cleanup of the previous patch. With these patches, ctdbd will enforce and (by default) always use tdb_transactions when updating/writing records to a persistent database. This might come with a small performance degratation since transactions are slower than no transactions at all. If a client, such as samba wants to use a persistent database but does NOT want to pay the performance penalty, it can specify TDB_NOSYNC as the srvid parameter in the ctdb_control() for CTDB_CONTROL_DB_ATTACH_PERSISTENT. In this case CTDBD will remember that "this database is not that important" so I can use unsafe (no transaction) tdb_stores to write the updates. It will be faster than the default (always use transaction) but less crash safe. commit 7fb6cf549de1b5e9ac5a3e4483c7591850ea2464 Author: Ronnie Sahlberg <[EMAIL PROTECTED]> Date: Thu May 22 12:47:33 2008 +1000 second try for safe transaction stores into persistend tdb databases for stores into persistent databases, ALWAYS use a lockwait child take out the lock for the record and never the daemon itself. ----------------------------------------------------------------------- Summary of changes: common/ctdb_ltdb.c | 64 ++++++++++++++++++++++++++++++++--------- include/ctdb_private.h | 2 + lib/tdb/common/transaction.c | 2 +- server/ctdb_persistent.c | 14 ++++++-- 4 files changed, 63 insertions(+), 19 deletions(-) Changeset truncated at 500 lines: diff --git a/common/ctdb_ltdb.c b/common/ctdb_ltdb.c index a3df65e..886115a 100644 --- a/common/ctdb_ltdb.c +++ b/common/ctdb_ltdb.c @@ -121,9 +121,7 @@ int ctdb_ltdb_fetch(struct ctdb_db_context *ctdb_db, /* - fetch a record from the ltdb, separating out the header information - and returning the body of the record. A valid (initial) header is - returned if the record is not present + write a record to a normal database */ int ctdb_ltdb_store(struct ctdb_db_context *ctdb_db, TDB_DATA key, struct ctdb_ltdb_header *header, TDB_DATA data) @@ -150,25 +148,64 @@ int ctdb_ltdb_store(struct ctdb_db_context *ctdb_db, TDB_DATA key, memcpy(rec.dptr, header, sizeof(*header)); memcpy(rec.dptr + sizeof(*header), data.dptr, data.dsize); + ret = tdb_store(ctdb_db->ltdb->tdb, key, rec, TDB_REPLACE); + if (ret != 0) { + DEBUG(DEBUG_ERR, (__location__ " Failed to store dynamic data\n")); + } + + talloc_free(rec.dptr); + + return ret; +} + +/* + write a record to a persistent database + at this stage the the record is locked by a lockwait child. +*/ +int ctdb_ltdb_persistent_store(struct ctdb_db_context *ctdb_db, TDB_DATA key, + struct ctdb_ltdb_header *header, TDB_DATA data) +{ + struct ctdb_context *ctdb = ctdb_db->ctdb; + TDB_DATA rec; + int ret; + + if (ctdb->flags & CTDB_FLAG_TORTURE) { + struct ctdb_ltdb_header *h2; + rec = tdb_fetch(ctdb_db->ltdb->tdb, key); + h2 = (struct ctdb_ltdb_header *)rec.dptr; + if (rec.dptr && rec.dsize >= sizeof(h2) && h2->rsn > header->rsn) { + DEBUG(DEBUG_CRIT,("RSN regression! %llu %llu\n", + (unsigned long long)h2->rsn, (unsigned long long)header->rsn)); + } + if (rec.dptr) free(rec.dptr); + } + + rec.dsize = sizeof(*header) + data.dsize; + rec.dptr = talloc_size(ctdb, rec.dsize); + CTDB_NO_MEMORY(ctdb, rec.dptr); + + memcpy(rec.dptr, header, sizeof(*header)); + memcpy(rec.dptr + sizeof(*header), data.dptr, data.dsize); + /* if this is a persistent database without NOSYNC then we will do this via a transaction */ - if (ctdb_db->persistent && !(ctdb_db->client_tdb_flags & TDB_NOSYNC)) { - bool transaction_started = true; - + if (!(ctdb_db->client_tdb_flags & TDB_NOSYNC)) { ret = tdb_transaction_start(ctdb_db->ltdb->tdb); if (ret != 0) { - transaction_started = false; - DEBUG(DEBUG_NOTICE, ("Failed to start local transaction\n")); + DEBUG(DEBUG_ERR, (__location__ " Failed to start local transaction\n")); + goto failed; } ret = tdb_store(ctdb_db->ltdb->tdb, key, rec, TDB_REPLACE); if (ret != 0) { - if (transaction_started) { - tdb_transaction_cancel(ctdb_db->ltdb->tdb); - } + DEBUG(DEBUG_ERR, (__location__ " Failed to store persistent data\n")); + tdb_transaction_cancel(ctdb_db->ltdb->tdb); goto failed; } - if (transaction_started) { - ret = tdb_transaction_commit(ctdb_db->ltdb->tdb); + ret = tdb_transaction_commit(ctdb_db->ltdb->tdb); + if (ret != 0) { + DEBUG(DEBUG_ERR, (__location__ " Failed to commit persistent store transaction.\n")); + tdb_transaction_cancel(ctdb_db->ltdb->tdb); + goto failed; } } else { ret = tdb_store(ctdb_db->ltdb->tdb, key, rec, TDB_REPLACE); @@ -180,7 +217,6 @@ failed: return ret; } - /* lock a record in the ltdb, given a key */ diff --git a/include/ctdb_private.h b/include/ctdb_private.h index 4eccc84..758b506 100644 --- a/include/ctdb_private.h +++ b/include/ctdb_private.h @@ -790,6 +790,8 @@ int ctdb_ltdb_fetch(struct ctdb_db_context *ctdb_db, TALLOC_CTX *mem_ctx, TDB_DATA *data); int ctdb_ltdb_store(struct ctdb_db_context *ctdb_db, TDB_DATA key, struct ctdb_ltdb_header *header, TDB_DATA data); +int ctdb_ltdb_persistent_store(struct ctdb_db_context *ctdb_db, TDB_DATA key, + struct ctdb_ltdb_header *header, TDB_DATA data); void ctdb_queue_packet(struct ctdb_context *ctdb, struct ctdb_req_header *hdr); int ctdb_ltdb_lock_requeue(struct ctdb_db_context *ctdb_db, TDB_DATA key, struct ctdb_req_header *hdr, diff --git a/lib/tdb/common/transaction.c b/lib/tdb/common/transaction.c index 5e5260b..4e2127b 100644 --- a/lib/tdb/common/transaction.c +++ b/lib/tdb/common/transaction.c @@ -419,7 +419,7 @@ int tdb_transaction_start(struct tdb_context *tdb) /* the caller must not have any locks when starting a transaction as otherwise we'll be screwed by lack of nested locks in posix */ -// TDB_LOG((tdb, TDB_DEBUG_TRACE, "tdb_transaction_start: cannot start a transaction with locks held\n")); + TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_start: cannot start a transaction with locks held\n")); tdb->ecode = TDB_ERR_LOCK; return -1; } diff --git a/server/ctdb_persistent.c b/server/ctdb_persistent.c index 053bd40..4247340 100644 --- a/server/ctdb_persistent.c +++ b/server/ctdb_persistent.c @@ -147,7 +147,7 @@ struct ctdb_persistent_lock_state { /* - called with a lock held in the current process + called with a lock held by a lockwait child */ static int ctdb_persistent_store(struct ctdb_persistent_lock_state *state) { @@ -169,7 +169,7 @@ static int ctdb_persistent_store(struct ctdb_persistent_lock_state *state) return -1; } - ret = ctdb_ltdb_store(state->ctdb_db, state->key, state->header, state->data); + ret = ctdb_ltdb_persistent_store(state->ctdb_db, state->key, state->header, state->data); if (ret != 0) { DEBUG(DEBUG_CRIT,("Failed to store record for db_id 0x%08x in ctdb_persistent_store\n", state->ctdb_db->db_id)); @@ -224,7 +224,6 @@ int32_t ctdb_control_update_record(struct ctdb_context *ctdb, bool *async_reply) { struct ctdb_rec_data *rec = (struct ctdb_rec_data *)&recdata.dptr[0]; - int ret; struct ctdb_db_context *ctdb_db; uint32_t db_id = rec->reqid; struct lockwait_handle *handle; @@ -262,13 +261,20 @@ int32_t ctdb_control_update_record(struct ctdb_context *ctdb, state->data.dptr += sizeof(struct ctdb_ltdb_header); state->data.dsize -= sizeof(struct ctdb_ltdb_header); - /* try and do it without a lockwait */ +#if 0 + /* We can not take out a lock here ourself since if this persistent + database needs safe transaction writes we can not be holding + a lock on the database. + Therefore we always create a lock wait child to take out and hold + the lock for us. + */ ret = tdb_chainlock_nonblock(state->tdb, state->key); if (ret == 0) { ret = ctdb_persistent_store(state); tdb_chainunlock(state->tdb, state->key); return ret; } +#endif /* wait until we have a lock on this record */ handle = ctdb_lockwait(ctdb_db, state->key, ctdb_persistent_lock_callback, state); -- CTDB repository