ANSC_STATUS
Bmc2ReqcoPecRetCookedPage
    (
        ANSC_HANDLE                 hThisObject,
        ANSC_HANDLE                 hCookedPage
    )
{
    ANSC_STATUS                     returnStatus       = ANSC_STATUS_SUCCESS;
    PBMC2_REQ_CONTROLLER_OBJECT     pMyObject          = (PBMC2_REQ_CONTROLLER_OBJECT)hThisObject;
    PBMC2_ENV_CONTROLLER_OBJECT     pBmc2EnvController = (PBMC2_ENV_CONTROLLER_OBJECT)pMyObject->hBmc2EnvController;
    PBMC2_COM_DOMAIN_OBJECT         pBmc2ComDomain     = (PBMC2_COM_DOMAIN_OBJECT    )pMyObject->hBmc2ComDomain;
    PBMC2_COM_TERMINAL_OBJECT       pBmc2ComTerminal   = (PBMC2_COM_TERMINAL_OBJECT  )pBmc2ComDomain->hBmc2ComTerminal;
    PBMC2_COM_EXECUTOR_OBJECT       pBmc2ComExecutor   = (PBMC2_COM_EXECUTOR_OBJECT  )pBmc2EnvController->hBmc2ComExecutor;
    PBWRM_ENV_CONTROLLER_OBJECT     pBwrmEnvController = (PBWRM_ENV_CONTROLLER_OBJECT)pBmc2EnvController->hBwrmEnvController;
    PBWRM_RAM_INTERFACE             pBwrmRamIf         = (PBWRM_RAM_INTERFACE        )pBwrmEnvController->GetBwrmRamIf((ANSC_HANDLE)pBwrmEnvController);
    PBWRM_COOKED_PAGE_OBJECT        pBwrmCookedPage    = (PBWRM_COOKED_PAGE_OBJECT   )hCookedPage;

    if ( !pBmc2EnvController->Property.bCacheScpPages && !pBwrmRamIf->IsPageCacheForced(pBwrmRamIf->hOwnerContext, pBwrmCookedPage->PagePath) )
    {
        pBwrmCookedPage->Remove((ANSC_HANDLE)pBwrmCookedPage);
    }
    else
    {
        pBwrmCookedPage->DecRefCount((ANSC_HANDLE)pBwrmCookedPage);
    }

    return   ANSC_STATUS_SUCCESS;
}
ANSC_STATUS
BwrmPmoDelPage
    (
        ANSC_HANDLE                 hThisObject,
        char*                       root_path,
        char*                       file_path
    )
{
    ANSC_STATUS                     returnStatus      = ANSC_STATUS_SUCCESS;
    PBWRM_PAGE_MANAGER_OBJECT       pMyObject         = (PBWRM_PAGE_MANAGER_OBJECT    )hThisObject;
    PBWRM_PAGE_MANAGER_PROPERTY     pProperty         = (PBWRM_PAGE_MANAGER_PROPERTY  )&pMyObject->Property;
    PANSC_TIMER_DESCRIPTOR_OBJECT   pCacheTimerObject = (PANSC_TIMER_DESCRIPTOR_OBJECT)pMyObject->hCacheTimerObject;
    PBWRM_COOKED_PAGE_OBJECT        pCookedPage       = (PBWRM_COOKED_PAGE_OBJECT     )NULL;
    PSINGLE_LINK_ENTRY              pSLinkEntry       = (PSINGLE_LINK_ENTRY           )NULL;
    ULONG                           ulHashIndex       = (ULONG                        )AnscHashString(file_path, AnscSizeOfString(file_path), BWRM_PMO_CPO_TABLE_SIZE);

    AnscAcquireLock(&pMyObject->CpoTableLock);

    pSLinkEntry = AnscSListGetFirstEntry(&pMyObject->CpoTable[ulHashIndex]);

    while ( pSLinkEntry )
    {
        pCookedPage = ACCESS_BWRM_COOKED_PAGE_OBJECT(pSLinkEntry);
        pSLinkEntry = AnscSListGetNextEntry(pSLinkEntry);

        if ( pCookedPage->MatchPath
                (
                    (ANSC_HANDLE)pCookedPage,
                    root_path,
                    file_path
                ) )
        {
            AnscSListPopEntryByLink(&pMyObject->CpoTable[ulHashIndex], &pCookedPage->Linkage);

            pCookedPage->Remove((ANSC_HANDLE)pCookedPage);

            break;
        }
    }

    AnscReleaseLock(&pMyObject->CpoTableLock);

    if ( pMyObject->GetPageCount((ANSC_HANDLE)pMyObject) == 0 )
    {
        pCacheTimerObject->Stop((ANSC_HANDLE)pCacheTimerObject);
    }

    return  ANSC_STATUS_SUCCESS;
}
ANSC_HANDLE
BwrmPmoGetPage
    (
        ANSC_HANDLE                 hThisObject,
        char*                       root_path,
        char*                       file_path
    )
{
    ANSC_STATUS                     returnStatus      = ANSC_STATUS_SUCCESS;
    PBWRM_PAGE_MANAGER_OBJECT       pMyObject         = (PBWRM_PAGE_MANAGER_OBJECT    )hThisObject;
    PBWRM_PAGE_MANAGER_PROPERTY     pProperty         = (PBWRM_PAGE_MANAGER_PROPERTY  )&pMyObject->Property;
    PANSC_TIMER_DESCRIPTOR_OBJECT   pCacheTimerObject = (PANSC_TIMER_DESCRIPTOR_OBJECT)pMyObject->hCacheTimerObject;
    PBWRM_COOKED_PAGE_OBJECT        pCookedPage       = (PBWRM_COOKED_PAGE_OBJECT     )NULL;
    PSINGLE_LINK_ENTRY              pSLinkEntry       = (PSINGLE_LINK_ENTRY           )NULL;
    ULONG                           ulHashIndex       = (ULONG                        )AnscHashString(file_path, AnscSizeOfString(file_path), BWRM_PMO_CPO_TABLE_SIZE);
    ULONG                           ulCurTime         = AnscGetTickInSeconds();

    pMyObject->Timestamp = ulCurTime;

    AnscAcquireLock(&pMyObject->CpoTableLock);

    pSLinkEntry = AnscSListGetFirstEntry(&pMyObject->CpoTable[ulHashIndex]);

    while ( pSLinkEntry )
    {
        pCookedPage = ACCESS_BWRM_COOKED_PAGE_OBJECT(pSLinkEntry);
        pSLinkEntry = AnscSListGetNextEntry(pSLinkEntry);

        if ( pCookedPage->MatchPath
                (
                    (ANSC_HANDLE)pCookedPage,
                    root_path,
                    file_path
                ) )
        {
            pCookedPage->SetTimestamp((ANSC_HANDLE)pCookedPage, ulCurTime);
            pCookedPage->IncRefCount ((ANSC_HANDLE)pCookedPage);

            AnscReleaseLock(&pMyObject->CpoTableLock);

            return  (ANSC_HANDLE)pCookedPage;
        }
    }

    AnscReleaseLock(&pMyObject->CpoTableLock);

    return  (ANSC_HANDLE)NULL;
}
ANSC_STATUS
BwrmPmoDelAllPages
    (
        ANSC_HANDLE                 hThisObject
    )
{
    ANSC_STATUS                     returnStatus      = ANSC_STATUS_SUCCESS;
    PBWRM_PAGE_MANAGER_OBJECT       pMyObject         = (PBWRM_PAGE_MANAGER_OBJECT    )hThisObject;
    PBWRM_PAGE_MANAGER_PROPERTY     pProperty         = (PBWRM_PAGE_MANAGER_PROPERTY  )&pMyObject->Property;
    PANSC_TIMER_DESCRIPTOR_OBJECT   pCacheTimerObject = (PANSC_TIMER_DESCRIPTOR_OBJECT)pMyObject->hCacheTimerObject;
    PBWRM_COOKED_PAGE_OBJECT        pCookedPage       = (PBWRM_COOKED_PAGE_OBJECT     )NULL;
    PSINGLE_LINK_ENTRY              pSLinkEntry       = (PSINGLE_LINK_ENTRY           )NULL;
    ULONG                           i                 = 0;
    ULONG                           ulPageInUse       = 0;

    AnscAcquireLock(&pMyObject->CpoTableLock);

    for ( i = 0; i < BWRM_PMO_CPO_TABLE_SIZE; i++ )
    {
        pSLinkEntry = AnscSListPopEntry(&pMyObject->CpoTable[i]);

        while ( pSLinkEntry )
        {
            pCookedPage = ACCESS_BWRM_COOKED_PAGE_OBJECT(pSLinkEntry);
            pSLinkEntry = AnscSListPopEntry(&pMyObject->CpoTable[i]);

            if ( 0 == pCookedPage->GetRefCount((ANSC_HANDLE)pCookedPage) )
            {
                pCookedPage->Remove((ANSC_HANDLE)pCookedPage);
            }
            else
            {
                ulPageInUse ++;
            }
        }
    }

    AnscReleaseLock(&pMyObject->CpoTableLock);

    if ( 0 == ulPageInUse )
    {
        pCacheTimerObject->Stop((ANSC_HANDLE)pCacheTimerObject);
    }

    return  ANSC_STATUS_SUCCESS;
}
ANSC_STATUS
BwrmPmoAddPage
    (
        ANSC_HANDLE                 hThisObject,
        char*                       root_path,
        char*                       file_path,
        ANSC_HANDLE                 hCookedPage
    )
{
    ANSC_STATUS                     returnStatus      = ANSC_STATUS_SUCCESS;
    PBWRM_PAGE_MANAGER_OBJECT       pMyObject         = (PBWRM_PAGE_MANAGER_OBJECT    )hThisObject;
    PBWRM_PAGE_MANAGER_PROPERTY     pProperty         = (PBWRM_PAGE_MANAGER_PROPERTY  )&pMyObject->Property;
    PANSC_TIMER_DESCRIPTOR_OBJECT   pCacheTimerObject = (PANSC_TIMER_DESCRIPTOR_OBJECT)pMyObject->hCacheTimerObject;
    PBWRM_COOKED_PAGE_OBJECT        pCookedPage       = (PBWRM_COOKED_PAGE_OBJECT     )hCookedPage;
    ULONG                           ulHashIndex       = (ULONG                        )AnscHashString(file_path, AnscSizeOfString(file_path), BWRM_PMO_CPO_TABLE_SIZE);
    ULONG                           ulPageCount       = 0;
    ULONG                           ulCurTime         = AnscGetTickInSeconds();

    pMyObject->Timestamp = ulCurTime;

    pCookedPage->SetRootPath ((ANSC_HANDLE)pCookedPage, root_path);
    pCookedPage->SetPagePath ((ANSC_HANDLE)pCookedPage, file_path);
    pCookedPage->SetTimestamp((ANSC_HANDLE)pCookedPage, ulCurTime);
    pCookedPage->IncRefCount ((ANSC_HANDLE)pCookedPage           );

    AnscAcquireLock   (&pMyObject->CpoTableLock);
    AnscSListPushEntry(&pMyObject->CpoTable[ulHashIndex], &pCookedPage->Linkage);
    AnscReleaseLock   (&pMyObject->CpoTableLock);

    if ( TRUE )
    {
        ulPageCount = pMyObject->GetPageCount((ANSC_HANDLE)pMyObject);

        if ( ulPageCount == 1 )
        {
            pCacheTimerObject->Start((ANSC_HANDLE)pCacheTimerObject);
        }
        else if ( ulPageCount > pProperty->CacheEntryCount )
        {
            pCookedPage = (PBWRM_COOKED_PAGE_OBJECT)pMyObject->GetOldestPage((ANSC_HANDLE)pMyObject);

            if ( pCookedPage && 0 == pCookedPage->GetRefCount((ANSC_HANDLE)pCookedPage) )
            {
                returnStatus =
                    pMyObject->DelPage
                        (
                            (ANSC_HANDLE)pMyObject,
                            pCookedPage->GetRootPath((ANSC_HANDLE)pCookedPage),
                            pCookedPage->GetPagePath((ANSC_HANDLE)pCookedPage)
                        );
            }
        }
    }

    return  ANSC_STATUS_SUCCESS;
}
ANSC_HANDLE
BwrmPmoGetOldestPage
    (
        ANSC_HANDLE                 hThisObject
    )
{
    ANSC_STATUS                     returnStatus      = ANSC_STATUS_SUCCESS;
    PBWRM_PAGE_MANAGER_OBJECT       pMyObject         = (PBWRM_PAGE_MANAGER_OBJECT    )hThisObject;
    PBWRM_PAGE_MANAGER_PROPERTY     pProperty         = (PBWRM_PAGE_MANAGER_PROPERTY  )&pMyObject->Property;
    PANSC_TIMER_DESCRIPTOR_OBJECT   pCacheTimerObject = (PANSC_TIMER_DESCRIPTOR_OBJECT)pMyObject->hCacheTimerObject;
    PBWRM_COOKED_PAGE_OBJECT        pOldestCookedPage = (PBWRM_COOKED_PAGE_OBJECT     )NULL;
    PBWRM_COOKED_PAGE_OBJECT        pCookedPage       = (PBWRM_COOKED_PAGE_OBJECT     )NULL;
    PSINGLE_LINK_ENTRY              pSLinkEntry       = (PSINGLE_LINK_ENTRY           )NULL;
    ULONG                           ulOldestTimestamp = 0xFFFFFFFF;
    ULONG                           ulTempTimestamp   = 0;
    ULONG                           i                 = 0;

    AnscAcquireLock(&pMyObject->CpoTableLock);

    for ( i = 0; i < BWRM_PMO_CPO_TABLE_SIZE; i++ )
    {
        pSLinkEntry = AnscSListGetFirstEntry(&pMyObject->CpoTable[i]);

        while ( pSLinkEntry )
        {
            pCookedPage     = ACCESS_BWRM_COOKED_PAGE_OBJECT(pSLinkEntry);
            pSLinkEntry     = AnscSListGetNextEntry(pSLinkEntry);
            ulTempTimestamp = pCookedPage->GetTimestamp((ANSC_HANDLE)pCookedPage);

            if ( ulTempTimestamp < ulOldestTimestamp )
            {
                ulOldestTimestamp = ulTempTimestamp;
                pOldestCookedPage = pCookedPage;
            }
        }
    }

    AnscReleaseLock(&pMyObject->CpoTableLock);

    return  (ANSC_HANDLE)pOldestCookedPage;
}
ANSC_HANDLE
Bmc2ReqcoPecGetCookedPage
    (
        ANSC_HANDLE                 hThisObject,
        char*                       page_path
    )
{
    ANSC_STATUS                     returnStatus       = ANSC_STATUS_SUCCESS;
    PBMC2_REQ_CONTROLLER_OBJECT     pMyObject          = (PBMC2_REQ_CONTROLLER_OBJECT)hThisObject;
    PBMC2_ENV_CONTROLLER_OBJECT     pBmc2EnvController = (PBMC2_ENV_CONTROLLER_OBJECT)pMyObject->hBmc2EnvController;
    PBMC2_COM_DOMAIN_OBJECT         pBmc2ComDomain     = (PBMC2_COM_DOMAIN_OBJECT    )pMyObject->hBmc2ComDomain;
    PBMC2_COM_TERMINAL_OBJECT       pBmc2ComTerminal   = (PBMC2_COM_TERMINAL_OBJECT  )pBmc2ComDomain->hBmc2ComTerminal;
    PBMC2_COM_EXECUTOR_OBJECT       pBmc2ComExecutor   = (PBMC2_COM_EXECUTOR_OBJECT  )pBmc2EnvController->hBmc2ComExecutor;
    PBWRM_ENV_CONTROLLER_OBJECT     pBwrmEnvController = (PBWRM_ENV_CONTROLLER_OBJECT)pBmc2EnvController->hBwrmEnvController;
    PBWRM_RAM_INTERFACE             pBwrmRamIf         = (PBWRM_RAM_INTERFACE        )pBwrmEnvController->GetBwrmRamIf((ANSC_HANDLE)pBwrmEnvController);
    char*                           pRootPath          = (char*                      )pBmc2EnvController->Property.RootPath;
    PBWRM_COOKED_PAGE_OBJECT        pBwrmCookedPage    = (PBWRM_COOKED_PAGE_OBJECT   )NULL;
    void*                           pPageBuffer        = (void*                      )NULL;
    ULONG                           ulPageSize         = (ULONG                      )0;

    /*
     * The script parsing can take fairly long time, which mandates some sort of page caching
     * mechanism to be used. The BWRM (BroadWay Web Resource Manager) module is responsible for
     * file-based page access and page caching. We first try to retrieve the requested page from
     * the in-memory cache, and only load the page from the underlying storage system if the
     * requested page is not in the cache.
     */
    returnStatus =
        pBwrmRamIf->GetCookedPage
            (
                pBwrmRamIf->hOwnerContext,
                pRootPath,
                page_path,
                &pBwrmCookedPage
            );

    if ( returnStatus != ANSC_STATUS_SUCCESS )
    {
        returnStatus =
            pBwrmRamIf->GetRawPage
                (
                    pBwrmRamIf->hOwnerContext,
                    pRootPath,
                    page_path,
                    &pPageBuffer,
                    &ulPageSize
                );

        if ( returnStatus != ANSC_STATUS_SUCCESS )
        {
            return  (ANSC_HANDLE)NULL;
        }
        else
        {
            pBwrmCookedPage =
                (PBWRM_COOKED_PAGE_OBJECT)pBmc2ComExecutor->PreparePage
                    (
                        (ANSC_HANDLE)pBmc2ComExecutor,
                        page_path,
                        pPageBuffer,
                        ulPageSize
                    );
        }

        if ( !pBwrmCookedPage )
        {
            AnscFreeMemory(pPageBuffer);

            return  (ANSC_HANDLE)NULL;
        }
        else if ( pBmc2EnvController->Property.bCacheScpPages || pBwrmRamIf->IsPageCacheForced(pBwrmRamIf->hOwnerContext, page_path) )
        {
            returnStatus =
                pBwrmRamIf->AddCookedPage
                    (
                        pBwrmRamIf->hOwnerContext,
                        pRootPath,
                        page_path,
                        (ANSC_HANDLE)pBwrmCookedPage
                    );
        }
        else
        {
            pBwrmCookedPage->SetRootPath ((ANSC_HANDLE)pBwrmCookedPage, pRootPath             );
            pBwrmCookedPage->SetPagePath ((ANSC_HANDLE)pBwrmCookedPage, page_path             );
            pBwrmCookedPage->SetTimestamp((ANSC_HANDLE)pBwrmCookedPage, AnscGetTickInSeconds());
        }
    }

    return  (ANSC_HANDLE)pBwrmCookedPage;
}