/*******************************************************************************
Utility API: clTcIterToSectionId

Descrition :

This API is utility related, used by the write and read feature APIs; in case 
no section ids were used during the create. 

*******************************************************************************/
int
clTcIterToSectionId (
	ClTcCkptDataT* 		ckpt_data,
	int			   		section_num,
    ClCkptSectionIdT*	section_id )
{
	ClRcT 						ret_code = CL_OK;
	int							iter_num;
	ClHandleT					section_iter_hdl;
    ClCkptSectionDescriptorT 	section_desc;

	/* assumption: all sections have same expiration time;
	 * for now set to never expire. We will iterate until
	 * we come to the section number specified
	 */
	ret_code = 
	clCkptSectionIterationInitialize((ClCkptHdlT)ckpt_data->ckpt_hdl,
									 CL_CKPT_SECTIONS_FOREVER,
									 (ClTimeT)-1,
									 &section_iter_hdl);
	if ( ret_code != CL_OK )
	{
		printf("clTcIterToSectionId: Failed initialize iteration: 0x%x\n",
			   ret_code); 
		return ret_code;
	}

	/* iterate until we reach the section number of interest
	 */
	for (iter_num = 0; iter_num < section_num; iter_num++)
	{
		ret_code = clCkptSectionIterationNext(section_iter_hdl,
											  &section_desc);	
		if ( ret_code != CL_OK )
		{
			printf("clTcIterToSectionId: Failed section iteration: 0x%x\n",
				   ret_code); 
			return ret_code;
		}
	}

	/* Finalize the iteration to free up internal resources
	 */
	ret_code = clCkptSectionIterationFinalize(section_iter_hdl);
	if ( ret_code != CL_OK )
	{
		printf("clTcIterToSectionId: Failed iteration finalize: 0x%x\n",
			   ret_code); 
		return ret_code;
	}

	/* assign the section id based on information retured from
	 * the iteration
	 */
	section_id->idLen = section_desc.sectionId.idLen;
	section_id->id    = section_desc.sectionId.id;

	return ret_code;
}
static ClBoolT clCkptEntryExist(ClCachedCkptSvcInfoT *serviceInfo, const SaNameT *sectionName)
{
    ClBoolT                    retVal         = CL_FALSE;
    ClRcT                      rc;
    ClHandleT                  hSecIter       = CL_HANDLE_INVALID_VALUE;
    ClCkptSectionDescriptorT   secDescriptor  = {{0}};

    rc = clCkptSectionIterationInitialize(serviceInfo->ckptHandle,
                                          CL_CKPT_SECTIONS_ANY,
                                          CL_TIME_END, &hSecIter);
    if( CL_OK != rc )
    {
        clLogError("CCK", "EXIST", "clCkptSectionIterationInitialize(): rc [0x%x].",rc);
        goto out;
    }

    do
    {
        rc = clCkptSectionIterationNext(hSecIter, &secDescriptor);
        if( CL_OK != rc)
        {
            break;
        }

        if ((sectionName->length == secDescriptor.sectionId.idLen)
                && (memcmp(sectionName->value, secDescriptor.sectionId.id, sectionName->length)==0) )
        {
            clHeapFree(secDescriptor.sectionId.id);
            secDescriptor.sectionId.idLen = 0;
            retVal = CL_TRUE;
            goto out_free;
        }
        clHeapFree(secDescriptor.sectionId.id);
        secDescriptor.sectionId.id = NULL;
        secDescriptor.sectionId.idLen = 0;
    } while( (rc == CL_OK) );

out_free:
    if(hSecIter)
    {
        rc = clCkptSectionIterationFinalize(hSecIter);
        if( CL_OK != rc )
        {
            clLogError("CCK", "EXIST", "clCkptSectionIterationFinalize(): rc [0x%x].",rc);
        }
    }

out:
    return retVal;
}
SaAisErrorT saCkptSectionIterationFinalize (
        SaCkptSectionIterationHandleT sectionIterationHandle)
{
    ClRcT          rc     = CL_OK;
    SaAisErrorT    safRc  = SA_AIS_OK;

    /*
     * Call the corresponding ckpt client library function.
     */
    rc = clCkptSectionIterationFinalize((ClHandleT)sectionIterationHandle);

    /*
     * Translate the clovis error type to SAF error type.
     */
    clErrorTxlate(rc, &safRc);
    
    return safRc;
}
ClRcT
clLogMasterStateRecover(ClLogSvrCommonEoDataT  *pCommonEoEntry,
                        ClLogMasterEoDataT    *pMasterEoEntry,
                        ClBoolT switchover)
{
    ClRcT                             rc             = CL_OK;
    ClHandleT                         hSecIter       = CL_HANDLE_INVALID_VALUE;
    ClCkptSectionDescriptorT          secDescriptor  = {{0}};
    ClCkptIOVectorElementT            ioVector       = {{0}};
    ClUint32T                         errIndex       = 0;
    ClCkptSectionCreationAttributesT  secAttr        = {0};
    ClBoolT                           logReadFlag    = CL_FALSE;

    CL_LOG_DEBUG_TRACE(("Enter"));

    rc = clLogMasterEoEntrySet(pMasterEoEntry);
    if( CL_OK != rc )
    {
        CL_LOG_DEBUG_ERROR(("clLogMasterEoEntrySet(): rc[0x %x]", rc));
        return rc;
    }

    if(switchover)
    {
        rc = clCkptActiveReplicaSetSwitchOver(pMasterEoEntry->hCkpt);
    }
    else
    {
        rc = clCkptActiveReplicaSet(pMasterEoEntry->hCkpt);
    }
    if (CL_OK != rc)
    {
        CL_LOG_DEBUG_ERROR(("clCkptActiveReplicaSet(): rc[%#x],switchover flag [%d]", rc, switchover));
        return rc;
    }

    rc = clCkptSectionIterationInitialize(pMasterEoEntry->hCkpt,
                                          CL_CKPT_SECTIONS_ANY,
                                          CL_TIME_END, &hSecIter);
    if( CL_OK != rc )
    {
        CL_LOG_DEBUG_ERROR(("clCkptSectionIterationInitialize(): rc[0x %x]",
                            rc));
        return rc;
    }

    do
    {
        rc = clCkptSectionIterationNext(hSecIter, &secDescriptor);
        if( CL_OK != rc)
        {
            break;
        }

        logReadFlag         = CL_TRUE;
        if( pCommonEoEntry->masterAddr == clIocLocalAddressGet() )
        {
            ioVector.sectionId  = secDescriptor.sectionId;
            ioVector.dataBuffer = NULL;
            ioVector.dataSize   = 0;
            ioVector.readSize   = 0;
            ioVector.dataOffset = 0;
            clLogNotice(CL_LOG_AREA_MASTER, CL_LOG_CTX_CKPT_READ,
                        "Got section [%.*s] to be read",
                        secDescriptor.sectionId.idLen, secDescriptor.sectionId.id);
            if( 0 != strncmp((ClCharT *) ioVector.sectionId.id,
                             (ClCharT *) gLogMasterCompDataSectionId.id,
                             gLogMasterCompDataSectionId.idLen) )
            {
                rc = clCkptCheckpointRead(pMasterEoEntry->hCkpt, &ioVector, 1,
                                          &errIndex);
                if( CL_OK == rc ) /* create whatever we can */
                {
                    if( 0 == strncmp((ClCharT *) ioVector.sectionId.id,
                                     (ClCharT *) gLogMasterDefaultSectionId.id,
                                     gLogMasterDefaultSectionId.idLen) )
                    {
                        rc = clLogMasterEoEntryRecover(pMasterEoEntry, &ioVector,
                                                       &errIndex);
                        if( CL_OK != rc )
                        {
                            clHeapFree(ioVector.dataBuffer);
                            clHeapFree(ioVector.sectionId.id);
                            break; /* break out of the loop, can't continue */
                        }
                        clHeapFree(ioVector.dataBuffer);
                    }
                    else
                    {
                        /* create whatever we can */
                        clLogMasterFileEntryRecover(pMasterEoEntry, &ioVector,
                                                    &errIndex);
                        clHeapFree(ioVector.dataBuffer);
                    }
                }
            }
            clHeapFree(secDescriptor.sectionId.id);
        }
        else
        {
            return rc;
        }
    } while( (rc == CL_OK) );

    CL_LOG_CLEANUP(clCkptSectionIterationFinalize(hSecIter), CL_OK);

    if( CL_TRUE == logReadFlag )
    {
        ioVector.sectionId  = gLogMasterCompDataSectionId;
        ioVector.dataBuffer = NULL;
        ioVector.dataSize   = 0;
        ioVector.readSize   = 0;
        ioVector.dataOffset = 0;
        rc = clCkptCheckpointRead(pMasterEoEntry->hCkpt, &ioVector, 1, &errIndex);
        if( CL_OK != rc )
        {
            CL_LOG_DEBUG_ERROR(("clCkptCheckpointRead():rc[0x %x]", rc));
            return rc;
        }
        rc = clLogMasterCompTableStateRecover(pMasterEoEntry, (ClUint8T*) ioVector.dataBuffer,
                                              ioVector.readSize);
        if( CL_OK != rc )
        {
            CL_LOG_DEBUG_ERROR(("Unable to recreate the state of compTable"));
        }
        clHeapFree(ioVector.dataBuffer);
    }
    else
    {
        secAttr.sectionId      = &gLogMasterDefaultSectionId;
        secAttr.expirationTime = CL_TIME_END;
        rc = clCkptSectionCreate(pMasterEoEntry->hCkpt, &secAttr, NULL, 0);
        if( CL_OK != rc )
        {
            CL_LOG_DEBUG_ERROR(("clCkptSectionCreate(): rc[0x %x]", rc));
            return rc;
        }
        secAttr.sectionId      = &gLogMasterCompDataSectionId;
        secAttr.expirationTime = CL_TIME_END;
        rc = clCkptSectionCreate(pMasterEoEntry->hCkpt, &secAttr, NULL,
                                 0);
        if( CL_OK != rc )
        {
            CL_LOG_DEBUG_ERROR(("clCkptSectionCreate(): rc[0x %x]", rc));
            CL_LOG_CLEANUP(clCkptSectionDelete(pMasterEoEntry->hCkpt,
                                               &gLogMasterDefaultSectionId),
                           CL_OK);
        }
    }

    CL_LOG_DEBUG_TRACE(("Exit"));
    return CL_OK;
}
/*
 * Function - clLogSOCkptRead()
 *  Walk thru the list of sections.
 *  Read the checkpoint data.
 *  Recreate the entry 
 */
