[SCM] CTDB repository - branch 1.2.40 updated - ctdb-1.9.1-546-g0a52799

Ronnie Sahlberg sahlberg at samba.org
Thu Mar 1 16:16:41 MST 2012


The branch, 1.2.40 has been updated
       via  0a52799f85de9c9dc0ac8ae62e7f2829a30eb8bb (commit)
       via  ce57fcab99fa13548ae3693f471c7ecde08f67f3 (commit)
       via  dbf2c5b25833bf05cc3d1b9a9ee2186143386f35 (commit)
       via  1083ef705cb67185f6c199c01850e839d4f3c8bb (commit)
      from  fd33e6ff1e349e3d6d1d2e78ab14942c97aba731 (commit)

http://gitweb.samba.org/?p=ctdb.git;a=shortlog;h=1.2.40


- Log -----------------------------------------------------------------
commit 0a52799f85de9c9dc0ac8ae62e7f2829a30eb8bb
Author: Ronnie Sahlberg <ronniesahlberg at gmail.com>
Date:   Fri Mar 2 09:43:39 2012 +1100

    READONLY: when updating a remote node to revoke a delegation, make sure
    we dont create thje record if it doesnt exist

commit ce57fcab99fa13548ae3693f471c7ecde08f67f3
Author: Ronnie Sahlberg <ronniesahlberg at gmail.com>
Date:   Mon Feb 13 10:27:59 2012 +1100

    READONLY:  allow specifying the db name for setdbreadonly instead of just the hash

commit dbf2c5b25833bf05cc3d1b9a9ee2186143386f35
Author: Ronnie Sahlberg <ronniesahlberg at gmail.com>
Date:   Fri Mar 2 09:04:39 2012 +1100

    Niceify the readonlyrecord API. Dont force clients to be exposed to the fetch_with_header function
    
    We dont strictly need to force clients to use CTDB_FETCH_WITH_HEADER instead of CTDB_FETCH when they ask for readonly records.
    Have ctdbd internally remap this internally to FETCH_WITH_HEADER and map the reply back to CTDB_FETCH_FUNC or CTDB_FETCH_WITH_HEADER_FUNC based on what the client initially asked for.
    
    This removes the need for the client to know about the CTDB_FETCH_WITH_HEADER_FUNC function and simplifies the client code.
    Clients that do not care what the header after the request is can just continue using the old CTDB_FETCH_FUNC call and ctdbd will do all the difficult stuff.

commit 1083ef705cb67185f6c199c01850e839d4f3c8bb
Author: Ronnie Sahlberg <ronniesahlberg at gmail.com>
Date:   Fri Mar 2 08:53:16 2012 +1100

    READONLY: skip vacuuming or deleting records with readonly delegations.
    these records are hot. wait until they have been revoked before we recall them.

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

Summary of changes:
 doc/readonlyrecords.txt  |    7 +++++--
 libctdb/ctdb.c           |    8 ++++----
 server/ctdb_call.c       |    4 ++++
 server/ctdb_daemon.c     |   40 ++++++++++++++++++++++++++++++++++++++--
 server/ctdb_persistent.c |   17 +++++++++++++++++
 server/ctdb_recover.c    |   14 ++++++++++++++
 server/ctdb_vacuum.c     |    5 +++++
 tools/ctdb.c             |   33 +++++++++++++++++++++++++++++++--
 8 files changed, 118 insertions(+), 10 deletions(-)


Changeset truncated at 500 lines:

diff --git a/doc/readonlyrecords.txt b/doc/readonlyrecords.txt
index acdab2e..f8f1095 100644
--- a/doc/readonlyrecords.txt
+++ b/doc/readonlyrecords.txt
@@ -89,7 +89,10 @@ This new database is used for tracking delegations for the records. A record in
 This tracking database is lockless, using TDB_NOLOCK, and is only ever accessed by the main ctdbd daemon.
 The lockless nature and the fact that no other process ever access this TDB means we are guranteed non-blocking access to records in the trcking database.
 
-The ctdb_call PDU is allocated with two new flags WANT_READONLY and WITH_HEADER.
+The ctdb_call PDU is allocated with a new flags WANT_READONLY and possibly also a new callid: CTDB_FETCH_WITH_HEADER_FUNC.
+This new function returns not only the record, as CTDB_FETCH_FUNC does, but also returns the HEADER prepended to the record.
+This function is optional, clients that do not care what the header is can continue using just CTDB_FETCH_FUNC
+
 This first flag is used to explicitely requesting a read-only record from the DMASTER/LMASTER.
 The second flag is used to request that the fetch operation will return not only the data for the record but also
 the record header. 
