[SCM] Samba Shared Repository - branch v3-2-test updated - release-3-2-0pre2-838-g64450cc

Stefan Metzmacher metze at samba.org
Sat Apr 12 07:16:13 GMT 2008


The branch, v3-2-test has been updated
       via  64450cc1e441355aa8925b7183e90872eeab20b1 (commit)
       via  5cea2bf3673c982bafeef4a8bbd3bd2ab73cc0c5 (commit)
       via  aa6230de0d5f1875aa8c12c4fc017d3a40f90890 (commit)
       via  f34dad2b4ad97a845729ea0fb5beba7fd6cb7265 (commit)
       via  46a0d8e872af1ab420705a514c1d7b1b21459f82 (commit)
       via  7418c3ab1d8f18403f5a43817b2cc14e15090fca (commit)
       via  ee6325495f48bab43a37d740a6eca57192004d57 (commit)
      from  7258c780f0650c63d6c7c40fd704a9b841600f26 (commit)

http://gitweb.samba.org/?p=samba.git;a=shortlog;h=v3-2-test


- Log -----------------------------------------------------------------
commit 64450cc1e441355aa8925b7183e90872eeab20b1
Author: Stefan Metzmacher <metze at samba.org>
Date:   Tue Apr 1 14:01:28 2008 +0200

    dbwrap: wait for tdb2 change notifies in smbd, nmbd and winbindd
    
    metze

commit 5cea2bf3673c982bafeef4a8bbd3bd2ab73cc0c5
Author: Stefan Metzmacher <metze at samba.org>
Date:   Wed Mar 26 10:08:10 2008 +0100

    dbwrap: use db_open_tdb2() in for db_open_trans() if "dbwrap:use_tdb2=yes"
    
    For clustered setups you need to disable the ctdb backend for each
    tdb which should use the tdb2 backend (e.g. ctdb:registry.tdb=no).
    
    To disable tdb2 per tdb use something like "tdb2:passdb.tdb=no"
    
    metze

commit aa6230de0d5f1875aa8c12c4fc017d3a40f90890
Author: Stefan Metzmacher <metze at samba.org>
Date:   Wed Mar 19 19:40:10 2008 +0100

    dbwrap: add dbwrap_tdb2 backend
    
    This backend can be used untill ctdb knows about real
    transactions.
    
    It stores a master tdb in a shared location and a readonly copy
    on the local harddisk. Reads are always on the local tdb
    and writes always on both. Change notify messages are send
    to all message context, which ask for them. With the notifies
    it's possible to just update the changed records, instead of
    copying all records (which is the fallback).
    
    You need to configure:
    
    dbwrap:use_tdb2=yes
    dbwrap_tdb2:master directory=/some/shared/path
    dbwrap_tdb2:local directory=/var/lib/samba
    
    metze

commit f34dad2b4ad97a845729ea0fb5beba7fd6cb7265
Author: Stefan Metzmacher <metze at samba.org>
Date:   Mon Mar 31 11:18:12 2008 +0200

    rerun 'make idl'
    
    metze

commit 46a0d8e872af1ab420705a514c1d7b1b21459f82
Author: Stefan Metzmacher <metze at samba.org>
Date:   Mon Mar 31 11:17:15 2008 +0200

    messaging.idl: add structure to marshall dbwrap_tdb2 changes
    
    metze

commit 7418c3ab1d8f18403f5a43817b2cc14e15090fca
Author: Stefan Metzmacher <metze at samba.org>
Date:   Mon Mar 31 12:50:23 2008 +0200

    messaging: add MSG_DBWRAP_TDB2_CHANGES flag
    
    metze

commit ee6325495f48bab43a37d740a6eca57192004d57
Author: Stefan Metzmacher <metze at samba.org>
Date:   Mon Mar 31 12:50:23 2008 +0200

    messaging: add FLAG_MSG_DBWRAP message class flag
    
    metze

-----------------------------------------------------------------------

