let all databases default to not support this until enabled through this control
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);
+}
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 */
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
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,
};
/*
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;
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
}
}
- /* 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 */
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
*/
{ "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" },