ReadOnly: add a new control to activate readonly lock capability for a database.
authorRonnie Sahlberg <ronniesahlberg@gmail.com>
Thu, 1 Sep 2011 01:08:18 +0000 (11:08 +1000)
committerRonnie Sahlberg <ronniesahlberg@gmail.com>
Thu, 1 Sep 2011 01:08:18 +0000 (11:08 +1000)
let all databases default to not support this  until enabled through this control

client/ctdb_client.c
include/ctdb_client.h
include/ctdb_private.h
include/ctdb_protocol.h
server/ctdb_control.c
server/ctdb_ltdb_server.c
server/ctdb_recover.c
tools/ctdb.c

index f9d5e24c5caf55b0c35e42df998052e008d66ec3..b3061a855c5e5a958037e70d88fc5412c549c90f 100644 (file)
@@ -4593,3 +4593,45 @@ ctdb_ctrl_updaterecord(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct ti
        return ctdb_ctrl_updaterecord_recv(ctdb, state);
 }
 
+
+
+
+
+
+/*
+  set a database to be readonly
+ */
+struct ctdb_client_control_state *
+ctdb_ctrl_set_db_readonly_send(struct ctdb_context *ctdb, uint32_t destnode, uint32_t dbid)
+{
+       TDB_DATA data;
+
+       data.dptr = (uint8_t *)&dbid;
+       data.dsize = sizeof(dbid);
+
+       return ctdb_control_send(ctdb, destnode, 0, 
+                          CTDB_CONTROL_SET_DB_READONLY, 0, data, 
+                          ctdb, NULL, NULL);
+}
+
+int ctdb_ctrl_set_db_readonly_recv(struct ctdb_context *ctdb, struct ctdb_client_control_state *state)
+{
+       int ret;
+       int32_t res;
+
+       ret = ctdb_control_recv(ctdb, state, ctdb, NULL, &res, NULL);
+       if (ret != 0 || res != 0) {
+         DEBUG(DEBUG_ERR,(__location__ " ctdb_ctrl_set_db_readonly_recv failed  ret:%d res:%d\n", ret, res));
+               return -1;
+       }
+
+       return 0;
+}
+
+int ctdb_ctrl_set_db_readonly(struct ctdb_context *ctdb, uint32_t destnode, uint32_t dbid)
+{
+       struct ctdb_client_control_state *state;
+
+       state = ctdb_ctrl_set_db_readonly_send(ctdb, destnode, dbid);
+       return ctdb_ctrl_set_db_readonly_recv(ctdb, state);
+}
index a9e47be40ad9311b0b6eebb1980a3261fbbef3fa..ad31d24b317c6bf5eff285c07c96c9d42054f8b7 100644 (file)
@@ -599,4 +599,10 @@ int ctdb_ctrl_updaterecord_recv(struct ctdb_context *ctdb, struct ctdb_client_co
 int
 ctdb_ctrl_updaterecord(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx, struct timeval timeout, uint32_t destnode, struct ctdb_db_context *ctdb_db, TDB_DATA key, struct ctdb_ltdb_header *header, TDB_DATA data);
 
+
+struct ctdb_client_control_state *
+ctdb_ctrl_set_db_readonly_send(struct ctdb_context *ctdb, uint32_t destnode, uint32_t dbid);
+int ctdb_ctrl_set_db_readonly_recv(struct ctdb_context *ctdb, struct ctdb_client_control_state *state);
+int ctdb_ctrl_set_db_readonly(struct ctdb_context *ctdb, uint32_t destnode, uint32_t dbid);
+
 #endif /* _CTDB_CLIENT_H */
index 4cf3709fa3843b2f4a760b23c9b4d6877d13eb03..6a8ed187efc7424060b7c3e04f31d13fee7f8e9d 100644 (file)
@@ -1461,4 +1461,6 @@ typedef void (*deferred_requeue_fn)(void *call_context, struct ctdb_req_header *
 
 int ctdb_add_revoke_deferred_call(struct ctdb_context *ctdb, struct ctdb_db_context *ctdb_db, TDB_DATA key, struct ctdb_req_header *hdr, deferred_requeue_fn fn, void *call_context);
 
+int ctdb_set_db_readonly(struct ctdb_context *ctdb, struct ctdb_db_context *ctdb_db);
+
 #endif
index be7e7684362d88d0901840182b57d6a444fe3c1b..f4019ab172a66fb0ba348ddfda4e9f7b42a6cef6 100644 (file)
@@ -366,6 +366,7 @@ enum ctdb_controls {CTDB_CONTROL_PROCESS_EXISTS          = 0,
                    CTDB_CONTROL_TCP_ADD_DELAYED_UPDATE  = 126,
                    CTDB_CONTROL_GET_STAT_HISTORY        = 127,
                    CTDB_CONTROL_SCHEDULE_FOR_DELETION   = 128,
+                   CTDB_CONTROL_SET_DB_READONLY         = 129,
 };
 
 /*
index 748907f2a9c3f09e524033d4918bd3d4b43020ce..9c2f7429dd290e57eb81b6636cb81397f9d2b468 100644 (file)
@@ -194,6 +194,16 @@ static int32_t ctdb_control_dispatch(struct ctdb_context *ctdb,
                CHECK_CONTROL_DATA_SIZE(0);
                return ctdb->statistics.num_clients;
 
+       case CTDB_CONTROL_SET_DB_READONLY: {
+               uint32_t db_id;
+               struct ctdb_db_context *ctdb_db;
+
+               CHECK_CONTROL_DATA_SIZE(sizeof(db_id));
+               db_id = *(uint32_t *)indata.dptr;
+               ctdb_db = find_ctdb_db(ctdb, db_id);
+               if (ctdb_db == NULL) return -1;
+               return ctdb_set_db_readonly(ctdb, ctdb_db);
+       }
        case CTDB_CONTROL_GET_DBNAME: {
                uint32_t db_id;
                struct ctdb_db_context *ctdb_db;
index 3c41bb1ab70c5432f6683e8c5e64e94286530ff7..555d949ece7e265d918ec6d644977910b54dede9 100644 (file)
@@ -723,6 +723,44 @@ int32_t ctdb_control_db_get_health(struct ctdb_context *ctdb,
        return 0;
 }
 
+
+int ctdb_set_db_readonly(struct ctdb_context *ctdb, struct ctdb_db_context *ctdb_db)
+{
+       char *ropath;
+
+       DEBUG(DEBUG_ERR,("XXX set db readonly %s\n", ctdb_db->db_name));
+
+       if (ctdb_db->readonly) {
+               return 0;
+       }
+
+       if (ctdb_db->persistent) {
+               DEBUG(DEBUG_ERR,("Trying to set persistent database with readonly property\n"));
+               return -1;
+       }
+
+       ropath = talloc_asprintf(ctdb_db, "%s.RO", ctdb_db->db_path);
+       if (ropath == NULL) {
+               DEBUG(DEBUG_CRIT,("Failed to asprintf the tracking database\n"));
+               return -1;
+       }
+       ctdb_db->rottdb = tdb_open(ropath, 
+                             ctdb->tunable.database_hash_size, 
+                             TDB_NOLOCK|TDB_CLEAR_IF_FIRST|TDB_NOSYNC,
+                             O_CREAT|O_RDWR, 0);
+       if (ctdb_db->rottdb == NULL) {
+               DEBUG(DEBUG_CRIT,("Failed to open/create the tracking database '%s'\n", ropath));
+               talloc_free(ropath);
+               return -1;
+       }
+
+       DEBUG(DEBUG_NOTICE,("OPENED tracking database : '%s'\n", ropath));
+
+       ctdb_db->readonly = true;
+       talloc_free(ropath);
+       return 0;
+}
+
 /*
   attach to a database, handling both persistent and non-persistent databases
   return 0 on success, -1 on failure
@@ -926,35 +964,6 @@ again:
                }
        }
 
-       /* Assume all non-persistent databases support read only delegations */
-       if (!ctdb_db->persistent) {
-               ctdb_db->readonly = true;
-       }
-
-       if (ctdb_db->readonly) {
-               char *ropath;
-
-               ropath = talloc_asprintf(ctdb_db, "%s.RO", ctdb_db->db_path);
-               if (ropath == NULL) {
-                       DEBUG(DEBUG_CRIT,("Failed to asprintf the tracking database\n"));
-                       ctdb_db->readonly = false;
-                       talloc_free(ctdb_db);
-                       return -1;
-               }
-               ctdb_db->rottdb = tdb_open(ropath, 
-                                     ctdb->tunable.database_hash_size, 
-                                     TDB_NOLOCK|TDB_CLEAR_IF_FIRST|TDB_NOSYNC,
-                                     O_CREAT|O_RDWR, 0);
-               if (ctdb_db->rottdb == NULL) {
-                       DEBUG(DEBUG_CRIT,("Failed to open/create the tracking database '%s'\n", ropath));
-                       ctdb_db->readonly = false;
-                       talloc_free(ctdb_db);
-                       return -1;
-               }
-               DEBUG(DEBUG_NOTICE,("OPENED tracking database : '%s'\n", ropath));
-       }
-
-
        DLIST_ADD(ctdb->db_list, ctdb_db);
 
        /* setting this can help some high churn databases */
index e1a4776af18ae8d8d89a0c65418e35d61ce70966..5d98c4480b9f9cc8257a2d0ef8c121fb47d7307b 100644 (file)
@@ -1324,3 +1324,4 @@ int32_t ctdb_control_continue_node(struct ctdb_context *ctdb)
 
        return 0;
 }
+
index 1770fe4e8055c38ed810326a4a8deab9c22e0091..331392c2e430a9011850efb66d0bae07e2806403 100644 (file)
@@ -4081,6 +4081,29 @@ static int control_getdbprio(struct ctdb_context *ctdb, int argc, const char **a
        return 0;
 }
 
+/*
+  set the readonly capability for a database
+ */
+static int control_setdbreadonly(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+       uint32_t db_id;
+       int ret;
+
+       if (argc < 1) {
+               usage();
+       }
+
+       db_id = strtoul(argv[0], NULL, 0);
+
+       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"));
+               return -1;
+       }
+
+       return 0;
+}
+
 /*
   run an eventscript on a node
  */
@@ -5072,6 +5095,7 @@ static const struct {
        { "setrecmasterrole", control_setrecmasterrole, false,  false, "Set RECMASTER role to on/off", "{on|off}"},
        { "setdbprio",        control_setdbprio,        false,  false, "Set DB priority", "<dbid> <prio:1-3>"},
        { "getdbprio",        control_getdbprio,        false,  false, "Get DB priority", "<dbid>"},
+       { "setdbreadonly",    control_setdbreadonly,    false,  false, "Set DB readonly capable", "<dbid>"},
        { "msglisten",        control_msglisten,        false,  false, "Listen on a srvid port for messages", "<msg srvid>"},
        { "msgsend",          control_msgsend,  false,  false, "Send a message to srvid", "<srvid> <message>"},
        { "sync",            control_ipreallocate,      false,  false,  "wait until ctdbd has synced all state changes" },