#include "system/time.h"
#include "../include/ctdb_private.h"
#include "../common/rb_tree.h"
-#include "db_wrap.h"
+#include "lib/tdb_wrap/tdb_wrap.h"
#include "lib/util/dlinklist.h"
#include <ctype.h>
* fails. So storing the empty record makes sure that we do not
* need to change the client code.
*/
+ if ((header->flags & CTDB_REC_FLAG_VACUUM_MIGRATED) &&
+ (ctdb_db->ctdb->pnn == header->dmaster)) {
+ keep = true;
+ schedule_for_deletion = true;
+ }
if (!(header->flags & CTDB_REC_FLAG_VACUUM_MIGRATED)) {
keep = true;
} else if (ctdb_db->ctdb->pnn != header->dmaster) {
state->ignore_generation = ignore_generation;
/* now the contended path */
- lreq = ctdb_lock_record(ctdb_db, key, true, lock_fetch_callback, state);
+ lreq = ctdb_lock_record(state, ctdb_db, key, true, lock_fetch_callback, state);
if (lreq == NULL) {
return -1;
}
*/
static int ctdb_local_attach(struct ctdb_context *ctdb, const char *db_name,
bool persistent, const char *unhealthy_reason,
- bool jenkinshash)
+ bool jenkinshash, bool mutexes)
{
struct ctdb_db_context *ctdb_db, *tmp_db;
int ret;
if (jenkinshash) {
tdb_flags |= TDB_INCOMPATIBLE_HASH;
}
+#ifdef TDB_MUTEX_LOCKING
+ if (ctdb->tunable.mutex_enabled && mutexes &&
+ tdb_runtime_check_for_robust_mutexes()) {
+ tdb_flags |= (TDB_MUTEX_LOCKING | TDB_CLEAR_IF_FIRST);
+ }
+#endif
again:
- ctdb_db->ltdb = tdb_wrap_open(ctdb, ctdb_db->db_path,
+ ctdb_db->ltdb = tdb_wrap_open(ctdb_db, ctdb_db->db_path,
ctdb->tunable.database_hash_size,
tdb_flags,
O_CREAT|O_RDWR, mode);
return -1;
}
+ ctdb_db->defer_dmaster = trbt_create(ctdb_db, 0);
+ if (ctdb_db->defer_dmaster == NULL) {
+ DEBUG(DEBUG_ERR, ("Failed to create defer dmaster rb tree for %s\n",
+ ctdb_db->db_name));
+ talloc_free(ctdb_db);
+ return -1;
+ }
+
DLIST_ADD(ctdb->db_list, ctdb_db);
/* setting this can help some high churn databases */
struct ctdb_db_context *db;
struct ctdb_node *node = ctdb->nodes[ctdb->pnn];
struct ctdb_client *client = NULL;
+ bool with_jenkinshash, with_mutexes;
if (ctdb->tunable.allow_client_db_attach == 0) {
DEBUG(DEBUG_ERR, ("DB Attach to database %s denied by tunable "
only allow a subset of those on the database in ctdb. Note
that tdb_flags is passed in via the (otherwise unused)
srvid to the attach control */
+#ifdef TDB_MUTEX_LOCKING
+ tdb_flags &= (TDB_NOSYNC|TDB_INCOMPATIBLE_HASH|TDB_MUTEX_LOCKING|TDB_CLEAR_IF_FIRST);
+#else
tdb_flags &= (TDB_NOSYNC|TDB_INCOMPATIBLE_HASH);
+#endif
/* see if we already have this name */
db = ctdb_db_handle(ctdb, db_name);
return 0;
}
- if (ctdb_local_attach(ctdb, db_name, persistent, NULL, (tdb_flags&TDB_INCOMPATIBLE_HASH)?true:false) != 0) {
+ with_jenkinshash = (tdb_flags & TDB_INCOMPATIBLE_HASH) ? true : false;
+#ifdef TDB_MUTEX_LOCKING
+ with_mutexes = (tdb_flags & TDB_MUTEX_LOCKING) ? true : false;
+#else
+ with_mutexes = false;
+#endif
+
+ if (ctdb_local_attach(ctdb, db_name, persistent, NULL,
+ with_jenkinshash, with_mutexes) != 0) {
return -1;
}
outdata->dsize = sizeof(db->db_id);
/* Try to ensure it's locked in mem */
- ctdb_lockdown_memory(ctdb);
+ lockdown_memory(ctdb->valgrinding);
/* tell all the other nodes about this database */
ctdb_daemon_send_control(ctdb, CTDB_BROADCAST_ALL, tdb_flags,
return 0;
}
+/*
+ * a client has asked to detach from a database
+ */
+int32_t ctdb_control_db_detach(struct ctdb_context *ctdb, TDB_DATA indata,
+ uint32_t client_id)
+{
+ uint32_t db_id;
+ struct ctdb_db_context *ctdb_db;
+ struct ctdb_client *client = NULL;
+
+ db_id = *(uint32_t *)indata.dptr;
+ ctdb_db = find_ctdb_db(ctdb, db_id);
+ if (ctdb_db == NULL) {
+ DEBUG(DEBUG_ERR, ("Invalid dbid 0x%08x in DB detach\n",
+ db_id));
+ return -1;
+ }
+
+ if (ctdb->tunable.allow_client_db_attach == 1) {
+ DEBUG(DEBUG_ERR, ("DB detach from database %s denied. "
+ "Clients are allowed access to databases "
+ "(AllowClientDBAccess == 1)\n",
+ ctdb_db->db_name));
+ return -1;
+ }
+
+ if (ctdb_db->persistent) {
+ DEBUG(DEBUG_ERR, ("DB detach from persistent database %s "
+ "denied\n", ctdb_db->db_name));
+ return -1;
+ }
+
+ /* Cannot detach from database when in recovery */
+ if (ctdb->recovery_mode == CTDB_RECOVERY_ACTIVE) {
+ DEBUG(DEBUG_ERR, ("DB detach denied while in recovery\n"));
+ return -1;
+ }
+
+ /* If a control comes from a client, then broadcast it to all nodes.
+ * Do the actual detach only if the control comes from other daemons.
+ */
+ if (client_id != 0) {
+ client = ctdb_reqid_find(ctdb, client_id, struct ctdb_client);
+ if (client != NULL) {
+ /* forward the control to all the nodes */
+ ctdb_daemon_send_control(ctdb, CTDB_BROADCAST_ALL, 0,
+ CTDB_CONTROL_DB_DETACH, 0,
+ CTDB_CTRL_FLAG_NOREPLY,
+ indata, NULL, NULL);
+ return 0;
+ }
+ DEBUG(DEBUG_ERR, ("Client has gone away. Failing DB detach "
+ "for database '%s'\n", ctdb_db->db_name));
+ return -1;
+ }
+
+ /* Detach database from recoverd */
+ if (ctdb_daemon_send_message(ctdb, ctdb->pnn,
+ CTDB_SRVID_DETACH_DATABASE,
+ indata) != 0) {
+ DEBUG(DEBUG_ERR, ("Unable to detach DB from recoverd\n"));
+ return -1;
+ }
+
+ /* Disable vacuuming and drop all vacuuming data */
+ talloc_free(ctdb_db->vacuum_handle);
+ talloc_free(ctdb_db->delete_queue);
+
+ /* Terminate any deferred fetch */
+ talloc_free(ctdb_db->deferred_fetch);
+
+ /* Terminate any traverses */
+ while (ctdb_db->traverse) {
+ talloc_free(ctdb_db->traverse);
+ }
+
+ /* Terminate any revokes */
+ while (ctdb_db->revokechild_active) {
+ talloc_free(ctdb_db->revokechild_active);
+ }
+
+ /* Free readonly tracking database */
+ if (ctdb_db->readonly) {
+ talloc_free(ctdb_db->rottdb);
+ }
+
+ DLIST_REMOVE(ctdb->db_list, ctdb_db);
+
+ DEBUG(DEBUG_NOTICE, ("Detached from database '%s'\n",
+ ctdb_db->db_name));
+ talloc_free(ctdb_db);
+
+ return 0;
+}
/*
attach to all existing persistent databases
}
p[4] = 0;
- if (ctdb_local_attach(ctdb, s, true, unhealthy_reason, 0) != 0) {
+ if (ctdb_local_attach(ctdb, s, true, unhealthy_reason, false, false) != 0) {
DEBUG(DEBUG_ERR,("Failed to attach to persistent database '%s'\n", de->d_name));
closedir(d);
talloc_free(s);
return 0;
}
-int32_t ctdb_control_set_db_priority(struct ctdb_context *ctdb, TDB_DATA indata)
+int32_t ctdb_control_set_db_priority(struct ctdb_context *ctdb, TDB_DATA indata,
+ uint32_t client_id)
{
struct ctdb_db_priority *db_prio = (struct ctdb_db_priority *)indata.dptr;
struct ctdb_db_context *ctdb_db;
ctdb_db = find_ctdb_db(ctdb, db_prio->db_id);
if (!ctdb_db) {
- DEBUG(DEBUG_ERR,("Unknown db_id 0x%x in ctdb_set_db_priority\n", db_prio->db_id));
+ if (!(ctdb->nodes[ctdb->pnn]->flags & NODE_FLAGS_INACTIVE)) {
+ DEBUG(DEBUG_ERR,("Unknown db_id 0x%x in ctdb_set_db_priority\n",
+ db_prio->db_id));
+ }
return 0;
}
ctdb_db->priority = db_prio->priority;
DEBUG(DEBUG_INFO,("Setting DB priority to %u for db 0x%08x\n", db_prio->priority, db_prio->db_id));
+ if (client_id != 0) {
+ /* Broadcast the update to the rest of the cluster */
+ ctdb_daemon_send_control(ctdb, CTDB_BROADCAST_ALL, 0,
+ CTDB_CONTROL_SET_DB_PRIORITY, 0,
+ CTDB_CTRL_FLAG_NOREPLY, indata,
+ NULL, NULL);
+ }
return 0;
}