Sun Microsystems
Products & Services
 
Support & Training
 
 

Previous Previous     Contents     Index     Next Next

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() ;
    }
}

Previous Previous     Contents     Index     Next Next