Summary of changes:
 source/Makefile.in                    |    8 +-
 source/include/dbwrap.h               |    8 +
 source/include/messages.h             |    5 +
 source/lib/dbwrap.c                   |   59 ++-
 source/lib/dbwrap_tdb2.c              | 1265 +++++++++++++++++++++++++++++++++
 source/lib/messages.c                 |    2 +
 source/librpc/gen_ndr/messaging.h     |   11 +
 source/librpc/gen_ndr/ndr_messaging.c |   81 +++
 source/librpc/gen_ndr/ndr_messaging.h |    3 +
 source/librpc/idl/messaging.idl       |   15 +
 source/nmbd/nmbd.c                    |    8 +
 source/smbd/server.c                  |    6 +-
 source/winbindd/winbindd.c            |    7 +
 13 files changed, 1472 insertions(+), 6 deletions(-)
 create mode 100644 source/lib/dbwrap_tdb2.c


Changeset truncated at 500 lines:

diff --git a/source/Makefile.in b/source/Makefile.in
index 1c760d8..59eeecf 100644
--- a/source/Makefile.in
+++ b/source/Makefile.in
@@ -247,7 +247,8 @@ LIBTDB_OBJ0 = @TDB_OBJS@
 LIBTDB_OBJ = $(LIBTDB_OBJ0) $(LIBREPLACE_OBJ)
 
 TDB_OBJ = lib/util_tdb.o \
-	  lib/dbwrap.o lib/dbwrap_tdb.o lib/dbwrap_ctdb.o \
+	  lib/dbwrap.o lib/dbwrap_tdb.o \
+	  lib/dbwrap_tdb2.o lib/dbwrap_ctdb.o \
 	  lib/dbwrap_rbt.o @LIBTDB_STATIC@
 
 SMBLDAP_OBJ = @SMBLDAP@ @SMBLDAPUTIL@
@@ -710,7 +711,7 @@ NMBD_OBJ1 = nmbd/asyncdns.o nmbd/nmbd.o nmbd/nmbd_become_dmb.o \
             nmbd/nmbd_processlogon.o nmbd/nmbd_responserecordsdb.o \
             nmbd/nmbd_sendannounce.o nmbd/nmbd_serverlistdb.o \
             nmbd/nmbd_subnetdb.o nmbd/nmbd_winsproxy.o nmbd/nmbd_winsserver.o \
-            nmbd/nmbd_workgroupdb.o nmbd/nmbd_synclists.o
+            nmbd/nmbd_workgroupdb.o nmbd/nmbd_synclists.o smbd/connection.o
 
 NMBD_OBJ = $(NMBD_OBJ1) $(PARAM_OBJ) $(LIBSMB_OBJ) $(KRBCLIENT_OBJ) \
            $(PROFILE_OBJ) $(LIB_NONSMBD_OBJ) $(POPT_LIB_OBJ)
@@ -1031,7 +1032,8 @@ WINBINDD_OBJ1 = \
 		winbindd/winbindd_idmap.o \
 		winbindd/winbindd_locator.o \
 		winbindd/winbindd_ndr.o \
-		auth/token_util.o
+		auth/token_util.o \
+		smbd/connection.o
 
 WINBINDD_OBJ = \
 		$(WINBINDD_OBJ1) $(PASSDB_OBJ) @LIBWBCLIENT_STATIC@ $(GROUPDB_OBJ) \
diff --git a/source/include/dbwrap.h b/source/include/dbwrap.h
index fe84709..1f38816 100644
--- a/source/include/dbwrap.h
+++ b/source/include/dbwrap.h
@@ -66,6 +66,14 @@ struct db_context *db_open_tdb(TALLOC_CTX *mem_ctx,
 			       int hash_size, int tdb_flags,
 			       int open_flags, mode_t mode);
 