ClRcT
clLogStreamOwnerGlobalStateRecover(ClIocNodeAddressT  masterAddr, ClBoolT switchover)
{
    ClRcT                     rc            = CL_OK;
    ClHandleT                 hSecIter      = CL_HANDLE_INVALID_VALUE;
    ClCkptSectionDescriptorT  secDescriptor = {{0}};
    ClLogSOEoDataT            *pSoEoEntry   = NULL;
    ClIocNodeAddressT         localAddr     = 0;

    CL_LOG_DEBUG_TRACE(("Enter"));

    localAddr = clIocLocalAddressGet();
    rc = clLogStreamOwnerEoEntryGet(&pSoEoEntry, NULL);
    if( CL_OK != rc )
    {
        return rc;
    }
    if(switchover)
    {
        rc = clCkptActiveReplicaSetSwitchOver(pSoEoEntry->hCkpt);
    }
    else
    {
        rc = clCkptActiveReplicaSet(pSoEoEntry->hCkpt);
    }

    if (CL_OK != rc)
    {
        CL_LOG_DEBUG_ERROR(("clCkptActiveReplicaSet(): rc[%#x], switchover flag [%d]", rc, switchover));
        return rc;
    }
    rc = clCkptSectionIterationInitialize(pSoEoEntry->hCkpt,
                                          CL_CKPT_SECTIONS_ANY, 
                                          CL_TIME_END, &hSecIter);
    if( CL_OK != rc )
    {
        CL_LOG_DEBUG_ERROR(("clCkptSectionIterationInitialize(): rc[0x %x]",
                            rc));
        return rc;
    }    
    do
    {    
        rc = clCkptSectionIterationNext(hSecIter, &secDescriptor);
        if( (rc != CL_OK))
        {
            if( CL_ERR_NOT_EXIST == CL_GET_ERROR_CODE(rc)
                ||
                CL_CKPT_ERR_NO_SECTIONS == CL_GET_ERROR_CODE(rc))
            {
                rc = CL_OK;
            }
            break;
        }
        /* 
         * Create the entries as many as we can, so explicitly
         * not checking the rc.
         */
        if( localAddr == masterAddr )
        {
            clLogStreamOwnerGlobalEntryRecover(pSoEoEntry, &secDescriptor);
        }
        clHeapFree(secDescriptor.sectionId.id);
    }while((rc == CL_OK));

    CL_LOG_CLEANUP(clCkptSectionIterationFinalize(hSecIter), CL_OK);

    CL_LOG_DEBUG_TRACE(("Exit"));
    return rc;
}
ClRcT clCachedCkptSynch(ClCachedCkptSvcInfoT *serviceInfo, ClBoolT isEmpty)
{
    ClRcT                             rc             = CL_OK;
    ClHandleT                         hSecIter       = CL_HANDLE_INVALID_VALUE;
    ClCkptSectionDescriptorT          secDescriptor  = {{0}};
    ClCkptIOVectorElementT            ioVector       = {{0}};
    ClUint32T                         errIndex       = 0;

    rc = clCkptSectionIterationInitialize(serviceInfo->ckptHandle,
                                          CL_CKPT_SECTIONS_ANY,
                                          CL_TIME_END, &hSecIter);
    if( CL_OK != rc )
    {
        clLogError("CCK", "SYNC", "clCkptSectionIterationInitialize(): rc [0x%x].",rc);
        return rc;
    }

    do
    {
        rc = clCkptSectionIterationNext(hSecIter, &secDescriptor);
        if( CL_OK != rc)
        {
            break;
        }

        ioVector.sectionId  = secDescriptor.sectionId;
        ioVector.dataBuffer = NULL;
        ioVector.dataSize   = 0;
        ioVector.readSize   = 0;
        ioVector.dataOffset = 0;

        rc = clCkptCheckpointRead(serviceInfo->ckptHandle, &ioVector, 1,
                                  &errIndex);
        if( CL_OK == rc )
        {
            ClUint8T *ckptedData, *copyData;
            ClUint32T network_byte_order;
            ClCachedCkptDataT sectionData;

            ckptedData = (ClUint8T*) ioVector.dataBuffer;
            copyData = ckptedData;

            memset(&sectionData.sectionName, 0, sizeof (SaNameT));
            sectionData.sectionName.length = ioVector.sectionId.idLen;
            memcpy(sectionData.sectionName.value, ioVector.sectionId.id, sectionData.sectionName.length);

            memcpy(&network_byte_order, copyData, sizeof(ClUint32T));
            sectionData.sectionAddress.iocPhyAddress.nodeAddress = (ClUint32T) ntohl((ClUint32T)network_byte_order);
            copyData = copyData + sizeof(ClUint32T);

            memcpy(&network_byte_order, copyData, sizeof(ClUint32T));
            sectionData.sectionAddress.iocPhyAddress.portId = (ClUint32T) ntohl((ClUint32T)network_byte_order);
            copyData = copyData + sizeof(ClUint32T);

            sectionData.data = copyData;
            sectionData.dataSize = ioVector.readSize - sizeof(ClIocAddressT);

            if (isEmpty)
                clCacheEntryAdd(serviceInfo, (ClCachedCkptDataT *)&sectionData);
            else
                clCacheEntryUpdate(serviceInfo, (ClCachedCkptDataT *)&sectionData);

            clHeapFree(ioVector.dataBuffer);
        }

        clHeapFree(secDescriptor.sectionId.id);
    } while( (rc == CL_OK) );

    rc = clCkptSectionIterationFinalize(hSecIter);
    if( CL_OK != rc )
    {
        clLogError("CCK", "SYNC", "clCkptSectionIterationFinalize(): rc [0x%x].",rc);
        return rc;
    }

    return CL_OK;
}