Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1664 lines
37 KiB

//+--------------------------------------------------------------------------
//
// Copyright (c) 1997-1999 Microsoft Corporation
//
// File: wkstore.cpp
//
// Contents: Persistent job store routine.
//
// History:
//
//---------------------------------------------------------------------------
#include "pch.cpp"
#include "server.h"
#include "jobmgr.h"
#include "tlsjob.h"
#include "wkstore.h"
#include "debug.h"
WORKOBJECTINITFUNC g_WorkObjectInitFunList[] = {
{WORKTYPE_RETURN_LICENSE, InitializeCReturnWorkObject }
};
DWORD g_NumWorkObjectInitFunList = sizeof(g_WorkObjectInitFunList) / sizeof(g_WorkObjectInitFunList[0]);
//---------------------------------------------------
//
CLASS_PRIVATE
CWorkObject*
CPersistentWorkStorage::InitializeWorkObject(
IN DWORD dwWorkType,
IN PBYTE pbData,
IN DWORD cbData
)
/*++
--*/
{
DBGPrintf(
DBG_INFORMATION,
DBG_FACILITY_WORKMGR,
DBGLEVEL_FUNCTION_TRACE,
_TEXT("CPersistentWorkStorage::InitializeWorkObject() initializing work %d\n"),
dwWorkType
);
CWorkObject* ptr = NULL;
DWORD dwStatus = ERROR_SUCCESS;
try {
for(DWORD index =0; index < g_NumWorkObjectInitFunList; index ++)
{
if(dwWorkType == g_WorkObjectInitFunList[index].m_WorkType)
{
ptr = (g_WorkObjectInitFunList[index].m_WorkInitFunc)(
GetWorkManager(),
pbData,
cbData
);
break;
}
}
if(index >= g_NumWorkObjectInitFunList)
{
SetLastError(dwStatus = TLS_E_WORKSTORAGE_UNKNOWNWORKTYPE);
}
else
{
TLSWorkManagerSetJobDefaults(ptr);
}
}
catch( SE_Exception e ) {
SetLastError(dwStatus = e.getSeNumber());
TLSLogEvent(
EVENTLOG_ERROR_TYPE,
TLS_E_WORKMANAGERGENERAL,
TLS_E_WORKSTORAGE_INITWORK,
dwWorkType,
dwStatus
);
}
catch(...) {
SetLastError(dwStatus = TLS_E_WORKSTORAGE_INITWORKUNKNOWN);
TLSLogEvent(
EVENTLOG_ERROR_TYPE,
TLS_E_WORKMANAGERGENERAL,
TLS_E_WORKSTORAGE_INITWORKUNKNOWN,
dwWorkType
);
}
if(dwStatus != ERROR_SUCCESS)
{
DBGPrintf(
DBG_ERROR,
DBG_FACILITY_WORKMGR,
DBGLEVEL_FUNCTION_DETAILSIMPLE,
_TEXT("CPersistentWorkStorage::InitializeWorkObject() return 0x%08x\n"),
dwStatus
);
}
return ptr;
}
//---------------------------------------------------
//
CLASS_PRIVATE BOOL
CPersistentWorkStorage::DeleteWorkObject(
IN OUT CWorkObject* ptr
)
/*++
--*/
{
DWORD dwStatus = ERROR_SUCCESS;
DWORD dwWorkType = 0;
DBGPrintf(
DBG_INFORMATION,
DBG_FACILITY_WORKMGR,
DBGLEVEL_FUNCTION_TRACE,
_TEXT("CPersistentWorkStorage::DeleteWorkObject() deleting work %s\n"),
ptr->GetJobDescription()
);
try {
dwWorkType = ptr->GetWorkType();
ptr->SelfDestruct();
}
catch( SE_Exception e ) {
SetLastError(dwStatus = e.getSeNumber());
TLSLogEvent(
EVENTLOG_ERROR_TYPE,
TLS_E_WORKMANAGERGENERAL,
TLS_E_WORKSTORAGE_DELETEWORK,
dwWorkType,
dwStatus
);
}
catch(...) {
SetLastError(dwStatus = TLS_E_WORKSTORAGE_DELETEWORKUNKNOWN);
TLSLogEvent(
EVENTLOG_ERROR_TYPE,
TLS_E_WORKMANAGERGENERAL,
TLS_E_WORKSTORAGE_DELETEWORKUNKNOWN,
dwWorkType
);
}
if(dwStatus != ERROR_SUCCESS)
{
DBGPrintf(
DBG_ERROR,
DBG_FACILITY_WORKMGR,
DBGLEVEL_FUNCTION_DETAILSIMPLE,
_TEXT("CPersistentWorkStorage::DeleteWorkObject() return 0x%08x\n"),
dwStatus
);
}
return dwStatus == ERROR_SUCCESS;
}
//---------------------------------------------------
//
CPersistentWorkStorage::CPersistentWorkStorage(
IN WorkItemTable* pWkItemTable
) :
m_pWkItemTable(pWkItemTable),
m_dwNumJobs(0),
m_dwJobsInProcesssing(0),
m_dwNextJobTime(INFINITE),
m_pNextWorkObject(NULL)
/*++
--*/
{
}
//---------------------------------------------------
//
CPersistentWorkStorage::~CPersistentWorkStorage()
{
// just make sure we have shutdown
// TLSASSERT(m_pWkItemTable == NULL);
}
//---------------------------------------------------
//
BOOL
CPersistentWorkStorage::DeleteErrorJob(
IN CWorkObject* ptr
)
/*++
--*/
{
BOOL bSuccess = TRUE;
DWORD dwStatus = ERROR_SUCCESS;
PBYTE pbBookmark;
DWORD cbBookmark;
DWORD dwTime;
DWORD dwJobType;
if(IsValidWorkObject(ptr) == FALSE)
{
SetLastError(dwStatus = ERROR_INVALID_PARAMETER);
goto cleanup;
}
bSuccess = ptr->GetJobId(&pbBookmark, &cbBookmark);
if(bSuccess == FALSE)
{
SetLastError(dwStatus = ERROR_INVALID_DATA);
goto cleanup;
}
dwJobType = ptr->GetWorkType();
m_hTableLock.Lock();
bSuccess = UpdateWorkItemEntry(
m_pWkItemTable,
WORKITEM_DELETE,
pbBookmark,
cbBookmark,
INFINITE,
INFINITE,
dwJobType,
NULL,
0
);
if(bSuccess == FALSE)
{
dwStatus = GetLastError();
}
m_hTableLock.UnLock();
DeleteWorkObject(ptr);
cleanup:
return bSuccess;
}
//---------------------------------------------------
//
CLASS_PRIVATE DWORD
CPersistentWorkStorage::GetCurrentBookmark(
IN WorkItemTable* pTable,
IN PBYTE pbData,
IN OUT PDWORD pcbData
)
/*++
--*/
{
BOOL bSuccess = TRUE;
DWORD dwStatus = ERROR_SUCCESS;
if(pTable != NULL)
{
JET_ERR jbError;
bSuccess = pTable->GetBookmark(pbData, pcbData);
if(bSuccess == FALSE)
{
jbError = pTable->GetLastJetError();
if(jbError == JET_errNoCurrentRecord)
{
*pcbData = 0;
SetLastError(dwStatus = ERROR_NO_DATA);
}
else if(jbError == JET_errBufferTooSmall)
{
SetLastError(dwStatus = ERROR_INSUFFICIENT_BUFFER);
}
else
{
SetLastError(dwStatus = SET_JB_ERROR(jbError));
}
}
}
else
{
SetLastError(dwStatus = ERROR_INVALID_PARAMETER);
TLSASSERT(FALSE);
}
return dwStatus;
}
//-------------------------------------------------------------
//
CLASS_PRIVATE DWORD
CPersistentWorkStorage::GetCurrentBookmarkEx(
IN WorkItemTable* pTable,
IN OUT PBYTE* ppbData,
IN OUT PDWORD pcbData
)
/*++
--*/
{
DWORD dwStatus = ERROR_SUCCESS;
BOOL bSucess = TRUE;
if(ppbData == NULL || pcbData == NULL || pTable == 0)
{
SetLastError(dwStatus = ERROR_INVALID_PARAMETER);
return dwStatus;
}
*ppbData = NULL;
*pcbData = 0;
dwStatus = GetCurrentBookmark(
pTable,
*ppbData,
pcbData
);
if(dwStatus == ERROR_INSUFFICIENT_BUFFER)
{
*ppbData = (PBYTE)AllocateMemory(*pcbData);
if(*ppbData != NULL)
{
dwStatus = GetCurrentBookmark(
pTable,
*ppbData,
pcbData
);
}
}
if(dwStatus != ERROR_SUCCESS)
{
if(*ppbData != NULL)
{
FreeMemory(*ppbData);
}
*ppbData = NULL;
*pcbData = 0;
}
return dwStatus;
}
//------------------------------------------------------
CLASS_PRIVATE DWORD
CPersistentWorkStorage::SetCurrentBookmark(
IN WorkItemTable* pTable,
IN PBYTE pbData,
IN DWORD cbData
)
/*++
--*/
{
BOOL bSuccess;
DWORD dwStatus = ERROR_SUCCESS;
if(pTable != NULL && pbData != NULL && cbData != 0)
{
bSuccess = pTable->GotoBookmark(pbData, cbData);
if(bSuccess == FALSE)
{
if(pTable->GetLastJetError() == JET_errRecordDeleted)
{
SetLastError(dwStatus = ERROR_NO_DATA);
}
else
{
SetLastError(dwStatus = SET_JB_ERROR(pTable->GetLastJetError()));
}
}
}
else
{
SetLastError(dwStatus = ERROR_INVALID_PARAMETER);
TLSASSERT(FALSE);
}
return dwStatus;
}
//---------------------------------------------------
//
BOOL
CPersistentWorkStorage::Shutdown()
{
BOOL bSuccess = TRUE;
//
// CWorkManager will make sure
// no job is in processing state before calling this
// routine and no job can be scheduled.
//
m_hTableLock.Lock();
//
// Timing.
//
TLSASSERT(m_dwJobsInProcesssing == 0);
if(m_pWkItemTable != NULL)
{
bSuccess = m_pWkItemTable->CloseTable();
m_pWkItemTable = NULL;
}
TLSASSERT(bSuccess == TRUE);
m_pWkItemTable = NULL;
m_dwNumJobs = 0;
m_dwNextJobTime = INFINITE;
if(m_pNextWorkObject != NULL)
{
DeleteWorkObject( m_pNextWorkObject );
m_pNextWorkObject = NULL;
}
m_hTableLock.UnLock();
return bSuccess;
}
//---------------------------------------------------
//
DWORD
CPersistentWorkStorage::StartupUpdateExistingJobTime()
{
BOOL bSuccess;
DWORD dwStatus = ERROR_SUCCESS;
DWORD dwTime;
DWORD dwMinTime = INFINITE;
// CWorkObject* ptr = NULL;
BOOL bValidJob = TRUE;
DWORD dwCurrentTime;
m_hTableLock.Lock();
//
//
bSuccess = m_pWkItemTable->MoveToRecord(JET_MoveFirst);
if(bSuccess == FALSE)
{
SetLastError(dwStatus = SET_JB_ERROR(m_pWkItemTable->GetLastJetError()));
}
while(dwStatus == ERROR_SUCCESS)
{
WORKITEMRECORD wkItem;
//if(ptr != NULL)
//{
// DeleteWorkObject(ptr);
// ptr = NULL;
//}
bValidJob = FALSE;
//
// fetch the record
//
bSuccess = m_pWkItemTable->FetchRecord(wkItem);
if(bSuccess == FALSE)
{
SetLastError(dwStatus = SET_JB_ERROR(m_pWkItemTable->GetLastJetError()));
continue;
}
if(wkItem.dwRestartTime != INFINITE && wkItem.dwScheduledTime >= m_dwStartupTime)
{
if(wkItem.dwScheduledTime < dwMinTime)
{
dwMinTime = wkItem.dwScheduledTime;
}
break;
}
//
// invalid data
//
if(wkItem.cbData != 0 && wkItem.pbData != NULL)
{
if(wkItem.dwRestartTime != INFINITE)
{
wkItem.dwScheduledTime = wkItem.dwRestartTime + time(NULL);
wkItem.dwJobType &= ~WORKTYPE_PROCESSING;
bSuccess = m_pWkItemTable->UpdateRecord(
wkItem,
WORKITEM_PROCESS_JOBTIME | WORKITEM_PROCESS_JOBTYPE
);
if(bSuccess == FALSE)
{
SetLastError(dwStatus = SET_JB_ERROR(m_pWkItemTable->GetLastJetError()));
break;
}
if(wkItem.dwScheduledTime < dwMinTime)
{
dwMinTime = wkItem.dwScheduledTime;
}
bValidJob = TRUE;
}
}
if(bValidJob == FALSE)
{
m_pWkItemTable->DeleteRecord();
}
// move the record pointer
bSuccess = m_pWkItemTable->MoveToRecord();
if(bSuccess == FALSE)
{
JET_ERR jetErrCode;
jetErrCode = m_pWkItemTable->GetLastJetError();
if(jetErrCode != JET_errNoCurrentRecord)
{
SetLastError(dwStatus = SET_JB_ERROR(jetErrCode));
}
break;
}
}
if(dwStatus == ERROR_SUCCESS)
{
bSuccess = m_pWkItemTable->MoveToRecord(JET_MoveFirst);
if(bSuccess == FALSE)
{
SetLastError(dwStatus = SET_JB_ERROR(m_pWkItemTable->GetLastJetError()));
}
UpdateNextJobTime(dwMinTime);
}
m_hTableLock.UnLock();
//if(ptr != NULL)
//{
// DeleteWorkObject(ptr);
// ptr = NULL;
//}
return dwStatus;
}
//---------------------------------------------------
//
BOOL
CPersistentWorkStorage::Startup(
IN CWorkManager* pWkMgr
)
/*++
--*/
{
BOOL bSuccess;
DWORD dwStatus = ERROR_SUCCESS;
CWorkStorage::Startup(pWkMgr);
if(IsGood() == TRUE)
{
//
// loop thru all workitem and count number of job
//
m_hTableLock.Lock();
try {
m_dwStartupTime = time(NULL);
//
// Get number of job in queue
//
//
// GetCount() will set index to time column
m_dwNumJobs = m_pWkItemTable->GetCount(
FALSE,
0,
NULL
);
if(m_dwNumJobs == 0)
{
UpdateNextJobTime(INFINITE);
}
else
{
bSuccess = m_pWkItemTable->BeginTransaction();
if(bSuccess == TRUE)
{
dwStatus = StartupUpdateExistingJobTime();
if(dwStatus == ERROR_SUCCESS)
{
m_pWkItemTable->CommitTransaction();
}
else
{
m_pWkItemTable->RollbackTransaction();
}
}
else
{
dwStatus = GetLastError();
}
//
// constructor set next job time to 0 so
// work manager will immediately try to find next job
//
// Move to first record in table
//bSuccess = m_pWkItemTable->MoveToRecord(JET_MoveFirst);
}
}
catch( SE_Exception e ) {
SetLastError(dwStatus = e.getSeNumber());
}
catch(...) {
SetLastError(dwStatus = TLS_E_WORKMANAGER_INTERNAL);
}
m_hTableLock.UnLock();
}
else
{
SetLastError(dwStatus = ERROR_INVALID_PARAMETER);
}
return (dwStatus == ERROR_SUCCESS);
}
//----------------------------------------------------
//
CLASS_PRIVATE BOOL
CPersistentWorkStorage::IsValidWorkObject(
CWorkObject* ptr
)
/*++
--*/
{
BOOL bSuccess = FALSE;
DWORD dwJobType;
PBYTE pbData;
DWORD cbData;
//
// Validate input parameter
//
if(ptr == NULL)
{
TLSASSERT(FALSE);
goto cleanup;
}
dwJobType = ptr->GetWorkType();
if(dwJobType == WORK_TYPE_UNKNOWN)
{
TLSASSERT(FALSE);
goto cleanup;
}
ptr->GetWorkObjectData(&pbData, &cbData);
if(pbData == NULL || cbData == 0)
{
TLSASSERT(pbData != NULL && cbData != NULL);
goto cleanup;
}
bSuccess = TRUE;
cleanup:
return bSuccess;
}
//----------------------------------------------------
//
BOOL
CPersistentWorkStorage::IsGood()
{
if( m_pWkItemTable == NULL ||
m_hTableLock.IsGood() == FALSE ||
GetWorkManager() == NULL )
{
return FALSE;
}
return m_pWkItemTable->IsValid();
}
//----------------------------------------------------
//
CLASS_PRIVATE BOOL
CPersistentWorkStorage::UpdateJobEntry(
IN WorkItemTable* pTable,
IN PBYTE pbBookmark,
IN DWORD cbBookmark,
IN WORKITEMRECORD& wkItem
)
/*++
--*/
{
BOOL bSuccess = TRUE;
DWORD dwStatus = ERROR_SUCCESS;
dwStatus = SetCurrentBookmark(
pTable,
pbBookmark,
cbBookmark
);
if(dwStatus == ERROR_SUCCESS)
{
bSuccess = pTable->UpdateRecord(wkItem);
}
else
{
bSuccess = FALSE;
TLSASSERT(dwStatus == ERROR_SUCCESS);
}
return bSuccess;
}
//----------------------------------------------------
//
CLASS_PRIVATE BOOL
CPersistentWorkStorage::AddJobEntry(
IN WorkItemTable* pTable,
IN WORKITEMRECORD& wkItem
)
/*++
--*/
{
BOOL bSuccess;
bSuccess = pTable->InsertRecord(wkItem);
if(bSuccess == TRUE)
{
m_dwNumJobs++;
}
return bSuccess;
}
//----------------------------------------------------
//
CLASS_PRIVATE BOOL
CPersistentWorkStorage::DeleteJobEntry(
IN WorkItemTable* pTable,
IN PBYTE pbBookmark,
IN DWORD cbBookmark,
IN WORKITEMRECORD& wkItem
)
/*++
--*/
{
BOOL bSuccess = TRUE;
DWORD dwStatus = ERROR_SUCCESS;
dwStatus = SetCurrentBookmark(
pTable,
pbBookmark,
cbBookmark
);
if(dwStatus == ERROR_SUCCESS)
{
bSuccess = pTable->DeleteRecord();
if(bSuccess == TRUE)
{
m_dwNumJobs--;
}
}
else
{
bSuccess = FALSE;
TLSASSERT(dwStatus == ERROR_SUCCESS);
}
return bSuccess;
}
//----------------------------------------------------
//
CLASS_PRIVATE BOOL
CPersistentWorkStorage::UpdateWorkItemEntry(
IN WorkItemTable* pTable,
IN WORKITEM_OPERATION opCode,
IN PBYTE pbBookmark,
IN DWORD cbBookmark,
IN DWORD dwRestartTime,
IN DWORD dwTime,
IN DWORD dwJobType,
IN PBYTE pbJobData,
IN DWORD cbJobData
)
/*++
--*/
{
BOOL bSuccess = TRUE;
DWORD dwStatus = ERROR_SUCCESS;
WORKITEMRECORD item;
PBYTE pbCurrentBookmark=NULL;
DWORD cbCurrentBookmark=0;
m_hTableLock.Lock();
dwStatus = GetCurrentBookmarkEx(
pTable,
&pbCurrentBookmark,
&cbCurrentBookmark
);
if(dwStatus != ERROR_SUCCESS && dwStatus != ERROR_NO_DATA)
{
goto cleanup;
}
bSuccess = pTable->BeginTransaction();
if(bSuccess == FALSE)
{
dwStatus = GetLastError();
goto cleanup;
}
item.dwScheduledTime = dwTime;
item.dwRestartTime = dwRestartTime;
item.dwJobType = dwJobType;
item.cbData = cbJobData;
item.pbData = pbJobData;
switch(opCode)
{
case WORKITEM_ADD:
TLSASSERT(cbJobData != 0 && pbJobData != NULL);
m_pWkItemTable->SetInsertRepositionBookmark(
(dwTime < (DWORD)m_dwNextJobTime)
);
bSuccess = AddJobEntry(
pTable,
item
);
break;
case WORKITEM_BEGINPROCESSING:
item.dwJobType |= WORKTYPE_PROCESSING;
//
// FALL THRU
//
case WORKITEM_RESCHEDULE:
TLSASSERT(cbJobData != 0 && pbJobData != NULL);
bSuccess = UpdateJobEntry(
pTable,
pbBookmark,
cbBookmark,
item
);
break;
case WORKITEM_DELETE:
bSuccess = DeleteJobEntry(
pTable,
pbBookmark,
cbBookmark,
item
);
break;
default:
TLSASSERT(FALSE);
bSuccess = FALSE;
}
if(bSuccess == TRUE)
{
pTable->CommitTransaction();
dwStatus = ERROR_SUCCESS;
//
// constructor set time to first job 0 so that work manager can immediate kick off
//
if( (opCode != WORKITEM_ADD && opCode != WORKITEM_RESCHEDULE) || dwTime > (DWORD)m_dwNextJobTime )
{
if(pbCurrentBookmark != NULL && cbCurrentBookmark != 0)
{
dwStatus = SetCurrentBookmark(
pTable,
pbCurrentBookmark,
cbCurrentBookmark
);
if(dwStatus == ERROR_NO_DATA)
{
// record already deleted
dwStatus = ERROR_SUCCESS;
}
else
{
TLSASSERT(dwStatus == ERROR_SUCCESS);
}
}
}
else
{
UpdateNextJobTime(dwTime);
}
}
else
{
SetLastError(dwStatus = SET_JB_ERROR(pTable->GetLastJetError()));
pTable->RollbackTransaction();
TLSASSERT(FALSE);
}
cleanup:
m_hTableLock.UnLock();
if(pbCurrentBookmark != NULL)
{
FreeMemory(pbCurrentBookmark);
}
//
// WORKITEMRECORD will try to cleanup memory
//
item.pbData = NULL;
item.cbData = 0;
return dwStatus == ERROR_SUCCESS;
}
//----------------------------------------------------
//
BOOL
CPersistentWorkStorage::AddJob(
IN DWORD dwTime,
IN CWorkObject* ptr
)
/*++
--*/
{
DWORD dwStatus = ERROR_SUCCESS;
BOOL bSuccess = TRUE;
PBYTE pbData;
DWORD cbData;
DBGPrintf(
DBG_INFORMATION,
DBG_FACILITY_WORKMGR,
DBGLEVEL_FUNCTION_TRACE,
_TEXT("CPersistentWorkStorage::AddJob() scheduling job %s at time %d\n"),
ptr->GetJobDescription(),
dwTime
);
if(IsValidWorkObject(ptr) == FALSE)
{
SetLastError(dwStatus = ERROR_INVALID_PARAMETER);
goto cleanup;
}
bSuccess = ptr->GetWorkObjectData(&pbData, &cbData);
if(bSuccess == FALSE)
{
SetLastError(dwStatus = ERROR_INVALID_PARAMETER);
goto cleanup;
}
m_hTableLock.Lock();
if(m_pWkItemTable != NULL)
{
bSuccess = UpdateWorkItemEntry(
m_pWkItemTable,
WORKITEM_ADD,
NULL,
0,
ptr->GetJobRestartTime(),
dwTime + time(NULL),
ptr->GetWorkType(),
pbData,
cbData
);
if(bSuccess == FALSE)
{
dwStatus = GetLastError();
}
}
m_hTableLock.UnLock();
cleanup:
// Let Calling function delete it.
// DeleteWorkObject(ptr);
return dwStatus == ERROR_SUCCESS;
}
//----------------------------------------------------
//
BOOL
CPersistentWorkStorage::RescheduleJob(
CWorkObject* ptr
)
/*++
--*/
{
BOOL bSuccess = TRUE;
DWORD dwStatus = ERROR_SUCCESS;
PBYTE pbData;
DWORD cbData;
PBYTE pbBookmark;
DWORD cbBookmark;
DWORD dwTime;
DWORD dwJobType;
DBGPrintf(
DBG_INFORMATION,
DBG_FACILITY_WORKMGR,
DBGLEVEL_FUNCTION_TRACE,
_TEXT("CPersistentWorkStorage::RescheduleJob() scheduling job %s\n"),
ptr->GetJobDescription()
);
if(IsValidWorkObject(ptr) == FALSE)
{
SetLastError(dwStatus = ERROR_INVALID_PARAMETER);
goto cleanup;
}
bSuccess = ptr->GetWorkObjectData(&pbData, &cbData);
if(bSuccess == FALSE)
{
SetLastError(dwStatus = ERROR_INVALID_DATA);
goto cleanup;
}
bSuccess = ptr->GetJobId(&pbBookmark, &cbBookmark);
if(bSuccess == FALSE)
{
SetLastError(dwStatus = ERROR_INVALID_DATA);
goto cleanup;
}
dwTime = ptr->GetSuggestedScheduledTime();
dwJobType = ptr->GetWorkType();
m_hTableLock.Lock();
if(m_pWkItemTable != NULL)
{
bSuccess = UpdateWorkItemEntry(
m_pWkItemTable,
(dwTime == INFINITE) ? WORKITEM_DELETE : WORKITEM_RESCHEDULE,
pbBookmark,
cbBookmark,
ptr->GetJobRestartTime(),
(dwTime == INFINITE) ? dwTime : dwTime + time(NULL),
dwJobType,
pbData,
cbData
);
if(bSuccess == FALSE)
{
dwStatus = GetLastError();
}
}
m_hTableLock.UnLock();
cleanup:
DeleteWorkObject(ptr);
return dwStatus == ERROR_SUCCESS;
}
//----------------------------------------------------
//
CLASS_PRIVATE DWORD
CPersistentWorkStorage::FindNextJob()
{
DWORD dwStatus = ERROR_SUCCESS;
BOOL bSuccess = TRUE;
CWorkObject* ptr = NULL;
JET_ERR jetErrCode;
PBYTE pbBookmark = NULL;
DWORD cbBookmark = 0;
m_hTableLock.Lock();
while(dwStatus == ERROR_SUCCESS)
{
WORKITEMRECORD wkItem;
// move the record pointer
bSuccess = m_pWkItemTable->MoveToRecord();
if(bSuccess == FALSE)
{
jetErrCode = m_pWkItemTable->GetLastJetError();
if(jetErrCode == JET_errNoCurrentRecord)
{
// end of table
UpdateNextJobTime(INFINITE);
SetLastError(dwStatus = ERROR_NO_DATA);
continue;
}
}
//
// fetch the record
//
bSuccess = m_pWkItemTable->FetchRecord(wkItem);
if(bSuccess == FALSE)
{
SetLastError(dwStatus = SET_JB_ERROR(m_pWkItemTable->GetLastJetError()));
continue;
}
if(wkItem.dwJobType & WORKTYPE_PROCESSING)
{
// job is been processed, move to next one.
continue;
}
dwStatus = GetCurrentBookmarkEx(
m_pWkItemTable,
&pbBookmark,
&cbBookmark
);
if(dwStatus != ERROR_SUCCESS)
{
// Error...
TLSASSERT(dwStatus == ERROR_SUCCESS);
UpdateNextJobTime(INFINITE);
break;
}
if(wkItem.dwScheduledTime > m_dwStartupTime)
{
if(pbBookmark != NULL && cbBookmark != 0)
{
FreeMemory( pbBookmark );
pbBookmark = NULL;
cbBookmark = 0;
}
UpdateNextJobTime(wkItem.dwScheduledTime);
break;
}
//
// job is in queue before system startup, re-schedule
//
ptr = InitializeWorkObject(
wkItem.dwJobType,
wkItem.pbData,
wkItem.cbData
);
if(ptr == NULL)
{
if(pbBookmark != NULL && cbBookmark != 0)
{
FreeMemory( pbBookmark );
pbBookmark = NULL;
cbBookmark = 0;
}
//
// something is wrong, delete this job
// and move on to next job
//
m_pWkItemTable->DeleteRecord();
continue;
}
//
// Set Job's storage ID and re-schedule this job
//
ptr->SetJobId(pbBookmark, cbBookmark);
bSuccess = RescheduleJob(ptr);
if(bSuccess == FALSE)
{
dwStatus = GetLastError();
}
if(pbBookmark != NULL && cbBookmark != 0)
{
FreeMemory( pbBookmark );
pbBookmark = NULL;
cbBookmark = 0;
}
}
m_hTableLock.UnLock();
return dwStatus;
}
//----------------------------------------------------
//
CLASS_PRIVATE CWorkObject*
CPersistentWorkStorage::GetCurrentJob(
PDWORD pdwTime
)
/*++
--*/
{
DWORD dwStatus = ERROR_SUCCESS;
BOOL bSuccess = TRUE;
WORKITEMRECORD wkItem;
CWorkObject* ptr = NULL;
PBYTE pbBookmark=NULL;
DWORD cbBookmark=0;
TLSASSERT(IsGood() == TRUE);
m_hTableLock.Lock();
while(dwStatus == ERROR_SUCCESS)
{
//
// fetch the record
//
bSuccess = m_pWkItemTable->FetchRecord(wkItem);
TLSASSERT(bSuccess == TRUE);
//TLSASSERT(!(wkItem.dwJobType & WORKTYPE_PROCESSING));
if(bSuccess == FALSE)
{
SetLastError(dwStatus = SET_JB_ERROR(m_pWkItemTable->GetLastJetError()));
break;
}
if( wkItem.dwScheduledTime < m_dwStartupTime ||
wkItem.cbData == 0 ||
wkItem.pbData == NULL )
{
// FindNextJob() move record pointer one position down
m_pWkItemTable->MoveToRecord(JET_MovePrevious);
dwStatus = FindNextJob();
continue;
}
if( wkItem.dwJobType & WORKTYPE_PROCESSING )
{
dwStatus = FindNextJob();
continue;
}
ptr = InitializeWorkObject(
wkItem.dwJobType,
wkItem.pbData,
wkItem.cbData
);
dwStatus = GetCurrentBookmarkEx(
m_pWkItemTable,
&pbBookmark,
&cbBookmark
);
if(dwStatus != ERROR_SUCCESS)
{
// something is wrong, free up memory
// and exit.
SetLastError(dwStatus);
// TLSASSERT(FALSE);
DeleteWorkObject(ptr);
ptr = NULL;
// grab next job
dwStatus = FindNextJob();
continue;
}
//
// Set Job's storage ID
//
ptr->SetJobId(pbBookmark, cbBookmark);
//ptr->SetScheduledTime(wkItem.dwScheduledTime);
*pdwTime = wkItem.dwScheduledTime;
if(pbBookmark != NULL && cbBookmark != 0)
{
FreeMemory( pbBookmark );
pbBookmark = NULL;
cbBookmark = 0;
}
break;
}
m_hTableLock.UnLock();
return ptr;
}
//-----------------------------------------------------
//
DWORD
CPersistentWorkStorage::GetNextJobTime()
{
DWORD dwTime;
dwTime = (DWORD)m_dwNextJobTime;
return dwTime;
}
//-----------------------------------------------------
//
CWorkObject*
CPersistentWorkStorage::GetNextJob(
PDWORD pdwTime
)
/*++
--*/
{
CWorkObject* ptr = NULL;
if((DWORD)m_dwNextJobTime != INFINITE)
{
try {
m_hTableLock.Lock();
//
// Fetch record where current bookmark points to,
// it is possible that new job arrived after
// WorkManager already calls GetNextJobTime(),
// this is OK since in this case this new job
// needs immediate processing.
//
ptr = GetCurrentJob(pdwTime);
//
// reposition current record pointer
//
FindNextJob();
}
catch(...) {
SetLastError(TLS_E_WORKMANAGER_INTERNAL);
ptr = NULL;
}
m_hTableLock.UnLock();
}
return ptr;
}
//-----------------------------------------------------
//
BOOL
CPersistentWorkStorage::ReturnJobToQueue(
IN DWORD dwTime,
IN CWorkObject* ptr
)
/*++
--*/
{
DWORD dwStatus = ERROR_SUCCESS;
PBYTE pbBookmark;
DWORD cbBookmark;
DWORD dwJobType;
PBYTE pbData;
DWORD cbData;
if(IsValidWorkObject(ptr) == FALSE)
{
SetLastError(dwStatus = ERROR_INVALID_PARAMETER);
goto cleanup;
}
if(ptr->IsWorkPersistent() == FALSE)
{
SetLastError(dwStatus = ERROR_INVALID_DATA);
TLSASSERT(FALSE);
goto cleanup;
}
if(ptr->GetWorkObjectData(&pbData, &cbData) == FALSE)
{
SetLastError(dwStatus = ERROR_INVALID_DATA);
goto cleanup;
}
if(ptr->GetJobId(&pbBookmark, &cbBookmark) == FALSE)
{
SetLastError(dwStatus = ERROR_INVALID_DATA);
goto cleanup;
}
m_hTableLock.Lock();
if(dwTime < (DWORD)m_dwNextJobTime)
{
// Position current record
dwStatus = SetCurrentBookmark(
m_pWkItemTable,
pbBookmark,
cbBookmark
);
TLSASSERT(dwStatus == ERROR_SUCCESS);
if(dwStatus == ERROR_SUCCESS)
{
UpdateNextJobTime(dwTime);
}
}
m_hTableLock.UnLock();
cleanup:
DeleteWorkObject(ptr);
return dwStatus == ERROR_SUCCESS;
}
//-----------------------------------------------------
//
BOOL
CPersistentWorkStorage::EndProcessingJob(
IN ENDPROCESSINGJOB_CODE opCode,
IN DWORD dwOriginalTime,
IN CWorkObject* ptr
)
/*++
Abstract:
Parameter:
opCode : End Processing code.
ptr : Job has completed processing or been
returned by workmanager due to time or
resource constraint.
Return:
TRUE/FALSE
--*/
{
BOOL bSuccess = TRUE;
BYTE pbData = NULL;
DWORD cbData = 0;
DBGPrintf(
DBG_INFORMATION,
DBG_FACILITY_WORKMGR,
DBGLEVEL_FUNCTION_TRACE,
_TEXT("CPersistentWorkStorage::EndProcessingJob() - end processing %s opCode %d\n"),
ptr->GetJobDescription(),
opCode
);
if(ptr == NULL)
{
bSuccess = FALSE;
SetLastError(ERROR_INVALID_PARAMETER);
goto cleanup;
}
if(ptr->IsWorkPersistent() == FALSE)
{
SetLastError(ERROR_INVALID_DATA);
TLSASSERT(FALSE);
goto cleanup;
}
switch(opCode)
{
case ENDPROCESSINGJOB_SUCCESS:
bSuccess = RescheduleJob(ptr);
m_dwJobsInProcesssing--;
break;
case ENDPROCESSINGJOB_ERROR:
bSuccess = DeleteErrorJob(ptr);
m_dwJobsInProcesssing--;
break;
case ENDPROCESSINGJOB_RETURN:
bSuccess = ReturnJobToQueue(dwOriginalTime, ptr);
break;
default:
TLSASSERT(FALSE);
}
cleanup:
return bSuccess;
}
//-------------------------------------------------------
//
BOOL
CPersistentWorkStorage::BeginProcessingJob(
IN CWorkObject* ptr
)
/*++
Abstract:
Work Manager call this to inform. storage that
this job is about to be processed.
Parameter:
ptr - Job to be process.
Return:
TRUE/FALSE
--*/
{
BOOL bSuccess = TRUE;
DWORD dwStatus = ERROR_SUCCESS;
PBYTE pbBookmark;
DWORD cbBookmark;
DWORD dwTime;
PBYTE pbData;
DWORD cbData;
DBGPrintf(
DBG_INFORMATION,
DBG_FACILITY_WORKMGR,
DBGLEVEL_FUNCTION_TRACE,
_TEXT("CPersistentWorkStorage::BeginProcessingJob() - beginning processing %s\n"),
ptr->GetJobDescription()
);
if(IsValidWorkObject(ptr) == FALSE)
{
SetLastError(dwStatus = ERROR_INVALID_PARAMETER);
goto cleanup;
}
if(ptr->IsWorkPersistent() == FALSE)
{
SetLastError(dwStatus = ERROR_INVALID_DATA);
TLSASSERT(FALSE);
goto cleanup;
}
bSuccess = ptr->GetWorkObjectData(&pbData, &cbData);
if(bSuccess == FALSE)
{
SetLastError(dwStatus = ERROR_INVALID_DATA);
goto cleanup;
}
bSuccess = ptr->GetJobId(&pbBookmark, &cbBookmark);
if(bSuccess == FALSE)
{
SetLastError(dwStatus = ERROR_INVALID_DATA);
goto cleanup;
}
m_hTableLock.Lock();
bSuccess = UpdateWorkItemEntry(
m_pWkItemTable,
WORKITEM_BEGINPROCESSING,
pbBookmark,
cbBookmark,
ptr->GetJobRestartTime(),
ptr->GetScheduledTime(),
ptr->GetWorkType(),
pbData,
cbData
);
if(bSuccess == TRUE)
{
m_dwJobsInProcesssing ++;
}
else
{
dwStatus = GetLastError();
}
m_hTableLock.UnLock();
cleanup:
return dwStatus == ERROR_SUCCESS;
}