/*++ © 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 (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 pSession; CComPtr pWorkQueue; CComPtr 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 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(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(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(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(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(*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 pWorkQueue; CComPtr pRecallQueue; ULONG index; WsbTraceIn(OLESTR("CHsmTskMgr::StartFsaQueueType"),OLESTR("type = %d"), static_cast(type)); try { // Find the oldest queue of this type hr = FindOldestQueue(type, &index); if (S_OK == hr) { HSM_WORK_QUEUE_STATE state; CComPtr 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(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 l_pSession; CComPtr l_pWorkQueue; CComPtr 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 pSegDb; CComPtr pWsbDb; CComPtr pDbWorkSession; BOOL openedDb = FALSE; WsbTraceIn(OLESTR("CHsmTskMgr::FindRecallMediaToUse"),OLESTR("")); try { WsbAssert(pMediaToUse != 0, E_POINTER); *pMediaToUse = GUID_NULL; CComPtr 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 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); }