/*******************************************************************************
Feature  API: alarmClockCkptCallback

Description : 

Other API in this file are either completely generic or mostly so, the hot standby
feature cannot be generic as  the state needs to be conveyed to the application
and made "hot" so to speak. Here we are going to have to know internals of the 
alarm clock structure

Arguments In: 
    1. ClCkptHdlT : ckpt handle
    2. SaNameT *    ckpt_name being updated
    3. ClCkptIOVectorElementT   *io_vector containing updated checkpoint data (all sections)
    4. ClInt32T     number of sections within checkpoint
    5. ClPtrT       cookie; can be used to keep globals within the task

Return Value:
    ClInt32Teger 0 if success, non zero if failure
*******************************************************************************/
static ClRcT 
alarmClockCkptCallback( ClCkptHdlT              ckpt_hdl,
                        SaNameT                 *ckpt_name,
                        ClCkptIOVectorElementT  *io_vector,
                        ClUint32T               num_sections,
                        ClPtrT                  cookie )
{
    ClRcT       ret_code = CL_OK;
    ClInt32T    count;
    ClInt32T    pid = getpid();
    ClInt32T    data_size = sizeof(acClockT);
    ClUint32T section_index = 1; /*our section name apparently*/
    ClCkptSectionIdT target_section_id;

    target_section_id.id = (ClUint8T*)&section_index;
    target_section_id.idLen = sizeof(section_index);

    alarmClockLogWrite(CL_LOG_SEV_INFO, 
            "alarmClockCkptCallback(pid=%d): ckpt[%.*s] update received\n", 
            pid, ckpt_name->length, ckpt_name->value);
    for (count = 0; count < num_sections; count++)
    {
        /*
         * check if the received update is for the section of interest to us,
         * if it is update the section, 
         */
        if ((target_section_id.idLen == io_vector[count].sectionId.idLen) && 
            (memcmp(target_section_id.id, (ClCharT *)io_vector[count].sectionId.id, 
                    target_section_id.idLen) == 0))
        {
            if (io_vector[count].dataSize != data_size)
            {
                alarmClockLogWrite(CL_LOG_SEV_ERROR, 
                       "alarmClockCkptCallback(pid=%d): received %d bytes; expected %d bytes\n", 
                        pid, (ClInt32T)io_vector[count].readSize, (ClInt32T)sizeof(acClockT));
            }
            else
            {

                alarmClockLogWrite(CL_LOG_SEV_INFO, 
                        "alarmClockCkptCallback(pid=%d): received %d bytes from section %d\n", 
                        pid, (ClInt32T)io_vector[count].readSize, section_index); 

                alarmClockCopyHotStandby((acClockT*)io_vector[count].dataBuffer);
            }

            break;
        }
    }
    /*
     * ckpt in sync through hot standby update
     */
    if(!(g_hot_standby & HOT_STANDBY_ACTIVE))
        g_hot_standby |= HOT_STANDBY_ACTIVE;
    return ret_code;
}
/*******************************************************************************
Feature  API: alarmClockCkptCallback

Description : 

Other API in this file are either completely generic or mostly so, the hot standby
feature cannot be generic as  the state needs to be conveyed to the application
and made "hot" so to speak. Here we are going to have to know internals of the 
alarm clock structure

Arguments In: 
    1. ClCkptHdlT : ckpt handle
    2. SaNameT *    ckpt_name being updated
    3. ClCkptIOVectorElementT   *io_vector containing updated checkpoint data (all sections)
    4. ClInt32T     number of sections within checkpoint
    5. ClPtrT       cookie; can be used to keep globals within the task

Return Value:
    ClInt32Teger 0 if success, non zero if failure
*******************************************************************************/
static ClRcT 
alarmClockCkptCallback( ClCkptHdlT              ckpt_hdl,
                        SaNameT                 *ckpt_name,
                        ClCkptIOVectorElementT  *io_vector,
                        ClUint32T               num_sections,
                        ClPtrT                  cookie )
{
    ClRcT       ret_code = CL_OK;
    ClInt32T    count;
    ClInt32T    pid = getpid();
    ClInt32T    data_size = sizeof(acClockT);
    ClInt32T    section_id_len;
    ClCharT     section_id_name[ CL_MAX_NAME_LENGTH ];

    sprintf(section_id_name, "s00001");
    section_id_len = strlen(section_id_name);

    alarmClockLogWrite(CL_LOG_SEV_INFO, 
            "alarmClockCkptCallback(pid=%d): ckpt[%.*s] update received\n", 
            pid, ckpt_name->length, ckpt_name->value);
    for (count = 0; count < num_sections; count++)
    {
        /*
         * check if the received update is for the section of interest to us,
         * if it is update the section, 
         */
        if ((section_id_len == io_vector[count].sectionId.idLen) && 
            (strncmp(section_id_name, (ClCharT *)io_vector[count].sectionId.id, section_id_len) == 0))
        {
            if (io_vector[count].dataSize != data_size)
            {
                alarmClockLogWrite(CL_LOG_SEV_ERROR, 
                       "alarmClockCkptCallback(pid=%d): received %d bytes; expected %d bytes\n", 
                        pid, (ClInt32T)io_vector[count].readSize, (ClInt32T)sizeof(acClockT));
            }
            else
            {

                alarmClockLogWrite(CL_LOG_SEV_INFO, 
                        "alarmClockCkptCallback(pid=%d): received %d bytes from %s\n", 
                        pid, (ClInt32T)io_vector[count].readSize, section_id_name); 

                alarmClockCopyHotStandby((acClockT*)io_vector[count].dataBuffer);
            }

            break;
        }
    }
    /*
     * ckpt in sync through hot standby update
     */
    if(!(g_hot_standby & __HOT_STANDBY_ACTIVE))
        g_hot_standby |= __HOT_STANDBY_ACTIVE;
    return ret_code;
}
/*******************************************************************************
Feature  API: alarmClockCkptCallback

Description : 

Other API in this file are either completely generic or mostly so, the hot standby
feature cannot be generic as  the state needs to be conveyed to the application
and made "hot" so to speak. Here we are going to have to know internals of the 
alarm clock structure

Arguments In: 
    1. ClCkptHdlT : ckpt handle
    2. ClNameT *    ckpt_name being updated
    3. ClCkptIOVectorElementT   *io_vector containing updated checkpoint data (all sections)
    4. ClInt32T     number of sections within checkpoint
    5. ClPtrT       cookie; can be used to keep globals within the task

Return Value:
    ClInt32Teger 0 if success, non zero if failure
*******************************************************************************/
static ClRcT 
alarmClockCkptCallback( ClCkptHdlT              ckpt_hdl,
                        ClNameT                 *ckpt_name,
                        ClCkptIOVectorElementT  *io_vector,
                        ClUint32T               num_sections,
                        ClPtrT                  cookie )
{
    ClRcT       ret_code = CL_OK;
    ClInt32T    count;
    ClInt32T    pid = getpid();
    ClInt32T    data_size = sizeof(SessionT);
    ClCkptSectionIdT *target_section_id;

    target_section_id = (ClCkptSectionIdT*)&sectionIdMap[0].sectionId;

    alarmClockLogWrite(CL_LOG_SEV_INFO, 
            "alarmClockCkptCallback(pid=%d): ckpt[%.*s] update received\n", 
            pid, ckpt_name->length, ckpt_name->value);
    
    /*
     * Normal case, would be zero-contention on the lock and futex with no contention 
     * would incur no futex_wait or syscall overhead.
     */
    alarmClockCkptLock();

    for (count = 0; count < num_sections; count++)
    {
        /*
         * check if the received update is for the section of interest to us,
         * if it is update the section, 
         */
        if ((target_section_id->idLen == io_vector[count].sectionId.idLen) && 
            (memcmp(target_section_id->id, (ClCharT *)io_vector[count].sectionId.id, 
                    target_section_id->idLen) == 0))
        {
            if (io_vector[count].dataSize != data_size)
            {
                alarmClockLogWrite(CL_LOG_SEV_ERROR, 
                       "alarmClockCkptCallback(pid=%d): received %d bytes; expected %d bytes\n", 
                        pid, (ClInt32T)io_vector[count].readSize, (ClInt32T)sizeof(acClockT));
            }
            else
            {

                alarmClockLogWrite(CL_LOG_SEV_INFO, 
                                   "alarmClockCkptCallback(pid=%d): received %d bytes from section %.*s "
                                   "for offset [%d]", 
                                   pid, (ClInt32T)io_vector[count].readSize, 
                                   target_section_id->idLen, (const char *)target_section_id->id,
                                   (ClUint32T)io_vector[count].dataOffset);
                
                SessionT *session = (SessionT*)io_vector[count].dataBuffer;
                ClUint32T offset = (ClUint32T)io_vector[count].dataOffset/data_size;
                sessionUpdate(session, offset);
                alarmClockCopyHotStandby(&session->clock);
            }

            break;
        }
    }
    /*
     * ckpt in sync through hot standby update
     */
    if(!(g_hot_standby & HOT_STANDBY_ACTIVE))
        g_hot_standby |= HOT_STANDBY_ACTIVE;

    alarmClockCkptUnlock();

    return ret_code;
}