|
|
/*++
� 1998 Seagate Software, Inc. All rights reserved.
Module Name:
tskmgr.cpp
Abstract:
This class represents the HSM task manager
Author:
Cat Brant [cbrant] 6-Dec-1996
Revision History:
Incorporate demand recall queue support - Ravisankar Pudipeddi [ravisp] 1-Oct-199
--*/
#include "stdafx.h"
#define WSB_TRACE_IS WSB_TRACE_BIT_HSMTSKMGR
#include "wsb.h"
#include "hsmconn.h"
#include "hsmeng.h"
#include "fsa.h"
#include "task.h"
#include "tskmgr.h"
#include "hsmWorkQ.h"
#include "engine.h"
#define MAX_WORK_QUEUE_TYPES 7
HRESULT CHsmTskMgr::FinalConstruct( void ) /*++
Routine Description:
This method does some initialization of the object that is necessary after construction.
Arguments:
None.
Return Value:
S_OK Anything returned by CWsbCollectable::FinalConstruct().
--*/ { HRESULT hr = S_OK;
WsbTraceIn(OLESTR("CHsmTskMgr::FinalConstruct"),OLESTR("")); try { m_bCritSecCreated = FALSE;
int index = 0;
WsbAssertHr(CComObjectRoot::FinalConstruct()); m_pWorkQueues = 0; m_NumWorkQueues = 0;
// Set up queue type info and set limits
m_nWorkQueueTypes = 0; m_pWorkQueueTypeInfo = static_cast<PHSM_WORK_QUEUE_TYPE_INFO> (WsbAlloc(MAX_WORK_QUEUE_TYPES * sizeof(HSM_WORK_QUEUE_TYPE_INFO))); WsbAffirmPointer(m_pWorkQueueTypeInfo);
// Migrate queues
WsbAffirm(index < MAX_WORK_QUEUE_TYPES, WSB_E_INVALID_DATA); m_pWorkQueueTypeInfo[index].Type = HSM_WORK_TYPE_FSA_MIGRATE; m_pWorkQueueTypeInfo[index].MaxActiveAllowed = 1; // For Migrate, this is useless now
// - the limit is dynamically set
m_pWorkQueueTypeInfo[index].NumActive = 0; index++;
// Recall queues
WsbAffirm(index < MAX_WORK_QUEUE_TYPES, WSB_E_INVALID_DATA); m_pWorkQueueTypeInfo[index].Type = HSM_WORK_TYPE_FSA_RECALL; m_pWorkQueueTypeInfo[index].MaxActiveAllowed = 1; m_pWorkQueueTypeInfo[index].NumActive = 0; index++;
// Demand Recall queues
WsbAffirm(index < MAX_WORK_QUEUE_TYPES, WSB_E_INVALID_DATA); m_pWorkQueueTypeInfo[index].Type = HSM_WORK_TYPE_FSA_DEMAND_RECALL; //
// MaxActiveAllowed is irrelevant for demand recall queues
// as it is computed afresh
//
m_pWorkQueueTypeInfo[index].MaxActiveAllowed = 1; m_pWorkQueueTypeInfo[index].NumActive = 0; index++;
// Validate queues
WsbAffirm(index < MAX_WORK_QUEUE_TYPES, WSB_E_INVALID_DATA); m_pWorkQueueTypeInfo[index].Type = HSM_WORK_TYPE_FSA_VALIDATE; m_pWorkQueueTypeInfo[index].MaxActiveAllowed = 2; m_pWorkQueueTypeInfo[index].NumActive = 0; index++;
// Validate_for_truncate queues. MaxActiveAllowed is essentially
// unlimited because this is the type of queue that the FSA's
// auto-truncator creates. Because there is one queue for each managed
// volume and these queues never go away, we can't limit the number
// or we will create problems. The Truncate job also
// creates this type of queue which means that type of job is not
// limited by this mechanism, but that's the way it goes.
WsbAffirm(index < MAX_WORK_QUEUE_TYPES, WSB_E_INVALID_DATA); m_pWorkQueueTypeInfo[index].Type = HSM_WORK_TYPE_FSA_VALIDATE_FOR_TRUNCATE; m_pWorkQueueTypeInfo[index].MaxActiveAllowed = 99999; m_pWorkQueueTypeInfo[index].NumActive = 0; index++;
m_nWorkQueueTypes = index;
}WsbCatch(hr);
WsbTraceOut(OLESTR("CHsmTskMgr::FinalConstruct"),OLESTR("hr = <%ls>"),WsbHrAsString(hr)); return(hr); }
HRESULT CHsmTskMgr::FinalRelease( void ) /*++
Routine Description:
This method does some clean up of the object that is necessary before destruction.
Arguments:
None.
Return Value:
S_OK Anything returned by CWsbCollection::FinalRelease().
--*/ { HRESULT hr = S_OK; HSM_SYSTEM_STATE SysState;
WsbTraceIn(OLESTR("CHsmTskMgr::FinalRelease"),OLESTR(""));
SysState.State = HSM_STATE_SHUTDOWN; ChangeSysState(&SysState);
CComObjectRoot::FinalRelease();
// Free member resources
if (0 != m_pWorkQueues) { WsbFree(m_pWorkQueues); m_pWorkQueues = NULL; } if (m_pWorkQueueTypeInfo) { WsbFree(m_pWorkQueueTypeInfo); m_pWorkQueueTypeInfo = NULL; } m_nWorkQueueTypes = 0;
if (m_bCritSecCreated) { DeleteCriticalSection(&m_WorkQueueLock); DeleteCriticalSection(&m_CurrentRunningLock); DeleteCriticalSection(&m_CreateWorkQueueLock); }
WsbTraceOut(OLESTR("CHsmTskMgr::FinalRelease"),OLESTR("hr = <%ls>"),WsbHrAsString(hr)); return(hr); }
HRESULT CHsmTskMgr::Init( IUnknown *pServer ) /*++
Routine Description:
This method does some initialization of the object that is necessary after construction.
Arguments:
None.
Return Value:
S_OK --*/ { HRESULT hr = S_OK;
WsbTraceIn(OLESTR("CHsmTskMgr::Init"),OLESTR("")); try { // Initialize critical sections
WsbAffirmStatus(InitializeCriticalSectionAndSpinCount (&m_WorkQueueLock, 1000)); if (! InitializeCriticalSectionAndSpinCount (&m_CurrentRunningLock, 1000)) { DWORD dwErr = GetLastError(); hr = HRESULT_FROM_WIN32(dwErr); DeleteCriticalSection(&m_WorkQueueLock); WsbAffirmHr(hr); } if (! InitializeCriticalSectionAndSpinCount (&m_CreateWorkQueueLock, 1000)) { DWORD dwErr = GetLastError(); hr = HRESULT_FROM_WIN32(dwErr); DeleteCriticalSection(&m_WorkQueueLock); DeleteCriticalSection(&m_CurrentRunningLock); WsbAffirmHr(hr); } m_bCritSecCreated = TRUE;
//
// Get the server interface
//
WsbAffirmHr(pServer->QueryInterface(IID_IHsmServer, (void **)&m_pServer)); //We want a weak link to the server so decrement the reference count
m_pServer->Release(); WsbAffirmHr(m_pServer->QueryInterface(IID_IWsbCreateLocalObject, (void **)&m_pHsmServerCreate)); // We want a weak link to the server so decrement the reference count
m_pHsmServerCreate->Release();
// Go ahead and preallocate some space for the work queues
WsbAffirmHr(IncreaseWorkQueueArraySize(HsmWorkQueueArrayBumpSize));
}WsbCatch( hr );
WsbTraceOut(OLESTR("CHsmTskMgr::Init"),OLESTR("hr = <%ls>"),WsbHrAsString(hr)); return( hr );
}
HRESULT CHsmTskMgr::ContactOk( void ) /*++
Routine Description:
This allows the caller to see if the RPC connection to the task manager is OK
Arguments:
None.
Return Value:
S_OK --*/ {
return( S_OK );
}
HRESULT CHsmTskMgr::DoFsaWork( IFsaPostIt *pFsaWorkItem ) /*++
Implements:
IHsmFsaTskMgr::DoFsaWork
--*/ { HRESULT hr = S_OK; CComPtr<IHsmSession> pSession; CComPtr<IHsmWorkQueue> pWorkQueue; CComPtr<IHsmRecallQueue> pRecallQueue; FSA_REQUEST_ACTION workAction; GUID mediaId; LONGLONG dataSetStart;
WsbTraceIn(OLESTR("CHsmTskMgr::DoFsaWork"),OLESTR("")); try { CWsbStringPtr path; LONGLONG fileVersionId; FSA_PLACEHOLDER placeholder; GUID hsmId, bagId; BOOL bCreated;
// Get the version Id from the work Item.
WsbAffirmHr(pFsaWorkItem->GetFileVersionId(&fileVersionId));
// Get the placeholder from the work item
WsbAffirmHr(pFsaWorkItem->GetPlaceholder(&placeholder));
// Get the HSM ID from the server
WsbAffirmHr(m_pServer->GetID(&hsmId));
//
// Make sure this instance of the engine managed the file
//
if ((GUID_NULL != placeholder.hsmId) && (hsmId != placeholder.hsmId)) { CWsbStringPtr path;
(void)pFsaWorkItem->GetPath(&path, 0); hr = HSM_E_FILE_MANAGED_BY_DIFFERENT_HSM; WsbLogEvent(HSM_MESSAGE_FILE_MANAGED_BY_DIFFERENT_HSM, 0, NULL, WsbAbbreviatePath(path, 120), WsbHrAsString(hr), NULL); WsbThrow(hr); }
//
// Make sure there is a work allocater for this session
//
WsbAffirmHr(pFsaWorkItem->GetPath(&path, 0)); WsbAffirmHr(pFsaWorkItem->GetSession(&pSession)); WsbAffirmHr(pFsaWorkItem->GetRequestAction(&workAction)); WsbTrace(OLESTR("CHsmTskMgr::DoFsaWork for <%ls> for <%lu>.\n"), (WCHAR *)path, workAction);
if ((workAction == FSA_REQUEST_ACTION_FILTER_RECALL) || (workAction == FSA_REQUEST_ACTION_FILTER_READ)) { WsbAffirmHr(FindRecallMediaToUse(pFsaWorkItem, &mediaId, &bagId, &dataSetStart)); WsbAffirmHr(AddToRecallQueueForFsaSession(pSession,&pRecallQueue, &bCreated, &mediaId, &bagId, dataSetStart, pFsaWorkItem));
} else { WsbAffirmHr(EnsureQueueForFsaSession(pSession, workAction, &pWorkQueue, &bCreated)); //
// Give the work to a queue
//
WsbAffirmHr(pWorkQueue->Add(pFsaWorkItem)); } //
// Start any queues that qualify (performance: only when a new queue is created)
//
if (bCreated) { WsbAffirmHr(StartQueues()); }
}WsbCatch (hr);
WsbTraceOut(OLESTR("CHsmTskMgr::DoFsaWork"),OLESTR("hr = <%ls>"),WsbHrAsString(hr)); return(hr); }
HRESULT CHsmTskMgr::EnsureQueueForFsaSession( IN IHsmSession *pSession, IN FSA_REQUEST_ACTION fsaAction, OUT IHsmWorkQueue **ppWorkQueue, OUT BOOL *bCreated )
/*++
--*/ { HRESULT hr = S_OK; HSM_WORK_QUEUE_STATE state; ULONG index; CComPtr<IHsmSession> l_pSession; HSM_WORK_QUEUE_TYPE type1=HSM_WORK_TYPE_NONE; HSM_WORK_QUEUE_TYPE type2; FILETIME birthDate; SYSTEMTIME systemTime; GUID sessionGuid;
WsbTraceIn(OLESTR("CHsmTskMgr::EnsureQueueForFsaSession"),OLESTR("FsaRequestAction = <%lu>, Waiting on CreateWorkQueueLock"), fsaAction); EnterCriticalSection(&m_CreateWorkQueueLock); try { WsbAffirm(0 != ppWorkQueue, E_POINTER); // Convert FSA action to work queue type
switch (fsaAction) { case FSA_REQUEST_ACTION_FILTER_READ: case FSA_REQUEST_ACTION_FILTER_RECALL: //
// Should not happen!! AddToRecallQueueForFsaSession is the
// right interface for recall items
//
WsbThrow(E_INVALIDARG); break; case FSA_REQUEST_ACTION_RECALL: type1 = HSM_WORK_TYPE_FSA_RECALL; break; case FSA_REQUEST_ACTION_PREMIGRATE: type1 = HSM_WORK_TYPE_FSA_MIGRATE; break; case FSA_REQUEST_ACTION_VALIDATE: type1 = HSM_WORK_TYPE_FSA_VALIDATE; break; case FSA_REQUEST_ACTION_VALIDATE_FOR_TRUNCATE: type1 = HSM_WORK_TYPE_FSA_VALIDATE_FOR_TRUNCATE; break; default: hr = E_NOTIMPL; type1 = HSM_WORK_TYPE_NONE; break; } WsbTrace(OLESTR("CHsmTskMgr::EnsureQueueForFsaSession: type1 = %d\n"), static_cast<int>(type1));
// Check the array of work queues and see if there is one for
// this session.
*bCreated = FALSE; hr = FindWorkQueueElement(pSession, type1, &index, NULL); if (hr == S_OK) { WsbAffirmHr(GetWorkQueueElement(index, &l_pSession, ppWorkQueue, &type2, &state, &birthDate)); if ((l_pSession != pSession) || (type1 != type2)) { *ppWorkQueue = 0; WsbAssertHr(E_UNEXPECTED); } if (HSM_WORK_QUEUE_NONE == state) { WsbTrace(OLESTR("CHsmTskMgr::EnsureQueueForFsaSession: Creating new queue (state is NONE)\n")); WsbAffirmHr(m_pHsmServerCreate->CreateInstance(CLSID_CHsmWorkQueue, IID_IHsmWorkQueue, (void **)ppWorkQueue)); WsbAffirmHr((*ppWorkQueue)->Init(m_pServer, pSession, (IHsmFsaTskMgr *)this, type1)); GetSystemTime(&systemTime); WsbAffirmStatus(SystemTimeToFileTime(&systemTime, &birthDate)); WsbAffirmHr(pSession->GetIdentifier(&sessionGuid)); m_pWorkQueues[index].sessionId = sessionGuid; WsbAffirmHr(SetWorkQueueElement(index, pSession, *ppWorkQueue, type1, HSM_WORK_QUEUE_IDLE, birthDate)); *bCreated = TRUE; } } else { if (hr == WSB_E_NOTFOUND) { hr = S_OK; WsbTrace(OLESTR("CHsmTskMgr::EnsureQueueForFsaSession: Creating new queue (queue not found)\n")); WsbAffirmHr(AddWorkQueueElement(pSession, type1, &index)); // The work queue has not been created so create it
WsbAffirmHr(m_pHsmServerCreate->CreateInstance(CLSID_CHsmWorkQueue, IID_IHsmWorkQueue, (void **)ppWorkQueue)); WsbAffirmHr((*ppWorkQueue)->Init(m_pServer, pSession, (IHsmFsaTskMgr *)this, type1)); GetSystemTime(&systemTime); WsbAffirmStatus(SystemTimeToFileTime(&systemTime, &birthDate)); WsbAffirmHr(pSession->GetIdentifier(&sessionGuid)); m_pWorkQueues[index].sessionId = sessionGuid; WsbAffirmHr(SetWorkQueueElement(index, pSession, *ppWorkQueue, type1, HSM_WORK_QUEUE_IDLE, birthDate)); *bCreated = TRUE; } }
}WsbCatch( hr );
LeaveCriticalSection(&m_CreateWorkQueueLock); WsbTraceOut(OLESTR("CHsmTskMgr::EnsureQueueForFsaSession"),OLESTR("hr = <%ls>"),WsbHrAsString(hr)); return(hr); }
HRESULT CHsmTskMgr::AddToRecallQueueForFsaSession( IN IHsmSession *pSession, OUT IHsmRecallQueue **ppWorkQueue, OUT BOOL *bCreated, IN GUID *pMediaId, IN GUID *pBagId, IN LONGLONG dataSetStart, IN IFsaPostIt *pFsaWorkItem )
/*++
--*/ { HRESULT hr = S_OK;
WsbTraceIn(OLESTR("CHsmTskMgr::AddToRecallQueueForFsaSession"),OLESTR("Waiting on CreateWorkQueueLock"));
EnterCriticalSection(&m_WorkQueueLock); try { WsbAffirm(0 != ppWorkQueue, E_POINTER); //
// This call will find the queue if it's already present -
// and if not it will create a new queue and set it to the required media id
//
WsbAffirmHr(FindRecallQueueElement(pSession, pMediaId, ppWorkQueue, bCreated)); hr = (*ppWorkQueue)->Add(pFsaWorkItem, pBagId, dataSetStart);
}WsbCatch( hr );
LeaveCriticalSection(&m_WorkQueueLock); WsbTraceOut(OLESTR("CHsmTskMgr::AddToRecallQueueForFsaSession"),OLESTR("hr = <%ls>"),WsbHrAsString(hr)); return(hr); }
HRESULT CHsmTskMgr::IncreaseWorkQueueArraySize( ULONG numToAdd ) { HRESULT hr = S_OK; ULONG memSize; LPVOID pTemp;
//Begin Critical Section
WsbTraceIn(OLESTR("CHsmTskMgr::IncreaseWorkQueueArraySize"),OLESTR("NumToAdd = %lu - Waiting for WorkQueueLock"), numToAdd); EnterCriticalSection(&m_WorkQueueLock); try { memSize = (m_NumWorkQueues + numToAdd) * sizeof(HSM_WORK_QUEUES); pTemp = WsbRealloc(m_pWorkQueues, memSize); WsbAffirm(0 != pTemp, E_FAIL); m_pWorkQueues = (HSM_WORK_QUEUES *) pTemp; ZeroMemory( (m_pWorkQueues + m_NumWorkQueues), (numToAdd * sizeof(HSM_WORK_QUEUES)) ); m_NumWorkQueues += numToAdd; }WsbCatch (hr);
//End Critical Section
LeaveCriticalSection(&m_WorkQueueLock); WsbTraceOut(OLESTR("CHsmTskMgr::IncreaseWorkQueueArraySize"),OLESTR("hr = <%ls>, QueuesInArray = <%lu>"), WsbHrAsString(hr), m_NumWorkQueues); return(hr); }
HRESULT CHsmTskMgr::WorkQueueDone( IHsmSession *pSession, HSM_WORK_QUEUE_TYPE type, GUID *pMediaId ) { HRESULT hr = S_OK; ULONG index; FILETIME dummyTime; IHsmRecallQueue *pRecallQueue; BOOL locked = FALSE;
WsbTraceIn(OLESTR("CHsmTskMgr::WorkQueueDone"),OLESTR("type = %d"), static_cast<int>(type)); try { EnterCriticalSection(&m_WorkQueueLock); locked = TRUE; //
// Get the work queue index
//
hr = FindWorkQueueElement(pSession, type, &index, pMediaId); if (hr == S_OK) { WsbTrace(OLESTR("CHsmTskMgr::WorkQueueDone - ending queue # %lu\n"), index); ZeroMemory(&dummyTime, sizeof(FILETIME)); if (type == HSM_WORK_TYPE_FSA_DEMAND_RECALL) { //
// It is possible for recall queues that an element was added
// just before we entered the critical section above
//
pRecallQueue = m_pWorkQueues[index].pRecallQueue; if (pRecallQueue->IsEmpty() == S_OK) { //
// Ok to destroy the queue
//
WsbAffirmHr(SetRecallQueueElement(index, 0, HSM_WORK_TYPE_NONE, HSM_WORK_QUEUE_NONE, dummyTime)); } else { //
// We are not going to destroy the queue, since an element seems to have been added
// before we locked the work queues
//
hr = S_FALSE; } } else { WsbAffirmHr(SetWorkQueueElement(index, 0, 0, HSM_WORK_TYPE_NONE, HSM_WORK_QUEUE_NONE, dummyTime)); } LeaveCriticalSection(&m_WorkQueueLock); locked = FALSE;
if (hr == S_OK) { // Reduce active count for this work queue type
// It must protected from starting (activating) queues
EnterCriticalSection(&m_CurrentRunningLock); for (ULONG i = 0; i < m_nWorkQueueTypes; i++) { if (type == m_pWorkQueueTypeInfo[i].Type) { if (m_pWorkQueueTypeInfo[i].NumActive > 0) { m_pWorkQueueTypeInfo[i].NumActive--; } break; } } LeaveCriticalSection(&m_CurrentRunningLock); } } else { LeaveCriticalSection(&m_WorkQueueLock); locked = FALSE; WsbAffirmHr(hr); }
if (hr == S_OK) { //
// If there are any queues waiting to start, start them
//
WsbAffirmHr(StartQueues()); } }WsbCatchAndDo (hr, if (locked) { LeaveCriticalSection(&m_WorkQueueLock); locked = FALSE; } );
WsbTraceOut(OLESTR("CHsmTskMgr::WorkQueueDone"),OLESTR("hr = <%ls>"),WsbHrAsString(hr)); return(hr); }
HRESULT CHsmTskMgr::AddWorkQueueElement( IHsmSession *pSession, HSM_WORK_QUEUE_TYPE type, ULONG *pIndex ) { HRESULT hr = S_OK; BOOLEAN foundOne = FALSE;
WsbTraceIn(OLESTR("CHsmTskMgr::AddWorkQueueElement"), OLESTR("type = %d, Waiting on WorkQueueLock"), static_cast<int>(type));
//Begin Critical Section
EnterCriticalSection(&m_WorkQueueLock);
try { WsbAssert(0 != pIndex, E_POINTER); // Scan the array looking for an empty element
for (ULONG i = 0; ((i < m_NumWorkQueues) && (foundOne == FALSE)); i++) { if (m_pWorkQueues[i].queueType == HSM_WORK_TYPE_NONE) { foundOne = TRUE; *pIndex = i; if (type != HSM_WORK_TYPE_FSA_DEMAND_RECALL) { //
// Stow away the session. For recall queues, the session
// is stored in the work item
//
m_pWorkQueues[i].pSession = pSession; } m_pWorkQueues[i].queueType = type; } }
if (foundOne == FALSE) { // There are no empty elements so we need to add more
*pIndex = m_NumWorkQueues; WsbAffirmHr(IncreaseWorkQueueArraySize(HsmWorkQueueArrayBumpSize)); if (type != HSM_WORK_TYPE_FSA_DEMAND_RECALL) { //
// We store the session in the work-queue element itself..
// Just indicate this slot is taken..
//
m_pWorkQueues[*pIndex].pSession = pSession; } m_pWorkQueues[*pIndex].queueType = type; }
}WsbCatch (hr);
//End Critical Section
LeaveCriticalSection(&m_WorkQueueLock);
WsbTraceOut(OLESTR("CHsmTskMgr::AddWorkQueueElement"), OLESTR("hr = <%ls>, index = %lu"),WsbHrAsString(hr), *pIndex); return(hr); }
HRESULT CHsmTskMgr::FindWorkQueueElement( IHsmSession *pSession, HSM_WORK_QUEUE_TYPE type, ULONG *pIndex, GUID *pMediaId ) { HRESULT hr = S_OK; BOOLEAN foundOne = FALSE; GUID id;
WsbTraceIn(OLESTR("CHsmTskMgr::FindWorkQueueElement"), OLESTR("type = %d, Waiting on WorkQueueLock"), static_cast<int>(type));
//Begin Critical Section
EnterCriticalSection(&m_WorkQueueLock);
try {
WsbAssert(0 != pIndex, E_POINTER);
// Scan the array looking for an empty element
for (ULONG i = 0; ((i < m_NumWorkQueues) && (foundOne == FALSE)); i++) { if (m_pWorkQueues[i].queueType == type) { if (type == HSM_WORK_TYPE_FSA_DEMAND_RECALL) { m_pWorkQueues[i].pRecallQueue->GetMediaId(&id); if (WsbCompareGuid(id, *pMediaId) != 0) { continue; } } else if (pSession != m_pWorkQueues[i].pSession) { continue; } foundOne = TRUE; *pIndex = i; } }
if (FALSE == foundOne) { hr = WSB_E_NOTFOUND; } }WsbCatch (hr); //End Critical Section
LeaveCriticalSection(&m_WorkQueueLock); WsbTraceOut(OLESTR("CHsmTskMgr::FindWorkQueueElement"),OLESTR("hr = <%ls>, index = <%ls>"), WsbHrAsString(hr), WsbPtrToUlongAsString(pIndex)); return(hr); }
HRESULT CHsmTskMgr::FindRecallQueueElement( IN IHsmSession *pSession, IN GUID *pMediaId, OUT IHsmRecallQueue **ppWorkQueue, OUT BOOL *bCreated ) { HRESULT hr = S_OK; BOOLEAN foundOne = FALSE; GUID id; FILETIME birthDate; SYSTEMTIME systemTime; ULONG index=0;
UNREFERENCED_PARAMETER(pSession);
//
// Important assumption: m_WorkQueueLock is held before calling this function
//
WsbTraceIn(OLESTR("CHsmTskMgr::FindRecallQueueElement"), OLESTR("Waiting on WorkQueueLock"));
*bCreated = FALSE;
try { for (ULONG i=0; (i < m_NumWorkQueues) && (foundOne == FALSE); i++) { //
// Get the media id for the work queue
//
if (m_pWorkQueues[i].queueType == HSM_WORK_TYPE_FSA_DEMAND_RECALL) { if (m_pWorkQueues[i].pRecallQueue != NULL) { WsbAffirmHr(m_pWorkQueues[i].pRecallQueue->GetMediaId(&id)); if ((WsbCompareGuid(id, *pMediaId) == 0)) { foundOne = TRUE; index = i; } } } }
if (FALSE == foundOne) { //
// No exisiting media queue was found. Make a new one
//
for (ULONG i = 0; ((i < m_NumWorkQueues) && (foundOne == FALSE)); i++) { if (m_pWorkQueues[i].queueType == HSM_WORK_TYPE_NONE) { foundOne = TRUE; index = i; } }
if (foundOne == FALSE) { // There are no empty elements so we need to add more
index = m_NumWorkQueues; WsbAffirmHr(IncreaseWorkQueueArraySize(HsmWorkQueueArrayBumpSize)); } //
// At this point we have the free slot index in index
// The work queue has not been created so create it
//
WsbAffirmHr(m_pHsmServerCreate->CreateInstance(CLSID_CHsmRecallQueue, IID_IHsmRecallQueue, (void **)ppWorkQueue)); WsbAffirmHr((*ppWorkQueue)->SetMediaId(pMediaId)); WsbAffirmHr((*ppWorkQueue)->Init(m_pServer, (IHsmFsaTskMgr *)this)); GetSystemTime(&systemTime); WsbAffirmStatus(SystemTimeToFileTime(&systemTime, &birthDate)); m_pWorkQueues[index].queueType = HSM_WORK_TYPE_FSA_DEMAND_RECALL; m_pWorkQueues[index].pSession = NULL; m_pWorkQueues[index].pRecallQueue = *ppWorkQueue; m_pWorkQueues[index].queueState = HSM_WORK_QUEUE_IDLE; m_pWorkQueues[index].birthDate = birthDate; //
// Indicate a new queue was created
//
*bCreated = TRUE; } else { //
// Queue is already present, index points to it
//
*ppWorkQueue = m_pWorkQueues[index].pRecallQueue; if (0 != *ppWorkQueue) { //
// We need to AddRef it..
//
(*ppWorkQueue)->AddRef(); } } }WsbCatch (hr);
WsbTraceOut(OLESTR("CHsmTskMgr::FindRecallQueueElement"),OLESTR("hr = <%ls>, index = <%ls>"), WsbHrAsString(hr), WsbLongAsString((LONG)index)); return(hr); }
HRESULT CHsmTskMgr::GetWorkQueueElement( ULONG index, IHsmSession **ppSession, IHsmWorkQueue **ppWorkQueue, HSM_WORK_QUEUE_TYPE *pType, HSM_WORK_QUEUE_STATE *pState, FILETIME *pBirthDate ) { HRESULT hr = S_OK;
WsbTraceIn(OLESTR("CHsmTskMgr::GetWorkQueueElement"), OLESTR("index = %lu, Waiting on WorkQueueLock"), index); //Begin Critical Section
EnterCriticalSection(&m_WorkQueueLock); try { *pType = m_pWorkQueues[index].queueType;
*ppSession = m_pWorkQueues[index].pSession; if (0 != *ppSession) { (*ppSession)->AddRef(); }
*ppWorkQueue = m_pWorkQueues[index].pWorkQueue; if (0 != *ppWorkQueue) { (*ppWorkQueue)->AddRef(); } *pState = m_pWorkQueues[index].queueState; *pBirthDate = m_pWorkQueues[index].birthDate;
}WsbCatch (hr);
//End Critical Section
LeaveCriticalSection(&m_WorkQueueLock); WsbTraceOut(OLESTR("CHsmTskMgr::GetWorkQueueElement"), OLESTR("hr = <%ls>, type = %d"),WsbHrAsString(hr), static_cast<int>(*pType)); return(hr); }
HRESULT CHsmTskMgr::GetRecallQueueElement( ULONG index, IHsmRecallQueue **ppWorkQueue, HSM_WORK_QUEUE_STATE *pState, FILETIME *pBirthDate ) { HRESULT hr = S_OK;
WsbTraceIn(OLESTR("CHsmTskMgr::GetRecallQueueElement"), OLESTR("index = %lu, Waiting on WorkQueueLock"), index); //Begin Critical Section
EnterCriticalSection(&m_WorkQueueLock); try { WsbAffirm(m_pWorkQueues[index].queueType == HSM_WORK_TYPE_FSA_DEMAND_RECALL, E_INVALIDARG);
*ppWorkQueue = m_pWorkQueues[index].pRecallQueue; if (0 != *ppWorkQueue) { (*ppWorkQueue)->AddRef(); } *pState = m_pWorkQueues[index].queueState; *pBirthDate = m_pWorkQueues[index].birthDate;
}WsbCatch (hr);
//End Critical Section
LeaveCriticalSection(&m_WorkQueueLock); WsbTraceOut(OLESTR("CHsmTskMgr::GetRecallQueueElement"), OLESTR("hr = <%ls>"),WsbHrAsString(hr)); return(hr); }
HRESULT CHsmTskMgr::SetWorkQueueElement( ULONG index, IHsmSession *pSession, IHsmWorkQueue *pWorkQueue, HSM_WORK_QUEUE_TYPE type, HSM_WORK_QUEUE_STATE state, FILETIME birthDate ) { HRESULT hr = S_OK;
WsbTraceIn(OLESTR("CHsmTskMgr::SetWorkQueueElement"),OLESTR("Waiting on WorkQueueLock")); //Begin Critical Section
EnterCriticalSection(&m_WorkQueueLock); try { m_pWorkQueues[index].pSession = pSession; m_pWorkQueues[index].pWorkQueue = pWorkQueue; m_pWorkQueues[index].queueType = type; m_pWorkQueues[index].queueState = state; m_pWorkQueues[index].birthDate = birthDate;
}WsbCatch (hr);
//End Critical Section
LeaveCriticalSection(&m_WorkQueueLock); WsbTraceOut(OLESTR("CHsmTskMgr::SetWorkQueueElement"),OLESTR("hr = <%ls>"),WsbHrAsString(hr)); return(hr); }
HRESULT CHsmTskMgr::SetRecallQueueElement( ULONG index, IHsmRecallQueue *pWorkQueue, HSM_WORK_QUEUE_TYPE queueType, HSM_WORK_QUEUE_STATE state, FILETIME birthDate ) { HRESULT hr = S_OK;
WsbTraceIn(OLESTR("CHsmTskMgr::SetWorkQueueElement"),OLESTR("Waiting on WorkQueueLock")); //Begin Critical Section
EnterCriticalSection(&m_WorkQueueLock); try { WsbAffirm(m_pWorkQueues[index].queueType == HSM_WORK_TYPE_FSA_DEMAND_RECALL, E_INVALIDARG); //
// Ensure the session pointer is empty, this is unused for recall queues
//
m_pWorkQueues[index].pSession = NULL; m_pWorkQueues[index].queueType = queueType; m_pWorkQueues[index].pRecallQueue = pWorkQueue; m_pWorkQueues[index].queueState = state; m_pWorkQueues[index].birthDate = birthDate; }WsbCatch (hr);
//End Critical Section
LeaveCriticalSection(&m_WorkQueueLock); WsbTraceOut(OLESTR("CHsmTskMgr::SetWorkQueueElement"),OLESTR("hr = <%ls>"),WsbHrAsString(hr)); return(hr); }
HRESULT CHsmTskMgr::RemoveWorkQueueElement( ULONG index ) { HRESULT hr = S_OK;
WsbTraceIn(OLESTR("CHsmTskMgr::RemoveWorkQueueElement"),OLESTR("Waiting on WorkQueueLock")); //Begin Critical Section
EnterCriticalSection(&m_WorkQueueLock); try { m_pWorkQueues[index].pSession = 0; m_pWorkQueues[index].pWorkQueue = 0; m_pWorkQueues[index].queueType = HSM_WORK_TYPE_NONE; m_pWorkQueues[index].queueState = HSM_WORK_QUEUE_NONE; ZeroMemory(&(m_pWorkQueues[index].birthDate), sizeof(FILETIME));
}WsbCatch (hr);
//End Critical Section
LeaveCriticalSection(&m_WorkQueueLock); WsbTraceOut(OLESTR("CHsmTskMgr::RemoveWorkQueueElement"),OLESTR("hr = <%ls>"),WsbHrAsString(hr)); return(hr); }
HRESULT CHsmTskMgr::StartQueues( void ) { HRESULT hr = S_OK; ULONG uActive;
WsbTraceIn(OLESTR("CHsmTskMgr::StartQueues"),OLESTR("Waiting on CurrentRunningLock")); //Begin Critical Section
EnterCriticalSection(&m_CurrentRunningLock); try { // Go over work types, and start (activate) queues until the threshold
// for the work type is reached
for (ULONG i = 0; i < m_nWorkQueueTypes; i++) { // For Migrate queues, get the (dynamically set) Allowed limit
if ((HSM_WORK_TYPE_FSA_MIGRATE == m_pWorkQueueTypeInfo[i].Type) || (HSM_WORK_TYPE_FSA_DEMAND_RECALL == m_pWorkQueueTypeInfo[i].Type)) { WsbAffirmHr(m_pServer->GetCopyFilesLimit( &(m_pWorkQueueTypeInfo[i].MaxActiveAllowed) )); }
WsbTrace(OLESTR("CHsmTskMgr::StartQueues: QueueType[%lu].NumActive = %lu, Allowed = %lu\n"), i, m_pWorkQueueTypeInfo[i].NumActive, m_pWorkQueueTypeInfo[i].MaxActiveAllowed); while ((uActive = m_pWorkQueueTypeInfo[i].NumActive) < m_pWorkQueueTypeInfo[i].MaxActiveAllowed) { WsbAffirmHr(StartFsaQueueType(m_pWorkQueueTypeInfo[i].Type)); if (uActive == m_pWorkQueueTypeInfo[i].NumActive) { // no more work queues to activate - get out...
break; } } } }WsbCatch (hr);
//End Critical Section
LeaveCriticalSection(&m_CurrentRunningLock); WsbTraceOut(OLESTR("CHsmTskMgr::StartQueues"),OLESTR("hr = <%ls>"),WsbHrAsString(hr)); return(hr); }
HRESULT CHsmTskMgr::StartFsaQueueType(HSM_WORK_QUEUE_TYPE type) { HRESULT hr = S_OK; CComPtr<IHsmWorkQueue> pWorkQueue; CComPtr<IHsmRecallQueue> pRecallQueue; ULONG index;
WsbTraceIn(OLESTR("CHsmTskMgr::StartFsaQueueType"),OLESTR("type = %d"), static_cast<int>(type)); try { // Find the oldest queue of this type
hr = FindOldestQueue(type, &index); if (S_OK == hr) { HSM_WORK_QUEUE_STATE state; CComPtr<IHsmSession> l_pSession; HSM_WORK_QUEUE_TYPE l_type; FILETIME birthDate;
// Make sure that the queue is idle
if (type == HSM_WORK_TYPE_FSA_DEMAND_RECALL) { WsbAffirmHr(GetRecallQueueElement(index, &pRecallQueue, &state, &birthDate)); } else { WsbAffirmHr(GetWorkQueueElement(index, &l_pSession, &pWorkQueue, &l_type, &state, &birthDate)); } if (HSM_WORK_QUEUE_IDLE == state) { if (type == HSM_WORK_TYPE_FSA_DEMAND_RECALL) { WsbAffirmHr(SetRecallQueueElement(index, pRecallQueue, HSM_WORK_TYPE_FSA_DEMAND_RECALL, HSM_WORK_QUEUE_STARTING, birthDate)); WsbAffirmHr(pRecallQueue->Start()); WsbAffirmHr(SetRecallQueueElement(index, pRecallQueue, HSM_WORK_TYPE_FSA_DEMAND_RECALL, HSM_WORK_QUEUE_STARTED, birthDate)); } else { WsbAffirmHr(SetWorkQueueElement(index, l_pSession, pWorkQueue, type, HSM_WORK_QUEUE_STARTING, birthDate)); WsbAffirmHr(pWorkQueue->Start()); WsbAffirmHr(SetWorkQueueElement(index, l_pSession, pWorkQueue, type, HSM_WORK_QUEUE_STARTED, birthDate)); } WsbTrace(OLESTR("CHsmTskMgr::StartFsaQueueType - started work queue %lu\n"), index);
// Increment active count for this work queue type
for (ULONG i = 0; i < m_nWorkQueueTypes; i++) { if (type == m_pWorkQueueTypeInfo[i].Type) { m_pWorkQueueTypeInfo[i].NumActive++; break; } } } } else { if (WSB_E_NOTFOUND == hr) { hr = S_OK; } } WsbAffirmHr( hr );
}WsbCatch (hr);
WsbTraceOut(OLESTR("CHsmTskMgr::StartFsaQueueType"),OLESTR("hr = <%ls>"),WsbHrAsString(hr)); return(hr); }
HRESULT CHsmTskMgr::FindOldestQueue( HSM_WORK_QUEUE_TYPE type, ULONG *pIndex ) { HRESULT hr = S_OK; FILETIME oldestOne; LONG compare; ULONG oldestIndex = 0xFFFFFFFF; BOOLEAN firstOne;
WsbTraceIn(OLESTR("CHsmTskMgr::FindOldestQueue"),OLESTR("type = %d"), static_cast<int>(type)); try { WsbAffirmPointer(pIndex);
// Start out with the first time flag equal to TRUE so we select the first one with the right state and type
firstOne = TRUE;
for (ULONG i = 0; (i < m_NumWorkQueues); i++) { if ((type == m_pWorkQueues[i].queueType) && (HSM_WORK_QUEUE_IDLE == m_pWorkQueues[i].queueState)) { if (!firstOne) compare = CompareFileTime(&(m_pWorkQueues[i].birthDate), &(oldestOne)); else compare = -1; if (compare < 0) { // found an older one
firstOne = FALSE; oldestOne.dwLowDateTime = m_pWorkQueues[i].birthDate.dwLowDateTime; oldestOne.dwHighDateTime = m_pWorkQueues[i].birthDate.dwHighDateTime; oldestIndex = i; } } }
if (0xFFFFFFFF == oldestIndex) { // Didn't find a match
hr = WSB_E_NOTFOUND; } else { HSM_WORK_QUEUE_STATE state; CComPtr<IHsmSession> l_pSession; CComPtr<IHsmWorkQueue> l_pWorkQueue; CComPtr<IHsmRecallQueue> l_pRecallQueue; HSM_WORK_QUEUE_TYPE type2; FILETIME birthDate;
// Make sure that the queue is idle
if (type == HSM_WORK_TYPE_FSA_DEMAND_RECALL) { WsbAffirmHr(GetRecallQueueElement(oldestIndex, &l_pRecallQueue, &state, &birthDate)); } else { WsbAffirmHr(GetWorkQueueElement(oldestIndex, &l_pSession, &l_pWorkQueue, &type2, &state, &birthDate)); } if (HSM_WORK_QUEUE_IDLE == state) { *pIndex = oldestIndex; WsbTrace(OLESTR("CHsmTskMgr::FindOldestQueue: found index = %lu\n"), oldestIndex); } else { WsbTrace(OLESTR("CHsmTskMgr::FindOldestQueue - found NULL queue\n")); hr = WSB_E_NOTFOUND; } }
}WsbCatch (hr);
WsbTraceOut(OLESTR("CHsmTskMgr::FindOldestQueue"),OLESTR("hr = <%ls>"),WsbHrAsString(hr)); return(hr); }
HRESULT CHsmTskMgr::ChangeSysState( IN OUT HSM_SYSTEM_STATE* pSysState )
/*++
Implements:
IHsmSystemState::ChangeSysState().
--*/ { HRESULT hr = S_OK;
WsbTraceIn(OLESTR("CHsmTskMgr::ChangeSysState"), OLESTR(""));
try {
// Loop over work queues
if (0 != m_pWorkQueues) { FILETIME dummyTime; ZeroMemory(&dummyTime, sizeof(FILETIME)); for (ULONG i = 0; i < m_NumWorkQueues; i++) { if (m_pWorkQueues[i].pWorkQueue) {
if (m_pWorkQueues[i].queueType == HSM_WORK_TYPE_FSA_DEMAND_RECALL) { if (pSysState->State & HSM_STATE_SHUTDOWN) { m_pWorkQueues[i].pRecallQueue->Stop(); } m_pWorkQueues[i].pRecallQueue->ChangeSysState(pSysState); } else { if (pSysState->State & HSM_STATE_SHUTDOWN) { m_pWorkQueues[i].pWorkQueue->Stop(); } m_pWorkQueues[i].pWorkQueue->ChangeSysState(pSysState); } }
if (pSysState->State & HSM_STATE_SHUTDOWN) { hr = SetWorkQueueElement(i, 0, 0, HSM_WORK_TYPE_NONE, HSM_WORK_QUEUE_NONE, dummyTime); } } }
}WsbCatch(hr);
WsbTraceOut(OLESTR("CHsmTskMgr::ChangeSysState"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
return(hr); }
HRESULT CHsmTskMgr::FindRecallMediaToUse( IN IFsaPostIt *pFsaWorkItem, OUT GUID *pMediaToUse, OUT GUID *pBagId, OUT LONGLONG *pDataSetStart ) /*++
--*/ { HRESULT hr = S_OK; CComQIPtr<ISegDb, &IID_ISegDb> pSegDb; CComPtr<IWsbDb> pWsbDb; CComPtr<IWsbDbSession> pDbWorkSession; BOOL openedDb = FALSE;
WsbTraceIn(OLESTR("CHsmTskMgr::FindRecallMediaToUse"),OLESTR("")); try { WsbAssert(pMediaToUse != 0, E_POINTER); *pMediaToUse = GUID_NULL;
CComPtr<ISegRec> pSegRec; GUID l_BagId; LONGLONG l_FileStart; LONGLONG l_FileSize; USHORT l_SegFlags; GUID l_PrimPos; LONGLONG l_SecPos; GUID storagePoolId; FSA_PLACEHOLDER placeholder;
//
// Get the segment database
//
WsbAffirmHr(m_pServer->GetSegmentDb(&pWsbDb)); pSegDb = pWsbDb; //
// Go to the segment database to find out where the data
// is located.
//
WsbAffirmHr(pFsaWorkItem->GetPlaceholder(&placeholder)); WsbAffirmHr(pFsaWorkItem->GetStoragePoolId(&storagePoolId));
WsbTrace(OLESTR("Finding SegmentRecord: <%ls>, <%ls>, <%ls>\n"), WsbGuidAsString(placeholder.bagId), WsbStringCopy(WsbLonglongAsString(placeholder.fileStart)), WsbStringCopy(WsbLonglongAsString(placeholder.fileSize)));
WsbAffirmHr(pSegDb->Open(&pDbWorkSession)); openedDb = TRUE; hr = pSegDb->SegFind(pDbWorkSession, placeholder.bagId, placeholder.fileStart, placeholder.fileSize, &pSegRec); if (S_OK != hr) { //
// We couldn't find the segment record for this information!
//
hr = HSM_E_SEGMENT_INFO_NOT_FOUND; WsbAffirmHr(hr); } WsbAffirmHr(pSegRec->GetSegmentRecord(&l_BagId, &l_FileStart, &l_FileSize, &l_SegFlags, &l_PrimPos, &l_SecPos)); WsbAssert(0 != l_SecPos, HSM_E_BAD_SEGMENT_INFORMATION);
//
// In case of an indirect record, go to the dirtect record to get real location info
//
if (l_SegFlags & SEG_REC_INDIRECT_RECORD) { pSegRec = 0;
WsbTrace(OLESTR("Finding indirect SegmentRecord: <%ls>, <%ls>, <%ls>\n"), WsbGuidAsString(l_PrimPos), WsbStringCopy(WsbLonglongAsString(l_SecPos)), WsbStringCopy(WsbLonglongAsString(placeholder.fileSize)));
hr = pSegDb->SegFind(pDbWorkSession, l_PrimPos, l_SecPos, placeholder.fileSize, &pSegRec); if (S_OK != hr) { //
// We couldn't find the direct segment record for this segment!
//
hr = HSM_E_SEGMENT_INFO_NOT_FOUND; WsbAffirmHr(hr); }
WsbAffirmHr(pSegRec->GetSegmentRecord(&l_BagId, &l_FileStart, &l_FileSize, &l_SegFlags, &l_PrimPos, &l_SecPos)); WsbAssert(0 != l_SecPos, HSM_E_BAD_SEGMENT_INFORMATION);
// Don't support a second indirection for now !!
WsbAssert(0 == (l_SegFlags & SEG_REC_INDIRECT_RECORD), HSM_E_BAD_SEGMENT_INFORMATION); }
//
// Go to the media database to get the media ID
//
CComPtr<IMediaInfo> pMediaInfo; GUID l_RmsMediaId;
WsbAffirmHr(pSegDb->GetEntity(pDbWorkSession, HSM_MEDIA_INFO_REC_TYPE, IID_IMediaInfo, (void**)&pMediaInfo)); WsbAffirmHr(pMediaInfo->SetId(l_PrimPos)); hr = pMediaInfo->FindEQ(); if (S_OK != hr) { hr = HSM_E_MEDIA_INFO_NOT_FOUND; WsbAffirmHr(hr); } WsbAffirmHr(pMediaInfo->GetMediaSubsystemId(&l_RmsMediaId)); *pMediaToUse = l_RmsMediaId; *pDataSetStart = l_SecPos; *pBagId = l_BagId; if (openedDb) { pSegDb->Close(pDbWorkSession); openedDb = FALSE; }
}WsbCatchAndDo( hr, if (openedDb){ pSegDb->Close(pDbWorkSession);} ) ;
WsbTraceOut(OLESTR("CHsmTskMgr::FindRecallMediaToUse"),OLESTR("hr = <%ls>"),WsbHrAsString(hr)); return(hr); }
|