+struct db_context *db_open_tdb2(TALLOC_CTX *mem_ctx,
+			        const char *name,
+			        int hash_size, int tdb_flags,
+			        int open_flags, mode_t mode);
+
+struct messaging_context;
+void db_tdb2_setup_messaging(struct messaging_context *msg_ctx, bool server);
+
 #ifdef CLUSTER_SUPPORT
 struct db_context *db_open_ctdb(TALLOC_CTX *mem_ctx,
 				const char *name,
diff --git a/source/include/messages.h b/source/include/messages.h
index c97ad98..8f0112a 100644
--- a/source/include/messages.h
+++ b/source/include/messages.h
@@ -102,6 +102,9 @@
 /* event messages */
 #define MSG_DUMP_EVENT_LIST		0x0500
 
+/* dbwrap messages 4001-4999 */
+#define MSG_DBWRAP_TDB2_CHANGES		4001
+
 /*
  * Special flags passed to message_send. Allocated from the top, lets see when
  * it collides with the message types in the lower 16 bits :-)
@@ -122,6 +125,8 @@
 #define FLAG_MSG_NMBD			0x0004
 #define FLAG_MSG_PRINT_NOTIFY		0x0008
 #define FLAG_MSG_PRINT_GENERAL		0x0010
+/* dbwrap messages 4001-4999 */
+#define FLAG_MSG_DBWRAP			0x0020
 
 
 /*
diff --git a/source/lib/dbwrap.c b/source/lib/dbwrap.c
index fd92463..d688b83 100644
--- a/source/lib/dbwrap.c
+++ b/source/lib/dbwrap.c
@@ -104,8 +104,63 @@ struct db_context *db_open_trans(TALLOC_CTX *mem_ctx,
 				 int hash_size, int tdb_flags,
 				 int open_flags, mode_t mode)
 {
-	/* TODO: implement this differently */
-	return db_open(mem_ctx, name, hash_size, tdb_flags, open_flags, mode);
+	bool use_tdb2 = lp_parm_bool(-1, "dbwrap", "use_tdb2", false);
+#ifdef CLUSTER_SUPPORT
+	const char *sockname = lp_ctdbd_socket();
+#endif
+
+	if (tdb_flags & TDB_CLEAR_IF_FIRST) {
+		DEBUG(0,("db_open_trans: called with TDB_CLEAR_IF_FIRST: %s\n",
+			 name));
+		smb_panic("db_open_trans: called with TDB_CLEAR_IF_FIRST");
+	}
+
+#ifdef CLUSTER_SUPPORT
+	if(!sockname || !*sockname) {
+		sockname = CTDB_PATH;
+	}
+
+	if (lp_clustering() && socket_exist(sockname)) {
+		const char *partname;
+		/* ctdb only wants the file part of the name */
+		partname = strrchr(name, '/');
+		if (partname) {
+			partname++;
+		} else {
+			partname = name;
+		}
+		/* allow ctdb for individual databases to be disabled */
+		if (lp_parm_bool(-1, "ctdb", partname, true)) {
+			result = db_open_ctdb(mem_ctx, partname, hash_size,
+					      tdb_flags, open_flags, mode);
+			if (result == NULL) {
+				DEBUG(0,("failed to attach to ctdb %s\n",
+					 partname));
+				smb_panic("failed to attach to a ctdb "
+					  "database");
+			}
+		}
+	}
+#endif
+
+	if (use_tdb2) {
+		const char *partname;
+		/* tdb2 only wants the file part of the name */
+		partname = strrchr(name, '/');
+		if (partname) {
+			partname++;
+		} else {
+			partname = name;
+		}
+		/* allow ctdb for individual databases to be disabled */
+		if (lp_parm_bool(-1, "tdb2", partname, true)) {
+			return db_open_tdb2(mem_ctx, partname, hash_size,
+					    tdb_flags, open_flags, mode);
+		}
+	}
+
+	return db_open_tdb(mem_ctx, name, hash_size,
+			   tdb_flags, open_flags, mode);
 }
 
 NTSTATUS dbwrap_delete_bystring(struct db_context *db, const char *key)