@@ -137,7 +140,7 @@ This will change to instead do
                 goto finished
             else
                 unlock record 
-                ask ctdb for read-only copy (WANT_READONLY|WITH_HEADER)
+                ask ctdb for read-only copy (WANT_READONLY[|WITH_HEADER])
                 if failed to get read-only copy (*A)
                     ask ctdb to migrate the record onto the node
                     goto try_again
diff --git a/libctdb/ctdb.c b/libctdb/ctdb.c
index 36cc113..46f4953 100644
--- a/libctdb/ctdb.c
+++ b/libctdb/ctdb.c
@@ -819,13 +819,13 @@ static void readrecordlock_retry(struct ctdb_connection *ctdb,
 	struct ctdb_reply_call *reply;
 	TDB_DATA data;
 
-	/* OK, we've received reply to fetch-with-header migration */
-	reply = unpack_reply_call(ctdb, req, CTDB_FETCH_WITH_HEADER_FUNC);
+	/* OK, we've received reply to fetch migration */
+	reply = unpack_reply_call(ctdb, req, CTDB_FETCH_FUNC);
 	if (!reply || reply->status != 0) {
 		if (reply) {
 			DEBUG(ctdb, LOG_ERR,
 			      "ctdb_readrecordlock_async(async):"
-			      " FETCH_WITH_HEADER_FUNC returned %i", reply->status);
+			      " FETCH returned %i", reply->status);
 		}
 		lock->callback(lock->ctdb_db, NULL, tdb_null, private);
 		ctdb_request_free(ctdb, req); /* Also frees lock. */
@@ -905,7 +905,7 @@ ctdb_readrecordlock_internal(struct ctdb_db *ctdb_db, TDB_DATA key,
 		req->hdr.call->flags = CTDB_IMMEDIATE_MIGRATION;
 	}
 	req->hdr.call->db_id = ctdb_db->id;
-	req->hdr.call->callid = CTDB_FETCH_WITH_HEADER_FUNC;
+	req->hdr.call->callid = CTDB_FETCH_FUNC;
 	req->hdr.call->hopcount = 0;
 	req->hdr.call->keylen = key.dsize;
 	req->hdr.call->calldatalen = 0;
diff --git a/server/ctdb_call.c b/server/ctdb_call.c
index 23d10b9..2657f8b 100644
--- a/server/ctdb_call.c
+++ b/server/ctdb_call.c
@@ -937,6 +937,9 @@ struct ctdb_call_state *ctdb_call_local_send(struct ctdb_db_context *ctdb_db,
 	state->ctdb_db = ctdb_db;
 
 	ret = ctdb_call_local(ctdb_db, state->call, header, state, data, true);
+	if (ret != 0) {
+		DEBUG(DEBUG_DEBUG,("ctdb_call_local() failed, ignoring return code %d\n", ret));
+	}
 
 	event_add_timed(ctdb->ev, state, timeval_zero(), call_local_trigger, state);
 
@@ -1293,6 +1296,7 @@ int ctdb_start_revoke_ro_record(struct ctdb_context *ctdb, struct ctdb_db_contex
 	int ret;
 
 	header->flags &= ~(CTDB_REC_RO_REVOKING_READONLY|CTDB_REC_RO_HAVE_DELEGATIONS|CTDB_REC_RO_HAVE_READONLY);
+	header->flags |= CTDB_REC_FLAG_MIGRATED_WITH_DATA;
 	header->rsn   -= 1;
 
 	if ((rc = talloc_zero(ctdb_db, struct revokechild_handle)) == NULL) {
diff --git a/server/ctdb_daemon.c b/server/ctdb_daemon.c
index abf5ed2..c4f46b1 100644
--- a/server/ctdb_daemon.c
+++ b/server/ctdb_daemon.c
@@ -274,6 +274,10 @@ struct daemon_call_state {
 	uint32_t reqid;
 	struct ctdb_call *call;
 	struct timeval start_time;
+
+	/* readonly request ? */
+	uint32_t readonly_fetch;
+	uint32_t client_callid;
 };
 
 /* 
@@ -302,6 +306,16 @@ static void daemon_call_from_client_callback(struct ctdb_call_state *state)
 	}
 
 	length = offsetof(struct ctdb_reply_call, data) + dstate->call->reply_data.dsize;
+	/* If the client asked for readonly FETCH, we remapped this to 
+	   FETCH_WITH_HEADER when calling the daemon. So we must
+	   strip the extra header off the reply data before passing
+	   it back to the client.
+	*/
+	if (dstate->readonly_fetch
+	&& dstate->client_callid == CTDB_FETCH_FUNC) {
+		length -= sizeof(struct ctdb_ltdb_header);
+	}
+
 	r = ctdbd_allocate_pkt(client->ctdb, dstate, CTDB_REPLY_CALL, 
 			       length, struct ctdb_reply_call);
 	if (r == NULL) {
@@ -311,9 +325,19 @@ static void daemon_call_from_client_callback(struct ctdb_call_state *state)
 		return;
 	}
 	r->hdr.reqid        = dstate->reqid;
-	r->datalen          = dstate->call->reply_data.dsize;
 	r->status           = dstate->call->status;
-	memcpy(&r->data[0], dstate->call->reply_data.dptr, r->datalen);
+
+	if (dstate->readonly_fetch
+	&& dstate->client_callid == CTDB_FETCH_FUNC) {
+		/* client only asked for a FETCH so we must strip off
+		   the extra ctdb_ltdb header
+		*/
+		r->datalen          = dstate->call->reply_data.dsize - sizeof(struct ctdb_ltdb_header);
+		memcpy(&r->data[0], dstate->call->reply_data.dptr + sizeof(struct ctdb_ltdb_header), r->datalen);
+	} else {
+		r->datalen          = dstate->call->reply_data.dsize;
+		memcpy(&r->data[0], dstate->call->reply_data.dptr, r->datalen);
+	}
 
 	res = daemon_queue_send(client, &r->hdr);
 	if (res == -1) {
@@ -503,12 +527,24 @@ static void daemon_request_call_from_client(struct ctdb_client *client,
 		return;
 	}
 
+	dstate->readonly_fetch = 0;
 	call->call_id = c->callid;
 	call->key = key;
 	call->call_data.dptr = c->data + c->keylen;
 	call->call_data.dsize = c->calldatalen;
 	call->flags = c->flags;
 
+	if (c->flags & CTDB_WANT_READONLY) {
+		/* client wants readonly record, so translate this into a 
+		   fetch with header. remember what the client asked for
+		   so we can remap the reply back to the proper format for
+		   the client in the reply
+		 */
+		dstate->client_callid = call->call_id;
+		call->call_id = CTDB_FETCH_WITH_HEADER_FUNC;
+		dstate->readonly_fetch = 1;
+	}
+
 	if (header.dmaster == ctdb->pnn) {
 		state = ctdb_call_local_send(ctdb_db, call, &header, &data);
 	} else {
diff --git a/server/ctdb_persistent.c b/server/ctdb_persistent.c
index b95f456..669021a 100644
--- a/server/ctdb_persistent.c
+++ b/server/ctdb_persistent.c
@@ -436,8 +436,11 @@ struct ctdb_persistent_write_state {
 	struct ctdb_db_context *ctdb_db;
 	struct ctdb_marshall_buffer *m;
 	struct ctdb_req_control *c;
+	uint32_t flags;
 };
 
+/* dont create/update records that does not exist locally */
+#define UPDATE_FLAGS_REPLACE_ONLY	1
 
 /*
   called from a child process to write the data
@@ -470,6 +473,19 @@ static int ctdb_persistent_store(struct ctdb_persistent_write_state *state)
 			goto failed;			
 		}
 
+		/* we must check if the record exists or not because
+		   ctdb_ltdb_fetch will unconditionally create a record
+		 */
+		if (state->flags & UPDATE_FLAGS_REPLACE_ONLY) {
+			TDB_DATA rec;
+			rec = tdb_fetch(state->ctdb_db->ltdb->tdb, key);
+			if (rec.dsize == 0) {
+				talloc_free(tmp_ctx);
+				continue;
+			}
+			free(rec.dptr);
+		}
+
 		/* fetch the old header and ensure the rsn is less than the new rsn */
 		ret = ctdb_ltdb_fetch(state->ctdb_db, key, &oldheader, tmp_ctx, &olddata);
 		if (ret != 0) {
@@ -716,6 +732,7 @@ int32_t ctdb_control_update_record(struct ctdb_context *ctdb,
 	state->ctdb_db = ctdb_db;
 	state->c       = c;
 	state->m       = m;
+	state->flags   = UPDATE_FLAGS_REPLACE_ONLY;
 
 	/* create a child process to take out a transaction and 
 	   write the data.
diff --git a/server/ctdb_recover.c b/server/ctdb_recover.c
index 3d56f77..06b5ed1 100644
--- a/server/ctdb_recover.c
+++ b/server/ctdb_recover.c
@@ -954,6 +954,20 @@ static int delete_tdb_record(struct ctdb_context *ctdb, struct ctdb_db_context *
 		return -1;		
 	}
 
+	/* do not allow deleting record that have readonly flags set. */
+	if (hdr->flags & (CTDB_REC_RO_HAVE_DELEGATIONS|CTDB_REC_RO_HAVE_READONLY|CTDB_REC_RO_REVOKING_READONLY|CTDB_REC_RO_REVOKE_COMPLETE)) {
+		tdb_chainunlock(ctdb_db->ltdb->tdb, key);
+		DEBUG(DEBUG_INFO,(__location__ " Skipping record with readonly flags set\n"));
+		free(data.dptr);
+		return -1;		
+	}
+	if (hdr2->flags & (CTDB_REC_RO_HAVE_DELEGATIONS|CTDB_REC_RO_HAVE_READONLY|CTDB_REC_RO_REVOKING_READONLY|CTDB_REC_RO_REVOKE_COMPLETE)) {
+		tdb_chainunlock(ctdb_db->ltdb->tdb, key);
+		DEBUG(DEBUG_INFO,(__location__ " Skipping record with readonly flags set\n"));
+		free(data.dptr);
+		return -1;		
+	}
+
 	if (hdr2->dmaster == ctdb->pnn) {
 		tdb_chainunlock(ctdb_db->ltdb->tdb, key);
 		DEBUG(DEBUG_INFO,(__location__ " Attempted delete record where we are the dmaster\n"));
diff --git a/server/ctdb_vacuum.c b/server/ctdb_vacuum.c
index bdb7c40..181393b 100644
--- a/server/ctdb_vacuum.c
+++ b/server/ctdb_vacuum.c
@@ -356,6 +356,11 @@ static void delete_queue_traverse(void *param, void *data)
 
 	header = (struct ctdb_ltdb_header *)tdb_data.dptr;
 
+	if (header->flags & (CTDB_REC_RO_HAVE_DELEGATIONS|CTDB_REC_RO_HAVE_READONLY|CTDB_REC_RO_REVOKING_READONLY|CTDB_REC_RO_REVOKE_COMPLETE)) {
+	  /* The record has readonly flags set. skip deleting */
+		goto skipped;
+	}
+
 	if (header->dmaster != ctdb->pnn) {
 		/* The record has been migrated off the node. Skip. */
 		goto skipped;
diff --git a/tools/ctdb.c b/tools/ctdb.c
index c3f8a7a..92ef63d 100644
--- a/tools/ctdb.c
+++ b/tools/ctdb.c
@@ -4126,21 +4126,50 @@ static int control_getdbprio(struct ctdb_context *ctdb, int argc, const char **a
  */
 static int control_setdbreadonly(struct ctdb_context *ctdb, int argc, const char **argv)
 {
+	TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
 	uint32_t db_id;
-	int ret;
+	struct ctdb_dbid_map *dbmap=NULL;
+	int i, ret;
 
 	if (argc < 1) {
 		usage();
 	}
 
-	db_id = strtoul(argv[0], NULL, 0);
+	if (!strncmp(argv[0], "0x", 2)) {
+		db_id = strtoul(argv[0] + 2, NULL, 0);
+	} else {
+		ret = ctdb_ctrl_getdbmap(ctdb, TIMELIMIT(), options.pnn, tmp_ctx, &dbmap);
+		if (ret != 0) {
+			DEBUG(DEBUG_ERR, ("Unable to get dbids from node %u\n", options.pnn));
+			talloc_free(tmp_ctx);
+			return ret;
+		}
+		for(i=0;i<dbmap->num;i++){
+			const char *name;
+
+			ctdb_ctrl_getdbname(ctdb, TIMELIMIT(), options.pnn, dbmap->dbs[i].dbid, tmp_ctx, &name);
+			if(!strcmp(argv[0], name)){
+				talloc_free(discard_const(name));
+				break;
+			}
+			talloc_free(discard_const(name));
+		}
+		if (i == dbmap->num) {
+			DEBUG(DEBUG_ERR,("No database with name '%s' found\n", argv[0]));
+			talloc_free(tmp_ctx);
+			return -1;
+		}
+		db_id = dbmap->dbs[i].dbid;
+	}
 
 	ret = ctdb_ctrl_set_db_readonly(ctdb, options.pnn, db_id);
 	if (ret != 0) {
 		DEBUG(DEBUG_ERR,("Unable to set db to support readonly\n"));
+		talloc_free(tmp_ctx);
 		return -1;
 	}
 
+	talloc_free(tmp_ctx);
 	return 0;
 }
 


-- 
CTDB repository


More information about the samba-cvs mailing list