mirror of
https://github.com/samba-team/samba.git
synced 2025-03-24 10:50:22 +03:00
Add a mechanism where we can register notifications to be sent out to a SRVID when the client disconnects.
The way to use this is from a client to : 1, first create a message handle and bind it to a SRVID A special prefix for the srvid space has been set aside for samba : Only samba is allowed to use srvid's with the top 32 bits set like this. The lower 32 bits are for samba to use internally. 2, register a "notification" using the new control : CTDB_CONTROL_REGISTER_NOTIFY = 114, This control takes as indata a structure like this : struct ctdb_client_notify_register { uint64_t srvid; uint32_t len; uint8_t notify_data[1]; }; srvid is the srvid used in the space set aside above. len and notify_data is an arbitrary blob. When notifications are later sent out to all clients, this is the payload of that notification message. If a client has registered with control 114 and then disconnects from ctdbd, ctdbd will broadcast a message to that srvid to all nodes/listeners in the cluster. A client can resister itself with as many different srvid's it want, but this is handled through a linked list from the client structure so it mainly designed for "few notifications per client". 3, a client that no longer wants to have a notification set up can deregister using control CTDB_CONTROL_DEREGISTER_NOTIFY = 115, which takes this as arguments : struct ctdb_client_notify_deregister { uint64_t srvid; }; When a client deregisters, there will no longer be sent a message to all other clients when this client disconnects from ctdbd. (This used to be ctdb commit f1b6ee4a55cdca60f93d992f0431d91bf301af2c)
This commit is contained in:
parent
c61c655769
commit
86d1b4c465
@ -111,6 +111,10 @@ struct ctdb_call_info {
|
||||
*/
|
||||
#define CTDB_SRVID_TAKEOVER_RUN_RESPONSE 0xFD00000000000000LL
|
||||
|
||||
/* A port reserved for samba (top 32 bits)
|
||||
*/
|
||||
#define CTDB_SRVID_SAMBA_NOTIFY 0xFE00000000000000LL
|
||||
|
||||
/* used on the domain socket, send a pdu to the local daemon */
|
||||
#define CTDB_CURRENT_NODE 0xF0000001
|
||||
/* send a broadcast to all nodes in the cluster, active or not */
|
||||
@ -144,6 +148,15 @@ struct ctdb_client_control_state {
|
||||
} async;
|
||||
};
|
||||
|
||||
struct ctdb_client_notify_register {
|
||||
uint64_t srvid;
|
||||
uint32_t len;
|
||||
uint8_t notify_data[1];
|
||||
};
|
||||
|
||||
struct ctdb_client_notify_deregister {
|
||||
uint64_t srvid;
|
||||
};
|
||||
|
||||
struct event_context;
|
||||
|
||||
|
@ -160,7 +160,6 @@ typedef void (*ctdb_control_callback_fn_t)(struct ctdb_context *,
|
||||
int32_t status, TDB_DATA data,
|
||||
const char *errormsg,
|
||||
void *private_data);
|
||||
|
||||
/*
|
||||
structure describing a connected client in the daemon
|
||||
*/
|
||||
@ -173,6 +172,7 @@ struct ctdb_client {
|
||||
struct ctdb_tcp_list *tcp_list;
|
||||
uint32_t db_id;
|
||||
uint32_t num_persistent_updates;
|
||||
struct ctdb_client_notify_list *notify;
|
||||
};
|
||||
|
||||
|
||||
@ -612,6 +612,8 @@ enum ctdb_controls {CTDB_CONTROL_PROCESS_EXISTS = 0,
|
||||
CTDB_CONTROL_SET_DB_PRIORITY = 111,
|
||||
CTDB_CONTROL_GET_DB_PRIORITY = 112,
|
||||
CTDB_CONTROL_TRANSACTION_CANCEL = 113,
|
||||
CTDB_CONTROL_REGISTER_NOTIFY = 114,
|
||||
CTDB_CONTROL_DEREGISTER_NOTIFY = 115,
|
||||
};
|
||||
|
||||
/*
|
||||
@ -1501,4 +1503,8 @@ int32_t ctdb_control_set_ban_state(struct ctdb_context *ctdb, TDB_DATA indata);
|
||||
int32_t ctdb_control_get_ban_state(struct ctdb_context *ctdb, TDB_DATA *outdata);
|
||||
int32_t ctdb_control_set_db_priority(struct ctdb_context *ctdb, TDB_DATA indata);
|
||||
|
||||
int32_t ctdb_control_register_notify(struct ctdb_context *ctdb, uint32_t client_id, TDB_DATA indata);
|
||||
|
||||
int32_t ctdb_control_deregister_notify(struct ctdb_context *ctdb, uint32_t client_id, TDB_DATA indata);
|
||||
|
||||
#endif
|
||||
|
@ -552,6 +552,13 @@ static int32_t ctdb_control_dispatch(struct ctdb_context *ctdb,
|
||||
CHECK_CONTROL_DATA_SIZE(0);
|
||||
return ctdb_control_transaction_cancel(ctdb);
|
||||
|
||||
case CTDB_CONTROL_REGISTER_NOTIFY:
|
||||
return ctdb_control_register_notify(ctdb, client_id, indata);
|
||||
|
||||
case CTDB_CONTROL_DEREGISTER_NOTIFY:
|
||||
CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_client_notify_deregister));
|
||||
return ctdb_control_deregister_notify(ctdb, client_id, indata);
|
||||
|
||||
default:
|
||||
DEBUG(DEBUG_CRIT,(__location__ " Unknown CTDB control opcode %u\n", opcode));
|
||||
return -1;
|
||||
|
@ -31,7 +31,6 @@
|
||||
|
||||
static void daemon_incoming_packet(void *, struct ctdb_req_header *);
|
||||
|
||||
|
||||
static void print_exit_message(void)
|
||||
{
|
||||
DEBUG(DEBUG_NOTICE,("CTDB daemon shutting down\n"));
|
||||
@ -1043,3 +1042,105 @@ int ctdb_daemon_send_message(struct ctdb_context *ctdb, uint32_t pnn,
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct ctdb_client_notify_list {
|
||||
struct ctdb_client_notify_list *next, *prev;
|
||||
struct ctdb_context *ctdb;
|
||||
uint64_t srvid;
|
||||
TDB_DATA data;
|
||||
};
|
||||
|
||||
|
||||
static int ctdb_client_notify_destructor(struct ctdb_client_notify_list *nl)
|
||||
{
|
||||
int ret;
|
||||
|
||||
DEBUG(DEBUG_ERR,("Sending client notify message for srvid:%llu\n", (unsigned long long)nl->srvid));
|
||||
|
||||
ret = ctdb_daemon_send_message(nl->ctdb, CTDB_BROADCAST_CONNECTED, (unsigned long long)nl->srvid, nl->data);
|
||||
if (ret != 0) {
|
||||
DEBUG(DEBUG_ERR,("Failed to send client notify message\n"));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t ctdb_control_register_notify(struct ctdb_context *ctdb, uint32_t client_id, TDB_DATA indata)
|
||||
{
|
||||
struct ctdb_client_notify_register *notify = (struct ctdb_client_notify_register *)indata.dptr;
|
||||
struct ctdb_client *client = ctdb_reqid_find(ctdb, client_id, struct ctdb_client);
|
||||
struct ctdb_client_notify_list *nl;
|
||||
|
||||
DEBUG(DEBUG_ERR,("Register srvid %llu for client %d\n", (unsigned long long)notify->srvid, client_id));
|
||||
|
||||
if (indata.dsize < offsetof(struct ctdb_client_notify_register, notify_data)) {
|
||||
DEBUG(DEBUG_ERR,(__location__ " Too little data in control : %d\n", (int)indata.dsize));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (indata.dsize != (notify->len + offsetof(struct ctdb_client_notify_register, notify_data))) {
|
||||
DEBUG(DEBUG_ERR,(__location__ " Wrong amount of data in control. Got %d, expected %d\n", (int)indata.dsize, (int)(notify->len + offsetof(struct ctdb_client_notify_register, notify_data))));
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
if (client == NULL) {
|
||||
DEBUG(DEBUG_ERR,(__location__ " Could not find client parent structure. You can not send this control to a remote node\n"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
for(nl=client->notify; nl; nl=nl->next) {
|
||||
if (nl->srvid == notify->srvid) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (nl != NULL) {
|
||||
DEBUG(DEBUG_ERR,(__location__ " Notification for srvid:%llu already exists for this client\n", (unsigned long long)notify->srvid));
|
||||
return -1;
|
||||
}
|
||||
|
||||
nl = talloc(client, struct ctdb_client_notify_list);
|
||||
CTDB_NO_MEMORY(ctdb, nl);
|
||||
nl->ctdb = ctdb;
|
||||
nl->srvid = notify->srvid;
|
||||
nl->data.dsize = notify->len;
|
||||
nl->data.dptr = talloc_size(nl, nl->data.dsize);
|
||||
CTDB_NO_MEMORY(ctdb, nl->data.dptr);
|
||||
memcpy(nl->data.dptr, notify->notify_data, nl->data.dsize);
|
||||
|
||||
DLIST_ADD(client->notify, nl);
|
||||
talloc_set_destructor(nl, ctdb_client_notify_destructor);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t ctdb_control_deregister_notify(struct ctdb_context *ctdb, uint32_t client_id, TDB_DATA indata)
|
||||
{
|
||||
struct ctdb_client_notify_deregister *notify = (struct ctdb_client_notify_deregister *)indata.dptr;
|
||||
struct ctdb_client *client = ctdb_reqid_find(ctdb, client_id, struct ctdb_client);
|
||||
struct ctdb_client_notify_list *nl;
|
||||
|
||||
DEBUG(DEBUG_ERR,("Deregister srvid %llu for client %d\n", (unsigned long long)notify->srvid, client_id));
|
||||
|
||||
if (client == NULL) {
|
||||
DEBUG(DEBUG_ERR,(__location__ " Could not find client parent structure. You can not send this control to a remote node\n"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
for(nl=client->notify; nl; nl=nl->next) {
|
||||
if (nl->srvid == notify->srvid) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (nl == NULL) {
|
||||
DEBUG(DEBUG_ERR,(__location__ " No notification for srvid:%llu found for this client\n", (unsigned long long)notify->srvid));
|
||||
return -1;
|
||||
}
|
||||
|
||||
DLIST_REMOVE(client->notify, nl);
|
||||
talloc_set_destructor(nl, NULL);
|
||||
talloc_free(nl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user