diff --git a/source/lib/dbwrap_tdb2.c b/source/lib/dbwrap_tdb2.c
new file mode 100644
index 0000000..cbcbe71
--- /dev/null
+++ b/source/lib/dbwrap_tdb2.c
@@ -0,0 +1,1265 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   Database interface wrapper around tdb/ctdb
+
+   Copyright (C) Volker Lendecke 2005-2007
+   Copyright (C) Stefan Metzmacher 2008
+
+   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/>.
+*/
+
+#include "includes.h"
+#include "librpc/gen_ndr/ndr_messaging.h"
+
+struct db_tdb2_ctx {
+	struct db_context *db;
+	const char *name;
+	struct tdb_wrap *mtdb;
+	const char *mtdb_path;
+	bool master_transaction;
+	struct {
+		int hash_size;
+		int tdb_flags;
+		int open_flags;
+		mode_t mode;
+	} open;
+	struct tdb_wrap *ltdb;
+	const char *ltdb_path;
+	bool local_transaction;
+	int transaction;
+	bool out_of_sync;
+	uint32_t lseqnum;
+	uint32_t mseqnum;
+#define DB_TDB2_MASTER_SEQNUM_KEYSTR "DB_TDB2_MASTER_SEQNUM_KEYSTR"
+	TDB_DATA mseqkey;
+	uint32_t max_buffer_size;
+	uint32_t current_buffer_size;
+	struct dbwrap_tdb2_changes changes;
+};
+
+
+static NTSTATUS db_tdb2_store(struct db_record *rec, TDB_DATA data, int flag);
+static NTSTATUS db_tdb2_delete(struct db_record *rec);
+
+static void db_tdb2_queue_change(struct db_tdb2_ctx *db_ctx, const TDB_DATA key);
+static void db_tdb2_send_notify(struct db_tdb2_ctx *db_ctx);
+
+static struct db_context *db_open_tdb2_ex(TALLOC_CTX *mem_ctx,
+					  const char *name,
+					  int hash_size, int tdb_flags,
+					  int open_flags, mode_t mode,
+					  const struct dbwrap_tdb2_changes *chgs);
+
+static int db_tdb2_sync_from_master(struct db_tdb2_ctx *db_ctx,
+				    const struct dbwrap_tdb2_changes *changes);
+
+static int db_tdb2_open_master(struct db_tdb2_ctx *db_ctx, bool transaction,
+			       const struct dbwrap_tdb2_changes *changes);
+static int db_tdb2_commit_local(struct db_tdb2_ctx *db_ctx, uint32_t mseqnum);
+static int db_tdb2_close_master(struct db_tdb2_ctx *db_ctx);
+static int db_tdb2_transaction_cancel(struct db_context *db);
+
+static void db_tdb2_receive_changes(struct messaging_context *msg,
+				    void *private_data,
+				    uint32_t msg_type,
+				    struct server_id server_id,
+				    DATA_BLOB *data);
+
+static struct messaging_context *global_tdb2_msg_ctx;
+static bool global_tdb2_msg_ctx_initialized;
+
+void db_tdb2_setup_messaging(struct messaging_context *msg_ctx, bool server)
+{
+	global_tdb2_msg_ctx = msg_ctx;
+
+	global_tdb2_msg_ctx_initialized = true;
+
+	if (!server) {
+		return;
+	}
+
+	if (!lp_parm_bool(-1, "dbwrap", "use_tdb2", false)) {
+		return;
+	}
+
+	messaging_register(msg_ctx, NULL, MSG_DBWRAP_TDB2_CHANGES,
+			   db_tdb2_receive_changes);
+}
+
+static struct messaging_context *db_tdb2_get_global_messaging_context(void)
+{
+	struct messaging_context *msg_ctx;
+
+	if (global_tdb2_msg_ctx_initialized) {
+		return global_tdb2_msg_ctx;
+	}
+
+	msg_ctx = messaging_init(NULL, procid_self(),
+				 event_context_init(NULL));
+
+	db_tdb2_setup_messaging(msg_ctx, false);
+
+	return global_tdb2_msg_ctx;
+}
+
+struct tdb_fetch_locked_state {
+	TALLOC_CTX *mem_ctx;
+	struct db_record *result;
+};
+
+static int db_tdb2_fetchlock_parse(TDB_DATA key, TDB_DATA data,
+				  void *private_data)
+{
+	struct tdb_fetch_locked_state *state =
+		(struct tdb_fetch_locked_state *)private_data;
+
+	state->result = (struct db_record *)talloc_size(
+		state->mem_ctx,
+		sizeof(struct db_record) + key.dsize + data.dsize);
+
+	if (state->result == NULL) {
+		return 0;
+	}
+
+	state->result->key.dsize = key.dsize;
+	state->result->key.dptr = ((uint8 *)state->result)
+		+ sizeof(struct db_record);
+	memcpy(state->result->key.dptr, key.dptr, key.dsize);
+
+	state->result->value.dsize = data.dsize;
+
+	if (data.dsize > 0) {
+		state->result->value.dptr = state->result->key.dptr+key.dsize;
+		memcpy(state->result->value.dptr, data.dptr, data.dsize);
+	}
+	else {
+		state->result->value.dptr = NULL;
+	}
+
+	return 0;
+}
+
+static struct db_record *db_tdb2_fetch_locked(struct db_context *db,
+					      TALLOC_CTX *mem_ctx, TDB_DATA key)
+{
+	struct db_tdb2_ctx *ctx = talloc_get_type_abort(db->private_data,
+							struct db_tdb2_ctx);
+	struct tdb_fetch_locked_state state;
+
+	/* Do not accidently allocate/deallocate w/o need when debug level is lower than needed */
+	if(DEBUGLEVEL >= 10) {
+		char *keystr = hex_encode(NULL, (unsigned char*)key.dptr, key.dsize);
+		DEBUG(10, (DEBUGLEVEL > 10
+			   ? "Locking key %s\n" : "Locking key %.20s\n",
+			   keystr));
+		TALLOC_FREE(keystr);
+	}
+
+	/*
+	 * we only support modifications within a
+	 * started transaction.
+	 */
+	if (ctx->transaction == 0) {
+		DEBUG(0, ("db_tdb2_fetch_locked[%s]: no transaction started\n",
+			  ctx->name));
+		smb_panic("no transaction");
+		return NULL;
+	}
+
+	state.mem_ctx = mem_ctx;
+	state.result = NULL;
+
+	tdb_parse_record(ctx->mtdb->tdb, key, db_tdb2_fetchlock_parse, &state);
+
+	if (state.result == NULL) {
+		db_tdb2_fetchlock_parse(key, tdb_null, &state);
+	}
+
+	if (state.result == NULL) {
+		return NULL;
+	}
+
+	state.result->private_data = talloc_reference(state.result, ctx);
+	state.result->store = db_tdb2_store;
+	state.result->delete_rec = db_tdb2_delete;
+
+	DEBUG(10, ("Allocated locked data 0x%p\n", state.result));
+
+	return state.result;
+}
+
+struct tdb_fetch_state {
+	TALLOC_CTX *mem_ctx;
+	int result;
+	TDB_DATA data;
+};
+
+static int db_tdb2_fetch_parse(TDB_DATA key, TDB_DATA data,
+			       void *private_data)
+{
+	struct tdb_fetch_state *state =
+		(struct tdb_fetch_state *)private_data;
+
+	state->data.dptr = (uint8 *)talloc_memdup(state->mem_ctx, data.dptr,
+						  data.dsize);
+	if (state->data.dptr == NULL) {
+		state->result = -1;
+		return 0;
+	}
+
+	state->data.dsize = data.dsize;
+	return 0;
+}
+
+static void db_tdb2_resync_before_read(struct db_tdb2_ctx *db_ctx, TDB_DATA *kbuf)
+{
+	if (db_ctx->mtdb) {
+		return;
+	}
+
+	if (!db_ctx->out_of_sync) {
+		return;
+	}
+
+	/*
+	 * this function operates on the local copy,
+	 * so hide the DB_TDB2_MASTER_SEQNUM_KEYSTR from the caller.
+	 */
+	if (kbuf && (db_ctx->mseqkey.dsize == kbuf->dsize) &&
+	    (memcmp(db_ctx->mseqkey.dptr, kbuf->dptr, kbuf->dsize) == 0)) {
+		return;
+	}
+
+	DEBUG(0,("resync_before_read[%s/%s]\n",
+		 db_ctx->mtdb_path, db_ctx->ltdb_path));
+
+	db_tdb2_open_master(db_ctx, false, NULL);
+	db_tdb2_close_master(db_ctx);
+}
+
+static int db_tdb2_fetch(struct db_context *db, TALLOC_CTX *mem_ctx,
+			 TDB_DATA key, TDB_DATA *pdata)
+{
+	struct db_tdb2_ctx *ctx = talloc_get_type_abort(
+		db->private_data, struct db_tdb2_ctx);
+
+	struct tdb_fetch_state state;
+
+	db_tdb2_resync_before_read(ctx, &key);
+
+	if (ctx->out_of_sync) {
+		DEBUG(0,("out of sync[%s] failing fetch\n",
+			 ctx->ltdb_path));
+		errno = EIO;
+		return -1;
+	}
+
+	state.mem_ctx = mem_ctx;
+	state.result = 0;
+	state.data = tdb_null;
+
+	tdb_parse_record(ctx->ltdb->tdb, key, db_tdb2_fetch_parse, &state);
+
+	if (state.result == -1) {
+		return -1;
+	}
+
+	*pdata = state.data;
+	return 0;
+}
+
+static NTSTATUS db_tdb2_store(struct db_record *rec, TDB_DATA data, int flag)
+{
+	struct db_tdb2_ctx *ctx = talloc_get_type_abort(rec->private_data,
+						       struct db_tdb2_ctx);
+	int ret;
+
+	/*
+	 * This has a bug: We need to replace rec->value for correct
+	 * operation, but right now brlock and locking don't use the value
+	 * anymore after it was stored.
+	 */
+
+	/* first store it to the master copy */
+	ret = tdb_store(ctx->mtdb->tdb, rec->key, data, flag);
+	if (ret != 0) {
+		return NT_STATUS_UNSUCCESSFUL;
+	}
+
+	/* then store it to the local copy */
+	ret = tdb_store(ctx->ltdb->tdb, rec->key, data, flag);
+	if (ret != 0) {
+		/* try to restore the old value in the master copy */
+		if (rec->value.dptr) {
+			tdb_store(ctx->mtdb->tdb, rec->key,
+				  rec->value, TDB_REPLACE);
+		} else {
+			tdb_delete(ctx->mtdb->tdb, rec->key);
+		}
+		return NT_STATUS_INTERNAL_DB_CORRUPTION;
+	}
+
+	db_tdb2_queue_change(ctx, rec->key);
+
+	return NT_STATUS_OK;
+}
+
+static NTSTATUS db_tdb2_delete(struct db_record *rec)
+{
+	struct db_tdb2_ctx *ctx = talloc_get_type_abort(rec->private_data,
+						       struct db_tdb2_ctx);
+	int ret;
+
+	ret = tdb_delete(ctx->mtdb->tdb, rec->key);
+	if (ret != 0) {
+		if (tdb_error(ctx->mtdb->tdb) == TDB_ERR_NOEXIST) {
+			return NT_STATUS_NOT_FOUND;
+		}
+
+		return NT_STATUS_UNSUCCESSFUL;
+	}
+
+	ret = tdb_delete(ctx->ltdb->tdb, rec->key);
+	if (ret != 0) {
+		/* try to restore the value in the master copy */
+		tdb_store(ctx->mtdb->tdb, rec->key,
+			  rec->value, TDB_REPLACE);
+		return NT_STATUS_INTERNAL_DB_CORRUPTION;
+	}
+
+	db_tdb2_queue_change(ctx, rec->key);
+
+	return NT_STATUS_OK;
+}
+
+struct db_tdb2_traverse_ctx {
+	struct db_tdb2_ctx *db_ctx;
+	int (*f)(struct db_record *rec, void *private_data);


-- 
Samba Shared Repository


More information about the samba-cvs mailing list