Registering to Receive Notifications
To receive notifications, applications
or services can use the cmm_cmc_register() function to
register a callback with the nhcmmd daemon. When a membership
change occurs in the cluster, the nhcmmd daemon notifies
the application or service through the callback function by sending a notification.
Applications or services receive notifications by polling, using a function
such as the poll() function. For more information, see
the poll(2) man page.
To change a registration, an application or service must first cancel
the existing registration by using the cmm_cmc_unregister()
function, and then register a new notification by using the cmm_cmc_register() function.
For an example of how to use these functions, see Example 7-2.
For further information, see the cmm_cmc_register(3CMM) and cmm_cmc_unregister(3CMM)
man pages.
Filtering Notifications
By default, when an application registers to receive notifications,
the application receives a notification for every change in the cluster state.
These notifications can be filtered by using the cmm_cmc_filter() function.
For each notification present in the filter, as selected by using the cmm_cmc_filter() function, the registered callback is invoked. The
defined filter is applied for further calls to the cmm_notify_dispatch() function.
For an example of how to use these functions, see Example 7-2.
For further information about how to use the cmm_cmc_filter()
function, see the cmm_cmc_filter(3CMM) man page.
Receiving and Dispatching Notifications
Applications
or services that are registered to receive notifications can use the cmm_notify_getfd() function. This function returns the file descriptor
through which the notifications are delivered.
An
application uses a polling function, such as poll(), to
monitor the file descriptors returned by cmm_notify_getfd().
When the polling function indicates activity on this file descriptor, cmm_notify_dispatch() must be called. For each pending notification,
before invoking the callback, the CMM API checks that this notification is
present in the filter (as selected with cmm_cmc_filter()).
The callback is invoked with the notification and the client_data argument passed to the cmm_cmc_register()
function.
For an example of how to use these functions, see Example 7-2.
For further information see the cmm_cmc_register(3CMM), cmm_notify_getfd(3CMM), cmm_notify_dispatch(3CMM) and poll(2) man pages.
Retrieving Change Notifications
The following example demonstrates how to use the functions that
enable you to filter, receive and dispatch notifications:
Example 7-2 Retrieving Change Notifications
#include <cmm.h>
#include <stdio.h>
#include <stdlib.h> /* for exit() */
#include <strings.h> /* for strcpy */
#include "common.h"
/*******************************************************************/
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
void CMM_notify_cb(const cmm_cmc_notification_t *change_notification,
void *client_data)
{
cmm_member_t member ;
switch (change_notification->cmchange)
{
case CMM_MASTER_ELECTED:
printf("[USER CB] master elected = %d\n",
change_notification->nodeid) ;
if (cmm_master_getinfo(&member) == CMM_OK)
print_member(&member) ;
break ;
case CMM_MASTER_DEMOTED:
printf("[USER CB] master demoted = %d\n",
change_notification->nodeid) ;
break ;
case CMM_VICEMASTER_ELECTED:
printf("[USER CB] vicemaster elected = %d\n",
change_notification->nodeid) ;
break ;
case CMM_VICEMASTER_DEMOTED:
printf("[USER CB] vicemaster demoted = %d\n",
change_notification->nodeid) ;
break ;
case CMM_MEMBER_JOINED:
if (cmm_member_getinfo(change_notification->nodeid,
&member) == CMM_OK)
print_member(&member) ;
break ;
case CMM_MEMBER_LEFT:
printf("[USER CB] member left cluster = %d\n",
change_notification->nodeid) ;
break ;
case CMM_INVALID_CLUSTER:
printf("[USER CB] INVALID CLUSTER\n") ;
break ;
case CMM_STALE_CLUSTER:
printf("[USER CB] STALE CLUSTER\n") ;
break ;
case CMM_VALID_CLUSTER:
printf("[USER CB] VALID CLUSTER\n") ;
break ;
}
}
/********************************************************************/
/********************************************************************/
/********************************************************************/
/********************************************************************/
int main(int P_argc, char *P_argv[])
{
uint32_t L_node_count ;
cmm_error_t result ;
struct pollfd fifo_poll ;
boolean_t go_on_poll = B_TRUE ;
/* FILTERING PART */
cmm_cmchanges_t L_notify[2] = { CMM_MASTER_ELECTED,
CMM_INVALID_CLUSTER } ;
cmm_cmc_filter(CMM_CMC_NOTIFY_SET, L_notify, 2) ;
result = cmm_cmc_register(CMM_notify_cb, (void *) NULL) ;
if (result != CMM_OK)
{
fprintf(stderr,
" register error (%s) => EXIT\n",
cmm_strerror(result)) ;
exit(1) ;
}
result = cmm_notify_getfd(&fifo_poll.fd) ;
if (result != CMM_OK) {
fprintf(stderr,
" getfd error (%s) => EXIT\n",
cmm_strerror(result)) ;
exit(1) ;
}
printf("file descriptor to poll = %d\n", fifo_poll.fd) ;
fifo_poll.events
= (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI);
fifo_poll.revents = 0 ;
while (1) {
/* this loop ends when exit asked or poll succeeded */
go_on_poll = B_TRUE ;
while (go_on_poll == B_TRUE) {
result = cmm_notify_getfd(&fifo_poll.fd) ;
switch (poll(&fifo_poll, 1, 2500) )
{
case -1:
puts("error on poll") ;
break ;
case 0:
/* time-out */
break ;
default:
go_on_poll = B_FALSE ;
}
if ((fifo_poll.revents & POLLHUP) ||
(fifo_poll.fd == -1))
{
printf("reconnection required\n") ;
result = cmm_cmc_unregister() ;
result = cmm_cmc_register(CMM_notify_cb,
(void *) NULL) ;
result = cmm_notify_getfd(&fifo_poll.fd) ;
poll(NULL, 0 , 500) ;
}
}
cmm_notify_dispatch() ;
}
} |
|