The branch, master has been updated via 83fffbe... s3:g_lock: remove a nested event loop, replacing the inner loop by select via e4af0bc... s3:ctdb_conn: add ctdbd_conn_get_fd() to get the fd out of the ctdb connection via 8e306b5... s3:g_lock: remove an unreached code path. via 1933214... s3:dbwrap_ctdb: fix reading/storing of special key __db_sequence_number__ via c311697... s3:dbwrap_ctdb: exit early when nothing has been written in transaction_commit. via 1d594bd... s3:dbwrap_ctdb: fix brown paperbag bug in ctdb_transaction_commit. via 524072b... s3:dbwrap_ctdb: fix logic error in pull_newest_from_marshall_buffer(). via 1505b69... s3:dbwrap_ctdb: fix an uninitialized variable. via fb981cd... s3:dbwrap_ctdb: fix two "may be used uninitialized" warnings via 10a44ee... s3:dbwrap_ctdb: fix db_ctdb_fetch_db_seqnum_from_db() when NT_STATUS_NOT_FOUND. via a66c40f... s3:dbwrap: If "-n" is given to dbwrap_torture, open db with CLEAR_IF_FIRST via 9113ce8... s3:build: remove checks for deprecated ctdb controls. via 3fe7ce1... s3:dbwrap_ctdb: maintain a database sequence number that bumps in transactions via 26225d3... s3:dbwrap_ctdb: change db_ctdb_transaction_store() to return NTSTATUS. via 5a0c427... s3:dbwrap_ctdb: update (C) via d4c0afa... build: Add a configure check for CTDB_CONTROL_TRANS3_COMMIT. via ebc08b9... s3: Add tdb_data_equal via a035062... s3:torture: add a test LOCAL-DBTRANS to torture dbwrap with transactions. via 16bc6ba... s3:dbwrap_ctdb: start rewrite of transactions using the global lock (g_lock) via b13dd17... s3: setup debug for smbtorture via 12abab7... s3: Add ctdb_conn_msg_ctx() via 4c1c3f2... s3: Implement global locks in a g_lock tdb from 30797ce... s4:kdc Fill in created_by principal field
http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master - Log ----------------------------------------------------------------- commit 83fffbeb44441a87569e543054af21d975eb20ae Author: Michael Adam <ob...@samba.org> Date: Sat Jan 23 01:17:06 2010 +0100 s3:g_lock: remove a nested event loop, replacing the inner loop by select This made smbd crash in g_lock_lock() when trying to start a transaction on a db with an already started transaction, e.g. in a tcon_and_X where the share_info.tdb was not yet initialized but share_info.tdb was already locked by another process or writing acces to the winreg rpc pipe where the registry tdb was already locked by another process. What we really _want_ to do here by design is to react to MSG_DBWRAP_G_LOCK_RETRY messages that are either sent by a client doing g_lock_unlock or by ourselves when we receive a CTDB_SRVID_SAMBA_NOTIFY or CTDB_SRVID_RECONFIGURE message from ctdbd, i.e. when either a client holding a lock or a complete node has died. Doing this properly involves calling tevent_loop_once(), but doing this here with the main ctdbd messaging context creates a nested event loop when g_lock_lock() is called from the main event loop. So as a quick fix, we act a little corasely here: we do a select on the ctdb connection fd and when it is readable or we get EINTR, then we retry without actually parsing any ctdb packages or dispatching messages. This means that we retry more often than necessary and intended by design, but this does not harm and it is unobtrusive. When we have finished, the main loop will pick up all the messages and ctdb packets. The only extra twist is that we cannot use timed events here but have to handcode a timeout for select. Michael commit e4af0bc5af2c3ee025ca7fac251c3672ba2c8dd5 Author: Michael Adam <ob...@samba.org> Date: Sat Jan 23 00:05:15 2010 +0100 s3:ctdb_conn: add ctdbd_conn_get_fd() to get the fd out of the ctdb connection Michael commit 8e306b51b79d3dacd68be9f13aa8455e2eb4c03f Author: Michael Adam <ob...@samba.org> Date: Fri Jan 22 15:56:28 2010 +0100 s3:g_lock: remove an unreached code path. Michael commit 1933214108d1a71bc6473a696ce35020a427d8f4 Author: Michael Adam <ob...@samba.org> Date: Mon Jan 18 17:26:04 2010 +0100 s3:dbwrap_ctdb: fix reading/storing of special key __db_sequence_number__ The key for reading and writing was inconsistent due to a off by one data length. Michael commit c311697aded87ce624d40cbf14e05d6e6377c257 Author: Michael Adam <ob...@samba.org> Date: Wed Jan 13 23:53:54 2010 +0100 s3:dbwrap_ctdb: exit early when nothing has been written in transaction_commit. This skips update of the __db_sequence_number__ record when nothing else has been written. There are transactions that are just openend and then nothing is written until transaction_commit is called. This is for instance the case with registry initialization routines: They start a transaction and only write somthing when the registry has not been initialized yet. So this change will skip many db_seqnum bumps and TRANS3_COMMIT roundtrips. Michael commit 1d594bd734a2f7146ed52872456a16c5e41816f1 Author: Michael Adam <ob...@samba.org> Date: Wed Jan 13 23:51:34 2010 +0100 s3:dbwrap_ctdb: fix brown paperbag bug in ctdb_transaction_commit. I carefully prepared the return value only to "return 0;" at the bottom. :-( This may well have hit us for instance in the nested cancel case and produced random errors. Michael commit 524072b56bf659002410a817749bf86fe6f51e83 Author: Michael Adam <ob...@samba.org> Date: Wed Jan 6 00:37:21 2010 +0100 s3:dbwrap_ctdb: fix logic error in pull_newest_from_marshall_buffer(). The logic bug was that if a record was found in the marshall buffer, then always the ctdb header of tha last record in the marshall buffer was returned, and not the ctdb header of the last occurrence of the requested record. This is fixed by introducing an additional temporary variable. Michael commit 1505b69dea6044a13a59f672e22f5833256cb981 Author: Michael Adam <ob...@samba.org> Date: Tue Jan 5 16:17:27 2010 +0100 s3:dbwrap_ctdb: fix an uninitialized variable. Michael commit fb981cdb8282d3b9b46d9ca515a5685add232a72 Author: Michael Adam <ob...@samba.org> Date: Sat Dec 12 00:38:14 2009 +0100 s3:dbwrap_ctdb: fix two "may be used uninitialized" warnings Michael commit 10a44ee6930bb51b4b20ce42f35bc455ac1b7293 Author: Michael Adam <ob...@samba.org> Date: Sat Dec 12 00:30:37 2009 +0100 s3:dbwrap_ctdb: fix db_ctdb_fetch_db_seqnum_from_db() when NT_STATUS_NOT_FOUND. Don't treat this as an error but return seqnum 0 instead. Michael commit a66c40ff3853d109f13ad3a0dd79b170bb1c5366 Author: Volker Lendecke <v...@samba.org> Date: Fri Dec 11 16:51:40 2009 +0100 s3:dbwrap: If "-n" is given to dbwrap_torture, open db with CLEAR_IF_FIRST commit 9113ce82b59c718ac709eb01b125e9e6746a96b7 Author: Michael Adam <ob...@samba.org> Date: Fri Dec 11 16:45:38 2009 +0100 s3:build: remove checks for deprecated ctdb controls. Michael commit 3fe7ce141d6afe3825b06c5feb90558911e4df1e Author: Michael Adam <ob...@samba.org> Date: Fri Dec 11 14:07:28 2009 +0100 s3:dbwrap_ctdb: maintain a database sequence number that bumps in transactions For persistent databases, 64bit integer is kept in a special record __db_sequence_number__. This record is incremented with each completed transaction. The retry mechanism for failing TRANS3_COMMIT controls inside the db_ctdb_transaction_commit() function now relies one a modified behaviour of ctdbd's treatment of persistent databases in recoveries. Recently, a special treatment for persistent databases had been introduced in ctdb (1.0.108) to work around the problems with the orinal design of persistent transactions. Now with the rewrite we need to revert to the old behaviour that ctdb always takes the newest copies of all records. This change also paves the way for a next step, which will make recovery use the db seqnum to tell which node has the newest copy of a persistent db and use that node's copy. This will greatly reduce the amount of data transferred with each recovery. Michael commit 26225d3e798892b39b3c238b0bee465bffac6550 Author: Michael Adam <ob...@samba.org> Date: Fri Dec 11 12:30:57 2009 +0100 s3:dbwrap_ctdb: change db_ctdb_transaction_store() to return NTSTATUS. The return values calculated by the callers were wrong anyways since the new marshalling code does not set the local tdbs tdb error code. Michael commit 5a0c42770b349877928a2b3fd8316903dd62e5b7 Author: Michael Adam <ob...@samba.org> Date: Fri Dec 11 10:35:50 2009 +0100 s3:dbwrap_ctdb: update (C) Michael commit d4c0afa841ecdae1cab955cc73360deae23f5873 Author: Michael Adam <ob...@samba.org> Date: Fri Dec 4 11:49:21 2009 +0100 build: Add a configure check for CTDB_CONTROL_TRANS3_COMMIT. This is the new implementation of ctdb transactions using the global lock feature. It is needed by the current dbwrap_ctdb code. Michael commit ebc08b9938a4d266be16ca7e06d27813952cd00f Author: Volker Lendecke <v...@samba.org> Date: Thu Dec 3 18:43:49 2009 +0100 s3: Add tdb_data_equal commit a035062f11f831875e397b16e0e4c6e2d7ba5c76 Author: Volker Lendecke <v...@samba.org> Date: Fri Dec 11 15:37:52 2009 +0100 s3:torture: add a test LOCAL-DBTRANS to torture dbwrap with transactions. commit 16bc6ba2268e3660d026076264de8666356e00bf Author: Michael Adam <ob...@samba.org> Date: Thu Dec 3 17:29:54 2009 +0100 s3:dbwrap_ctdb: start rewrite of transactions using the global lock (g_lock) This simplifies the transaction code a lot: * transaction_start essentially consists of acquiring a global lock. * No write operations at all are performed on the local database until the transaction is committed: Every store operation is just going into the marshall buffer. * The commit operation calls a new simplified TRANS3_COMMIT control in ctdb which rolls out thae changes to all nodes including the node that is performing the transaction. Michael commit b13dd17840a598ae3441e48b130a2b2a2b940572 Author: Volker Lendecke <v...@samba.org> Date: Mon Dec 7 00:36:51 2009 +0100 s3: setup debug for smbtorture commit 12abab711b58237ddccfa1d9bb526f8c7dbb6e9f Author: Volker Lendecke <v...@samba.org> Date: Fri Dec 4 13:22:30 2009 +0100 s3: Add ctdb_conn_msg_ctx() commit 4c1c3f2549f32fd069e0e7bf3aec299213f1e85b Author: Volker Lendecke <v...@samba.org> Date: Sun Oct 25 16:12:12 2009 +0100 s3: Implement global locks in a g_lock tdb This is the basis to implement global locks in ctdb without depending on a shared file system. The initial goal is to make ctdb persistent transactions deterministic without too many timeouts. ----------------------------------------------------------------------- Summary of changes: lib/util/util_tdb.c | 8 + lib/util/util_tdb.h | 1 + source3/Makefile.in | 2 + source3/configure.in | 23 +- source3/include/ctdbd_conn.h | 5 + source3/include/g_lock.h | 55 +++ source3/lib/ctdbd_conn.c | 83 ++++- source3/lib/dbwrap_ctdb.c | 601 ++++++++++++++---------------- source3/lib/g_lock.c | 653 ++++++++++++++++++++++++++++++++ source3/librpc/gen_ndr/messaging.h | 4 +- source3/librpc/gen_ndr/ndr_messaging.c | 1 + source3/librpc/idl/messaging.idl | 3 +- source3/torture/torture.c | 132 +++++++ source3/utils/dbwrap_torture.c | 4 + source3/utils/net.c | 7 + source3/utils/net_g_lock.c | 213 +++++++++++ source3/utils/net_proto.h | 3 + 17 files changed, 1450 insertions(+), 348 deletions(-) create mode 100644 source3/include/g_lock.h create mode 100644 source3/lib/g_lock.c create mode 100644 source3/utils/net_g_lock.c Changeset truncated at 500 lines: diff --git a/lib/util/util_tdb.c b/lib/util/util_tdb.c index cda8dc7..46dbf6d 100644 --- a/lib/util/util_tdb.c +++ b/lib/util/util_tdb.c @@ -38,6 +38,14 @@ TDB_DATA make_tdb_data(const uint8_t *dptr, size_t dsize) return ret; } +bool tdb_data_equal(TDB_DATA t1, TDB_DATA t2) +{ + if (t1.dsize != t2.dsize) { + return false; + } + return (memcmp(t1.dptr, t2.dptr, t1.dsize) == 0); +} + TDB_DATA string_tdb_data(const char *string) { return make_tdb_data((const uint8_t *)string, string ? strlen(string) : 0 ); diff --git a/lib/util/util_tdb.h b/lib/util/util_tdb.h index da6378e..79c4671 100644 --- a/lib/util/util_tdb.h +++ b/lib/util/util_tdb.h @@ -6,6 +6,7 @@ Make a TDB_DATA and keep the const warning in one place ****************************************************************/ TDB_DATA make_tdb_data(const uint8_t *dptr, size_t dsize); +bool tdb_data_equal(TDB_DATA t1, TDB_DATA t2); TDB_DATA string_tdb_data(const char *string); TDB_DATA string_term_tdb_data(const char *string); diff --git a/source3/Makefile.in b/source3/Makefile.in index dcd133c..aad1bf5 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -266,6 +266,7 @@ EXTRA_ALL_TARGETS = @EXTRA_ALL_TARGETS@ TDB_LIB_OBJ = lib/util_tdb.o ../lib/util/util_tdb.o \ lib/dbwrap.o lib/dbwrap_tdb.o \ lib/dbwrap_ctdb.o \ + lib/g_lock.o \ lib/dbwrap_rbt.o TDB_VALIDATE_OBJ = lib/tdb_validate.o @@ -1010,6 +1011,7 @@ NET_OBJ1 = utils/net.o utils/net_ads.o utils/net_help.o \ utils/net_conf.o utils/net_join.o utils/net_user.o \ utils/net_group.o utils/net_file.o utils/net_registry.o \ auth/token_util.o utils/net_dom.o utils/net_share.o \ + utils/net_g_lock.o \ utils/net_eventlog.o # these are not processed by make proto diff --git a/source3/configure.in b/source3/configure.in index 1f69609..0de367a 100644 --- a/source3/configure.in +++ b/source3/configure.in @@ -5296,7 +5296,7 @@ AC_CHECK_HEADERS(ctdb.h ctdb_private.h,,,[ #include <ctdb.h> ]) -AC_HAVE_DECL(CTDB_CONTROL_TRANS2_COMMIT_RETRY,[ +AC_HAVE_DECL(CTDB_CONTROL_TRANS3_COMMIT,[ #include "confdefs.h" #define NO_CONFIG_H #include "replace.h" @@ -5307,27 +5307,10 @@ AC_HAVE_DECL(CTDB_CONTROL_TRANS2_COMMIT_RETRY,[ #include <ctdb.h> #include <ctdb_private.h> ]) -if test x"$ac_cv_have_CTDB_CONTROL_TRANS2_COMMIT_RETRY_decl" = x"yes"; then +if test x"$ac_cv_have_CTDB_CONTROL_TRANS3_COMMIT_decl" = x"yes"; then ctdb_broken=no else - ctdb_broken="missing transaction support" -fi - -AC_HAVE_DECL(CTDB_CONTROL_TRANS2_ACTIVE,[ -#include "confdefs.h" -#define NO_CONFIG_H -#include "replace.h" -#include "system/wait.h" -#include "system/network.h" -#include <talloc.h> -#include <tdb.h> -#include <ctdb.h> -#include <ctdb_private.h> -]) -if test x"$ac_cv_have_CTDB_CONTROL_TRANS2_ACTIVE_decl" = x"yes"; then - ctdb_broken=no -else - ctdb_broken="transaction support too old" + ctdb_broken="ctdb transaction support missing or too old" fi # in ctdb 1.0.57 ctdb_control_tcp was temparary renamed to ctdb_tcp_client diff --git a/source3/include/ctdbd_conn.h b/source3/include/ctdbd_conn.h index d721235..c5ba572 100644 --- a/source3/include/ctdbd_conn.h +++ b/source3/include/ctdbd_conn.h @@ -31,6 +31,9 @@ uint32 ctdbd_vnn(const struct ctdbd_connection *conn); NTSTATUS ctdbd_register_msg_ctx(struct ctdbd_connection *conn, struct messaging_context *msg_ctx); +struct messaging_context *ctdb_conn_msg_ctx(struct ctdbd_connection *conn); + +int ctdbd_conn_get_fd(struct ctdbd_connection *conn); NTSTATUS ctdbd_messaging_send(struct ctdbd_connection *conn, uint32 dst_vnn, uint64 dst_srvid, @@ -73,5 +76,7 @@ NTSTATUS ctdbd_control_local(struct ctdbd_connection *conn, uint32 opcode, uint64_t srvid, uint32_t flags, TDB_DATA data, TALLOC_CTX *mem_ctx, TDB_DATA *outdata, int *cstatus); +NTSTATUS ctdb_watch_us(struct ctdbd_connection *conn); +NTSTATUS ctdb_unwatch(struct ctdbd_connection *conn); #endif /* _CTDBD_CONN_H */ diff --git a/source3/include/g_lock.h b/source3/include/g_lock.h new file mode 100644 index 0000000..c0eed38 --- /dev/null +++ b/source3/include/g_lock.h @@ -0,0 +1,55 @@ +/* + Unix SMB/CIFS implementation. + global locks based on ctdb + Copyright (C) 2009 by Volker Lendecke + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef _G_LOCK_H_ +#define _G_LOCK_H_ + +#include "dbwrap.h" + +struct g_lock_ctx; + +enum g_lock_type { + G_LOCK_READ = 0, + G_LOCK_WRITE = 1, +}; + +/* + * Or'ed with g_lock_type + */ +#define G_LOCK_PENDING (2) + +struct g_lock_ctx *g_lock_ctx_init(TALLOC_CTX *mem_ctx, + struct messaging_context *msg); + +NTSTATUS g_lock_lock(struct g_lock_ctx *ctx, const char *name, + enum g_lock_type lock_type, struct timeval timeout); +NTSTATUS g_lock_unlock(struct g_lock_ctx *ctx, const char *name); +NTSTATUS g_lock_get(struct g_lock_ctx *ctx, const char *name, + struct server_id *pid); + +int g_lock_locks(struct g_lock_ctx *ctx, + int (*fn)(const char *name, void *private_data), + void *private_data); +NTSTATUS g_lock_dump(struct g_lock_ctx *ctx, const char *name, + int (*fn)(struct server_id pid, + enum g_lock_type lock_type, + void *private_data), + void *private_data); + +#endif diff --git a/source3/lib/ctdbd_conn.c b/source3/lib/ctdbd_conn.c index 8ddb12a..6b50009 100644 --- a/source3/lib/ctdbd_conn.c +++ b/source3/lib/ctdbd_conn.c @@ -361,10 +361,18 @@ static NTSTATUS ctdb_read_req(struct ctdbd_connection *conn, uint32 reqid, goto next_pkt; } - if (msg->srvid == CTDB_SRVID_RECONFIGURE) { - DEBUG(0,("Got cluster reconfigure message in ctdb_read_req\n")); + if ((msg->srvid == CTDB_SRVID_RECONFIGURE) + || (msg->srvid == CTDB_SRVID_SAMBA_NOTIFY)) { + + DEBUG(1, ("ctdb_read_req: Got %s message\n", + (msg->srvid == CTDB_SRVID_RECONFIGURE) + ? "cluster reconfigure" : "SAMBA_NOTIFY")); + messaging_send(conn->msg_ctx, procid_self(), MSG_SMB_BRL_VALIDATE, &data_blob_null); + messaging_send(conn->msg_ctx, procid_self(), + MSG_DBWRAP_G_LOCK_RETRY, + &data_blob_null); TALLOC_FREE(hdr); goto next_pkt; } @@ -493,6 +501,11 @@ NTSTATUS ctdbd_messaging_connection(TALLOC_CTX *mem_ctx, goto fail; } + status = register_with_ctdbd(conn, CTDB_SRVID_SAMBA_NOTIFY); + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + *pconn = conn; return NT_STATUS_OK; @@ -501,6 +514,16 @@ NTSTATUS ctdbd_messaging_connection(TALLOC_CTX *mem_ctx, return status; } +struct messaging_context *ctdb_conn_msg_ctx(struct ctdbd_connection *conn) +{ + return conn->msg_ctx; +} + +int ctdbd_conn_get_fd(struct ctdbd_connection *conn) +{ + return packet_get_fd(conn->pkt); +} + /* * Packet handler to receive and handle a ctdb message */ @@ -533,15 +556,21 @@ static NTSTATUS ctdb_handle_message(uint8_t *buf, size_t length, SMB_ASSERT(conn->msg_ctx != NULL); - if (msg->srvid == CTDB_SRVID_RECONFIGURE) { + if ((msg->srvid == CTDB_SRVID_RECONFIGURE) + || (msg->srvid == CTDB_SRVID_SAMBA_NOTIFY)){ DEBUG(0,("Got cluster reconfigure message\n")); /* - * when the cluster is reconfigured, we need to clean the brl - * database + * when the cluster is reconfigured or someone of the + * family has passed away (SAMBA_NOTIFY), we need to + * clean the brl database */ messaging_send(conn->msg_ctx, procid_self(), MSG_SMB_BRL_VALIDATE, &data_blob_null); + messaging_send(conn->msg_ctx, procid_self(), + MSG_DBWRAP_G_LOCK_RETRY, + &data_blob_null); + TALLOC_FREE(buf); return NT_STATUS_OK; } @@ -1302,6 +1331,50 @@ NTSTATUS ctdbd_control_local(struct ctdbd_connection *conn, uint32 opcode, return ctdbd_control(conn, CTDB_CURRENT_NODE, opcode, srvid, flags, data, mem_ctx, outdata, cstatus); } +NTSTATUS ctdb_watch_us(struct ctdbd_connection *conn) +{ + struct ctdb_client_notify_register reg_data; + size_t struct_len; + NTSTATUS status; + int cstatus; + + reg_data.srvid = CTDB_SRVID_SAMBA_NOTIFY; + reg_data.len = 1; + reg_data.notify_data[0] = 0; + + struct_len = offsetof(struct ctdb_client_notify_register, + notify_data) + reg_data.len; + + status = ctdbd_control_local( + conn, CTDB_CONTROL_REGISTER_NOTIFY, conn->rand_srvid, 0, + make_tdb_data((uint8_t *)®_data, struct_len), + NULL, NULL, &cstatus); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(1, ("ctdbd_control_local failed: %s\n", + nt_errstr(status))); + } + return status; +} + +NTSTATUS ctdb_unwatch(struct ctdbd_connection *conn) +{ + struct ctdb_client_notify_deregister dereg_data; + NTSTATUS status; + int cstatus; + + dereg_data.srvid = CTDB_SRVID_SAMBA_NOTIFY; + + status = ctdbd_control_local( + conn, CTDB_CONTROL_DEREGISTER_NOTIFY, conn->rand_srvid, 0, + make_tdb_data((uint8_t *)&dereg_data, sizeof(dereg_data)), + NULL, NULL, &cstatus); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(1, ("ctdbd_control_local failed: %s\n", + nt_errstr(status))); + } + return status; +} + #else NTSTATUS ctdbd_init_connection(TALLOC_CTX *mem_ctx, diff --git a/source3/lib/dbwrap_ctdb.c b/source3/lib/dbwrap_ctdb.c index 8e188d0..ddc8868 100644 --- a/source3/lib/dbwrap_ctdb.c +++ b/source3/lib/dbwrap_ctdb.c @@ -1,7 +1,8 @@ /* Unix SMB/CIFS implementation. Database interface wrapper around ctdbd - Copyright (C) Volker Lendecke 2007 + Copyright (C) Volker Lendecke 2007-2009 + Copyright (C) Michael Adam 2009 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -22,10 +23,10 @@ #include "ctdb.h" #include "ctdb_private.h" #include "ctdbd_conn.h" +#include "g_lock.h" struct db_ctdb_transaction_handle { struct db_ctdb_ctx *ctx; - bool in_replay; /* * we store the reads and writes done under a transaction: * - one list stores both reads and writes (m_all), @@ -35,6 +36,7 @@ struct db_ctdb_transaction_handle { struct ctdb_marshall_buffer *m_write; uint32_t nesting; bool nested_cancel; + char *lock_name; }; struct db_ctdb_ctx { @@ -42,6 +44,7 @@ struct db_ctdb_ctx { struct tdb_wrap *wtdb; uint32 db_id; struct db_ctdb_transaction_handle *transaction; + struct g_lock_ctx *lock_ctx; }; struct db_ctdb_rec { @@ -297,145 +300,21 @@ static struct ctdb_rec_data *db_ctdb_marshall_loop_next(struct ctdb_marshall_buf return r; } - -static int32_t db_ctdb_transaction_active(uint32_t db_id) -{ - int32_t status; - NTSTATUS ret; - TDB_DATA indata; - - indata.dptr = (uint8_t *)&db_id; - indata.dsize = sizeof(db_id); - - ret = ctdbd_control_local(messaging_ctdbd_connection(), - CTDB_CONTROL_TRANS2_ACTIVE, 0, 0, - indata, NULL, NULL, &status); - - if (!NT_STATUS_IS_OK(ret)) { - DEBUG(2, ("ctdb control TRANS2_ACTIVE failed\n")); - return -1; - } - - return status; -} - - /** * CTDB transaction destructor */ static int db_ctdb_transaction_destructor(struct db_ctdb_transaction_handle *h) { - tdb_transaction_cancel(h->ctx->wtdb->tdb); - return 0; -} - -/** - * start a transaction on a ctdb database: - * - lock the transaction lock key - * - start the tdb transaction - */ -static int db_ctdb_transaction_fetch_start(struct db_ctdb_transaction_handle *h) -{ - struct db_record *rh; - struct db_ctdb_rec *crec; - TDB_DATA key; - TALLOC_CTX *tmp_ctx; - const char *keyname = CTDB_TRANSACTION_LOCK_KEY; - int ret; - struct db_ctdb_ctx *ctx = h->ctx; - TDB_DATA data; - pid_t pid; NTSTATUS status; - struct ctdb_ltdb_header header; - int32_t transaction_status; - key.dptr = (uint8_t *)discard_const(keyname); - key.dsize = strlen(keyname); - -again: - tmp_ctx = talloc_new(h); - - rh = fetch_locked_internal(ctx, tmp_ctx, key, true); - if (rh == NULL) { - DEBUG(0,(__location__ " Failed to fetch_lock database\n")); - talloc_free(tmp_ctx); - return -1; - } - crec = talloc_get_type_abort(rh->private_data, struct db_ctdb_rec); - - transaction_status = db_ctdb_transaction_active(ctx->db_id); - if (transaction_status == 1) { - unsigned long int usec = (1000 + random()) % 100000; - DEBUG(3, ("Transaction already active on db_id[0x%08x]." - "Re-trying after %lu microseconds...", - ctx->db_id, usec)); - talloc_free(tmp_ctx); - usleep(usec); - goto again; - } - - /* - * store the pid in the database: - * it is not enought that the node is dmaster... - */ - pid = getpid(); - data.dptr = (unsigned char *)&pid; - data.dsize = sizeof(pid_t); - crec->header.rsn++; - crec->header.dmaster = get_my_vnn(); - status = db_ctdb_ltdb_store(ctx, key, &(crec->header), data); + status = g_lock_unlock(h->ctx->lock_ctx, h->lock_name); if (!NT_STATUS_IS_OK(status)) { - DEBUG(0, (__location__ " Failed to store pid in transaction " - "record: %s\n", nt_errstr(status))); - talloc_free(tmp_ctx); + DEBUG(0, ("g_lock_unlock failed: %s\n", nt_errstr(status))); return -1; } - - talloc_free(rh); - - ret = tdb_transaction_start(ctx->wtdb->tdb); - if (ret != 0) { - DEBUG(0,(__location__ " Failed to start tdb transaction\n")); - talloc_free(tmp_ctx); - return -1; - } - - status = db_ctdb_ltdb_fetch(ctx, key, &header, tmp_ctx, &data); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0, (__location__ " failed to refetch transaction lock " - "record inside transaction: %s - retrying\n", - nt_errstr(status))); - tdb_transaction_cancel(ctx->wtdb->tdb); - talloc_free(tmp_ctx); - goto again; - } - - if (header.dmaster != get_my_vnn()) { - DEBUG(3, (__location__ " refetch transaction lock record : " - "we are not dmaster any more " - "(dmaster[%u] != my_vnn[%u]) - retrying\n", - header.dmaster, get_my_vnn())); - tdb_transaction_cancel(ctx->wtdb->tdb); - talloc_free(tmp_ctx); - goto again; - } - - if ((data.dsize != sizeof(pid_t)) || (*(pid_t *)(data.dptr) != pid)) { - DEBUG(3, (__location__ " refetch transaction lock record: " - "another local process has started a transaction " - "(stored pid [%u] != my pid [%u]) - retrying\n", - *(pid_t *)(data.dptr), pid)); - tdb_transaction_cancel(ctx->wtdb->tdb); - talloc_free(tmp_ctx); - goto again; - } - - talloc_free(tmp_ctx); - return 0; } - /** * CTDB dbwrap API: transaction_start function * starts a transaction on a persistent database @@ -443,7 +322,7 @@ again: static int db_ctdb_transaction_start(struct db_context *db) { -- Samba Shared Repository