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.
5807 lines
208 KiB
5807 lines
208 KiB
|
|
/*++
|
|
|
|
Copyright (c) 1998 Seagate Software, Inc. All rights reserved.
|
|
|
|
Module Name:
|
|
|
|
hsmWorkQ.cpp
|
|
|
|
Abstract:
|
|
|
|
This class represents the HSM task manager
|
|
|
|
Author:
|
|
|
|
Cat Brant [cbrant] 6-Dec-1996
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "stdafx.h"
|
|
|
|
#define WSB_TRACE_IS WSB_TRACE_BIT_HSMTSKMGR
|
|
static USHORT icountWorkq = 0;
|
|
|
|
#include "fsa.h"
|
|
#include "rms.h"
|
|
#include "metadef.h"
|
|
#include "jobint.h"
|
|
#include "hsmconn.h"
|
|
#include "wsb.h"
|
|
#include "hsmeng.h"
|
|
#include "mover.h"
|
|
#include "hsmWorkQ.h"
|
|
|
|
#include "engine.h"
|
|
#include "task.h"
|
|
#include "tskmgr.h"
|
|
#include "segdb.h"
|
|
|
|
#define HSM_STORAGE_OVERHEAD 5000
|
|
|
|
#define MIN_FREE_SPACE_IN_FULL_MEDIA_DEFAULT 4
|
|
#define MAX_FREE_SPACE_IN_FULL_MEDIA_DEFAULT 5
|
|
|
|
#define STRINGIZE(_str) (OLESTR( #_str ))
|
|
#define RETURN_STRINGIZED_CASE(_case) \
|
|
case _case: \
|
|
return ( STRINGIZE( _case ) );
|
|
|
|
// Local prototypes
|
|
DWORD HsmWorkQueueThread(void *pVoid);
|
|
static const OLECHAR * JobStateAsString (HSM_JOB_STATE state);
|
|
|
|
|
|
|
|
|
|
static const OLECHAR *
|
|
JobStateAsString (
|
|
IN HSM_JOB_STATE state
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Gives back a static string representing the connection state.
|
|
|
|
Arguments:
|
|
|
|
state - the state to return a string for.
|
|
|
|
Return Value:
|
|
|
|
NULL - invalid state passed in.
|
|
|
|
Otherwise, a valid char *.
|
|
|
|
--*/
|
|
|
|
{
|
|
//
|
|
// Do the Switch
|
|
//
|
|
|
|
switch ( state ) {
|
|
|
|
RETURN_STRINGIZED_CASE( HSM_JOB_STATE_ACTIVE );
|
|
RETURN_STRINGIZED_CASE( HSM_JOB_STATE_CANCELLED );
|
|
RETURN_STRINGIZED_CASE( HSM_JOB_STATE_CANCELLING );
|
|
RETURN_STRINGIZED_CASE( HSM_JOB_STATE_DONE );
|
|
RETURN_STRINGIZED_CASE( HSM_JOB_STATE_FAILED );
|
|
RETURN_STRINGIZED_CASE( HSM_JOB_STATE_IDLE );
|
|
RETURN_STRINGIZED_CASE( HSM_JOB_STATE_PAUSED );
|
|
RETURN_STRINGIZED_CASE( HSM_JOB_STATE_PAUSING );
|
|
RETURN_STRINGIZED_CASE( HSM_JOB_STATE_RESUMING );
|
|
RETURN_STRINGIZED_CASE( HSM_JOB_STATE_SKIPPED );
|
|
RETURN_STRINGIZED_CASE( HSM_JOB_STATE_STARTING );
|
|
RETURN_STRINGIZED_CASE( HSM_JOB_STATE_SUSPENDED );
|
|
RETURN_STRINGIZED_CASE( HSM_JOB_STATE_SUSPENDING );
|
|
|
|
default:
|
|
|
|
return ( OLESTR("Invalid Value") );
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
CHsmWorkQueue::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("CHsmWorkQueue::FinalConstruct"),OLESTR(""));
|
|
try {
|
|
|
|
WsbAssertHr(CComObjectRoot::FinalConstruct());
|
|
|
|
//
|
|
// Initialize the member data
|
|
//
|
|
m_pServer = 0;
|
|
m_pHsmServerCreate = 0;
|
|
m_pTskMgr;
|
|
|
|
m_pFsaResource = 0;
|
|
m_pSession = 0;
|
|
m_pRmsServer = 0;
|
|
m_pRmsCartridge = 0;
|
|
m_pDataMover = 0;
|
|
|
|
m_pSegmentDb = 0;
|
|
m_pDbWorkSession = 0;
|
|
m_pStoragePools = 0;
|
|
m_pWorkToDo = 0;
|
|
m_pWorkToCommit = 0;
|
|
|
|
UnsetMediaInfo();
|
|
|
|
m_BagId = GUID_NULL;
|
|
m_HsmId = GUID_NULL;
|
|
m_RemoteDataSetStart.QuadPart = 0;
|
|
m_RmsMediaSetId = GUID_NULL;
|
|
m_RmsMediaSetName = OLESTR("");
|
|
m_RequestAction = FSA_REQUEST_ACTION_NONE;
|
|
m_QueueType = HSM_WORK_TYPE_NONE;
|
|
m_BeginSessionHr = S_FALSE;
|
|
|
|
m_StateCookie = 0;
|
|
m_EventCookie = 0;
|
|
|
|
m_JobPriority = HSM_JOB_PRIORITY_NORMAL;
|
|
m_JobAction = HSM_JOB_ACTION_UNKNOWN;
|
|
m_JobState = HSM_JOB_STATE_IDLE;
|
|
m_JobPhase = HSM_JOB_PHASE_MOVE_ACTION;
|
|
|
|
m_WorkerThread = 0;
|
|
|
|
m_TerminateQueue = FALSE;
|
|
m_CurrentPath = OLESTR("");
|
|
|
|
// Set threshold defaults
|
|
m_MinFilesToMigrate = 100;
|
|
m_MinBytesToMigrate = 10000000;
|
|
m_FilesBeforeCommit = 2000;
|
|
m_MaxBytesBeforeCommit = 750000000;
|
|
m_MinBytesBeforeCommit = 10000000;
|
|
m_FreeMediaBytesAtEndOfMedia = 10000000;
|
|
m_MinFreeSpaceInFullMedia = MIN_FREE_SPACE_IN_FULL_MEDIA_DEFAULT;
|
|
m_MaxFreeSpaceInFullMedia = MAX_FREE_SPACE_IN_FULL_MEDIA_DEFAULT;
|
|
|
|
m_DataCountBeforeCommit = 0;
|
|
m_FilesCountBeforeCommit = 0;
|
|
m_StoreDatabasesInBags = TRUE;
|
|
|
|
m_QueueItemsToPause = 500;
|
|
m_QueueItemsToResume = 450;
|
|
m_ScannerPaused = FALSE;
|
|
|
|
// Job abort on errors parameters
|
|
m_JobAbortMaxConsecutiveErrors = 5;
|
|
m_JobAbortMaxTotalErrors = 25;
|
|
m_JobConsecutiveErrors = 0;
|
|
m_JobTotalErrors = 0;
|
|
m_JobAbortSysDiskSpace = 2 * 1024 * 1024;
|
|
|
|
m_mediaCount = 0;
|
|
m_ScratchFailed = FALSE;
|
|
m_uErrorReportFlags = 0;
|
|
WSB_OBJECT_ADD(CLSID_CHsmWorkQueue, this);
|
|
|
|
} WsbCatch(hr);
|
|
|
|
icountWorkq++;
|
|
WsbTraceOut(OLESTR("CHsmWorkQueue::FinalConstruct"),OLESTR("hr = <%ls>, Count is <%d>"),
|
|
WsbHrAsString(hr), icountWorkq);
|
|
return(hr);
|
|
}
|
|
|
|
HRESULT
|
|
CHsmWorkQueue::FinalRelease(
|
|
void
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This method does some initialization of the object that is necessary
|
|
before destruction.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
S_OK
|
|
Anything returned by CWsbCollection::FinalDestruct().
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
HSM_SYSTEM_STATE SysState;
|
|
|
|
WsbTraceIn(OLESTR("CHsmWorkQueue::FinalRelease"),OLESTR(""));
|
|
|
|
SysState.State = HSM_STATE_SHUTDOWN;
|
|
ChangeSysState(&SysState);
|
|
|
|
WSB_OBJECT_SUB(CLSID_CHsmWorkQueue, this);
|
|
CComObjectRoot::FinalRelease();
|
|
|
|
// Free String members
|
|
// Note: Member objects held in smart-pointers are freed when the
|
|
// smart-pointer destructor is being called (as part of this object destruction)
|
|
m_MediaName.Free();
|
|
m_MediaBarCode.Free();
|
|
m_RmsMediaSetName.Free();
|
|
m_CurrentPath.Free();
|
|
|
|
icountWorkq--;
|
|
WsbTraceOut(OLESTR("CHsmWorkQueue::FinalRelease"),OLESTR("hr = <%ls>, Count is <%d>"),
|
|
WsbHrAsString(hr), icountWorkq);
|
|
return(hr);
|
|
}
|
|
|
|
HRESULT
|
|
CHsmWorkQueue::Init(
|
|
IUnknown *pServer,
|
|
IHsmSession *pSession,
|
|
IHsmFsaTskMgr *pTskMgr,
|
|
HSM_WORK_QUEUE_TYPE queueType
|
|
)
|
|
/*++
|
|
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("CHsmWorkQueue::Init"),OLESTR(""));
|
|
try {
|
|
//
|
|
// Establish contact with the server and get the
|
|
// databases
|
|
//
|
|
WsbAffirmHr(pServer->QueryInterface(IID_IHsmServer, (void **)&m_pServer));
|
|
//We want a weak link to the server so decrement the reference count
|
|
m_pServer->Release();
|
|
|
|
m_pTskMgr = pTskMgr;
|
|
m_pTskMgr->AddRef();
|
|
m_QueueType = queueType;
|
|
|
|
WsbAffirmHr(m_pServer->GetSegmentDb(&m_pSegmentDb));
|
|
WsbAffirmHr(m_pServer->GetStoragePools(&m_pStoragePools));
|
|
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();
|
|
WsbAffirmHr(m_pServer->GetID(&m_HsmId));
|
|
|
|
WsbAffirmHr(CheckSession(pSession));
|
|
|
|
//
|
|
// Make a collection for the work items
|
|
//
|
|
WsbAffirmHr(m_pHsmServerCreate->CreateInstance(CLSID_CWsbOrderedCollection,
|
|
IID_IWsbIndexedCollection,
|
|
(void **)&m_pWorkToDo ));
|
|
|
|
WsbAffirmHr(m_pHsmServerCreate->CreateInstance(CLSID_CWsbOrderedCollection,
|
|
IID_IWsbIndexedCollection,
|
|
(void **)&m_pWorkToCommit ));
|
|
|
|
//
|
|
// Make sure our connection to RMS is current
|
|
//
|
|
WsbAffirmHr(CheckRms());
|
|
|
|
// Check the registry to see if there are changes to default settings
|
|
CheckRegistry();
|
|
|
|
} WsbCatch( hr );
|
|
|
|
WsbTraceOut(OLESTR("CHsmWorkQueue::Init"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
|
|
return( hr );
|
|
|
|
}
|
|
|
|
HRESULT
|
|
CHsmWorkQueue::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
|
|
CHsmWorkQueue::ProcessSessionEvent(
|
|
IHsmSession *pSession,
|
|
HSM_JOB_PHASE phase,
|
|
HSM_JOB_EVENT event
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
WsbTraceIn(OLESTR("CHsmWorkQueue::ProcessSessionEvent"),OLESTR(""));
|
|
try {
|
|
|
|
WsbAssert(0 != pSession, E_POINTER);
|
|
|
|
// If the phase applies to us (MOVER or ALL), then do any work required by the
|
|
// event.
|
|
if ((HSM_JOB_PHASE_ALL == phase) || (HSM_JOB_PHASE_MOVE_ACTION == phase)) {
|
|
|
|
switch(event) {
|
|
|
|
case HSM_JOB_EVENT_SUSPEND:
|
|
case HSM_JOB_EVENT_CANCEL:
|
|
case HSM_JOB_EVENT_FAIL:
|
|
WsbAffirmHr(Cancel());
|
|
break;
|
|
|
|
case HSM_JOB_EVENT_PAUSE:
|
|
WsbAffirmHr(Pause());
|
|
break;
|
|
|
|
case HSM_JOB_EVENT_RESUME:
|
|
WsbAffirmHr(Resume());
|
|
break;
|
|
|
|
case HSM_JOB_EVENT_RAISE_PRIORITY:
|
|
WsbAffirmHr(RaisePriority());
|
|
break;
|
|
|
|
case HSM_JOB_EVENT_LOWER_PRIORITY:
|
|
WsbAffirmHr(LowerPriority());
|
|
break;
|
|
|
|
default:
|
|
case HSM_JOB_EVENT_START:
|
|
WsbAssert(FALSE, E_UNEXPECTED);
|
|
break;
|
|
}
|
|
}
|
|
|
|
} WsbCatch(hr);
|
|
|
|
WsbTraceOut(OLESTR("CHsmWorkQueue::ProcessSessionEvent"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
|
|
return( S_OK );
|
|
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CHsmWorkQueue::ProcessSessionState(
|
|
IHsmSession* /*pSession*/,
|
|
IHsmPhase* pPhase,
|
|
OLECHAR* /*currentPath*/
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
HSM_JOB_PHASE phase;
|
|
HSM_JOB_STATE state;
|
|
|
|
WsbTraceIn(OLESTR("CHsmWorkQueue::ProcessSessionState"),OLESTR(""));
|
|
try {
|
|
|
|
WsbAffirmHr(pPhase->GetState(&state));
|
|
WsbAffirmHr(pPhase->GetPhase(&phase));
|
|
WsbTrace( OLESTR("CHsmWorkQueue::ProcessSessionState - State = <%d>, phase = <%d>\n"), state, phase );
|
|
|
|
if ( HSM_JOB_PHASE_SCAN == phase ) {
|
|
|
|
// If the session has finished, then we have some cleanup to do so that it can go
|
|
// away.
|
|
if ((state == HSM_JOB_STATE_DONE) || (state == HSM_JOB_STATE_FAILED) || (state == HSM_JOB_STATE_SUSPENDED) ) {
|
|
WsbTrace( OLESTR("Job is done, failed, or suspended\n") );
|
|
// Create a work item and append it to the work queue to
|
|
// indicate that the job is done
|
|
WsbAffirmHr(MarkQueueAsDone());
|
|
}
|
|
}
|
|
|
|
} WsbCatch( hr );
|
|
|
|
WsbTraceOut(OLESTR("CHsmWorkQueue::ProcessSessionState"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
|
|
return( S_OK );
|
|
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CHsmWorkQueue::Add(
|
|
IFsaPostIt *pFsaWorkItem
|
|
)
|
|
/*++
|
|
|
|
Implements:
|
|
|
|
IHsmFsaTskMgr::Add
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CComPtr<IHsmSession> pSession;
|
|
|
|
WsbTraceIn(OLESTR("CHsmWorkQueue::Add"),OLESTR(""));
|
|
try {
|
|
//
|
|
// Make sure there is a work allocater for this session
|
|
//
|
|
WsbAffirmHr(pFsaWorkItem->GetSession(&pSession));
|
|
WsbAffirmHr(CheckSession(pSession));
|
|
|
|
//
|
|
// Create a work item, load it up and add it to this
|
|
// Queue's collection
|
|
//
|
|
CComPtr<IHsmWorkItem> pWorkItem;
|
|
WsbAffirmHr(m_pHsmServerCreate->CreateInstance(CLSID_CHsmWorkItem, IID_IHsmWorkItem,
|
|
(void **)&pWorkItem));
|
|
WsbAffirmHr(pWorkItem->SetWorkType(HSM_WORK_ITEM_FSA_WORK));
|
|
WsbAffirmHr(pWorkItem->SetFsaPostIt(pFsaWorkItem));
|
|
WsbAffirmHr(m_pWorkToDo->Append(pWorkItem));
|
|
|
|
//
|
|
// If adding this item to the queue meets or exceeds the count for pausing
|
|
// pause the scanner so there is no more work submitted.
|
|
//
|
|
ULONG numItems;
|
|
WsbAffirmHr(m_pWorkToDo->GetEntries(&numItems));
|
|
WsbTrace(OLESTR("CHsmWorkQueue::Add - num items in queue = <%lu>\n"),numItems);
|
|
if (numItems >= m_QueueItemsToPause) {
|
|
WsbAffirmHr(PauseScanner());
|
|
}
|
|
|
|
} WsbCatch (hr);
|
|
|
|
WsbTraceOut(OLESTR("CHsmWorkQueue::Add"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
|
|
return (hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CHsmWorkQueue::Start( void )
|
|
/*++
|
|
|
|
Implements:
|
|
|
|
IHsmWorkQueue::Start
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD tid;
|
|
|
|
WsbTraceIn(OLESTR("CHsmWorkQueue::Start"),OLESTR(""));
|
|
try {
|
|
//
|
|
// If the worker thread is already started, just return
|
|
//
|
|
WsbAffirm(m_WorkerThread == 0, S_OK);
|
|
// Launch a thread to do work that is queued
|
|
WsbAffirm((m_WorkerThread = CreateThread(0, 0, HsmWorkQueueThread, (void*) this, 0, &tid)) != 0, HRESULT_FROM_WIN32(GetLastError()));
|
|
|
|
if (m_WorkerThread == NULL) {
|
|
WsbAssertHr(E_FAIL); // TBD What error to return here??
|
|
}
|
|
|
|
} WsbCatch (hr);
|
|
|
|
WsbTraceOut(OLESTR("CHsmWorkQueue::Start"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
|
|
return (hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CHsmWorkQueue::Stop( void )
|
|
/*++
|
|
|
|
Implements:
|
|
|
|
IHsmWorkQueue::Stop
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
WsbTraceIn(OLESTR("CHsmWorkQueue::Stop"),OLESTR(""));
|
|
|
|
// Stop the thread (signal, wait, terminate if it still running)
|
|
m_TerminateQueue = TRUE;
|
|
|
|
if (m_WorkerThread) {
|
|
switch (WaitForSingleObject(m_WorkerThread, 20000)) {
|
|
case WAIT_FAILED: {
|
|
WsbTrace(OLESTR("CHsmWorkQueue::Stop: WaitForSingleObject returned error %lu\n"), GetLastError());
|
|
}
|
|
// fall through...
|
|
|
|
case WAIT_TIMEOUT: {
|
|
WsbTrace(OLESTR("CHsmWorkQueue::Stop: force terminating of working thread.\n"));
|
|
|
|
DWORD dwExitCode;
|
|
if (GetExitCodeThread( m_WorkerThread, &dwExitCode)) {
|
|
if (dwExitCode == STILL_ACTIVE) { // thread still active
|
|
if (!TerminateThread (m_WorkerThread, 0)) {
|
|
WsbTrace(OLESTR("CHsmWorkQueue::Stop: TerminateThread returned error %lu\n"), GetLastError());
|
|
}
|
|
}
|
|
} else {
|
|
WsbTrace(OLESTR("CHsmWorkQueue::Stop: GetExitCodeThread returned error %lu\n"), GetLastError());
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
// Thread terminated gracefully
|
|
WsbTrace(OLESTR("CHsmWorkQueue::Stop: working thread terminated gracefully\n"));
|
|
break;
|
|
}
|
|
}
|
|
|
|
WsbTraceOut(OLESTR("CHsmWorkQueue::Stop"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
|
|
return (hr);
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
CHsmWorkQueue::PremigrateIt(
|
|
IFsaPostIt *pFsaWorkItem
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
GUID mediaToUse;
|
|
GUID firstSide;
|
|
BOOLEAN done = FALSE;
|
|
FSA_PLACEHOLDER placeholder;
|
|
LONGLONG requestSize;
|
|
LONGLONG requestStart;
|
|
LONGLONG fileVersionId;
|
|
|
|
WsbTraceIn(OLESTR("CHsmWorkQueue::PremigrateIt"),OLESTR(""));
|
|
try {
|
|
//
|
|
// Check to see if anything has changed since the request
|
|
//
|
|
WsbAffirmHr(CheckForChanges(pFsaWorkItem));
|
|
|
|
// Check for sufficient space on system volume
|
|
WsbAffirmHr(CheckForDiskSpace());
|
|
|
|
//
|
|
// Go to the Storage Pool and get the media set associated
|
|
// with this data
|
|
//
|
|
WsbAffirmHr(GetMediaSet(pFsaWorkItem));
|
|
|
|
//
|
|
// Loop here to try to recover from certain types of errors
|
|
//
|
|
while (done == FALSE){
|
|
CComPtr<IWsbIndexedCollection> pMountingCollection;
|
|
CComPtr<IMountingMedia> pMountingMedia;
|
|
CComPtr<IMountingMedia> pMediaToFind;
|
|
BOOL bMediaMounting = FALSE;
|
|
BOOL bMediaMountingAdded = FALSE;
|
|
BOOL bMediaChanged = FALSE;
|
|
LONGLONG llRequiredSize = 0;
|
|
|
|
// Lock mounting media while searching for a media to use
|
|
WsbAffirmHr(m_pServer->LockMountingMedias());
|
|
|
|
// Find a media to use and set up interfaces to RMS
|
|
try {
|
|
WsbAffirmHr(FindMigrateMediaToUse(pFsaWorkItem, &mediaToUse, &firstSide, &bMediaChanged, &llRequiredSize));
|
|
|
|
// Check if the media-to-use have changed and is a non-scratch media
|
|
if ((GUID_NULL != mediaToUse) && bMediaChanged) {
|
|
|
|
// Check if the media to mount is already mounting
|
|
WsbAffirmHr(m_pServer->GetMountingMedias(&pMountingCollection));
|
|
WsbAffirmHr(CoCreateInstance(CLSID_CMountingMedia, 0, CLSCTX_SERVER, IID_IMountingMedia, (void**)&pMediaToFind));
|
|
WsbAffirmHr(pMediaToFind->SetMediaId(mediaToUse));
|
|
hr = pMountingCollection->Find(pMediaToFind, IID_IMountingMedia, (void **)&pMountingMedia);
|
|
|
|
if (hr == S_OK) {
|
|
// Media is already mounting...
|
|
bMediaMounting = TRUE;
|
|
WsbAffirmHr(pMediaToFind->SetIsReadOnly(FALSE));
|
|
|
|
} else if (hr == WSB_E_NOTFOUND) {
|
|
// New media to mount - add to the mounting list
|
|
hr = S_OK;
|
|
WsbAffirmHr(pMediaToFind->Init(mediaToUse, FALSE));
|
|
WsbAffirmHr(pMountingCollection->Add(pMediaToFind));
|
|
bMediaMountingAdded = TRUE;
|
|
|
|
} else {
|
|
WsbAffirmHr(hr);
|
|
}
|
|
}
|
|
|
|
} WsbCatchAndDo(hr,
|
|
// Unlock mounting media
|
|
m_pServer->UnlockMountingMedias();
|
|
|
|
WsbTraceAlways(OLESTR("CHsmWorkQueue::PremigrateIt: error while trying to find/add mounting media. hr=<%ls>\n"),
|
|
WsbHrAsString(hr));
|
|
|
|
// Bale out
|
|
WsbThrow(hr);
|
|
);
|
|
|
|
// Release the lock
|
|
WsbAffirmHr(m_pServer->UnlockMountingMedias());
|
|
|
|
// If the media is mounting - wait for the mount event
|
|
if (bMediaMounting) {
|
|
WsbAffirmHr(pMountingMedia->WaitForMount(INFINITE));
|
|
pMountingMedia = 0;
|
|
}
|
|
|
|
// Mount the media. Ask for short timeout.
|
|
hr = MountMedia(pFsaWorkItem, mediaToUse, firstSide, TRUE, TRUE, llRequiredSize);
|
|
|
|
// If we added a mounting media to the list - remove it once the mount is done
|
|
if (bMediaMountingAdded) {
|
|
HRESULT hrRemove = S_OK;
|
|
|
|
// No matter how the Mount finished - free waiting clients and remove from the list
|
|
hrRemove = m_pServer->LockMountingMedias();
|
|
WsbAffirmHr(hrRemove);
|
|
|
|
try {
|
|
WsbAffirmHr(pMediaToFind->MountDone());
|
|
WsbAffirmHr(pMountingCollection->RemoveAndRelease(pMediaToFind));
|
|
pMediaToFind = 0;
|
|
|
|
} WsbCatch(hrRemove);
|
|
|
|
m_pServer->UnlockMountingMedias();
|
|
|
|
// We don't expect any errors while removing the mounting media -
|
|
// The thread that added to the collection is always the one that removes
|
|
if (! SUCCEEDED(hrRemove)) {
|
|
WsbTraceAlways(OLESTR("CHsmWorkQueue::PremigrateIt: error while trying to remove a mounting media. hr=<%ls>\n"),
|
|
WsbHrAsString(hrRemove));
|
|
|
|
WsbThrow(hrRemove);
|
|
}
|
|
}
|
|
|
|
// Check for job cancellation
|
|
if (HSM_JOB_STATE_CANCELLING == m_JobState) {
|
|
WsbThrow(HSM_E_WORK_SKIPPED_CANCELLED);
|
|
}
|
|
|
|
//
|
|
// Process RMS errors
|
|
//
|
|
switch (hr) {
|
|
case RMS_E_CARTRIDGE_NOT_FOUND: {
|
|
// If this media wasn't found, mark it as bad and try a different one
|
|
WsbAffirmHr(MarkMediaBad(pFsaWorkItem, m_MediaId, hr));
|
|
hr = S_OK;
|
|
continue;
|
|
}
|
|
|
|
case RMS_E_TIMEOUT:
|
|
case HSM_E_NO_MORE_MEDIA:
|
|
case RMS_E_CARTRIDGE_DISABLED:
|
|
case HSM_E_MEDIA_NOT_AVAILABLE: {
|
|
// In all these cases, let FindMigrateMediaToUse try to find a different media
|
|
hr = S_OK;
|
|
continue;
|
|
}
|
|
|
|
default: {
|
|
WsbAffirmHr(hr);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Make sure the data has not been modified since the
|
|
// FSA determined the migration request
|
|
//
|
|
hr = CheckForChanges(pFsaWorkItem);
|
|
if (S_OK == hr) {
|
|
//
|
|
// Build the source path
|
|
//
|
|
CWsbStringPtr tmpString;
|
|
WsbAffirmHr(GetSource(pFsaWorkItem, &tmpString));
|
|
CWsbBstrPtr localName = tmpString;
|
|
//
|
|
// Ask the Data mover to store the data
|
|
//
|
|
ULARGE_INTEGER localDataStart;
|
|
ULARGE_INTEGER localDataSize;
|
|
ULARGE_INTEGER remoteFileStart;
|
|
ULARGE_INTEGER remoteFileSize;
|
|
ULARGE_INTEGER remoteDataSetStart;
|
|
ULARGE_INTEGER remoteDataStart;
|
|
ULARGE_INTEGER remoteDataSize;
|
|
ULARGE_INTEGER remoteVerificationData;
|
|
ULONG remoteVerificationType;
|
|
ULARGE_INTEGER dataStreamCRC;
|
|
ULONG dataStreamCRCType;
|
|
ULARGE_INTEGER usn;
|
|
|
|
|
|
WsbAffirmHr(pFsaWorkItem->GetPlaceholder(&placeholder));
|
|
WsbAffirmHr(pFsaWorkItem->GetRequestSize(&requestSize));
|
|
WsbAffirmHr(pFsaWorkItem->GetRequestOffset(&requestStart));
|
|
WsbAffirmHr(pFsaWorkItem->GetFileVersionId(&fileVersionId));
|
|
localDataStart.QuadPart = requestStart;
|
|
localDataSize.QuadPart = requestSize;
|
|
ReportMediaProgress(HSM_JOB_MEDIA_STATE_TRANSFERRING, hr);
|
|
// Make sure data mover is ready for work.
|
|
WsbAffirmPointer(m_pDataMover);
|
|
|
|
hr = m_pDataMover->StoreData( localName,
|
|
localDataStart,
|
|
localDataSize,
|
|
MVR_FLAG_BACKUP_SEMANTICS | MVR_FLAG_POSIX_SEMANTICS,
|
|
&remoteDataSetStart,
|
|
&remoteFileStart,
|
|
&remoteFileSize,
|
|
&remoteDataStart,
|
|
&remoteDataSize,
|
|
&remoteVerificationType,
|
|
&remoteVerificationData,
|
|
&dataStreamCRCType,
|
|
&dataStreamCRC,
|
|
&usn);
|
|
WsbTrace(OLESTR("StoreData returned hr = <%ls>\n"),WsbHrAsString(hr));
|
|
ReportMediaProgress(HSM_JOB_MEDIA_STATE_TRANSFERRED, hr);
|
|
|
|
if (S_OK == hr) {
|
|
|
|
// Save the offset on the tape of the data set if we
|
|
// don't have it; confirm it if we do
|
|
if (0 == m_RemoteDataSetStart.QuadPart) {
|
|
m_RemoteDataSetStart = remoteDataSetStart;
|
|
} else {
|
|
WsbAssert(m_RemoteDataSetStart.QuadPart ==
|
|
remoteDataSetStart.QuadPart,
|
|
WSB_E_INVALID_DATA);
|
|
}
|
|
|
|
//
|
|
// Fill in the placeholder data
|
|
//
|
|
placeholder.bagId = m_BagId;
|
|
placeholder.hsmId = m_HsmId;
|
|
placeholder.fileStart = remoteFileStart.QuadPart;
|
|
placeholder.fileSize = remoteFileSize.QuadPart;
|
|
placeholder.dataStart = remoteDataStart.QuadPart;
|
|
placeholder.dataSize = remoteDataSize.QuadPart;
|
|
placeholder.verificationData = remoteVerificationData.QuadPart;
|
|
placeholder.verificationType = remoteVerificationType;
|
|
placeholder.fileVersionId = fileVersionId;
|
|
placeholder.dataStreamCRCType = dataStreamCRCType;
|
|
placeholder.dataStreamCRC = dataStreamCRC.QuadPart;
|
|
WsbAffirmHr(pFsaWorkItem->SetPlaceholder(&placeholder));
|
|
WsbAffirmHr(pFsaWorkItem->SetUSN(usn.QuadPart));
|
|
|
|
//
|
|
// Update media information
|
|
WsbAffirmHr(GetMediaParameters());
|
|
|
|
done = TRUE;
|
|
} else {
|
|
switch (hr) {
|
|
|
|
case MVR_E_END_OF_MEDIA:
|
|
case MVR_E_DISK_FULL:
|
|
//
|
|
// We have run out of disk space so mark the media full
|
|
// and try again
|
|
//
|
|
// To really cleanup, we should remove the portion
|
|
// written TBD
|
|
//
|
|
WsbAffirmHr(MarkMediaFull(pFsaWorkItem, m_MediaId));
|
|
mediaToUse = GUID_NULL;
|
|
break;
|
|
|
|
case MVR_E_MEDIA_ABORT:
|
|
//
|
|
// Media is most likely bad - mark it as such, then abort
|
|
//
|
|
WsbAffirmHr(MarkMediaBad(pFsaWorkItem, m_MediaId, hr));
|
|
done = TRUE;
|
|
break;
|
|
|
|
default:
|
|
// We failed the copy somehow. Report this error.
|
|
done = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
done = TRUE;
|
|
}
|
|
}
|
|
} WsbCatch( hr );
|
|
|
|
WsbTraceOut(OLESTR("CHsmWorkQueue::PremigrateIt"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
|
|
return( hr );
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CHsmWorkQueue::RecallIt(
|
|
IFsaPostIt *pFsaWorkItem
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
GUID mediaToUse = GUID_NULL;
|
|
CComPtr<IFsaScanItem> pScanItem;
|
|
LONGLONG readOffset;
|
|
|
|
WsbTraceIn(OLESTR("CHsmWorkQueue::RecallIt"),OLESTR(""));
|
|
try {
|
|
|
|
GetScanItem(pFsaWorkItem, &pScanItem);
|
|
|
|
if ((m_RequestAction != FSA_REQUEST_ACTION_FILTER_READ) &&
|
|
(m_RequestAction != FSA_REQUEST_ACTION_FILTER_RECALL)) {
|
|
//
|
|
// Non-demand recall - make sure the file has not changed
|
|
//
|
|
hr = CheckForChanges(pFsaWorkItem);
|
|
} else {
|
|
//
|
|
// For demand recalls we have to assume the file has not changed since we
|
|
// recall on the first read or write.
|
|
//
|
|
hr = S_OK; //CheckForChanges(pFsaWorkItem);
|
|
}
|
|
if ( S_OK == hr ) {
|
|
CComPtr<IWsbIndexedCollection> pMountingCollection;
|
|
CComPtr<IMountingMedia> pMountingMedia;
|
|
CComPtr<IMountingMedia> pMediaToFind;
|
|
BOOL bMediaMounting = FALSE;
|
|
BOOL bMediaMountingAdded = FALSE;
|
|
BOOL bMediaChanged = FALSE;
|
|
|
|
// Find the media that contains the file
|
|
WsbAffirmHr(FindRecallMediaToUse(pFsaWorkItem, &mediaToUse, &bMediaChanged));
|
|
|
|
if (bMediaChanged) {
|
|
// Check if the media is already in the process of mounting
|
|
WsbAffirmHr(m_pServer->LockMountingMedias());
|
|
|
|
try {
|
|
// Check if the media to mount is already mounting
|
|
WsbAffirmHr(m_pServer->GetMountingMedias(&pMountingCollection));
|
|
WsbAffirmHr(CoCreateInstance(CLSID_CMountingMedia, 0, CLSCTX_SERVER, IID_IMountingMedia, (void**)&pMediaToFind));
|
|
WsbAffirmHr(pMediaToFind->SetMediaId(mediaToUse));
|
|
hr = pMountingCollection->Find(pMediaToFind, IID_IMountingMedia, (void **)&pMountingMedia);
|
|
|
|
if (hr == S_OK) {
|
|
// Media is already mounting...
|
|
bMediaMounting = TRUE;
|
|
|
|
} else if (hr == WSB_E_NOTFOUND) {
|
|
// New media to mount - add to the mounting list
|
|
hr = S_OK;
|
|
WsbAffirmHr(pMediaToFind->Init(mediaToUse, TRUE));
|
|
WsbAffirmHr(pMountingCollection->Add(pMediaToFind));
|
|
bMediaMountingAdded = TRUE;
|
|
|
|
} else {
|
|
WsbAffirmHr(hr);
|
|
}
|
|
} WsbCatchAndDo(hr,
|
|
// Unlock mounting media
|
|
m_pServer->UnlockMountingMedias();
|
|
|
|
WsbTraceAlways(OLESTR("CHsmWorkQueue::RecallIt: error while trying to find/add mounting media. hr=<%ls>\n"),
|
|
WsbHrAsString(hr));
|
|
|
|
// Bale out
|
|
WsbThrow(hr);
|
|
);
|
|
|
|
// Release the lock
|
|
WsbAffirmHr(m_pServer->UnlockMountingMedias());
|
|
}
|
|
|
|
// If the media is mounting - wait for the mount event
|
|
if (bMediaMounting) {
|
|
WsbAffirmHr(pMountingMedia->WaitForMount(INFINITE));
|
|
pMountingMedia = 0;
|
|
}
|
|
|
|
//
|
|
// Get the media mounted (hr is checked only after removing from the mounting-media list)
|
|
//
|
|
hr = MountMedia(pFsaWorkItem, mediaToUse);
|
|
|
|
// If added to the mounting list - remove
|
|
if (bMediaMountingAdded) {
|
|
HRESULT hrRemove = S_OK;
|
|
|
|
// No matter how the Mount finished - free waiting clients and remove from the list
|
|
hrRemove = m_pServer->LockMountingMedias();
|
|
WsbAffirmHr(hrRemove);
|
|
|
|
try {
|
|
WsbAffirmHr(pMediaToFind->MountDone());
|
|
WsbAffirmHr(pMountingCollection->RemoveAndRelease(pMediaToFind));
|
|
pMediaToFind = 0;
|
|
|
|
} WsbCatch(hrRemove);
|
|
|
|
m_pServer->UnlockMountingMedias();
|
|
|
|
// We don't expect any errors while removing the mounting media -
|
|
// The thread that added to the collection is always the one that removes
|
|
if (! SUCCEEDED(hrRemove)) {
|
|
WsbTraceAlways(OLESTR("CHsmWorkQueue::RecallIt: error while trying to remove a mounting media. hr=<%ls>\n"),
|
|
WsbHrAsString(hrRemove));
|
|
|
|
WsbThrow(hrRemove);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check the Mount result
|
|
//
|
|
WsbAffirmHr(hr);
|
|
|
|
//
|
|
// Copy the data
|
|
//
|
|
// Build the source path
|
|
CWsbStringPtr tmpString;
|
|
WsbAffirmHr(GetSource(pFsaWorkItem, &tmpString));
|
|
CWsbBstrPtr localName = tmpString;
|
|
// Ask the Data mover to store the data
|
|
LONGLONG requestSize;
|
|
LONGLONG requestStart;
|
|
ULARGE_INTEGER localDataStart;
|
|
ULARGE_INTEGER localDataSize;
|
|
ULARGE_INTEGER remoteFileStart;
|
|
ULARGE_INTEGER remoteFileSize;
|
|
ULARGE_INTEGER remoteDataStart;
|
|
ULARGE_INTEGER remoteDataSize;
|
|
ULARGE_INTEGER remoteVerificationData;
|
|
ULONG remoteVerificationType;
|
|
|
|
FSA_PLACEHOLDER placeholder;
|
|
WsbAffirmHr(pFsaWorkItem->GetPlaceholder(&placeholder));
|
|
WsbAffirmHr(pFsaWorkItem->GetRequestSize(&requestSize));
|
|
WsbAffirmHr(pFsaWorkItem->GetRequestOffset(&requestStart));
|
|
|
|
//
|
|
// Build strings
|
|
//
|
|
CWsbStringPtr strGuid;
|
|
|
|
CWsbBstrPtr sessionName = HSM_BAG_NAME;
|
|
WsbAffirmHr(WsbSafeGuidAsString(m_BagId, strGuid));
|
|
sessionName.Append(strGuid);
|
|
|
|
CWsbBstrPtr sessionDescription = HSM_ENGINE_ID;
|
|
WsbAffirmHr(WsbSafeGuidAsString(m_HsmId, strGuid));
|
|
sessionDescription.Append(strGuid);
|
|
|
|
localDataStart.QuadPart = requestStart;
|
|
localDataSize.QuadPart = requestSize;
|
|
remoteFileStart.QuadPart = placeholder.fileStart;
|
|
remoteFileSize.QuadPart = placeholder.fileSize;
|
|
remoteDataStart.QuadPart = placeholder.dataStart;
|
|
remoteDataSize.QuadPart = placeholder.dataSize;
|
|
remoteVerificationData.QuadPart = placeholder.verificationData;
|
|
remoteVerificationType = placeholder.verificationType;
|
|
|
|
|
|
ReportMediaProgress(HSM_JOB_MEDIA_STATE_TRANSFERRING, hr);
|
|
|
|
CComPtr<IStream> pLocalStream;
|
|
CComPtr<IStream> pRemoteStream;
|
|
ULARGE_INTEGER offset, read, written;
|
|
DWORD verifyType;
|
|
|
|
|
|
if ((m_RequestAction == FSA_REQUEST_ACTION_FILTER_READ) ||
|
|
(m_RequestAction == FSA_REQUEST_ACTION_FILTER_RECALL)) {
|
|
//
|
|
// We are doing a read without recall, so get the
|
|
// recall object's data mover
|
|
//
|
|
CComPtr<IFsaFilterRecall> pRecall;
|
|
WsbAffirmHr(pFsaWorkItem->GetFilterRecall(&pRecall));
|
|
WsbAffirmHr(pRecall->CreateLocalStream( &pLocalStream));
|
|
WsbAffirmHr(pRecall->GetSize( (LONGLONG *) &remoteDataSize.QuadPart ));
|
|
WsbAffirmHr(pRecall->GetOffset( &readOffset ));
|
|
if (readOffset == 0) {
|
|
verifyType = MVR_VERIFICATION_TYPE_HEADER_CRC;
|
|
} else {
|
|
verifyType = MVR_VERIFICATION_TYPE_NONE;
|
|
}
|
|
} else {
|
|
//
|
|
// We are doing a file recall (not a demand recall) so get the FSA data mover
|
|
//
|
|
verifyType = MVR_VERIFICATION_TYPE_HEADER_CRC;
|
|
readOffset = 0;
|
|
WsbAffirmPointer(pScanItem);
|
|
WsbAffirmHr(pScanItem->CreateLocalStream( &pLocalStream ) );
|
|
}
|
|
|
|
//
|
|
// Create remote data mover stream
|
|
// TEMPORARY: Consider removing the NO_CACHING flag for a NO_RECALL recall
|
|
//
|
|
|
|
WsbAssert(0 != m_RemoteDataSetStart.QuadPart, HSM_E_BAD_SEGMENT_INFORMATION);
|
|
WsbAffirmHr( m_pDataMover->CreateRemoteStream(
|
|
CWsbBstrPtr(L""),
|
|
MVR_MODE_READ | MVR_FLAG_HSM_SEMANTICS | MVR_FLAG_NO_CACHING,
|
|
sessionName,
|
|
sessionDescription,
|
|
m_RemoteDataSetStart,
|
|
remoteFileStart,
|
|
remoteFileSize,
|
|
remoteDataStart,
|
|
remoteDataSize,
|
|
verifyType,
|
|
remoteVerificationData,
|
|
&pRemoteStream ) );
|
|
|
|
//
|
|
// The offset given here is the offset into the stream itself (readOffset).
|
|
// The actual position on remote media will be the bag start plus the file start
|
|
// plus the file-data start (all given in CreateRemoteStream) plus this offset.
|
|
//
|
|
WsbTrace(OLESTR("Setting offset to %I64d reading %I64u\n"), readOffset, remoteDataSize.QuadPart);
|
|
|
|
offset.QuadPart = readOffset;
|
|
WsbAffirmHr( m_pDataMover->SetInitialOffset( offset ) );
|
|
|
|
//
|
|
// Once the remote stream has been created we must make sure we detach it
|
|
//
|
|
|
|
try {
|
|
|
|
WsbAffirmHr( pRemoteStream->CopyTo( pLocalStream, remoteDataSize, &read, &written ) );
|
|
WsbAffirmHr( pLocalStream->Commit( STGC_DEFAULT ) );
|
|
|
|
//
|
|
// The CopyTo succeeded... make sure we got all the bytes
|
|
// we asked for.
|
|
//
|
|
// If we attempt to read from a incomplete Master that
|
|
// does not contain the migrated data we'll fail here with
|
|
// MVR_S_NO_DATA_DETECTED.
|
|
//
|
|
WsbAffirm( written.QuadPart == remoteDataSize.QuadPart, HSM_E_VALIDATE_DATA_NOT_ON_MEDIA );
|
|
|
|
WsbAffirmHr( m_pDataMover->CloseStream() );
|
|
} WsbCatchAndDo(hr,
|
|
WsbAffirmHr( m_pDataMover->CloseStream() );
|
|
);
|
|
|
|
ReportMediaProgress(HSM_JOB_MEDIA_STATE_TRANSFERRED, hr);
|
|
WsbTrace(OLESTR("RecallData returned hr = <%ls>\n"),WsbHrAsString(hr));
|
|
} else {
|
|
//
|
|
// The file has changed or is not in the correct state
|
|
//
|
|
WsbTrace(OLESTR("The file has changed between asking for the recall and the actual recall\n"));
|
|
WsbAffirmHr( hr );
|
|
}
|
|
|
|
} WsbCatch( hr );
|
|
|
|
// Tell the session whether or not the work was done.
|
|
// We don't really care about the return code, there is nothing
|
|
// we can do if it fails.
|
|
WsbTrace(OLESTR("Tried HSM work, calling Session to Process Item\n"));
|
|
if (pScanItem) {
|
|
m_pSession->ProcessItem(m_JobPhase, m_JobAction, pScanItem, hr);
|
|
}
|
|
|
|
WsbTraceOut(OLESTR("CHsmWorkQueue::RecallIt"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
|
|
return( hr );
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
CHsmWorkQueue::validateIt(
|
|
IFsaPostIt *pFsaWorkItem
|
|
)
|
|
/*
|
|
|
|
Routine Description:
|
|
|
|
This Engine internal helper method is used to validate a scan item which has a
|
|
reparse point (found by the FSA during a resource scan).
|
|
|
|
When this method gets control it already knows the resource (e.g., volume) it is
|
|
operating against by virtue of the work queue being tied to a volume. The PostIt
|
|
object whose interface pointer has been passed into this method is tied to a
|
|
specific scan item (e.g.,file). So on call this method knows both the resource
|
|
and scan item it is validating.
|
|
|
|
Validating a file with a reparse point on it means verifying that this file's info
|
|
is properly contained in the HSM databases and that the file's bag is contained on
|
|
its master secondary storage media.
|
|
|
|
After getting basic info (the resource id and the file's placeholder info), the method
|
|
first verifies that the placeholder's bag is contained in the Bag Info Table. If so,
|
|
the file's segment is then verified as being contained in the Segment Table. Providing
|
|
it is, the master media id contained in the Segment Table record is verified as
|
|
being contained in the Media Info Table. Finally the Remote Data Set (bag) the file
|
|
belongs to is verified as being contained on the master media.
|
|
|
|
If any of the above verifications fail the PostIt object is marked to request a
|
|
Result Action of 'Validate Bad' from the FSA, and the PostIt is sent back to the
|
|
FSA to perform that action. (Validate Bad action means that a file in a Premigrated
|
|
state will have its placeholder removed, changing it to a normal (unmanaged) file,
|
|
and a Truncated file will be deleted.)
|
|
|
|
If the file validates up to this point, then the PostIt is marked accordingly (which
|
|
will cause the FSA to update the Premigrated/Truncated stats as appropriate) and a
|
|
couple of final checks are made. First, if the resource the file is presently on
|
|
does not agree with the resource stored in the Bag Info Table record (meaning
|
|
the reparsed file was moved without being recalled, e.g., backing up the file and
|
|
restoring it to another volume), an entry is added to the Volume Assignment Table.
|
|
Secondly, if the file is present in the Bag Hole Table (meaning it has been deleted)
|
|
it is removed from there.
|
|
|
|
Arguments:
|
|
|
|
pFsaWorkItem - Interface pointer to the PostIt object initiated by the FSA. The
|
|
PostIt object correlates to a specific scan item.
|
|
|
|
Return Value:
|
|
|
|
S_OK - The call succeeded (the specified scan item was validated, and the appropriate
|
|
result action was filled into the PostIt, which will be sent back to the
|
|
FSA for action).
|
|
|
|
Any other value - The call failed in one of the embedded Remote Storage API calls.
|
|
The result will be specific to the call that failed.
|
|
|
|
*/
|
|
|
|
{
|
|
HRESULT hr = S_OK;
|
|
GUID l_BagVolId;
|
|
GUID resourceId;
|
|
LONGLONG l_FileStart = 0;
|
|
FSA_PLACEHOLDER placeholder;
|
|
CWsbStringPtr path;
|
|
CComQIPtr<ISegDb, &IID_ISegDb> pSegDb = m_pSegmentDb;
|
|
CComPtr<IRmsServer> pRmsServer;
|
|
CComPtr<IRmsCartridge> pMedia;
|
|
GUID mediaSubsystemId;
|
|
|
|
|
|
WsbTraceIn(OLESTR("CHsmWorkQueue::validateIt"),OLESTR(""));
|
|
|
|
try {
|
|
|
|
memset(&placeholder, 0, sizeof(FSA_PLACEHOLDER));
|
|
|
|
//
|
|
// Get starting info and set hsm work queue object's bag id to that contained
|
|
// in the scan item's placeholder
|
|
//
|
|
WsbAffirmHr( m_pFsaResource->GetIdentifier( &resourceId ));
|
|
WsbAffirmHr( pFsaWorkItem->GetPlaceholder( &placeholder ));
|
|
m_BagId = placeholder.bagId;
|
|
l_FileStart = placeholder.fileStart;
|
|
|
|
WsbAffirmHr( pFsaWorkItem->GetPath( &path, 0 ));
|
|
WsbTrace( OLESTR("Beginning to validate <%s>.\n"), path );
|
|
|
|
//
|
|
// Make sure the segment is in the Segment Table (seek the segment record
|
|
// whose keys (bag id, file start and file size) match what is in the placeholder).
|
|
// Note: We need to start with this table since the real BAG is different for indirect segments.
|
|
//
|
|
CComPtr<ISegRec> pSegRec;
|
|
GUID l_BagId;
|
|
LONGLONG l_FileSize;
|
|
USHORT l_SegFlags;
|
|
GUID l_PrimPos;
|
|
LONGLONG l_SecPos;
|
|
|
|
hr = pSegDb->SegFind( m_pDbWorkSession, m_BagId, placeholder.fileStart,
|
|
placeholder.fileSize, &pSegRec );
|
|
if (S_OK != hr ) {
|
|
hr = HSM_E_VALIDATE_SEGMENT_NOT_FOUND;
|
|
WsbAffirmHr(pFsaWorkItem->SetResult(hr));
|
|
WsbThrow(hr);
|
|
}
|
|
|
|
|
|
// Segment is in the table. Get segment record since we use l_PrimPos in next step
|
|
WsbTrace( OLESTR("(validateIt) <%s> found in Segment table, continuing...\n"),
|
|
path );
|
|
WsbAffirmHr( pSegRec->GetSegmentRecord( &l_BagId, &l_FileStart, &l_FileSize,
|
|
&l_SegFlags, &l_PrimPos, &l_SecPos ));
|
|
|
|
//
|
|
// 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;
|
|
|
|
hr = pSegDb->SegFind(m_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_VALIDATE_SEGMENT_NOT_FOUND;
|
|
WsbAffirmHr(pFsaWorkItem->SetResult(hr));
|
|
WsbThrow(hr);
|
|
}
|
|
|
|
WsbTrace( OLESTR("(validateIt) direct segment for <%s> found in Segment table, continuing...\n"),
|
|
path );
|
|
WsbAffirmHr(pSegRec->GetSegmentRecord(&l_BagId, &l_FileStart, &l_FileSize,
|
|
&l_SegFlags, &l_PrimPos, &l_SecPos));
|
|
|
|
// Don't support a second indirection for now !!
|
|
if (l_SegFlags & SEG_REC_INDIRECT_RECORD) {
|
|
hr = HSM_E_BAD_SEGMENT_INFORMATION;
|
|
WsbAffirmHr(pFsaWorkItem->SetResult(hr));
|
|
WsbThrow(hr);
|
|
}
|
|
|
|
// Change Bag id to the real one
|
|
m_BagId = l_BagId;
|
|
}
|
|
|
|
//
|
|
// Make sure the BAG ID is in the Bag Info Table (get the Bag Info Table
|
|
// (entity) in the Segment database, set the key value (bag id) to that
|
|
// contained in the placeholder and get that record. If found, the Bag
|
|
// is in the Bag Info Table).
|
|
//
|
|
CComPtr<IBagInfo> pBagInfo;
|
|
FILETIME l_BirthDate;
|
|
HSM_BAG_STATUS l_BagStatus;
|
|
LONGLONG l_BagLen;
|
|
USHORT l_BagType;
|
|
LONGLONG l_DeletedBagAmount;
|
|
SHORT l_RemoteDataSet;
|
|
|
|
WsbAffirmHr( m_pSegmentDb->GetEntity( m_pDbWorkSession, HSM_BAG_INFO_REC_TYPE,
|
|
IID_IBagInfo, (void**)&pBagInfo ));
|
|
|
|
GetSystemTimeAsFileTime(&l_BirthDate);
|
|
WsbAffirmHr( pBagInfo->SetBagInfo( HSM_BAG_STATUS_IN_PROGRESS, m_BagId,
|
|
l_BirthDate, 0, 0, GUID_NULL, 0, 0 ));
|
|
hr = pBagInfo->FindEQ();
|
|
if (S_OK != hr ) {
|
|
hr = HSM_E_VALIDATE_BAG_NOT_FOUND;
|
|
WsbAffirmHr(pFsaWorkItem->SetResult(hr));
|
|
WsbThrow(hr);
|
|
}
|
|
|
|
// Bag is in the table. Trace, then get bag record since we will use some
|
|
// info later (l_RemoteDataSet, l_BagVolId).
|
|
WsbTrace( OLESTR("(validateIt) <%s> found in Bag Info table, continuing...\n"),
|
|
path );
|
|
WsbAffirmHr( pBagInfo->GetBagInfo( &l_BagStatus, &l_BagId, &l_BirthDate,
|
|
&l_BagLen, &l_BagType, &l_BagVolId,
|
|
&l_DeletedBagAmount, &l_RemoteDataSet ));
|
|
|
|
//
|
|
// Make sure the media is in the Media Info table (get Media Info Table, set
|
|
// the key (media id) to what is in the Segment record and get the record).
|
|
// Note that for Sakkara the Primary Position field in the Segment record
|
|
// (l_PrimPos) contains the id (GUID) of the media where the bag/segment is stored.
|
|
//
|
|
CComPtr<IMediaInfo> pMediaInfo;
|
|
|
|
WsbAffirmHr( m_pSegmentDb->GetEntity( m_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_VALIDATE_MEDIA_NOT_FOUND;
|
|
WsbAffirmHr(pFsaWorkItem->SetResult(hr));
|
|
WsbThrow(hr);
|
|
}
|
|
|
|
WsbTrace( OLESTR("(validateIt) <%s> found in Media Info table, continuing...\n"),
|
|
path );
|
|
|
|
//
|
|
// Media is in the Media Info Table. Next step is to verify that the Remote Data
|
|
// Set (in concept equal to a bag) containing this scan item (e.g., file) is
|
|
// actually on the media.
|
|
//
|
|
SHORT l_MediaNextRemoteDataSet;
|
|
|
|
WsbAffirmHr( pMediaInfo->GetNextRemoteDataSet( &l_MediaNextRemoteDataSet ));
|
|
WsbTrace(
|
|
OLESTR("(validateIt) <%ls>: Bag remote dataset <%hd> Media remote dataset <%hd>\n"),
|
|
(OLECHAR*)path, l_RemoteDataSet, l_MediaNextRemoteDataSet );
|
|
if ( l_RemoteDataSet >= l_MediaNextRemoteDataSet ) {
|
|
// Remote data set containing the item is not on the media; we have a validate
|
|
// error, so set up to have FSA delete it
|
|
hr = HSM_E_VALIDATE_DATA_NOT_ON_MEDIA;
|
|
WsbAffirmHr(pFsaWorkItem->SetResult(hr));
|
|
WsbTrace( OLESTR("(validateIt) <%s>: remote data set not on media.\n"),
|
|
path );
|
|
WsbThrow(hr);
|
|
}
|
|
|
|
//
|
|
// Now verify that the media manager still knows about the media
|
|
//
|
|
WsbAffirmHr( pMediaInfo->GetMediaSubsystemId( &mediaSubsystemId ));
|
|
|
|
if (m_pRmsServer->FindCartridgeById(mediaSubsystemId , &pMedia) != S_OK) {
|
|
hr = HSM_E_VALIDATE_MEDIA_NOT_FOUND;
|
|
WsbAffirmHr(pFsaWorkItem->SetResult(hr));
|
|
WsbThrow(hr);
|
|
}
|
|
|
|
} WsbCatch( hr );
|
|
|
|
//
|
|
// If item failed to validate it has an invalid reparse point, tell FSA to remove it.
|
|
//
|
|
|
|
if (FAILED(hr)) {
|
|
WsbAffirmHr( pFsaWorkItem->SetResultAction( FSA_RESULT_ACTION_VALIDATE_BAD ));
|
|
WsbTrace(OLESTR("<%s> failed validation, result action = Validate Bad.\n"), path);
|
|
// No logging done here. Logging needs to be added to FSA (ProcessResult()).
|
|
// Clean up hr for return (tell caller this method completed).
|
|
hr = S_OK;
|
|
|
|
// Item validated, tell the FSA and do final clean-up checks
|
|
} else try {
|
|
WsbAffirmHr( pFsaWorkItem->SetResultAction( FSA_RESULT_ACTION_VALIDATE_OK ));
|
|
WsbTrace(OLESTR("<%s> passed validation, result action = Validate Ok.\n"), path);
|
|
|
|
//
|
|
// If the resource (volume) this item is on doesn't match that stored in the Bag
|
|
// Info Table, add an entry to the Volume Assignment Table
|
|
//
|
|
//
|
|
// Note: This code is commented out since nobody uses the Volume Assignment table.
|
|
// See bug 159449 in "Windows Bugs" database for more details.
|
|
//
|
|
// if ( !IsEqualGUID( resourceId, l_BagVolId )) {
|
|
// WsbAffirmHr( pSegDb->VolAssignAdd( m_pDbWorkSession, m_BagId, l_FileStart,
|
|
// placeholder.fileSize, resourceId));
|
|
// WsbTrace(OLESTR("(validateIt) <%s> volume mismatch. Entered in Vol Asgmnt Table\n"),
|
|
// path);
|
|
// }
|
|
|
|
} WsbCatch( hr );
|
|
|
|
WsbTraceOut(OLESTR("CHsmWorkQueue::validateIt"), OLESTR("hr = <%ls>"),
|
|
WsbHrAsString(hr));
|
|
return( hr );
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
CHsmWorkQueue::CheckForChanges(
|
|
IFsaPostIt *pFsaWorkItem
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
WsbTraceIn(OLESTR("CHsmWorkQueue::CheckForChanges"),OLESTR(""));
|
|
|
|
//
|
|
// Validate that the file is still migratable. Ask FSA
|
|
// for the latest USN of the file. If they match, then
|
|
// file is migratable, otherwise it is not. If it is
|
|
// not change the FSA_RESULT_ACTION to FSA_RESULT_ACTION_NONE.
|
|
// and quit.
|
|
//
|
|
|
|
try {
|
|
CComPtr<IFsaScanItem> pScanItem;
|
|
|
|
// Get a current scan item from the FSA for this work item
|
|
hr = GetScanItem(pFsaWorkItem, &pScanItem);
|
|
if (WSB_E_NOTFOUND == hr) {
|
|
//
|
|
// We cannot find the file, so just return not OK
|
|
//
|
|
WsbThrow(S_FALSE);
|
|
}
|
|
|
|
//
|
|
// Make sure we did not get some other kind of error.
|
|
//
|
|
WsbAffirmHr(hr);
|
|
|
|
|
|
// Check to see that the file is in the correct
|
|
// state to do the requested action
|
|
//
|
|
FSA_REQUEST_ACTION workAction;
|
|
WsbAffirmHr(pFsaWorkItem->GetRequestAction(&workAction));
|
|
switch (workAction) {
|
|
case FSA_REQUEST_ACTION_VALIDATE:
|
|
//
|
|
// No Checks required here
|
|
//
|
|
hr = S_OK;
|
|
break;
|
|
case FSA_REQUEST_ACTION_DELETE:
|
|
//
|
|
// Make it is still OK to delete the file
|
|
//
|
|
WsbAffirmHr(pScanItem->IsDeleteOK(pFsaWorkItem) );
|
|
break;
|
|
case FSA_REQUEST_ACTION_PREMIGRATE:
|
|
//
|
|
// Make sure the file is still manageable by asking the FSA
|
|
//
|
|
WsbAffirmHr(pScanItem->IsMigrateOK(pFsaWorkItem));
|
|
break;
|
|
case FSA_REQUEST_ACTION_FILTER_RECALL:
|
|
case FSA_REQUEST_ACTION_RECALL:
|
|
//
|
|
// Make sure the file is recallable by asking the FSA
|
|
//
|
|
WsbAffirmHr(pScanItem->IsRecallOK(pFsaWorkItem));
|
|
break;
|
|
case FSA_REQUEST_ACTION_FILTER_READ:
|
|
//
|
|
// Cannot check for truncated because the file is open
|
|
//
|
|
hr = S_OK;
|
|
break;
|
|
default:
|
|
hr = E_NOTIMPL;
|
|
break;
|
|
}
|
|
} WsbCatch (hr)
|
|
|
|
if (FSA_E_FILE_CHANGED == hr ) {
|
|
hr = HSM_E_FILE_CHANGED;
|
|
} else if (FSA_E_FILE_ALREADY_MANAGED == hr ) {
|
|
hr = HSM_E_FILE_ALREADY_MANAGED;
|
|
} else if (FSA_E_FILE_NOT_TRUNCATED == hr ) {
|
|
hr = HSM_E_FILE_NOT_TRUNCATED;
|
|
}
|
|
|
|
WsbTraceOut(OLESTR("CHsmWorkQueue::CheckForChanges"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
|
|
return( hr );
|
|
}
|
|
|
|
|
|
|
|
|
|
HRESULT
|
|
CHsmWorkQueue::RaisePriority(
|
|
void
|
|
)
|
|
|
|
/*++
|
|
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
WsbTraceIn(OLESTR("CHsmWorkQueue::RaisePriority"),OLESTR(""));
|
|
try {
|
|
|
|
WsbAssert(0 != m_WorkerThread, E_UNEXPECTED);
|
|
WsbAssert(m_pSession != 0, E_UNEXPECTED);
|
|
|
|
switch(m_JobPriority) {
|
|
|
|
case HSM_JOB_PRIORITY_IDLE:
|
|
WsbAffirmStatus(SetThreadPriority(m_WorkerThread, THREAD_PRIORITY_LOWEST));
|
|
m_JobPriority = HSM_JOB_PRIORITY_LOWEST;
|
|
break;
|
|
|
|
case HSM_JOB_PRIORITY_LOWEST:
|
|
WsbAffirmStatus(SetThreadPriority(m_WorkerThread, THREAD_PRIORITY_BELOW_NORMAL));
|
|
m_JobPriority = HSM_JOB_PRIORITY_LOW;
|
|
break;
|
|
|
|
case HSM_JOB_PRIORITY_LOW:
|
|
WsbAffirmStatus(SetThreadPriority(m_WorkerThread, THREAD_PRIORITY_NORMAL));
|
|
m_JobPriority = HSM_JOB_PRIORITY_NORMAL;
|
|
break;
|
|
|
|
case HSM_JOB_PRIORITY_NORMAL:
|
|
WsbAffirmStatus(SetThreadPriority(m_WorkerThread, THREAD_PRIORITY_ABOVE_NORMAL));
|
|
m_JobPriority = HSM_JOB_PRIORITY_HIGH;
|
|
break;
|
|
|
|
case HSM_JOB_PRIORITY_HIGH:
|
|
WsbAffirmStatus(SetThreadPriority(m_WorkerThread, THREAD_PRIORITY_HIGHEST));
|
|
m_JobPriority = HSM_JOB_PRIORITY_HIGHEST;
|
|
break;
|
|
|
|
case HSM_JOB_PRIORITY_HIGHEST:
|
|
WsbAffirmStatus(SetThreadPriority(m_WorkerThread, THREAD_PRIORITY_TIME_CRITICAL));
|
|
m_JobPriority = HSM_JOB_PRIORITY_CRITICAL;
|
|
break;
|
|
|
|
default:
|
|
case HSM_JOB_PRIORITY_CRITICAL:
|
|
WsbAffirm(FALSE, E_UNEXPECTED);
|
|
break;
|
|
}
|
|
|
|
WsbAffirmHr(m_pSession->ProcessPriority(m_JobPhase, m_JobPriority));
|
|
|
|
} WsbCatch(hr);
|
|
|
|
WsbTraceOut(OLESTR("CHsmWorkQueue::RaisePriority"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
|
|
return(hr);
|
|
}
|
|
|
|
HRESULT
|
|
CHsmWorkQueue::LowerPriority(
|
|
void
|
|
)
|
|
|
|
/*++
|
|
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
WsbTraceIn(OLESTR("CHsmWorkQueue::LowerPriority"),OLESTR(""));
|
|
try {
|
|
|
|
WsbAssert(0 != m_WorkerThread, E_UNEXPECTED);
|
|
WsbAssert(m_pSession != 0, E_UNEXPECTED);
|
|
|
|
switch(m_JobPriority) {
|
|
case HSM_JOB_PRIORITY_IDLE:
|
|
WsbAffirm(FALSE, E_UNEXPECTED);
|
|
break;
|
|
|
|
case HSM_JOB_PRIORITY_LOWEST:
|
|
WsbAffirmStatus(SetThreadPriority(m_WorkerThread, THREAD_PRIORITY_IDLE));
|
|
m_JobPriority = HSM_JOB_PRIORITY_IDLE;
|
|
break;
|
|
|
|
case HSM_JOB_PRIORITY_LOW:
|
|
WsbAffirmStatus(SetThreadPriority(m_WorkerThread, THREAD_PRIORITY_LOWEST));
|
|
m_JobPriority = HSM_JOB_PRIORITY_LOWEST;
|
|
break;
|
|
|
|
case HSM_JOB_PRIORITY_NORMAL:
|
|
WsbAffirmStatus(SetThreadPriority(m_WorkerThread, THREAD_PRIORITY_BELOW_NORMAL));
|
|
m_JobPriority = HSM_JOB_PRIORITY_LOW;
|
|
break;
|
|
|
|
case HSM_JOB_PRIORITY_HIGH:
|
|
WsbAffirmStatus(SetThreadPriority(m_WorkerThread, THREAD_PRIORITY_NORMAL));
|
|
m_JobPriority = HSM_JOB_PRIORITY_NORMAL;
|
|
break;
|
|
|
|
case HSM_JOB_PRIORITY_HIGHEST:
|
|
WsbAffirmStatus(SetThreadPriority(m_WorkerThread, THREAD_PRIORITY_ABOVE_NORMAL));
|
|
m_JobPriority = HSM_JOB_PRIORITY_HIGH;
|
|
break;
|
|
|
|
default:
|
|
case HSM_JOB_PRIORITY_CRITICAL:
|
|
WsbAffirmStatus(SetThreadPriority(m_WorkerThread, THREAD_PRIORITY_HIGHEST));
|
|
m_JobPriority = HSM_JOB_PRIORITY_HIGHEST;
|
|
break;
|
|
}
|
|
|
|
WsbAffirmHr(m_pSession->ProcessPriority(m_JobPhase, m_JobPriority));
|
|
|
|
} WsbCatch(hr);
|
|
|
|
WsbTraceOut(OLESTR("CHsmWorkQueue::LowerPriority"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
|
|
return(hr);
|
|
}
|
|
|
|
|
|
|
|
|
|
HRESULT
|
|
CHsmWorkQueue::CheckRms(
|
|
void
|
|
)
|
|
|
|
/*++
|
|
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
WsbTraceIn(OLESTR("CHsmWorkQueue::CheckRms"),OLESTR(""));
|
|
try {
|
|
//
|
|
// Make sure we can still talk to the RMS
|
|
//
|
|
if (m_pRmsServer != 0) {
|
|
CWsbBstrPtr name;
|
|
hr = m_pRmsServer->GetServerName( &name );
|
|
if (hr != S_OK) {
|
|
m_pRmsServer = 0;
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
//
|
|
// Get RMS that runs on this machine
|
|
//
|
|
if (m_pRmsServer == 0) {
|
|
WsbAffirmHr(m_pServer->GetHsmMediaMgr(&m_pRmsServer));
|
|
|
|
// wait for RMS to come ready
|
|
// (this may not be needed anymore - if Rms initialization is
|
|
// synced with Engine initialization)
|
|
CComObject<CRmsSink> *pSink = new CComObject<CRmsSink>;
|
|
WsbAffirm(0 != pSink, E_OUTOFMEMORY);
|
|
CComPtr<IUnknown> pSinkUnk = pSink; // holds refcount for use here
|
|
WsbAffirmHr( pSink->Construct( m_pRmsServer ) );
|
|
WsbAffirmHr( pSink->WaitForReady( ) );
|
|
WsbAffirmHr( pSink->DoUnadvise( ) );
|
|
}
|
|
} WsbCatch( hr );
|
|
|
|
WsbTraceOut(OLESTR("CHsmWorkQueue::CheckRms"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
|
|
return(hr);
|
|
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CHsmWorkQueue::CheckSession(
|
|
IHsmSession *pSession
|
|
)
|
|
|
|
/*++
|
|
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
BOOL bLog = TRUE;
|
|
|
|
WsbTraceIn(OLESTR("CHsmWorkQueue::CheckSession"),OLESTR(""));
|
|
try {
|
|
|
|
if ((m_pSession != 0) && (m_pSession != pSession)) {
|
|
//Don't expect this queue guy to switch sessions
|
|
WsbTrace(OLESTR("Not Switching sessions at this time so we are failing.\n"));
|
|
WsbThrow( E_UNEXPECTED );
|
|
}
|
|
|
|
//
|
|
// Check to see if we have dealt with this or any other session before.
|
|
if (m_pSession == 0) {
|
|
WsbTrace(OLESTR("New session.\n"));
|
|
//
|
|
// We have no on going session so we need to establish communication
|
|
// with this session.
|
|
//
|
|
CComPtr<IHsmSessionSinkEveryState> pSinkState;
|
|
CComPtr<IHsmSessionSinkEveryEvent> pSinkEvent;
|
|
CComPtr<IConnectionPointContainer> pCPC;
|
|
CComPtr<IConnectionPoint> pCP;
|
|
|
|
// Tell the session we are starting up.
|
|
m_JobState = HSM_JOB_STATE_STARTING;
|
|
WsbTrace(OLESTR("Before Process State.\n"));
|
|
WsbAffirmHr(pSession->ProcessState(m_JobPhase, m_JobState, m_CurrentPath, bLog));
|
|
WsbTrace(OLESTR("After Process State.\n"));
|
|
|
|
// Get the interface to the callback that the sessions should use.
|
|
WsbTrace(OLESTR("Before QI's for sinks.\n"));
|
|
WsbAffirmHr(((IUnknown*) (IHsmFsaTskMgr*) this)->QueryInterface(IID_IHsmSessionSinkEveryState, (void**) &pSinkState));
|
|
WsbAffirmHr(((IUnknown*) (IHsmFsaTskMgr*) this)->QueryInterface(IID_IHsmSessionSinkEveryEvent, (void**) &pSinkEvent));
|
|
WsbTrace(OLESTR("After QI's for sinks.\n"));
|
|
// Ask the session to advise of every state changes.
|
|
WsbTrace(OLESTR("Before QI for connection point containers.\n"));
|
|
WsbAffirmHr(pSession->QueryInterface(IID_IConnectionPointContainer, (void**) &pCPC));
|
|
WsbAffirmHr(pCPC->FindConnectionPoint(IID_IHsmSessionSinkEveryState, &pCP));
|
|
WsbAffirmHr(pCP->Advise(pSinkState, &m_StateCookie));
|
|
pCP = 0;
|
|
WsbAffirmHr(pCPC->FindConnectionPoint(IID_IHsmSessionSinkEveryEvent, &pCP));
|
|
WsbAffirmHr(pCP->Advise(pSinkEvent, &m_EventCookie));
|
|
pCP = 0;
|
|
WsbTrace(OLESTR("After Advises.\n"));
|
|
|
|
//
|
|
// Get the resource for this work from the session
|
|
//
|
|
WsbAffirmHr(pSession->GetResource(&m_pFsaResource));
|
|
|
|
// Since this is a new session, reset the counter that has become our bag start
|
|
// location
|
|
m_RemoteDataSetStart.QuadPart = 0;
|
|
|
|
m_JobState = HSM_JOB_STATE_ACTIVE;
|
|
WsbTrace(OLESTR("Before Process State.\n"));
|
|
WsbAffirmHr(pSession->ProcessState(m_JobPhase, m_JobState, m_CurrentPath, bLog));
|
|
WsbTrace(OLESTR("After Process State.\n"));
|
|
m_pSession = pSession;
|
|
|
|
}
|
|
|
|
} WsbCatch( hr );
|
|
|
|
WsbTraceOut(OLESTR("CHsmWorkQueue::CheckSession"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
|
|
return(hr);
|
|
|
|
}
|
|
|
|
HRESULT
|
|
CHsmWorkQueue::StartNewBag(
|
|
void
|
|
)
|
|
|
|
/*++
|
|
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CComPtr<IBagInfo> pBagInfo;
|
|
|
|
WsbTraceIn(OLESTR("CHsmWorkQueue::StartNewBag"),OLESTR(""));
|
|
try {
|
|
if (0 == m_RemoteDataSetStart.QuadPart) {
|
|
//
|
|
// Get a new ID
|
|
//
|
|
WsbAffirmHr(CoCreateGuid(&m_BagId));
|
|
|
|
// Add an entry into the Bag Info Table
|
|
FILETIME birthDate;
|
|
GUID resourceId;
|
|
|
|
WsbAffirmHr(m_pFsaResource->GetIdentifier(&resourceId));
|
|
|
|
WsbAffirmHr(m_pSegmentDb->GetEntity(m_pDbWorkSession, HSM_BAG_INFO_REC_TYPE, IID_IBagInfo,
|
|
(void**)&pBagInfo));
|
|
GetSystemTimeAsFileTime(&birthDate);
|
|
|
|
//??? what is the type for this bag? Need a define for Primary bag and Reorg bag
|
|
WsbAffirmHr(pBagInfo->SetBagInfo(HSM_BAG_STATUS_IN_PROGRESS, m_BagId, birthDate, 0, 0, resourceId, 0, 0));
|
|
WsbAffirmHr(pBagInfo->MarkAsNew());
|
|
WsbAffirmHr(pBagInfo->Write());
|
|
}
|
|
} WsbCatch( hr );
|
|
|
|
WsbTraceOut(OLESTR("CHsmWorkQueue::StartNewBag"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
|
|
return(hr);
|
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
CHsmWorkQueue::UpdateBagInfo(
|
|
IHsmWorkItem *pWorkItem
|
|
)
|
|
|
|
/*++
|
|
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CComPtr<IBagInfo> pBagInfo;
|
|
CComPtr<IFsaPostIt> pFsaWorkItem;
|
|
FSA_PLACEHOLDER placeholder;
|
|
|
|
WsbTraceIn(OLESTR("CHsmWorkQueue::UpdateBagInfo"),OLESTR(""));
|
|
try {
|
|
//
|
|
// Get the Bag id from the work item. It is in the placeholder
|
|
// information in the postit
|
|
//
|
|
WsbAffirmHr(pWorkItem->GetFsaPostIt(&pFsaWorkItem));
|
|
WsbAffirmHr(pFsaWorkItem->GetPlaceholder(&placeholder));
|
|
|
|
//
|
|
// Go to the Bag Info database and get the bag for this work
|
|
//
|
|
FILETIME pDummyFileTime;
|
|
|
|
GetSystemTimeAsFileTime(&pDummyFileTime);
|
|
|
|
WsbAffirmHr(m_pSegmentDb->GetEntity(m_pDbWorkSession, HSM_BAG_INFO_REC_TYPE, IID_IBagInfo,
|
|
(void**)&pBagInfo));
|
|
WsbAffirmHr(pBagInfo->SetBagInfo(HSM_BAG_STATUS_IN_PROGRESS, placeholder.bagId, pDummyFileTime, 0, 0, GUID_NULL, 0, 0 ));
|
|
WsbAffirmHr(pBagInfo->FindEQ());
|
|
|
|
// Update the bag Info table - mostly just change the size of the bag
|
|
FILETIME birthDate;
|
|
USHORT bagType;
|
|
GUID bagVolId;
|
|
LONGLONG bagLength;
|
|
LONGLONG requestSize;
|
|
LONGLONG deletedBagAmount;
|
|
SHORT remoteDataSet;
|
|
HSM_BAG_STATUS bagStatus;
|
|
GUID bagId;
|
|
|
|
WsbAffirmHr(pBagInfo->GetBagInfo(&bagStatus, &bagId, &birthDate, &bagLength, &bagType, &bagVolId, &deletedBagAmount, &remoteDataSet));
|
|
WsbAffirmHr(pFsaWorkItem->GetRequestSize(&requestSize));
|
|
bagLength += requestSize;
|
|
WsbAffirmHr(pBagInfo->SetBagInfo(bagStatus, bagId, birthDate, bagLength, bagType, bagVolId, deletedBagAmount, remoteDataSet));
|
|
WsbAffirmHr(pBagInfo->Write());
|
|
|
|
} WsbCatch(hr);
|
|
|
|
WsbTraceOut(OLESTR("CHsmWorkQueue::UpdateBagInfo"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
|
|
return(hr);
|
|
|
|
|
|
}
|
|
|
|
HRESULT
|
|
CHsmWorkQueue::CompleteBag( void )
|
|
/*++
|
|
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CComPtr<IBagInfo> pBagInfo;
|
|
|
|
WsbTraceIn(OLESTR("CHsmWorkQueue::CompleteBag"),OLESTR(""));
|
|
try {
|
|
//
|
|
// Go to the Bag Info database and get the bag for this work
|
|
//
|
|
FILETIME pDummyFileTime;
|
|
|
|
GetSystemTimeAsFileTime(&pDummyFileTime);
|
|
|
|
WsbAffirmHr(m_pSegmentDb->GetEntity(m_pDbWorkSession, HSM_BAG_INFO_REC_TYPE, IID_IBagInfo,
|
|
(void**)&pBagInfo));
|
|
WsbAffirmHr(pBagInfo->SetBagInfo(HSM_BAG_STATUS_IN_PROGRESS, m_BagId, pDummyFileTime, 0, 0, GUID_NULL, 0, 0 ));
|
|
WsbAffirmHr(pBagInfo->FindEQ());
|
|
|
|
// Update the bag Info table - mostly just change the size of the bag
|
|
FILETIME birthDate;
|
|
USHORT bagType;
|
|
GUID bagVolId;
|
|
LONGLONG bagLength;
|
|
LONGLONG deletedBagAmount;
|
|
SHORT remoteDataSet;
|
|
HSM_BAG_STATUS bagStatus;
|
|
GUID bagId;
|
|
|
|
WsbAffirmHr(pBagInfo->GetBagInfo(&bagStatus, &bagId, &birthDate, &bagLength, &bagType, &bagVolId, &deletedBagAmount, &remoteDataSet));
|
|
WsbAffirmHr(pBagInfo->SetBagInfo(HSM_BAG_STATUS_COMPLETED, bagId, birthDate, bagLength, bagType, bagVolId, deletedBagAmount, remoteDataSet));
|
|
WsbAffirmHr(pBagInfo->Write());
|
|
|
|
} WsbCatch(hr);
|
|
|
|
WsbTraceOut(OLESTR("CHsmWorkQueue::CompleteBag"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
|
|
return(hr);
|
|
|
|
|
|
}
|
|
|
|
HRESULT
|
|
CHsmWorkQueue::DoWork( void )
|
|
/*++
|
|
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CWsbStringPtr path;
|
|
CComPtr<IHsmWorkItem> pWorkItem;
|
|
CComPtr<IFsaPostIt> pFsaWorkItem;
|
|
CComPtr<IHsmSession> pSaveSessionPtr;
|
|
HSM_WORK_ITEM_TYPE workType;
|
|
BOOLEAN done = FALSE;
|
|
BOOLEAN OpenedDb = FALSE;
|
|
HRESULT skipWork = S_FALSE;
|
|
|
|
WsbTraceIn(OLESTR("CHsmWorkQueue::DoWork"),OLESTR(""));
|
|
|
|
// Make sure this object isn't released (and our thread killed
|
|
// before finishing up in this routine
|
|
((IUnknown*)(IHsmWorkQueue*)this)->AddRef();
|
|
|
|
try {
|
|
while (!done) {
|
|
BOOL WaitForMore = FALSE;
|
|
|
|
//
|
|
// Get the next work to do from the queue
|
|
//
|
|
hr = m_pWorkToDo->First(IID_IHsmWorkItem, (void **)&pWorkItem);
|
|
if (WSB_E_NOTFOUND == hr) {
|
|
// There are no entries in the queue so sleep and check
|
|
// again later
|
|
WaitForMore = TRUE;
|
|
hr = S_OK;
|
|
} else if (hr == S_OK) {
|
|
hr = CheckMigrateMinimums();
|
|
if (S_FALSE == hr) {
|
|
WaitForMore = TRUE;
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
WsbAffirmHr(hr);
|
|
|
|
if (WaitForMore) {
|
|
if (OpenedDb) {
|
|
//
|
|
// Close the db before we wait for more work
|
|
//
|
|
hr = m_pSegmentDb->Close(m_pDbWorkSession);
|
|
OpenedDb = FALSE;
|
|
m_pDbWorkSession = 0;
|
|
}
|
|
Sleep(1000);
|
|
} else {
|
|
if (!OpenedDb) {
|
|
//
|
|
// Open DB for this thread
|
|
//
|
|
hr = m_pSegmentDb->Open(&m_pDbWorkSession);
|
|
if (S_OK == hr) {
|
|
WsbTrace(OLESTR("CHsmWorkQueue::DoWork - Database Opened OK\n"));
|
|
OpenedDb = TRUE;
|
|
} else {
|
|
//
|
|
// We cannot open the database - this is a catastrophic
|
|
// problem. So skip all work in the queue
|
|
//
|
|
WsbTrace(OLESTR("CHsmWorkQueue::DoWork - Database Opened failed with hr = <%ls>\n"), WsbHrAsString(hr));
|
|
skipWork = HSM_E_WORK_SKIPPED_DATABASE_ACCESS;
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
|
|
WsbAffirmHr(pWorkItem->GetWorkType(&workType));
|
|
switch (workType) {
|
|
case HSM_WORK_ITEM_FSA_DONE: {
|
|
BOOL bNoDelay = FALSE; // whether to dismount immediately
|
|
|
|
//
|
|
// There is no more work to do for this queue
|
|
//
|
|
WsbTrace(OLESTR("CHsmWorkQueue::DoWork - FSA WORK DONE\n"));
|
|
|
|
//
|
|
// Finish any work that needs to be committed
|
|
// Mark the bag as complete if we are premigrating
|
|
//
|
|
if (HSM_JOB_ACTION_PREMIGRATE == m_JobAction) {
|
|
try {
|
|
WsbAffirmHr(CommitWork());
|
|
WsbAffirmHr(CompleteBag());
|
|
//
|
|
// Now save the databases at the end of the bag
|
|
// But make sure the begin session was OK.
|
|
// Note: even if there were errors while storing the data, we still want to try
|
|
// keeping the databases on the media, because some files were migrated
|
|
//
|
|
if (m_StoreDatabasesInBags && (S_OK == m_BeginSessionHr)) {
|
|
WsbAffirmHr(StoreDatabasesOnMedia());
|
|
}
|
|
} WsbCatch( hr );
|
|
|
|
// In case of premigrate - dismount immediately
|
|
bNoDelay = TRUE;
|
|
}
|
|
|
|
if (HSM_E_WORK_SKIPPED_CANCELLED == skipWork) {
|
|
//
|
|
// Let them know we are cancelled
|
|
//
|
|
(void)SetState(HSM_JOB_STATE_CANCELLED);
|
|
} else {
|
|
(void)SetState(HSM_JOB_STATE_DONE);
|
|
}
|
|
pSaveSessionPtr = m_pSession;
|
|
Remove(pWorkItem);
|
|
|
|
EndSessions(FALSE, bNoDelay);
|
|
|
|
// Close the DB
|
|
if (OpenedDb) {
|
|
WsbTrace(OLESTR("CHsmWorkQueue::DoWork - Closing the database\n"));
|
|
m_pSegmentDb->Close(m_pDbWorkSession);
|
|
OpenedDb = FALSE;
|
|
m_pDbWorkSession = 0;
|
|
}
|
|
m_pTskMgr->WorkQueueDone(pSaveSessionPtr, m_QueueType, NULL);
|
|
done = TRUE;
|
|
break;
|
|
}
|
|
|
|
case HSM_WORK_ITEM_FSA_WORK: {
|
|
if (S_FALSE == skipWork) {
|
|
//
|
|
// Get the FSA Work Item and do the work
|
|
//
|
|
hr = DoFsaWork(pWorkItem);
|
|
if (hr == RPC_E_DISCONNECTED) {
|
|
//
|
|
// This is a problem case. This means the FSA has done away with
|
|
// the recall. We would not be able process this recall any more.
|
|
// Just bail out.
|
|
//
|
|
WsbLogEvent(HSM_MESSAGE_ABORTING_RECALL_QUEUE,
|
|
0, NULL,NULL);
|
|
//
|
|
// Indicate we're done
|
|
//
|
|
(void)SetState(HSM_JOB_STATE_DONE);
|
|
pSaveSessionPtr = m_pSession;
|
|
Remove(pWorkItem);
|
|
// Clear out any remaining items in the queue.
|
|
do {
|
|
hr = m_pWorkToDo->First(IID_IHsmWorkItem, (void **)&pWorkItem) ;
|
|
if (hr == S_OK) {
|
|
Remove(pWorkItem);
|
|
}
|
|
} while (hr == S_OK);
|
|
|
|
EndSessions(FALSE, FALSE);
|
|
|
|
//
|
|
// Close the DB
|
|
//
|
|
if (OpenedDb) {
|
|
WsbTrace(OLESTR("CHsmWorkQueue::DoWork - Closing the database\n")) ;
|
|
m_pSegmentDb->Close(m_pDbWorkSession);
|
|
OpenedDb = FALSE;
|
|
m_pDbWorkSession = 0;
|
|
}
|
|
|
|
//
|
|
// Finish with the queue & get out
|
|
//
|
|
m_pTskMgr->WorkQueueDone(pSaveSessionPtr, m_QueueType, NULL);
|
|
done = TRUE;
|
|
} else {
|
|
(void)Remove(pWorkItem);
|
|
}
|
|
} else {
|
|
//
|
|
// Skip the work
|
|
//
|
|
try {
|
|
CComPtr<IFsaScanItem> pScanItem;
|
|
|
|
WsbAffirmHr(pWorkItem->GetFsaPostIt(&pFsaWorkItem));
|
|
WsbAffirmHr(GetScanItem(pFsaWorkItem, &pScanItem));
|
|
|
|
WsbAffirmHr(pFsaWorkItem->GetRequestAction(&m_RequestAction));
|
|
if ((m_RequestAction == FSA_REQUEST_ACTION_FILTER_RECALL) ||
|
|
(m_RequestAction == FSA_REQUEST_ACTION_FILTER_READ) ||
|
|
(m_RequestAction == FSA_REQUEST_ACTION_RECALL)) {
|
|
hr = pFsaWorkItem->SetResult(skipWork);
|
|
if (S_OK == hr) {
|
|
WsbTrace(OLESTR("HSM recall (filter, read or recall) complete, calling FSA\n"));
|
|
hr = m_pFsaResource->ProcessResult(pFsaWorkItem);
|
|
WsbTrace(OLESTR("FSA ProcessResult returned <%ls>\n"), WsbHrAsString(hr));
|
|
}
|
|
}
|
|
|
|
// Avoid logging errors if job is just cancelled
|
|
if (HSM_E_WORK_SKIPPED_CANCELLED != skipWork) {
|
|
(void)m_pSession->ProcessHr(m_JobPhase, 0, 0, hr);
|
|
}
|
|
|
|
WsbAffirmHr(m_pSession->ProcessItem(m_JobPhase,
|
|
m_JobAction, pScanItem, skipWork));
|
|
|
|
} WsbCatch( hr );
|
|
|
|
(void)Remove(pWorkItem);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case HSM_WORK_ITEM_MOVER_CANCELLED: {
|
|
WsbTrace(OLESTR("CHsmWorkQueue::DoWork - Mover Cancelled\n"));
|
|
try {
|
|
//
|
|
// We are cancelled, so skip all of the rest of the
|
|
// work in the queue
|
|
//
|
|
WsbAffirmHr(MarkQueueAsDone());
|
|
//
|
|
// Remove the cancelled work item
|
|
//
|
|
Remove(pWorkItem);
|
|
//
|
|
// Skip any other work to do
|
|
//
|
|
skipWork = HSM_E_WORK_SKIPPED_CANCELLED;
|
|
|
|
} WsbCatch( hr );
|
|
break;
|
|
}
|
|
|
|
default: {
|
|
hr = E_UNEXPECTED;
|
|
break;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
pSaveSessionPtr = 0;
|
|
pWorkItem = 0;
|
|
pFsaWorkItem = 0;
|
|
|
|
if (m_TerminateQueue) {
|
|
// signaled to terminate the working thread (should be trigerred only in shutdown cases)
|
|
done = TRUE;
|
|
}
|
|
}
|
|
|
|
} WsbCatch( hr );
|
|
|
|
if (OpenedDb) {
|
|
WsbTrace(OLESTR("CHsmWorkQueue::DoWork - Closing the database\n"));
|
|
m_pSegmentDb->Close(m_pDbWorkSession);
|
|
OpenedDb = FALSE;
|
|
m_pDbWorkSession = 0;
|
|
}
|
|
|
|
// Pretend everything is OK
|
|
hr = S_OK;
|
|
|
|
// Release the thread (the thread should terminate on exit
|
|
// from the routine that called this routine)
|
|
// In case of termination, the terminating thread will close the handle
|
|
if (! m_TerminateQueue) {
|
|
CloseHandle(m_WorkerThread);
|
|
m_WorkerThread = 0;
|
|
}
|
|
|
|
// Allow this object to be released
|
|
((IUnknown*)(IHsmWorkQueue*)this)->Release();
|
|
|
|
WsbTraceOut(OLESTR("CHsmWorkQueue::DoWork"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
|
|
return(hr);
|
|
|
|
}
|
|
|
|
HRESULT
|
|
CHsmWorkQueue::DoFsaWork(
|
|
IHsmWorkItem *pWorkItem
|
|
)
|
|
/*++
|
|
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
HRESULT workHr = S_OK;
|
|
HRESULT originalHr = S_OK;
|
|
|
|
CWsbStringPtr path;
|
|
FSA_RESULT_ACTION resultAction;
|
|
CComPtr<IFsaPostIt> pFsaWorkItem;
|
|
LONGLONG requestSize;
|
|
|
|
WsbTraceIn(OLESTR("CHsmWorkQueue::DoFsaWork"),OLESTR(""));
|
|
try {
|
|
CComPtr<IFsaScanItem> pScanItem;
|
|
|
|
//
|
|
// Do the work.
|
|
//
|
|
WsbAffirmHr(pWorkItem->GetFsaPostIt(&pFsaWorkItem));
|
|
try {
|
|
WsbAffirmHr(pFsaWorkItem->GetRequestAction(&m_RequestAction));
|
|
WsbAffirmHr(pFsaWorkItem->GetPath(&path, 0));
|
|
WsbAffirmHr(GetScanItem(pFsaWorkItem, &pScanItem));
|
|
} WsbCatchAndDo (hr,
|
|
originalHr = hr;
|
|
|
|
// Not-found error is expected if the file was renamed or deleted after
|
|
// the FSA scanning. There is no need to log an error.
|
|
if (hr != WSB_E_NOTFOUND) {
|
|
if (path == NULL){
|
|
WsbLogEvent(HSM_MESSAGE_PROCESS_WORK_ITEM_ERROR,
|
|
sizeof(m_RequestAction), &m_RequestAction, OLESTR("Path is NULL"),
|
|
WsbHrAsString(hr), NULL);
|
|
} else {
|
|
WsbLogEvent(HSM_MESSAGE_PROCESS_WORK_ITEM_ERROR,
|
|
sizeof(m_RequestAction), &m_RequestAction, (WCHAR *)path,
|
|
WsbHrAsString(hr), NULL);
|
|
}
|
|
}
|
|
|
|
// Report back to FSA on the error unless the error indiactes
|
|
// lost of connection with FSA.
|
|
if (hr != RPC_E_DISCONNECTED) {
|
|
hr = pFsaWorkItem->SetResult(hr);
|
|
if (hr != RPC_E_DISCONNECTED) {
|
|
hr = m_pFsaResource->ProcessResult(pFsaWorkItem);
|
|
}
|
|
}
|
|
);
|
|
|
|
if (originalHr != S_OK) {
|
|
goto my_try_exit;
|
|
}
|
|
|
|
WsbTrace(OLESTR("Handling file <%s>.\n"), WsbAbbreviatePath(path, 120));
|
|
switch (m_RequestAction) {
|
|
case FSA_REQUEST_ACTION_DELETE:
|
|
m_JobAction = HSM_JOB_ACTION_DELETE;
|
|
hr = E_NOTIMPL;
|
|
break;
|
|
case FSA_REQUEST_ACTION_PREMIGRATE:
|
|
m_JobAction = HSM_JOB_ACTION_PREMIGRATE;
|
|
WsbAffirmHr(pFsaWorkItem->GetRequestSize(&requestSize));
|
|
workHr = PremigrateIt(pFsaWorkItem);
|
|
//
|
|
// Fill in the work item, placeholder information in
|
|
// postit is set by premigrate code.
|
|
//
|
|
WsbAffirmHr(pWorkItem->SetResult(workHr));
|
|
if (S_OK == workHr) {
|
|
WsbAffirmHr(pWorkItem->SetMediaInfo(m_MediaId, m_MediaUpdate, m_BadMedia,
|
|
m_MediaReadOnly, m_MediaFreeSpace, m_RemoteDataSet));
|
|
WsbAffirmHr(pWorkItem->SetFsaResource(m_pFsaResource));
|
|
//
|
|
// Copy the work item to the work in waiting queue
|
|
//
|
|
WsbAffirmHr(CopyToWaitingQueue(pWorkItem));
|
|
if (S_OK == TimeToCommit()) {
|
|
workHr = CommitWork();
|
|
}
|
|
} else {
|
|
WsbTrace(OLESTR("Failed premigrate work.\n"));
|
|
if (pScanItem) {
|
|
WsbAffirmHr(m_pSession->ProcessItem(m_JobPhase,
|
|
m_JobAction, pScanItem, workHr));
|
|
}
|
|
|
|
//
|
|
// An item that was changed while waiting to be migrated is not really an error -
|
|
// the item is just skipped. Change hr here to avoid unnecessary error message
|
|
// and unnecessary count as error in ShouldJobContinue
|
|
// Same is true for file-too-big error
|
|
//
|
|
if ((HSM_E_FILE_CHANGED == workHr) || (HSM_E_WORK_SKIPPED_FILE_TOO_BIG == workHr)) {
|
|
workHr = S_OK;
|
|
}
|
|
}
|
|
break;
|
|
case FSA_REQUEST_ACTION_FILTER_RECALL:
|
|
case FSA_REQUEST_ACTION_FILTER_READ:
|
|
case FSA_REQUEST_ACTION_RECALL:
|
|
m_JobAction = HSM_JOB_ACTION_RECALL;
|
|
workHr = RecallIt(pFsaWorkItem);
|
|
//
|
|
// Tell the recaller right away about the success or failure
|
|
// of the recall, we do this here so the recall filter can
|
|
// release the open as soon as possible
|
|
//
|
|
hr = pFsaWorkItem->SetResult(workHr);
|
|
if (S_OK == hr) {
|
|
WsbTrace(OLESTR("HSM recall (filter, read or recall) complete, calling FSA\n"));
|
|
hr = m_pFsaResource->ProcessResult(pFsaWorkItem);
|
|
WsbTrace(OLESTR("FSA ProcessResult returned <%ls>\n"), WsbHrAsString(hr));
|
|
}
|
|
break;
|
|
case FSA_REQUEST_ACTION_VALIDATE:
|
|
m_JobAction = HSM_JOB_ACTION_VALIDATE;
|
|
workHr = validateIt(pFsaWorkItem);
|
|
if (S_OK == workHr) {
|
|
WsbAffirmHr(pFsaWorkItem->GetResultAction(&resultAction));
|
|
if (FSA_RESULT_ACTION_NONE != resultAction) {
|
|
WsbTrace(OLESTR("HSM validate complete, calling FSA\n"));
|
|
hr = m_pFsaResource->ProcessResult(pFsaWorkItem);
|
|
WsbTrace(OLESTR("FSA ProcessResult returned <%ls>\n"), WsbHrAsString(hr));
|
|
}
|
|
}
|
|
//
|
|
// Tell the session whether or not the work was done.
|
|
//
|
|
// For validate, we may not have a scan item
|
|
//
|
|
if (pScanItem) {
|
|
WsbTrace(OLESTR("Tried HSM work, calling Session to Process Item\n"));
|
|
m_pSession->ProcessItem(m_JobPhase, m_JobAction, pScanItem, workHr);
|
|
} else {
|
|
WsbTrace(OLESTR("Couldn't get scan item for validation.\n"));
|
|
}
|
|
break;
|
|
case FSA_REQUEST_ACTION_VALIDATE_FOR_TRUNCATE: {
|
|
HRESULT truncateHr = S_OK;
|
|
|
|
m_JobAction = HSM_JOB_ACTION_VALIDATE;
|
|
workHr = validateIt(pFsaWorkItem);
|
|
if (S_OK == workHr) {
|
|
WsbAffirmHr(pFsaWorkItem->GetResultAction(&resultAction));
|
|
if (resultAction == FSA_RESULT_ACTION_VALIDATE_BAD) {
|
|
WsbAffirmHr( pFsaWorkItem->SetResultAction( FSA_RESULT_ACTION_VALIDATE_FOR_TRUNCATE_BAD ));
|
|
resultAction = FSA_RESULT_ACTION_VALIDATE_FOR_TRUNCATE_BAD;
|
|
}
|
|
if (resultAction == FSA_RESULT_ACTION_VALIDATE_OK) {
|
|
WsbAffirmHr( pFsaWorkItem->SetResultAction( FSA_RESULT_ACTION_VALIDATE_FOR_TRUNCATE_OK ));
|
|
resultAction = FSA_RESULT_ACTION_VALIDATE_FOR_TRUNCATE_OK;
|
|
}
|
|
|
|
if (FSA_RESULT_ACTION_NONE != resultAction) {
|
|
WsbTrace(OLESTR("HSM validate for truncate complete, calling FSA\n"));
|
|
hr = m_pFsaResource->ProcessResult(pFsaWorkItem);
|
|
WsbTrace(OLESTR("FSA ProcessResult returned <%ls>\n"), WsbHrAsString(hr));
|
|
|
|
if (resultAction == FSA_RESULT_ACTION_VALIDATE_FOR_TRUNCATE_OK) {
|
|
// Analyze result of truncation: for expected errors, such as file-changed, set to S_FALSE
|
|
// in order to signal skipping, otherwize leave original error/success code
|
|
switch (hr) {
|
|
case FSA_E_ITEMCHANGED:
|
|
case FSA_E_ITEMINUSE:
|
|
case FSA_E_NOTMANAGED:
|
|
case FSA_E_FILE_ALREADY_MANAGED:
|
|
truncateHr = S_FALSE;
|
|
break;
|
|
default:
|
|
truncateHr = hr;
|
|
break;
|
|
}
|
|
} else if (resultAction == FSA_RESULT_ACTION_VALIDATE_FOR_TRUNCATE_BAD) {
|
|
// Set truncateHr to S_FALSE to signal for skipping this file in regards to truncation
|
|
truncateHr = S_FALSE;
|
|
}
|
|
}
|
|
}
|
|
//
|
|
// Tell the session whether or not the work was done.
|
|
//
|
|
// For validate, we may not have a scan item
|
|
//
|
|
if (pScanItem) {
|
|
WsbTrace(OLESTR("Tried HSM work, calling Session to Process Item\n"));
|
|
//
|
|
// For validate, the work-hr is always set to OK, therefore report on the truncate-hr instead
|
|
//
|
|
m_pSession->ProcessItem(m_JobPhase, m_JobAction, pScanItem, truncateHr);
|
|
} else {
|
|
WsbTrace(OLESTR("Couldn't get scan item for validation.\n"));
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
m_JobAction = HSM_JOB_ACTION_UNKNOWN;
|
|
hr = E_NOTIMPL;
|
|
break;
|
|
}
|
|
|
|
if (S_OK != workHr) {
|
|
|
|
// Replace to a specific RSS error codes for some errors
|
|
switch (HRESULT_CODE(workHr)) {
|
|
case ERROR_LOCK_VIOLATION:
|
|
workHr = HSM_E_FILE_LOCK_VIOLATION;
|
|
break;
|
|
case ERROR_SHARING_VIOLATION:
|
|
workHr = HSM_E_FILE_SHARING_VIOLATION;
|
|
break;
|
|
}
|
|
|
|
// Tell the session how things went if they didn't go well.
|
|
(void) m_pSession->ProcessHr(m_JobPhase, 0, 0, workHr);
|
|
}
|
|
|
|
//
|
|
// Now, evaluate the work result to see if we should fail the job.
|
|
//
|
|
(void)ShouldJobContinue(workHr);
|
|
|
|
my_try_exit:
|
|
;
|
|
} WsbCatch(hr);
|
|
|
|
WsbTraceOut(OLESTR("CHsmWorkQueue::DoFsaWork"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
|
|
return(hr);
|
|
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CHsmWorkQueue::UpdateMetaData(
|
|
IHsmWorkItem *pWorkItem
|
|
)
|
|
|
|
/*++
|
|
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
BOOL transactionBegun = FALSE;
|
|
|
|
WsbTraceIn(OLESTR("CHsmWorkQueue::UpdateMetaData"),OLESTR(""));
|
|
try {
|
|
//
|
|
// Start transaction
|
|
//
|
|
WsbAffirmHr(m_pDbWorkSession->TransactionBegin());
|
|
transactionBegun = TRUE;
|
|
|
|
//
|
|
// Update the various metadata records
|
|
//
|
|
WsbAffirmHr(UpdateBagInfo(pWorkItem));
|
|
WsbAffirmHr(UpdateSegmentInfo(pWorkItem));
|
|
WsbAffirmHr(UpdateMediaInfo(pWorkItem));
|
|
|
|
//
|
|
// End transaction
|
|
//
|
|
WsbAffirmHr(m_pDbWorkSession->TransactionEnd());
|
|
transactionBegun = FALSE;
|
|
|
|
} WsbCatchAndDo( hr, if (transactionBegun == TRUE) {m_pDbWorkSession->TransactionCancel();});
|
|
|
|
WsbTraceOut(OLESTR("CHsmWorkQueue::UpdateMetaData"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
|
|
return(hr);
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
CHsmWorkQueue::UpdateSegmentInfo(
|
|
IHsmWorkItem *pWorkItem
|
|
)
|
|
|
|
/*++
|
|
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
WsbTraceIn(OLESTR("CHsmWorkQueue::UpdateSegmentInfo"),OLESTR(""));
|
|
try {
|
|
// Add a record to the segment database or extend an existing one
|
|
CComQIPtr<ISegDb, &IID_ISegDb> pSegDb = m_pSegmentDb;
|
|
BOOLEAN done = FALSE;
|
|
FSA_PLACEHOLDER placeholder;
|
|
CComPtr<IFsaPostIt> pFsaWorkItem;
|
|
|
|
//
|
|
// Get the placeholder information from the postit in the work item
|
|
//
|
|
WsbAffirmHr(pWorkItem->GetFsaPostIt(&pFsaWorkItem));
|
|
WsbAffirmHr(pFsaWorkItem->GetPlaceholder(&placeholder));
|
|
WsbAssert(0 != m_RemoteDataSetStart.QuadPart, WSB_E_INVALID_DATA);
|
|
|
|
WsbTrace(OLESTR("Adding SegmentRecord: <%ls>, <%ls>, <%ls>\n"),
|
|
WsbGuidAsString(placeholder.bagId),
|
|
WsbStringCopy(WsbLonglongAsString(placeholder.fileStart)),
|
|
WsbStringCopy(WsbLonglongAsString(placeholder.fileSize)));
|
|
WsbAffirmHr(pSegDb->SegAdd(m_pDbWorkSession, placeholder.bagId, placeholder.fileStart,
|
|
placeholder.fileSize, m_MediaId, m_RemoteDataSetStart.QuadPart));
|
|
|
|
} WsbCatch( hr );
|
|
|
|
WsbTraceOut(OLESTR("CHsmWorkQueue::UpdateSegmentInfo"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
|
|
return(hr);
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
CHsmWorkQueue::UpdateMediaInfo(
|
|
IHsmWorkItem *pWorkItem
|
|
)
|
|
|
|
/*++
|
|
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
WsbTraceIn(OLESTR("CHsmWorkQueue::UpdateMediaInfo"),OLESTR(""));
|
|
try
|
|
{
|
|
LONGLONG mediaCapacity;
|
|
CComPtr<IFsaPostIt> pFsaWorkItem;
|
|
CComPtr<IMediaInfo> pMediaInfo;
|
|
GUID l_MediaId; // HSM Engine Media ID
|
|
FILETIME l_MediaLastUpdate; // Last update of copy
|
|
HRESULT l_MediaLastError; // S_OK or the last exception
|
|
// ..encountered when accessing
|
|
// ..the media
|
|
BOOL l_MediaRecallOnly; // True if no more data is to
|
|
// ..be premigrated to the media
|
|
// ..Set by internal operations,
|
|
// ..may not be changed externally
|
|
LONGLONG l_MediaFreeBytes; // Real free space on media
|
|
short l_MediaRemoteDataSet;
|
|
HRESULT currentMediaLastError;
|
|
|
|
//
|
|
// Get the PostIt and the media information for the work item
|
|
//
|
|
WsbAffirmHr(pWorkItem->GetFsaPostIt(&pFsaWorkItem));
|
|
WsbAffirmHr(pWorkItem->GetMediaInfo(&l_MediaId, &l_MediaLastUpdate,
|
|
&l_MediaLastError, &l_MediaRecallOnly,
|
|
&l_MediaFreeBytes, &l_MediaRemoteDataSet));
|
|
//
|
|
// Update the media information with the name, used space, and free space of
|
|
// the media.
|
|
//
|
|
WsbAffirmHr(m_pSegmentDb->GetEntity(m_pDbWorkSession, HSM_MEDIA_INFO_REC_TYPE, IID_IMediaInfo,
|
|
(void**)&pMediaInfo));
|
|
|
|
WsbAffirmHr(pMediaInfo->SetId(l_MediaId));
|
|
WsbAffirmHr(pMediaInfo->FindEQ());
|
|
WsbAffirmHr(pMediaInfo->SetUpdate(l_MediaLastUpdate));
|
|
WsbAffirmHr(pMediaInfo->SetFreeBytes(l_MediaFreeBytes));
|
|
WsbAffirmHr(pMediaInfo->SetNextRemoteDataSet(l_MediaRemoteDataSet));
|
|
|
|
// Avoid setting last error if the existing one already indicates an error
|
|
WsbAffirmHr(pMediaInfo->GetLastError(¤tMediaLastError));
|
|
if (SUCCEEDED(currentMediaLastError)) {
|
|
WsbAffirmHr(pMediaInfo->SetLastError(l_MediaLastError));
|
|
}
|
|
|
|
// Mark the media as RecallOnly if it's mostly full (passed the high watermark level)
|
|
WsbAffirmHr(pMediaInfo->GetCapacity(&mediaCapacity));
|
|
if (l_MediaRecallOnly || (l_MediaFreeBytes < ((mediaCapacity * m_MaxFreeSpaceInFullMedia) / 100) )) {
|
|
WsbAffirmHr(pMediaInfo->SetRecallOnlyStatus(TRUE));
|
|
|
|
WsbTrace(OLESTR("CHsmWorkQueue::UpdateMediaInfo: Marking media as Recall Only - Capacity = %I64d, Free Bytes = %I64d\n"),
|
|
mediaCapacity, l_MediaFreeBytes);
|
|
|
|
/*** If we like to allocate immediately a second side of a full meida, than the code below should be completed...
|
|
if (S_OK == m_pRmsServer->IsMultipleSidedMedia(m_RmsMediaSetId)) {
|
|
|
|
// Check if second size is avalaible for allocation
|
|
|
|
// Allocate (non-blocking) the second side
|
|
|
|
} ***/
|
|
|
|
}
|
|
WsbAffirmHr(pMediaInfo->UpdateLastKnownGoodMaster());
|
|
WsbAffirmHr(pMediaInfo->Write());
|
|
|
|
} WsbCatch( hr );
|
|
|
|
WsbTraceOut(OLESTR("CHsmWorkQueue::UpdateMediaInfo"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
|
|
return(hr);
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
CHsmWorkQueue::GetMediaSet(
|
|
IFsaPostIt *pFsaWorkItem
|
|
)
|
|
|
|
/*++
|
|
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
GUID storagePoolId;
|
|
|
|
WsbTraceIn(OLESTR("CHsmWorkQueue::GetMediaSet"),OLESTR(""));
|
|
try {
|
|
CComPtr<IHsmStoragePool> pStoragePool1;
|
|
CComPtr<IHsmStoragePool> pStoragePool2;
|
|
WsbAffirmHr(m_pHsmServerCreate->CreateInstance(CLSID_CHsmStoragePool, IID_IHsmStoragePool,
|
|
(void **)&pStoragePool1));
|
|
WsbAffirmHr(pFsaWorkItem->GetStoragePoolId(&storagePoolId));
|
|
WsbAffirmHr(pStoragePool1->SetId(storagePoolId));
|
|
WsbAffirmHr(m_pStoragePools->Find(pStoragePool1, IID_IHsmStoragePool, (void **) &pStoragePool2));
|
|
//
|
|
// If the storage pool cannot be found, make it a meaningful message
|
|
//
|
|
m_RmsMediaSetName.Free();
|
|
hr = pStoragePool2->GetMediaSet(&m_RmsMediaSetId, &m_RmsMediaSetName);
|
|
if (S_OK != hr) {
|
|
hr = HSM_E_STG_PL_NOT_FOUND;
|
|
}
|
|
|
|
} WsbCatch( hr );
|
|
|
|
WsbTraceOut(OLESTR("CHsmWorkQueue::GetMediaSet"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CHsmWorkQueue::FindMigrateMediaToUse(
|
|
IFsaPostIt *pFsaWorkItem,
|
|
GUID *pMediaToUse,
|
|
GUID *pFirstSideToUse,
|
|
BOOL *pMediaChanged,
|
|
LONGLONG *pRequiredSize
|
|
)
|
|
|
|
/*++
|
|
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
WsbTraceIn(OLESTR("CHsmWorkQueue::FindMigrateMediaToUse"),OLESTR(""));
|
|
try {
|
|
BOOLEAN found = FALSE;
|
|
GUID mediaId;
|
|
GUID storageId;
|
|
GUID storagePoolId;
|
|
CComPtr<IMediaInfo> pMediaInfo;
|
|
LONGLONG requestSize;
|
|
|
|
DWORD dwMediaCount= 0;
|
|
|
|
// data of alternative (offline or busy) media to use
|
|
GUID alternativeMediaId = GUID_NULL;
|
|
GUID alternativeMediaToUse = GUID_NULL;
|
|
CWsbStringPtr alternativeMediaName;
|
|
HSM_JOB_MEDIA_TYPE alternativeMediaType = HSM_JOB_MEDIA_TYPE_UNKNOWN;
|
|
SHORT alternativeRemoteDataSet= 0;
|
|
|
|
// data of meida candidates for second-side allocation
|
|
BOOL bTwoSidedMedias = FALSE;
|
|
CComPtr<IWsbCollection> pFirstSideCollection;
|
|
CComPtr<IWsbGuid> pFirstSideGuid;
|
|
GUID firstSideGuid;
|
|
|
|
|
|
WsbAssert(pMediaToUse != 0, E_POINTER);
|
|
*pMediaToUse = GUID_NULL;
|
|
WsbAssert(pFirstSideToUse != 0, E_POINTER);
|
|
*pFirstSideToUse = GUID_NULL;
|
|
WsbAssert(pMediaChanged != 0, E_POINTER);
|
|
*pMediaChanged = FALSE;
|
|
WsbAssert(pRequiredSize != 0, E_POINTER);
|
|
*pRequiredSize = 0;
|
|
|
|
// Determine how much space we need on the media for this file
|
|
// (we add some for overhead)
|
|
WsbAffirmHr(pFsaWorkItem->GetRequestSize(&requestSize));
|
|
requestSize += HSM_STORAGE_OVERHEAD;
|
|
*pRequiredSize = (requestSize * 100) / (100 - m_MinFreeSpaceInFullMedia); // relevant for new media
|
|
WsbTrace(OLESTR("CHsmWorkQueue::FindMigrateMediaToUse: size needed (with overhead) =%ls, free space on media = %ls\n"),
|
|
WsbQuickString(WsbLonglongAsString(requestSize)),
|
|
WsbQuickString(WsbLonglongAsString(m_MediaFreeSpace)));
|
|
|
|
// Set up for search
|
|
WsbAffirmHr(m_pSegmentDb->GetEntity(m_pDbWorkSession, HSM_MEDIA_INFO_REC_TYPE, IID_IMediaInfo,
|
|
(void**)&pMediaInfo));
|
|
WsbAffirmHr(pFsaWorkItem->GetStoragePoolId(&storagePoolId));
|
|
|
|
// If we already have media mounted, use it if possible
|
|
if (GUID_NULL != m_MountedMedia && !m_MediaReadOnly &&
|
|
(m_MediaFreeSpace > requestSize) &&
|
|
((m_MediaFreeSpace - requestSize) > ((m_MediaCapacity * m_MinFreeSpaceInFullMedia) / 100)) ) {
|
|
|
|
// Make sure the storage pool is correct
|
|
WsbAffirmHr(pMediaInfo->SetId(m_MediaId));
|
|
WsbAffirmHr(pMediaInfo->FindEQ());
|
|
WsbAffirmHr(pMediaInfo->GetStoragePoolId(&storageId));
|
|
if ((storageId == storagePoolId)) {
|
|
found = TRUE;
|
|
}
|
|
}
|
|
|
|
if (!found) {
|
|
// Not found ==> going to use a new media
|
|
*pMediaChanged = TRUE;
|
|
|
|
// If there's currently a mounted media and we aren't going to use it,
|
|
// make sure work is committed and media is dismounted
|
|
if (GUID_NULL != m_MountedMedia) {
|
|
WsbTrace(OLESTR("CHsmWorkQueue::FindMigrateMediaToUse: Dismounting current media - Capacity = %I64d, Free Bytes = %I64d\n"),
|
|
m_MediaCapacity, m_MediaFreeSpace);
|
|
|
|
WsbAffirmHr(CommitWork());
|
|
WsbAffirmHr(DismountMedia(TRUE));
|
|
}
|
|
}
|
|
|
|
// Search for a media
|
|
if (!found) {
|
|
LONGLONG freeSpace;
|
|
LONGLONG mediaCapacity;
|
|
BOOL readOnly;
|
|
HRESULT hrLastError;
|
|
BOOL bDataForOffline = FALSE;
|
|
|
|
// Check if we deal with two-sided medias
|
|
if (S_OK == m_pRmsServer->IsMultipleSidedMedia(m_RmsMediaSetId)) {
|
|
bTwoSidedMedias = TRUE;
|
|
WsbAffirmHr(m_pHsmServerCreate->CreateInstance(CLSID_CWsbOrderedCollection,
|
|
IID_IWsbCollection, (void **)&pFirstSideCollection));
|
|
}
|
|
|
|
// Search media table through all previously used media
|
|
for (hr = pMediaInfo->First(); S_OK == hr;
|
|
hr = pMediaInfo->Next()) {
|
|
|
|
// TEMPORARY - Just for debugging
|
|
{
|
|
CWsbStringPtr debugMediaName;
|
|
GUID debugSubsystemId;
|
|
CHAR *buff = NULL;
|
|
WsbAffirmHr(pMediaInfo->GetMediaSubsystemId(&debugSubsystemId));
|
|
debugMediaName.Free();
|
|
WsbAffirmHr(pMediaInfo->GetDescription(&debugMediaName,0));
|
|
WsbTraceAlways(OLESTR("RANK: Checking media <%ls> <%ls>\n"),
|
|
WsbGuidAsString(debugSubsystemId), (WCHAR *)debugMediaName);
|
|
debugMediaName.CopyTo (&buff);
|
|
if (buff)
|
|
WsbFree(buff);
|
|
}
|
|
|
|
WsbAffirmHr(pMediaInfo->GetStoragePoolId(&storageId));
|
|
WsbAffirmHr(pMediaInfo->GetFreeBytes(&freeSpace));
|
|
WsbAffirmHr(pMediaInfo->GetRecallOnlyStatus(&readOnly));
|
|
WsbAffirmHr(pMediaInfo->GetCapacity(&mediaCapacity));
|
|
WsbAffirmHr(pMediaInfo->GetLastError(&hrLastError));
|
|
WsbTrace( OLESTR("Looking for storagePool <%ls> and freeSpace <%ls>.\n"),
|
|
WsbGuidAsString(storagePoolId),
|
|
WsbLonglongAsString(requestSize));
|
|
WsbTrace( OLESTR("Found media with storagePool <%ls>, freeSpace <%ls> and read only <%ls>.\n"),
|
|
WsbGuidAsString(storageId),
|
|
WsbLonglongAsString(freeSpace),
|
|
WsbBoolAsString(readOnly));
|
|
|
|
// Reject media if it's ReadOnly or not from the right pool
|
|
if ((readOnly && (hrLastError != S_OK)) || (storageId != storagePoolId)) {
|
|
continue;
|
|
}
|
|
|
|
// Check full & mostly full condition & free space
|
|
// Note: a medias which is read-only because it's bad, is rejected in the previous if
|
|
if (readOnly || (freeSpace <= requestSize) ||
|
|
((freeSpace - requestSize) < ((mediaCapacity * m_MinFreeSpaceInFullMedia) / 100)) ) {
|
|
|
|
// In case of two-sided medias, such a media is candidate for second side allocation
|
|
// (but only if capacity of first side is large enough...)
|
|
if (bTwoSidedMedias && (*pRequiredSize < mediaCapacity)) {
|
|
WsbAffirmHr(pMediaInfo->GetMediaSubsystemId(&firstSideGuid));
|
|
WsbAffirmHr(m_pHsmServerCreate->CreateInstance(CLSID_CWsbGuid, IID_IWsbGuid, (void**) &pFirstSideGuid));
|
|
WsbAffirmHr(pFirstSideGuid->SetGuid(firstSideGuid));
|
|
WsbAffirmHr(pFirstSideCollection->Add(pFirstSideGuid));
|
|
pFirstSideGuid = 0;
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
// get media status data
|
|
DWORD dwStatus;
|
|
GUID mediaSubsystemId;
|
|
HRESULT hrStat;
|
|
WsbAffirmHr(pMediaInfo->GetMediaSubsystemId(&mediaSubsystemId));
|
|
hrStat = m_pRmsServer->FindCartridgeStatusById(mediaSubsystemId ,&dwStatus);
|
|
if (hrStat != S_OK) {
|
|
WsbTraceAlways(OLESTR("FindMigrateMediaToUse: Skipping media <%ls> (failed to retrieve its status)\n"),
|
|
WsbGuidAsString(mediaSubsystemId));
|
|
continue;
|
|
}
|
|
|
|
// If media disabled - skip it
|
|
if (!(dwStatus & RMS_MEDIA_ENABLED)) {
|
|
continue;
|
|
}
|
|
|
|
// From this point, the media is considered as a valid R/W media and should
|
|
// be counted as such
|
|
dwMediaCount++;
|
|
|
|
if ((dwStatus & RMS_MEDIA_ONLINE) && (dwStatus & RMS_MEDIA_AVAILABLE)) {
|
|
// Check if media is in the process of mounting:
|
|
// if so, it is also considered a busy media
|
|
CComPtr<IWsbIndexedCollection> pMountingCollection;
|
|
CComPtr<IMountingMedia> pMountingMedia;
|
|
CComPtr<IMountingMedia> pMediaToFind;
|
|
|
|
// Lock mounting media while searching the collection
|
|
WsbAffirmHr(m_pServer->LockMountingMedias());
|
|
|
|
try {
|
|
WsbAffirmHr(m_pServer->GetMountingMedias(&pMountingCollection));
|
|
WsbAffirmHr(CoCreateInstance(CLSID_CMountingMedia, 0, CLSCTX_SERVER, IID_IMountingMedia, (void**)&pMediaToFind));
|
|
WsbAffirmHr(pMediaToFind->SetMediaId(mediaSubsystemId));
|
|
hr = pMountingCollection->Find(pMediaToFind, IID_IMountingMedia, (void **)&pMountingMedia);
|
|
|
|
if (hr == S_OK) {
|
|
// Media is mounting...
|
|
|
|
// Consider adding here a check for media type and reason for mounting:
|
|
// If it's direct-access and mounting for read, it's not really busy
|
|
//
|
|
// Problem: for already mounted media, we don't track the mount reason (read or write)
|
|
//
|
|
// Also, one could argue that if we are below the concurrency limit, for better performance,
|
|
// we better use a different media, even if it's a direct-access media mounted for read
|
|
|
|
dwStatus &= ~ RMS_MEDIA_AVAILABLE;
|
|
pMountingMedia = 0;
|
|
|
|
} else if (hr == WSB_E_NOTFOUND) {
|
|
hr = S_OK;
|
|
}
|
|
|
|
} WsbCatch(hr);
|
|
|
|
m_pServer->UnlockMountingMedias();
|
|
|
|
if (! SUCCEEDED(hr)) {
|
|
WsbTraceAlways(OLESTR("CHsmWorkQueue::FindMigrateMediaToUse: Failed to check mounting media, hr= <%ls>\n"),
|
|
WsbHrAsString(hr));
|
|
}
|
|
}
|
|
|
|
if ((dwStatus & RMS_MEDIA_ONLINE) && (dwStatus & RMS_MEDIA_AVAILABLE)) {
|
|
// found a media to use
|
|
found = TRUE;
|
|
break;
|
|
} else {
|
|
// Save up to one offline or one busy media, because we may have to use it...
|
|
// Priority is given to offline medias over busy medias.
|
|
if ((alternativeMediaId != GUID_NULL) && bDataForOffline) {
|
|
// Already Have best alternative media
|
|
continue;
|
|
}
|
|
if ((alternativeMediaId != GUID_NULL) && (dwStatus & RMS_MEDIA_ONLINE)) {
|
|
// Media is busy, can't improve the alternative
|
|
continue;
|
|
}
|
|
// Determine which kind of alternative media are we saving
|
|
if (dwStatus & RMS_MEDIA_ONLINE) {
|
|
bDataForOffline = FALSE;
|
|
} else {
|
|
bDataForOffline = TRUE;
|
|
}
|
|
|
|
// Save data for alternative media
|
|
WsbAffirmHr(pMediaInfo->GetId(&alternativeMediaId));
|
|
WsbAffirmHr(pMediaInfo->GetMediaSubsystemId(&alternativeMediaToUse));
|
|
alternativeMediaName.Free();
|
|
WsbAffirmHr(pMediaInfo->GetDescription(&alternativeMediaName,0));
|
|
WsbAffirmHr(pMediaInfo->GetType(&alternativeMediaType));
|
|
WsbAffirmHr(pMediaInfo->GetNextRemoteDataSet(&alternativeRemoteDataSet));
|
|
}
|
|
|
|
}
|
|
|
|
// If we fell out of the loop because we ran out of media
|
|
// in our list, reset the HRESULT
|
|
if (hr == WSB_E_NOTFOUND) {
|
|
hr = S_OK;
|
|
} else {
|
|
WsbAffirmHr(hr);
|
|
}
|
|
}
|
|
|
|
// If we found a media to use, save information
|
|
if (found) {
|
|
WsbAffirmHr(pMediaInfo->GetId(&mediaId));
|
|
WsbAffirmHr(pMediaInfo->GetMediaSubsystemId(pMediaToUse));
|
|
if (mediaId != m_MediaId) {
|
|
m_MediaId = mediaId;
|
|
m_MediaName.Free();
|
|
WsbAffirmHr(pMediaInfo->GetDescription(&m_MediaName,0));
|
|
WsbAffirmHr(pMediaInfo->GetType(&m_MediaType));
|
|
WsbAffirmHr(pMediaInfo->GetNextRemoteDataSet(&m_RemoteDataSet));
|
|
}
|
|
//
|
|
// If we didn't find a media to use, check whether we should
|
|
// 1. Choose to allocate a second side of a full media (only for 2-sided medias)
|
|
// 2. Clear the information so we'll get a new piece of media
|
|
// 2. Return the id of an offline or busy R/W meida
|
|
} else {
|
|
|
|
if (bTwoSidedMedias) {
|
|
try {
|
|
// Go over the candidates, look for one with valid and non-allocated second side
|
|
CComPtr<IWsbEnum> pEnumIds;
|
|
GUID secondSideGuid;
|
|
BOOL bValid;
|
|
|
|
WsbAffirmHr(pFirstSideCollection->Enum(&pEnumIds));
|
|
for (hr = pEnumIds->First(IID_IWsbGuid, (void**) &pFirstSideGuid);
|
|
(hr == S_OK);
|
|
hr = pEnumIds->Next(IID_IWsbGuid, (void**) &pFirstSideGuid)) {
|
|
|
|
WsbAffirmHr(pFirstSideGuid->GetGuid(&firstSideGuid));
|
|
WsbAffirmHr(m_pRmsServer->CheckSecondSide(firstSideGuid, &bValid, &secondSideGuid));
|
|
if (bValid && (GUID_NULL == secondSideGuid)) {
|
|
// Found a valid & non-allocated second side - verify fisrt side status
|
|
DWORD status;
|
|
WsbAffirmHr(m_pRmsServer->FindCartridgeStatusById(firstSideGuid ,&status));
|
|
if ((status & RMS_MEDIA_ENABLED) && (status & RMS_MEDIA_ONLINE)) {
|
|
*pFirstSideToUse = firstSideGuid;
|
|
break;
|
|
}
|
|
}
|
|
|
|
pFirstSideGuid = 0;
|
|
}
|
|
|
|
if (hr == WSB_E_NOTFOUND) {
|
|
hr = S_OK;
|
|
}
|
|
|
|
} WsbCatchAndDo(hr,
|
|
WsbTraceAlways(OLESTR("FindMigrateMediaToUse: Skipping search for second side allocation, hr=<%ls>\n"),
|
|
WsbHrAsString(hr));
|
|
hr = S_OK;
|
|
);
|
|
|
|
} // if two sides
|
|
|
|
// Get max number for R/W medias
|
|
DWORD dwMaxMedia;
|
|
WsbAffirmHr(m_pServer->GetCopyFilesLimit(&dwMaxMedia));
|
|
|
|
if ((*pFirstSideToUse != GUID_NULL) || (dwMediaCount < dwMaxMedia) || (alternativeMediaId == GUID_NULL)) {
|
|
// Allowed to allocate a new piece of media OR no alternative media found OR second side found
|
|
m_MediaType = HSM_JOB_MEDIA_TYPE_UNKNOWN;
|
|
WsbAffirmHr(BuildMediaName(&m_MediaName));
|
|
m_MediaReadOnly = FALSE;
|
|
} else {
|
|
// Use the alternative (which is offline or busy) R/W media
|
|
*pMediaToUse = alternativeMediaToUse;
|
|
if (alternativeMediaId != m_MediaId) {
|
|
m_MediaId = alternativeMediaId;
|
|
m_MediaName.Free();
|
|
alternativeMediaName.CopyTo(&m_MediaName);
|
|
m_MediaType = alternativeMediaType;
|
|
m_RemoteDataSet = alternativeRemoteDataSet;
|
|
}
|
|
}
|
|
}
|
|
|
|
alternativeMediaName.Free();
|
|
if (pFirstSideCollection) {
|
|
WsbAffirmHr(pFirstSideCollection->RemoveAllAndRelease());
|
|
}
|
|
|
|
} WsbCatch( hr );
|
|
|
|
WsbTraceOut(OLESTR("CHsmWorkQueue::FindMigrateMediaToUse"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
|
|
return(hr);
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
CHsmWorkQueue::MountMedia(
|
|
IFsaPostIt *pFsaWorkItem,
|
|
GUID mediaToMount,
|
|
GUID firstSide,
|
|
BOOL bShortWait,
|
|
BOOL bSerialize,
|
|
LONGLONG llFreeSpace
|
|
)
|
|
|
|
/*++
|
|
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
GUID l_MediaToMount = mediaToMount;
|
|
CComPtr<IRmsDrive> pDrive;
|
|
CWsbBstrPtr pMediaName;
|
|
DWORD dwOptions = RMS_NONE;
|
|
|
|
WsbTraceIn(OLESTR("CHsmWorkQueue::MountMedia"),OLESTR("Display Name = <%ls>"), (WCHAR *)m_MediaName);
|
|
try {
|
|
// If we're switching tapes, dismount the current one
|
|
if ((m_MountedMedia != l_MediaToMount) && (m_MountedMedia != GUID_NULL)) {
|
|
WsbAffirmHr(DismountMedia());
|
|
}
|
|
|
|
// Ask RMS for short timeout, both for Mount and Allocate
|
|
if (bShortWait) {
|
|
dwOptions |= RMS_SHORT_TIMEOUT;
|
|
}
|
|
|
|
// Ask RMS to serialize mounts if required
|
|
if (bSerialize) {
|
|
dwOptions |= RMS_SERIALIZE_MOUNT;
|
|
}
|
|
|
|
// Ask RMS to fail scratch media alocation if all free media aren't big enough
|
|
// (In that case, MountScratchCartridge should fail with RMS_E_SCRATCH_NOT_FOUND_TOO_SMALL error)
|
|
dwOptions |= RMS_FAIL_ALLOCATE_ON_SIZE;
|
|
|
|
if (l_MediaToMount == GUID_NULL) {
|
|
CComPtr<IRmsCartridge> pCartridge;
|
|
CComPtr<IMediaInfo> pMediaInfo;
|
|
CWsbBstrPtr displayName;
|
|
|
|
//
|
|
// We are mounting scratch media so we provide the name and then need to find
|
|
// out the type of what got mounted
|
|
//
|
|
WsbTrace( OLESTR("Mounting Scratch Media <%ls>.\n"), (WCHAR *)m_MediaName );
|
|
displayName = m_MediaName;
|
|
ReportMediaProgress(HSM_JOB_MEDIA_STATE_MOUNTING, hr);
|
|
LONGLONG freeSpace = llFreeSpace; // Get input free space from caller (default is 0)
|
|
hr = m_pRmsServer->MountScratchCartridge( &l_MediaToMount, m_RmsMediaSetId, firstSide, &freeSpace, 0, displayName, &pDrive, &m_pRmsCartridge, &m_pDataMover, dwOptions );
|
|
hr = TranslateRmsMountHr(hr);
|
|
if (FAILED(hr)) {
|
|
m_ScratchFailed = TRUE;
|
|
} else {
|
|
m_ScratchFailed = FALSE;
|
|
}
|
|
|
|
// Update max media capacity for future migration jobs (ignore errors)
|
|
DWORD dummy;
|
|
m_pServer->UpdateMediaSizeLimit(&dummy);
|
|
|
|
// Check mount-scratch hr
|
|
WsbAffirmHr(hr);
|
|
WsbTrace( OLESTR("Mount Scratch completed.\n") );
|
|
m_MountedMedia = l_MediaToMount;
|
|
|
|
//
|
|
// Add a new Media
|
|
//
|
|
WsbAffirmHr(StartNewMedia(pFsaWorkItem));
|
|
|
|
if (m_RequestAction == FSA_REQUEST_ACTION_PREMIGRATE) {
|
|
//
|
|
// Start a new Bag to receive data
|
|
//
|
|
WsbAffirmHr(StartNewBag());
|
|
|
|
//
|
|
// Start a new session for the bag
|
|
//
|
|
WsbAffirmHr(StartNewSession());
|
|
|
|
// Getting media parameters after we start a new session ensures updated data
|
|
// (No need to supply default free-space - if driver doesn't support this info,
|
|
// mover will set free space to capacity. This is what we want for new media).
|
|
WsbAffirmHr(GetMediaParameters());
|
|
}
|
|
|
|
//
|
|
// Now check the capacity of the media and the size of the
|
|
// file to see if the file can even fit on this scratch
|
|
// media. If not, return the error.
|
|
//
|
|
LONGLONG requestSize;
|
|
WsbAffirmHr(pFsaWorkItem->GetRequestSize(&requestSize));
|
|
|
|
if ((requestSize + HSM_STORAGE_OVERHEAD) > m_MediaCapacity) {
|
|
WsbThrow( HSM_E_WORK_SKIPPED_FILE_BIGGER_MEDIA );
|
|
}
|
|
|
|
} else {
|
|
if (m_MountedMedia != l_MediaToMount) {
|
|
ReportMediaProgress(HSM_JOB_MEDIA_STATE_MOUNTING, hr);
|
|
hr = m_pRmsServer->MountCartridge( l_MediaToMount, &pDrive, &m_pRmsCartridge, &m_pDataMover, dwOptions );
|
|
hr = TranslateRmsMountHr(hr);
|
|
//
|
|
// If failure is because cartridge is disabled, need to get media label to put in error.
|
|
//
|
|
if (hr == RMS_E_CARTRIDGE_DISABLED) {
|
|
|
|
// Since this is just to get label, if any of these functions fail,
|
|
// don't throw, error will simply have blank label.
|
|
//
|
|
CComPtr<IRmsCartridge> pMedia;
|
|
HRESULT hrName;
|
|
|
|
hrName = m_pRmsServer->FindCartridgeById(l_MediaToMount , &pMedia);
|
|
if (hrName == S_OK) {
|
|
hrName = pMedia->GetName(&pMediaName);
|
|
}
|
|
if ((hrName != S_OK) || ((WCHAR *)pMediaName == NULL)) {
|
|
// Cannot get media name - set to blanks
|
|
pMediaName = L"";
|
|
}
|
|
|
|
WsbThrow(hr);
|
|
}
|
|
|
|
WsbAffirmHr(hr);
|
|
m_MountedMedia = l_MediaToMount;
|
|
WsbTrace( OLESTR("Mount completed.\n") );
|
|
|
|
if (m_RequestAction == FSA_REQUEST_ACTION_PREMIGRATE) {
|
|
//
|
|
// Start a new Bag since bags can't yet span media.
|
|
//
|
|
WsbAffirmHr(StartNewBag());
|
|
|
|
//
|
|
// Start a session
|
|
WsbAffirmHr(StartNewSession());
|
|
}
|
|
|
|
// Getting media parameters after we start a new session ensures updated data
|
|
LONGLONG internalFreeSpace;
|
|
WsbAffirmHr(GetMediaFreeSpace(&internalFreeSpace));
|
|
WsbAffirmHr(GetMediaParameters(internalFreeSpace));
|
|
}
|
|
}
|
|
} WsbCatchAndDo(hr,
|
|
switch (hr) {
|
|
case HSM_E_STG_PL_NOT_CFGD:
|
|
case HSM_E_STG_PL_INVALID:
|
|
FailJob();
|
|
break;
|
|
|
|
case RMS_E_CARTRIDGE_DISABLED:
|
|
if ((WCHAR *)pMediaName == NULL) {
|
|
pMediaName = L"";
|
|
}
|
|
WsbLogEvent(HSM_MESSAGE_MEDIA_DISABLED, 0, NULL, pMediaName, NULL);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
);
|
|
|
|
WsbTraceOut(OLESTR("CHsmWorkQueue::MountMedia"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
|
|
return(hr);
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
CHsmWorkQueue::MarkMediaFull(
|
|
IFsaPostIt* /*pFsaWorkItem*/,
|
|
GUID mediaId
|
|
)
|
|
|
|
/*++
|
|
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
WsbTraceIn(OLESTR("CHsmWorkQueue::MarkMediaFull"),OLESTR(""));
|
|
try {
|
|
//
|
|
// Update the media database
|
|
//
|
|
|
|
CComPtr<IMediaInfo> pMediaInfo;
|
|
|
|
WsbAffirmHr(m_pSegmentDb->GetEntity(m_pDbWorkSession, HSM_MEDIA_INFO_REC_TYPE, IID_IMediaInfo,
|
|
(void**)&pMediaInfo));
|
|
WsbAffirmHr(pMediaInfo->SetId(mediaId));
|
|
WsbAffirmHr(pMediaInfo->FindEQ());
|
|
m_MediaReadOnly = TRUE;
|
|
WsbAffirmHr(pMediaInfo->SetRecallOnlyStatus(m_MediaReadOnly));
|
|
WsbAffirmHr(pMediaInfo->UpdateLastKnownGoodMaster());
|
|
WsbAffirmHr(pMediaInfo->Write());
|
|
|
|
/*** If we like to allocate immediately a second side of a full meida, than the code below should be completed...
|
|
|
|
if (S_OK == m_pRmsServer->IsMultipleSidedMedia(m_RmsMediaSetId)) {
|
|
|
|
// Check if second size is avalaible for allocation
|
|
|
|
// Allocate (non-blocking) the second side
|
|
|
|
} ***/
|
|
|
|
} WsbCatch( hr );
|
|
|
|
WsbTraceOut(OLESTR("CHsmWorkQueue::MarkMediaFull"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
|
|
return(hr);
|
|
}
|
|
|
|
HRESULT
|
|
CHsmWorkQueue::MarkMediaBad(
|
|
IFsaPostIt * /*pFsaWorkItem */,
|
|
GUID mediaId,
|
|
HRESULT lastError
|
|
)
|
|
|
|
/*++
|
|
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
WsbTraceIn(OLESTR("CHsmWorkQueue::MarkMediaBad"),OLESTR(""));
|
|
try {
|
|
//
|
|
// Update the media database
|
|
//
|
|
|
|
CComPtr<IMediaInfo> pMediaInfo;
|
|
|
|
WsbAffirmHr(m_pSegmentDb->GetEntity(m_pDbWorkSession, HSM_MEDIA_INFO_REC_TYPE, IID_IMediaInfo,
|
|
(void**)&pMediaInfo));
|
|
WsbAffirmHr(pMediaInfo->SetId(mediaId));
|
|
WsbAffirmHr(pMediaInfo->FindEQ());
|
|
WsbAffirmHr(pMediaInfo->SetLastError(lastError));
|
|
m_MediaReadOnly = TRUE;
|
|
WsbAffirmHr(pMediaInfo->SetRecallOnlyStatus(m_MediaReadOnly));
|
|
WsbAffirmHr(pMediaInfo->Write());
|
|
|
|
} WsbCatch( hr );
|
|
|
|
WsbTraceOut(OLESTR("CHsmWorkQueue::MarkMediaBad"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
|
|
return(hr);
|
|
}
|
|
|
|
HRESULT
|
|
CHsmWorkQueue::FindRecallMediaToUse(
|
|
IFsaPostIt *pFsaWorkItem,
|
|
GUID *pMediaToUse,
|
|
BOOL *pMediaChanged
|
|
)
|
|
|
|
/*++
|
|
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
WsbTraceIn(OLESTR("CHsmWorkQueue::FindRecallMediaToUse"),OLESTR(""));
|
|
try {
|
|
WsbAssert(pMediaToUse != 0, E_POINTER);
|
|
*pMediaToUse = GUID_NULL;
|
|
WsbAssert(pMediaChanged != 0, E_POINTER);
|
|
*pMediaChanged = FALSE;
|
|
|
|
CComQIPtr<ISegDb, &IID_ISegDb> pSegDb = m_pSegmentDb;
|
|
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;
|
|
|
|
//
|
|
// Go to the segment database to find out where the data
|
|
// is located.
|
|
//
|
|
WsbAffirmHr(pFsaWorkItem->GetPlaceholder(&placeholder));
|
|
m_BagId = placeholder.bagId;
|
|
WsbAffirmHr(pFsaWorkItem->GetStoragePoolId(&storagePoolId));
|
|
|
|
WsbTrace(OLESTR("Finding SegmentRecord: <%ls>, <%ls>, <%ls>\n"),
|
|
WsbGuidAsString(placeholder.bagId),
|
|
WsbStringCopy(WsbLonglongAsString(placeholder.fileStart)),
|
|
WsbStringCopy(WsbLonglongAsString(placeholder.fileSize)));
|
|
|
|
hr = pSegDb->SegFind(m_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(m_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(m_pSegmentDb->GetEntity(m_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));
|
|
|
|
// If the current tape isn't the one ==> media changed
|
|
if (m_MountedMedia != l_RmsMediaId) {
|
|
*pMediaChanged = TRUE;
|
|
// If there is a current tape and it isn't the one, dismount it
|
|
if (m_MountedMedia != GUID_NULL) {
|
|
WsbAffirmHr(DismountMedia());
|
|
}
|
|
}
|
|
|
|
m_RemoteDataSetStart.QuadPart = l_SecPos;
|
|
*pMediaToUse = l_RmsMediaId;
|
|
|
|
// Keep HSM id of mounted media
|
|
m_MediaId = l_PrimPos;
|
|
|
|
} WsbCatch( hr );
|
|
|
|
WsbTraceOut(OLESTR("CHsmWorkQueue::FindRecallMediaToUse"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
|
|
return(hr);
|
|
}
|
|
|
|
|
|
|
|
|
|
HRESULT
|
|
CHsmWorkQueue::GetSource(
|
|
IFsaPostIt *pFsaWorkItem,
|
|
OLECHAR **pSourceString
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function builds the Source file name
|
|
|
|
Arguments:
|
|
|
|
pFsaWorkItem - the item to be migrated
|
|
pSourceString - the Source file name.
|
|
|
|
Return Value:
|
|
|
|
S_OK
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
CComPtr<IFsaResource> pResource;
|
|
CWsbStringPtr tmpString;
|
|
CComPtr<IHsmSession> pSession;
|
|
CWsbStringPtr path;
|
|
|
|
WsbTraceIn(OLESTR("CHsmWorkQueue::GetSource"),OLESTR(""));
|
|
try {
|
|
//
|
|
// Get the real session pointer from the IUnknown
|
|
//
|
|
WsbAffirmHr(pFsaWorkItem->GetSession(&pSession));
|
|
WsbAffirm(pSession != 0, E_POINTER);
|
|
|
|
// First get the name of the resource from the session
|
|
WsbAffirmHr(pSession->GetResource(&pResource));
|
|
WsbAffirmHr(pFsaWorkItem->GetPath(&path, 0));
|
|
|
|
tmpString.Alloc(1000);
|
|
WsbAffirmHr(pResource->GetPath(&tmpString, 0));
|
|
tmpString.Append(&(path[1]));
|
|
// tmpString.Prepend(OLESTR("\\\\?\\"));
|
|
WsbAffirmHr(tmpString.GiveTo(pSourceString));
|
|
|
|
} WsbCatch(hr);
|
|
|
|
WsbTraceOut(OLESTR("CHsmWorkQueue::GetSource"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
|
|
return (hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CHsmWorkQueue::EndSessions(
|
|
BOOL done,
|
|
BOOL bNoDelay
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
WsbTraceIn(OLESTR("CHsmWorkQueue::EndSessions"),OLESTR(""));
|
|
try {
|
|
HRESULT dismountHr = S_OK;
|
|
|
|
CComPtr<IConnectionPointContainer> pCPC;
|
|
CComPtr<IConnectionPoint> pCP;
|
|
|
|
//
|
|
// Release resources: should be earlier in completion
|
|
//
|
|
dismountHr = DismountMedia(bNoDelay);
|
|
|
|
// Tell the session that we don't want to be advised anymore.
|
|
try {
|
|
WsbAffirmHr(m_pSession->QueryInterface(IID_IConnectionPointContainer, (void**) &pCPC));
|
|
WsbAffirmHr(pCPC->FindConnectionPoint(IID_IHsmSessionSinkEveryState, &pCP));
|
|
WsbAffirmHr(pCP->Unadvise(m_StateCookie));
|
|
} WsbCatch( hr );
|
|
pCPC = 0;
|
|
pCP = 0;
|
|
m_StateCookie = 0;
|
|
|
|
try {
|
|
WsbAffirmHr(m_pSession->QueryInterface(IID_IConnectionPointContainer, (void**) &pCPC));
|
|
WsbAffirmHr(pCPC->FindConnectionPoint(IID_IHsmSessionSinkEveryEvent, &pCP));
|
|
WsbAffirmHr(pCP->Unadvise(m_EventCookie));
|
|
} WsbCatch( hr );
|
|
pCPC = 0;
|
|
pCP = 0;
|
|
m_EventCookie = 0;
|
|
|
|
if (done) {
|
|
try {
|
|
WsbTrace( OLESTR("Telling Session Data mover is done\n") );
|
|
WsbAffirmHr(SetState(HSM_JOB_STATE_DONE));
|
|
} WsbCatch( hr );
|
|
}
|
|
|
|
m_pSession = 0;
|
|
m_pFsaResource = 0;
|
|
|
|
WsbAffirmHr(dismountHr);
|
|
WsbAffirmHr(hr);
|
|
|
|
} WsbCatch (hr);
|
|
|
|
WsbTraceOut(OLESTR("CHsmWorkQueue::EndSessions"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
|
|
return (hr);
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
CHsmWorkQueue::GetScanItem(
|
|
IFsaPostIt * pFsaWorkItem,
|
|
IFsaScanItem ** ppIFsaScanItem
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CWsbStringPtr path;
|
|
|
|
WsbTraceIn(OLESTR("CHsmWorkQueue::GetScanItem"),OLESTR(""));
|
|
|
|
try {
|
|
WsbAffirmPointer(ppIFsaScanItem);
|
|
WsbAffirm(!*ppIFsaScanItem, E_INVALIDARG);
|
|
WsbAffirmHr(pFsaWorkItem->GetPath(&path, 0));
|
|
WsbAffirmHr(m_pFsaResource->FindFirst(path, m_pSession, ppIFsaScanItem));
|
|
|
|
} WsbCatch (hr)
|
|
|
|
WsbTraceOut(OLESTR("CHsmWorkQueue::GetScanItem"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
|
|
return( hr );
|
|
}
|
|
|
|
HRESULT
|
|
CHsmWorkQueue::GetNumWorkItems (
|
|
ULONG *pNumWorkItems
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CWsbStringPtr path;
|
|
|
|
WsbTraceIn(OLESTR("CHsmWorkQueue::GetNumWorkItems"),OLESTR(""));
|
|
|
|
|
|
try {
|
|
WsbAffirm(0 != pNumWorkItems, E_POINTER);
|
|
*pNumWorkItems = 0;
|
|
WsbAffirmHr(m_pWorkToDo->GetEntries(pNumWorkItems));
|
|
} WsbCatch (hr)
|
|
|
|
WsbTraceOut(OLESTR("CHsmWorkQueue::GetNumWorkItems"),OLESTR("hr = <%ls>, NumItems = <%ls>"),
|
|
WsbHrAsString(hr), WsbPtrToUlongAsString(pNumWorkItems));
|
|
return( hr );
|
|
}
|
|
|
|
HRESULT
|
|
CHsmWorkQueue::GetCurrentSessionId (
|
|
GUID *pSessionId
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CWsbStringPtr path;
|
|
|
|
WsbTraceIn(OLESTR("CsmWorkQueue::GetCurrentSessionId"),OLESTR(""));
|
|
try {
|
|
WsbAffirm(0 != pSessionId, E_POINTER);
|
|
WsbAffirmHr(m_pSession->GetIdentifier(pSessionId));
|
|
} WsbCatch (hr)
|
|
|
|
WsbTraceOut(OLESTR("CHsmWorkQueue::GetCurrentSessionId"),OLESTR("hr = <%ls>, Id = <%ls>"),
|
|
WsbHrAsString(hr), WsbPtrToGuidAsString(pSessionId));
|
|
return( hr );
|
|
}
|
|
|
|
DWORD HsmWorkQueueThread(
|
|
void *pVoid
|
|
)
|
|
|
|
/*++
|
|
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr;
|
|
|
|
hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
|
|
hr = ((CHsmWorkQueue*) pVoid)->DoWork();
|
|
|
|
CoUninitialize();
|
|
return(hr);
|
|
}
|
|
|
|
HRESULT
|
|
CHsmWorkQueue::Pause(
|
|
void
|
|
)
|
|
|
|
/*++
|
|
|
|
Implements:
|
|
|
|
CHsmWorkQueue::Pause().
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
HSM_JOB_STATE oldState;
|
|
|
|
WsbTraceIn(OLESTR("CHsmWorkQueue::Pause"), OLESTR(""));
|
|
|
|
try {
|
|
|
|
// If we are running, then suspend the thread.
|
|
WsbAffirm((HSM_JOB_STATE_STARTING == m_JobState) ||
|
|
(HSM_JOB_STATE_ACTIVE == m_JobState) ||
|
|
(HSM_JOB_STATE_RESUMING == m_JobState), E_UNEXPECTED);
|
|
oldState = m_JobState;
|
|
WsbAffirmHr(SetState(HSM_JOB_STATE_PAUSING));
|
|
|
|
// if we are unable to suspend, then return to the former state.
|
|
try {
|
|
WsbAffirm(0xffffffff != SuspendThread(m_WorkerThread), HRESULT_FROM_WIN32(GetLastError()));
|
|
WsbAffirmHr(SetState(HSM_JOB_STATE_PAUSED));
|
|
} WsbCatchAndDo(hr, SetState(oldState););
|
|
|
|
} WsbCatch(hr);
|
|
|
|
WsbTraceOut(OLESTR("CHsmWorkQueue::Pause"), OLESTR("hr = <%ls>"), WsbHrAsString(hr) );
|
|
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CHsmWorkQueue::Resume(
|
|
void
|
|
)
|
|
|
|
/*++
|
|
|
|
Implements:
|
|
|
|
CHsmWorkQueue::Resume().
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
HSM_JOB_STATE oldState;
|
|
|
|
WsbTraceIn(OLESTR("CHsmWorkQueue::Resume"), OLESTR(""));
|
|
try {
|
|
|
|
// If we are paused, then suspend the thread.
|
|
WsbAffirm((HSM_JOB_STATE_PAUSING == m_JobState) || (HSM_JOB_STATE_PAUSED == m_JobState), E_UNEXPECTED);
|
|
|
|
// If we are running, then suspend the thread.
|
|
|
|
oldState = m_JobState;
|
|
WsbAffirmHr(SetState(HSM_JOB_STATE_RESUMING));
|
|
|
|
// If we are unable to resume, then return to the former state.
|
|
try {
|
|
WsbAffirm(0xffffffff != ResumeThread(m_WorkerThread), HRESULT_FROM_WIN32(GetLastError()));
|
|
WsbAffirmHr(SetState(HSM_JOB_STATE_ACTIVE));
|
|
} WsbCatchAndDo(hr, SetState(oldState););
|
|
|
|
} WsbCatch(hr);
|
|
|
|
WsbTraceOut(OLESTR("CHsmWorkQueue::Resume"), OLESTR("hr = <%ls>"), WsbHrAsString(hr) );
|
|
return(hr);
|
|
}
|
|
|
|
HRESULT
|
|
CHsmWorkQueue::SetState(
|
|
IN HSM_JOB_STATE state
|
|
)
|
|
|
|
/*++
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
BOOL bLog = TRUE;
|
|
|
|
WsbTraceIn(OLESTR("CHsmWorkQueue:SetState"), OLESTR("state = <%ls>"), JobStateAsString( state ) );
|
|
|
|
try {
|
|
//
|
|
// Change the state and report the change to the session. Unless the current state is
|
|
// failed then leave it failed. Is is necessary because when this guy fails, it will
|
|
// cancel all sessions so that no more work is sent in and so we will skip any queued work.
|
|
// If the current state is failed, we don't need to spit out the failed message every time,
|
|
// so we send ProcessState a false fullmessage unless the state is cancelled.
|
|
//
|
|
if (HSM_JOB_STATE_FAILED != m_JobState) {
|
|
m_JobState = state;
|
|
}
|
|
|
|
if ((HSM_JOB_STATE_FAILED == m_JobState) && (HSM_JOB_STATE_CANCELLED != state)) {
|
|
bLog = FALSE;
|
|
}
|
|
|
|
WsbAffirmHr(m_pSession->ProcessState(m_JobPhase, m_JobState, m_CurrentPath, bLog));
|
|
|
|
} WsbCatch(hr);
|
|
|
|
WsbTraceOut(OLESTR("CHsmWorkQueue::SetState"), OLESTR("hr = <%ls> m_JobState = <%ls>"), WsbHrAsString(hr), JobStateAsString( m_JobState ) );
|
|
|
|
return(hr);
|
|
}
|
|
|
|
HRESULT
|
|
CHsmWorkQueue::Cancel(
|
|
void
|
|
)
|
|
|
|
/*++
|
|
|
|
Implements:
|
|
|
|
CHsmWorkQueue::Cancel().
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
WsbTraceIn(OLESTR("CHsmWorkQueue::Cancel"), OLESTR(""));
|
|
try {
|
|
|
|
WsbAffirmHr(SetState(HSM_JOB_STATE_CANCELLING));
|
|
//
|
|
// This needs to be prepended and the queue emptied out!
|
|
//
|
|
CComPtr<IHsmWorkItem> pWorkItem;
|
|
WsbAffirmHr(m_pHsmServerCreate->CreateInstance(CLSID_CHsmWorkItem, IID_IHsmWorkItem,
|
|
(void **)&pWorkItem));
|
|
WsbAffirmHr(pWorkItem->SetWorkType(HSM_WORK_ITEM_MOVER_CANCELLED));
|
|
WsbAffirmHr(m_pWorkToDo->Prepend(pWorkItem));
|
|
} WsbCatch(hr);
|
|
|
|
WsbTraceOut(OLESTR("CHsmWorkQueue::Cancel"), OLESTR("hr = <%ls>"), WsbHrAsString(hr) );
|
|
return(hr);
|
|
}
|
|
|
|
HRESULT
|
|
CHsmWorkQueue::FailJob(
|
|
void
|
|
)
|
|
|
|
/*++
|
|
|
|
Implements:
|
|
|
|
CHsmWorkQueue::FailJob().
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
WsbTraceIn(OLESTR("CHsmWorkQueue::FailJob"), OLESTR(""));
|
|
try {
|
|
//
|
|
// Set our state to failed and then cancel all work
|
|
//
|
|
WsbAffirmHr(SetState(HSM_JOB_STATE_FAILED));
|
|
if (m_pSession != 0) {
|
|
WsbAffirmHr(m_pSession->Cancel( HSM_JOB_PHASE_ALL ));
|
|
}
|
|
|
|
} WsbCatch(hr);
|
|
|
|
WsbTraceOut(OLESTR("CHsmWorkQueue::FailJob"), OLESTR("hr = <%ls>"), WsbHrAsString(hr) );
|
|
return(hr);
|
|
}
|
|
|
|
HRESULT
|
|
CHsmWorkQueue::PauseScanner(
|
|
void
|
|
)
|
|
|
|
/*++
|
|
|
|
Implements:
|
|
|
|
CHsmWorkQueue::PauseScanner().
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
WsbTraceIn(OLESTR("CHsmWorkQueue::PauseScanner"), OLESTR(""));
|
|
try {
|
|
//
|
|
// Set our state to failed and then cancel all work
|
|
//
|
|
if (m_pSession != 0) {
|
|
WsbAffirmHr(m_pSession->Pause( HSM_JOB_PHASE_SCAN ));
|
|
m_ScannerPaused = TRUE;
|
|
} else {
|
|
//
|
|
// We should never get here - this means we have been processing work but we
|
|
// have no session established
|
|
//
|
|
WsbThrow(E_POINTER);
|
|
}
|
|
|
|
} WsbCatch(hr);
|
|
|
|
WsbTraceOut(OLESTR("CHsmWorkQueue::PauseScanner"), OLESTR("hr = <%ls>"), WsbHrAsString(hr) );
|
|
return(hr);
|
|
}
|
|
|
|
HRESULT
|
|
CHsmWorkQueue::ResumeScanner(
|
|
void
|
|
)
|
|
|
|
/*++
|
|
|
|
Implements:
|
|
|
|
CHsmWorkQueue::ResumeScanner().
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
WsbTraceIn(OLESTR("CHsmWorkQueue::ResumeScanner"), OLESTR(""));
|
|
try {
|
|
//
|
|
// Set our state to failed and then cancel all work
|
|
//
|
|
if (m_pSession != 0) {
|
|
if (TRUE == m_ScannerPaused && HSM_JOB_STATE_ACTIVE == m_JobState) {
|
|
WsbAffirmHr(m_pSession->Resume( HSM_JOB_PHASE_SCAN ));
|
|
m_ScannerPaused = FALSE;
|
|
}
|
|
} else {
|
|
//
|
|
// We should never get here - this means we have been processing work but we
|
|
// have no session established
|
|
//
|
|
WsbThrow(E_POINTER);
|
|
}
|
|
|
|
} WsbCatch(hr);
|
|
|
|
WsbTraceOut(OLESTR("CHsmWorkQueue::ResumeScanner"), OLESTR("hr = <%ls>"), WsbHrAsString(hr) );
|
|
return(hr);
|
|
}
|
|
|
|
void
|
|
CHsmWorkQueue::ReportMediaProgress(
|
|
HSM_JOB_MEDIA_STATE state,
|
|
HRESULT /*status*/
|
|
)
|
|
|
|
/*++
|
|
|
|
Implements:
|
|
|
|
CHsmWorkQueue::ReportMediaProgress().
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CWsbStringPtr mediaName;
|
|
HSM_JOB_MEDIA_TYPE mediaType = HSM_JOB_MEDIA_TYPE_UNKNOWN;
|
|
|
|
WsbTraceIn(OLESTR("CHsmWorkQueue::ReportMediaProgress"), OLESTR(""));
|
|
try {
|
|
|
|
// Report Progress but we don't really care if it succeeds.
|
|
hr = m_pSession->ProcessMediaState(m_JobPhase, state, m_MediaName, m_MediaType, 0);
|
|
hr = S_OK;
|
|
// if (status != S_OK) {
|
|
// (void) m_pSession->ProcessHr(m_JobPhase, __FILE__, __LINE__, status);
|
|
// }
|
|
} WsbCatch(hr);
|
|
|
|
WsbTraceOut(OLESTR("CHsmWorkQueue::ReportMediaProgress"), OLESTR("hr = <%ls>"), WsbHrAsString(hr) );
|
|
}
|
|
|
|
HRESULT
|
|
CHsmWorkQueue::BuildMediaName(
|
|
OLECHAR **pMediaName
|
|
)
|
|
|
|
/*++
|
|
|
|
Implements:
|
|
|
|
CHsmWorkQueue::BuildMediaName
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CWsbStringPtr tmpName;
|
|
|
|
WsbTraceIn(OLESTR("CHsmWorkQueue::BuildMediaName"), OLESTR(""));
|
|
try {
|
|
ULONG len = 0;
|
|
|
|
|
|
// Get the next media number only when last scratch mount succeeded
|
|
// (which means, either first time or we need a second media for the same queue)
|
|
if (! m_ScratchFailed) {
|
|
WsbAffirmHr(m_pServer->GetNextMedia(&m_mediaCount));
|
|
}
|
|
WsbAssert(0 != m_mediaCount, E_UNEXPECTED);
|
|
|
|
// Use the base name from the registry if available
|
|
WsbAffirmHr(m_MediaBaseName.GetLen(&len));
|
|
if (len) {
|
|
tmpName = m_MediaBaseName;
|
|
} else {
|
|
// Otherwise use the name of the HSM
|
|
tmpName.Realloc(512);
|
|
WsbAffirmHr(m_pServer->GetName(&tmpName));
|
|
tmpName.Prepend("RS-");
|
|
}
|
|
tmpName.Append("-");
|
|
tmpName.Append(WsbLongAsString(m_mediaCount));
|
|
|
|
tmpName.GiveTo(pMediaName);
|
|
|
|
} WsbCatch(hr);
|
|
|
|
WsbTraceOut(OLESTR("CHsmWorkQueue::BuildMediaName"), OLESTR("hr = <%ls>, name = <%ls>"), WsbHrAsString(hr),
|
|
WsbPtrToStringAsString(pMediaName));
|
|
return(hr);
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
CHsmWorkQueue::GetMediaParameters( LONGLONG defaultFreeSpace )
|
|
|
|
/*++
|
|
|
|
Implements:
|
|
|
|
CHsmWorkQueue::GetMediaParameters
|
|
|
|
Note:
|
|
The defaultFreeSpace parameter is passed to the mover to maintain internally
|
|
media free space in case that the device doesn't provide this information.
|
|
If the device supports reporting on free space, then this parameter has no affect.
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LONG rmsCartridgeType;
|
|
CWsbBstrPtr barCode;
|
|
|
|
|
|
WsbTraceIn(OLESTR("CHsmWorkQueue::GetMediaParameters"), OLESTR(""));
|
|
try {
|
|
//
|
|
// Get some information about the media
|
|
//
|
|
LARGE_INTEGER tempFreeSpace;
|
|
tempFreeSpace.QuadPart = defaultFreeSpace;
|
|
WsbAffirmHr(m_pDataMover->GetLargestFreeSpace(&m_MediaFreeSpace, &m_MediaCapacity,
|
|
tempFreeSpace.LowPart, tempFreeSpace.HighPart));
|
|
|
|
WsbAffirmHr(m_pRmsCartridge->GetType(&rmsCartridgeType));
|
|
WsbAffirmHr(ConvertRmsCartridgeType(rmsCartridgeType, &m_MediaType));
|
|
WsbAffirmHr(m_pRmsCartridge->GetName(&barCode));
|
|
WsbAffirmHr(CoFileTimeNow(&m_MediaUpdate));
|
|
m_MediaBarCode = barCode;
|
|
|
|
} WsbCatch(hr);
|
|
|
|
WsbTraceOut(OLESTR("CHsmWorkQueue::GetMediaParameters"), OLESTR("hr = <%ls>"),WsbHrAsString(hr));
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CHsmWorkQueue::DismountMedia(BOOL bNoDelay)
|
|
|
|
/*++
|
|
|
|
Implements:
|
|
|
|
CHsmWorkQueue::DismountMedia
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
WsbTraceIn(OLESTR("CHsmWorkQueue::DismountMedia"), OLESTR(""));
|
|
try {
|
|
if ((m_pRmsCartridge != 0) && (m_MountedMedia != GUID_NULL)) {
|
|
//
|
|
// End the session with the data mover. If this doesn't work, report
|
|
// the problem but continue with the dismount.
|
|
//
|
|
try {
|
|
if ((m_RequestAction == FSA_REQUEST_ACTION_PREMIGRATE) && (m_pDataMover != 0)) {
|
|
if (S_OK == m_BeginSessionHr) {
|
|
//
|
|
// Don't do an end session if the Begin didn't work OK
|
|
//
|
|
m_BeginSessionHr = S_FALSE;
|
|
WsbAffirmHr(m_pDataMover->EndSession());
|
|
|
|
// Update media free space after all data has been written to the media
|
|
WsbAffirmHr(UpdateMediaFreeSpace());
|
|
}
|
|
}
|
|
} WsbCatchAndDo( hr,
|
|
WsbTraceAlways(OLESTR("CHsmWorkQueue::DismountMedia: End session or DB update failed, hr = <%ls>\n"),
|
|
WsbHrAsString(hr));
|
|
);
|
|
|
|
//
|
|
// Tell the session that we are dismounting media. Ignore any problems
|
|
// with the reporting
|
|
//
|
|
(void )ReportMediaProgress(HSM_JOB_MEDIA_STATE_DISMOUNTING, S_OK);
|
|
|
|
//
|
|
// Dismount the cartridge and report progress
|
|
//
|
|
|
|
// !!! IMPORTANT NOTE !!!
|
|
//
|
|
// Must free Rms resources used before dismounting...
|
|
//
|
|
m_pRmsCartridge = 0;
|
|
m_pDataMover = 0;
|
|
|
|
DWORD dwOptions = RMS_NONE;
|
|
if (bNoDelay) {
|
|
dwOptions |= RMS_DISMOUNT_DEFERRED_ONLY;
|
|
}
|
|
hr = m_pRmsServer->DismountCartridge(m_MountedMedia, dwOptions);
|
|
(void) ReportMediaProgress(HSM_JOB_MEDIA_STATE_DISMOUNTED, hr);
|
|
|
|
//
|
|
// Clear out the knowledge of media that was just dismounted
|
|
//
|
|
WsbAffirmHr(UnsetMediaInfo());
|
|
|
|
WsbAffirmHr(hr);
|
|
WsbTrace( OLESTR("Dismount completed OK.\n") );
|
|
} else {
|
|
WsbTrace( OLESTR("There is no media to dismount.\n") );
|
|
}
|
|
} WsbCatch(hr);
|
|
|
|
WsbTraceOut(OLESTR("CHsmWorkQueue::DismountMedia"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CHsmWorkQueue::ConvertRmsCartridgeType(
|
|
LONG rmsCartridgeType,
|
|
HSM_JOB_MEDIA_TYPE *pMediaType
|
|
)
|
|
|
|
/*++
|
|
|
|
Implements:
|
|
|
|
CHsmWorkQueue::ConvertRmsCartridgeType
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
WsbTraceIn(OLESTR("CHsmWorkQueue::ConvertRmsCartridgeType"), OLESTR(""));
|
|
try {
|
|
|
|
WsbAssert(0 != pMediaType, E_POINTER);
|
|
|
|
switch (rmsCartridgeType) {
|
|
case RmsMedia8mm:
|
|
case RmsMedia4mm:
|
|
case RmsMediaDLT:
|
|
case RmsMediaTape:
|
|
*pMediaType = HSM_JOB_MEDIA_TYPE_TAPE;
|
|
break;
|
|
case RmsMediaOptical:
|
|
case RmsMediaMO35:
|
|
case RmsMediaWORM:
|
|
case RmsMediaCDR:
|
|
case RmsMediaDVD:
|
|
*pMediaType = HSM_JOB_MEDIA_TYPE_OPTICAL;
|
|
break;
|
|
case RmsMediaDisk:
|
|
*pMediaType = HSM_JOB_MEDIA_TYPE_REMOVABLE_MAG;
|
|
break;
|
|
case RmsMediaFixed:
|
|
*pMediaType = HSM_JOB_MEDIA_TYPE_FIXED_MAG;
|
|
break;
|
|
case RmsMediaUnknown:
|
|
default:
|
|
*pMediaType = HSM_JOB_MEDIA_TYPE_UNKNOWN;
|
|
break;
|
|
}
|
|
} WsbCatch( hr );
|
|
|
|
WsbTraceOut(OLESTR("CHsmWorkQueue::ConvertRmsCartridgeType"), OLESTR("hr = <%ls>"),
|
|
WsbHrAsString(hr));
|
|
return(hr);
|
|
}
|
|
|
|
HRESULT
|
|
CHsmWorkQueue::MarkQueueAsDone( void )
|
|
|
|
/*++
|
|
|
|
Implements:
|
|
|
|
CHsmWorkQueue::MarkQueueAsDone
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
|
|
WsbTraceIn(OLESTR("CHsmWorkQueue::MarkQueueAsDone"), OLESTR(""));
|
|
try {
|
|
// Create a work item and append it to the work queue to
|
|
// indicate that the job is done
|
|
CComPtr<IHsmWorkItem> pWorkItem;
|
|
WsbAffirmHr(m_pHsmServerCreate->CreateInstance(CLSID_CHsmWorkItem, IID_IHsmWorkItem,
|
|
(void **)&pWorkItem));
|
|
WsbAffirmHr(pWorkItem->SetWorkType(HSM_WORK_ITEM_FSA_DONE));
|
|
WsbAffirmHr(m_pWorkToDo->Append(pWorkItem));
|
|
|
|
} WsbCatch(hr);
|
|
|
|
WsbTraceOut(OLESTR("CHsmWorkQueue::MarkQueueAsDone"), OLESTR("hr = <%ls>"),WsbHrAsString(hr));
|
|
return(hr);
|
|
}
|
|
|
|
HRESULT
|
|
CHsmWorkQueue::CopyToWaitingQueue(
|
|
IHsmWorkItem *pWorkItem
|
|
)
|
|
|
|
/*++
|
|
|
|
Implements:
|
|
|
|
CHsmWorkQueue::CopyToWaitingQueue
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CComPtr<IFsaPostIt> pFsaWorkItem;
|
|
FSA_PLACEHOLDER placeholder;
|
|
|
|
|
|
WsbTraceIn(OLESTR("CHsmWorkQueue::CopyToWaitingQueue"), OLESTR(""));
|
|
try {
|
|
//
|
|
// Append the work item to the end of the waiting queue
|
|
//
|
|
WsbAffirmHr(m_pWorkToCommit->Append(pWorkItem));
|
|
|
|
//
|
|
// If adding this item to the waiting queue triggers
|
|
// then cause the commit
|
|
//
|
|
WsbAffirmHr(pWorkItem->GetFsaPostIt(&pFsaWorkItem));
|
|
WsbAffirmHr(pFsaWorkItem->GetPlaceholder(&placeholder));
|
|
|
|
m_DataCountBeforeCommit += placeholder.fileSize;
|
|
m_FilesCountBeforeCommit++;
|
|
|
|
|
|
} WsbCatch(hr);
|
|
|
|
WsbTraceOut(OLESTR("CHsmWorkQueue::CopyToWaitingQueue"), OLESTR("hr = <%ls>"),WsbHrAsString(hr));
|
|
return(hr);
|
|
}
|
|
|
|
HRESULT
|
|
CHsmWorkQueue::CompleteWorkItem(
|
|
IHsmWorkItem *pWorkItem
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
CWsbStringPtr path;
|
|
FSA_RESULT_ACTION resultAction;
|
|
CComPtr<IFsaPostIt> pFsaWorkItem;
|
|
CComPtr<IFsaResource> pFsaResource;
|
|
FSA_REQUEST_ACTION requestAction;
|
|
|
|
WsbTraceIn(OLESTR("CHsmWorkQueue::CompleteWorkItem"), OLESTR(""));
|
|
try {
|
|
//
|
|
// Get the stuff
|
|
//
|
|
WsbAffirmHr(pWorkItem->GetFsaPostIt(&pFsaWorkItem));
|
|
WsbAffirmHr(pWorkItem->GetFsaResource(&pFsaResource));
|
|
WsbAffirmHr(pFsaWorkItem->GetPath(&path, 0));
|
|
WsbAffirmHr(pFsaWorkItem->GetRequestAction(&requestAction));
|
|
WsbTrace(OLESTR("Completing work for <%s>.\n"), (OLECHAR *)path);
|
|
|
|
//
|
|
// Update the metadata - If this fails don't process
|
|
// results.
|
|
//
|
|
WsbAffirmHr(UpdateMetaData(pWorkItem));
|
|
|
|
//
|
|
// Complete the work
|
|
//
|
|
WsbAffirmHr(pFsaWorkItem->GetResultAction(&resultAction));
|
|
if ((resultAction != FSA_RESULT_ACTION_NONE) &&
|
|
(requestAction != FSA_REQUEST_ACTION_FILTER_RECALL) &&
|
|
(requestAction != FSA_REQUEST_ACTION_FILTER_READ) &&
|
|
(requestAction != FSA_REQUEST_ACTION_RECALL) ) {
|
|
WsbTrace(OLESTR("HSM work item complete, calling FSA\n"));
|
|
hr = pFsaResource->ProcessResult(pFsaWorkItem);
|
|
WsbTrace(OLESTR("FSA ProcessResult returned <%ls>\n"), WsbHrAsString(hr));
|
|
|
|
//
|
|
// If the process results fails, find out if the reparse point has been written,
|
|
// if not, put the file in the bag hole table.
|
|
//
|
|
if ( FSA_E_REPARSE_NOT_WRITTEN_FILE_CHANGED == hr ) {
|
|
//
|
|
// Put the file in the bag hole table
|
|
//
|
|
}
|
|
WsbAffirmHr(hr);
|
|
}
|
|
|
|
} WsbCatch( hr );
|
|
|
|
WsbTraceOut(OLESTR("CHsmWorkQueue::CompleteWorkItem"), OLESTR("hr = <%ls>"),WsbHrAsString(hr));
|
|
return( hr );
|
|
}
|
|
|
|
HRESULT
|
|
CHsmWorkQueue::TimeToCommit( void )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
// Call the other version since it has the trace in it
|
|
hr = TimeToCommit(0, 0);
|
|
return( hr );
|
|
}
|
|
|
|
HRESULT
|
|
CHsmWorkQueue::TimeToCommit(
|
|
LONGLONG numFiles,
|
|
LONGLONG amountOfData
|
|
)
|
|
{
|
|
HRESULT hr = S_FALSE;
|
|
|
|
WsbTraceIn(OLESTR("CHsmWorkQueue::TimeToCommit"), OLESTR("numFiles = <%ls>, amountOfData = <%ls>"),
|
|
WsbQuickString(WsbLonglongAsString(numFiles)), WsbQuickString(WsbLonglongAsString(amountOfData)));
|
|
WsbTrace(OLESTR("CHsmWorkQueue::TimeToCommit: m_DataCountBeforeCommit = %ls, ")
|
|
OLESTR("m_FilesCountBeforeCommit = %ls, m_MediaFreeSpace = %ls\n"),
|
|
WsbQuickString(WsbLonglongAsString(m_DataCountBeforeCommit)),
|
|
WsbQuickString(WsbLonglongAsString(m_FilesCountBeforeCommit)),
|
|
WsbQuickString(WsbLonglongAsString(m_MediaFreeSpace)));
|
|
WsbTrace(OLESTR("CHsmWorkQueue::TimeToCommit: m_MaxBytesBeforeCommit = %lu, m_MinBytesBeforeCommit = %lu\n"),
|
|
m_MaxBytesBeforeCommit, m_MinBytesBeforeCommit);
|
|
WsbTrace(OLESTR("CHsmWorkQueue::TimeToCommit: m_FilesBeforeCommit = %lu, m_FreeMediaBytesAtEndOfMedia = %lu\n"),
|
|
m_FilesBeforeCommit, m_FreeMediaBytesAtEndOfMedia);
|
|
try {
|
|
//
|
|
// If we have enough data or enough files then say it is time
|
|
|
|
// Check for lots of data written to media:
|
|
if ((m_DataCountBeforeCommit + amountOfData) >= m_MaxBytesBeforeCommit) {
|
|
WsbTrace(OLESTR("CHsmWorkQueue::TimeToCommit: commit because enough data was written\n"));
|
|
hr = S_OK;
|
|
|
|
// Check for lots of files written
|
|
} else if (((m_FilesCountBeforeCommit + numFiles) >= m_FilesBeforeCommit) &&
|
|
((m_DataCountBeforeCommit + amountOfData) >= m_MinBytesBeforeCommit)) {
|
|
WsbTrace(OLESTR("CHsmWorkQueue::TimeToCommit: commit because enough files were written\n"));
|
|
hr = S_OK;
|
|
|
|
// Check for shortage of space on the media
|
|
} else if (((m_MediaFreeSpace - amountOfData) <= m_FreeMediaBytesAtEndOfMedia) &&
|
|
((m_DataCountBeforeCommit + amountOfData) >= m_MinBytesBeforeCommit)) {
|
|
WsbTrace(OLESTR("CHsmWorkQueue::TimeToCommit: commit because end of media is near\n"));
|
|
hr = S_OK;
|
|
}
|
|
|
|
} WsbCatch( hr );
|
|
|
|
WsbTraceOut(OLESTR("CHsmWorkQueue::TimeToCommit"), OLESTR("hr = <%ls>"),WsbHrAsString(hr));
|
|
return( hr );
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CHsmWorkQueue::CheckMigrateMinimums(void)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Check that there is enough work in the queue to start a migrate session.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
S_OK - There is enough to start a session,
|
|
we hit the end of the queue, or this isn't a migrate queue.
|
|
S_FALSE - There isn't enough yet.
|
|
E_* - An error was encountered.
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_FALSE;
|
|
|
|
WsbTraceIn(OLESTR("CHsmWorkQueue::CheckMigrateMinimums"), OLESTR(""));
|
|
|
|
// Only check if the session has not already started (or been attempted).
|
|
if (S_FALSE != m_BeginSessionHr) {
|
|
WsbTrace(OLESTR("CHsmWorkQueue::CheckMigrateMinimums: session already started\n"));
|
|
hr = S_OK;
|
|
} else {
|
|
try {
|
|
ULONG BytesOfData = 0;
|
|
ULONG NumEntries;
|
|
|
|
// Get the number of items in the queue
|
|
WsbAffirmHr(m_pWorkToDo->GetEntries(&NumEntries));
|
|
WsbTrace(OLESTR("CHsmWorkQueue::CheckMigrateMinimums: size of queue = %lu, Min = %lu\n"),
|
|
NumEntries, m_MinFilesToMigrate);
|
|
|
|
// If the queue is already large enough, don't check individual
|
|
// items.
|
|
if (NumEntries >= m_MinFilesToMigrate) {
|
|
WsbTrace(OLESTR("CHsmWorkQueue::CheckMigrateMinimums: enough queue items\n"));
|
|
hr = S_OK;
|
|
} else {
|
|
|
|
// Loop over the items in the queue
|
|
for (ULONG i = 0; i < NumEntries; i++) {
|
|
CComPtr<IFsaPostIt> pFsaWorkItem;
|
|
CComPtr<IHsmWorkItem> pWorkItem;
|
|
FSA_REQUEST_ACTION RequestAction;
|
|
LONGLONG RequestSize;
|
|
HSM_WORK_ITEM_TYPE workType;
|
|
|
|
WsbAffirmHr(m_pWorkToDo->At(i, IID_IHsmWorkItem,
|
|
(void **)&pWorkItem));
|
|
WsbAffirmHr(pWorkItem->GetWorkType(&workType));
|
|
|
|
// Check the type of work item
|
|
if (HSM_WORK_ITEM_FSA_WORK != workType) {
|
|
// Hit the end of the queue or some other unusual
|
|
// condition. Allow processing of the queue.
|
|
WsbTrace(OLESTR("CHsmWorkQueue::CheckMigrateMinimums: non-standard work type\n"));
|
|
hr = S_OK;
|
|
break;
|
|
}
|
|
|
|
// Make sure this is a migrate queue. (This assumes a queue
|
|
// doesn't contain different types of FSA requests.)
|
|
WsbAffirmHr(pWorkItem->GetFsaPostIt(&pFsaWorkItem));
|
|
WsbAffirmHr(pFsaWorkItem->GetRequestAction(&RequestAction));
|
|
WsbTrace(OLESTR("CHsmWorkQueue::CheckMigrateMinimums: RequestAction = %d\n"),
|
|
static_cast<int>(RequestAction));
|
|
if (FSA_REQUEST_ACTION_PREMIGRATE != RequestAction) {
|
|
WsbTrace(OLESTR("CHsmWorkQueue::CheckMigrateMinimums: item is not migrate\n"));
|
|
hr = S_OK;
|
|
break;
|
|
}
|
|
|
|
// Check for minimum amount of data
|
|
WsbAffirmHr(pFsaWorkItem->GetRequestSize(&RequestSize));
|
|
WsbTrace(OLESTR("CHsmWorkQueue::CheckMigrateMinimums: RequestSize = %ls, Min = %lu\n"),
|
|
WsbLonglongAsString(RequestSize), m_MinBytesToMigrate);
|
|
if ((static_cast<LONGLONG>(BytesOfData) + RequestSize) >=
|
|
static_cast<LONGLONG>(m_MinBytesToMigrate)) {
|
|
WsbTrace(OLESTR("CHsmWorkQueue::CheckMigrateMinimums: enough data\n"));
|
|
hr = S_OK;
|
|
break;
|
|
} else {
|
|
BytesOfData += static_cast<ULONG>(RequestSize);
|
|
WsbTrace(OLESTR("CHsmWorkQueue::CheckMigrateMinimums: new BytesOfData = %lu\n"),
|
|
BytesOfData);
|
|
}
|
|
}
|
|
}
|
|
} WsbCatch( hr );
|
|
}
|
|
|
|
WsbTraceOut(OLESTR("CHsmWorkQueue::CheckMigrateMinimums"), OLESTR("hr = <%ls>"),
|
|
WsbHrAsString(hr));
|
|
|
|
return( hr );
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CHsmWorkQueue::CheckRegistry(void)
|
|
{
|
|
OLECHAR dataString[100];
|
|
HRESULT hr = S_OK;
|
|
ULONG l_value;
|
|
DWORD sizeGot;
|
|
|
|
WsbTraceIn(OLESTR("CHsmWorkQueue::CheckRegistry"), OLESTR(""));
|
|
|
|
try {
|
|
// Minimum files to migrate
|
|
WsbAffirmHr(WsbRegistryValueUlongAsString(NULL, HSM_ENGINE_REGISTRY_STRING, HSM_MIN_FILES_TO_MIGRATE,
|
|
&m_MinFilesToMigrate));
|
|
WsbTrace(OLESTR("CHsmWorkQueue::CheckRegistry: m_MinFilesToMigrate = %lu\n"),
|
|
m_MinFilesToMigrate);
|
|
|
|
// Minimum bytes to migrate
|
|
WsbAffirmHr(WsbRegistryValueUlongAsString(NULL, HSM_ENGINE_REGISTRY_STRING, HSM_MIN_BYTES_TO_MIGRATE,
|
|
&m_MinBytesToMigrate));
|
|
WsbTrace(OLESTR("CHsmWorkQueue::CheckRegistry: m_MinBytesToMigrate = %lu\n"),
|
|
m_MinBytesToMigrate);
|
|
|
|
// Minimum files before commit
|
|
WsbAffirmHr(WsbRegistryValueUlongAsString(NULL, HSM_ENGINE_REGISTRY_STRING, HSM_FILES_BEFORE_COMMIT,
|
|
&m_FilesBeforeCommit));
|
|
WsbTrace(OLESTR("CHsmWorkQueue::CheckRegistry: m_FilesBeforeCommit = %lu\n"),
|
|
m_FilesBeforeCommit);
|
|
|
|
// Maximum bytes before commit
|
|
WsbAffirmHr(WsbRegistryValueUlongAsString(NULL, HSM_ENGINE_REGISTRY_STRING, HSM_MAX_BYTES_BEFORE_COMMIT,
|
|
&m_MaxBytesBeforeCommit));
|
|
WsbTrace(OLESTR("CHsmWorkQueue::CheckRegistry: m_MaxBytesBeforeCommit = %lu\n"),
|
|
m_MaxBytesBeforeCommit);
|
|
|
|
// Minimum bytes before commit
|
|
WsbAffirmHr(WsbRegistryValueUlongAsString(NULL, HSM_ENGINE_REGISTRY_STRING, HSM_MIN_BYTES_BEFORE_COMMIT,
|
|
&m_MinBytesBeforeCommit));
|
|
WsbTrace(OLESTR("CHsmWorkQueue::CheckRegistry: m_MinBytesBeforeCommit = %lu\n"),
|
|
m_MinBytesBeforeCommit);
|
|
|
|
// Bytes to perserve at end of tape (This is really just for security, we shouldn't reach this threshold at all)
|
|
WsbAffirmHr(WsbRegistryValueUlongAsString(NULL, HSM_ENGINE_REGISTRY_STRING, HSM_MIN_BYTES_AT_END_OF_MEDIA,
|
|
&m_FreeMediaBytesAtEndOfMedia));
|
|
WsbTrace(OLESTR("CHsmWorkQueue::CheckRegistry: m_FreeMediaBytesAtEndOfMedia = %lu\n"),
|
|
m_FreeMediaBytesAtEndOfMedia);
|
|
|
|
// Minimum percent to preserve as free space in end of meida
|
|
WsbAffirmHr(WsbRegistryValueUlongAsString(NULL, HSM_ENGINE_REGISTRY_STRING, HSM_MIN_FREE_SPACE_IN_FULL_MEDIA,
|
|
&m_MinFreeSpaceInFullMedia));
|
|
if (m_MinFreeSpaceInFullMedia >= 100) {
|
|
m_MinFreeSpaceInFullMedia = MIN_FREE_SPACE_IN_FULL_MEDIA_DEFAULT;
|
|
}
|
|
WsbTrace(OLESTR("CHsmWorkQueue::CheckRegistry: m_MinFreeSpaceInFullMedia = %lu\n"),
|
|
m_MinFreeSpaceInFullMedia);
|
|
|
|
// Maximum percent to preserve as free space in end of meida
|
|
WsbAffirmHr(WsbRegistryValueUlongAsString(NULL, HSM_ENGINE_REGISTRY_STRING, HSM_MAX_FREE_SPACE_IN_FULL_MEDIA,
|
|
&m_MaxFreeSpaceInFullMedia));
|
|
if (m_MaxFreeSpaceInFullMedia >= 100) {
|
|
m_MaxFreeSpaceInFullMedia = MAX_FREE_SPACE_IN_FULL_MEDIA_DEFAULT;
|
|
}
|
|
WsbTrace(OLESTR("CHsmWorkQueue::CheckRegistry: m_MaxFreeSpaceInFullMedia = %lu\n"),
|
|
m_MaxFreeSpaceInFullMedia);
|
|
|
|
// Save DBs in dataset? (Note: registry value has opposite meaning!)
|
|
l_value = m_StoreDatabasesInBags ? 0 : 1;
|
|
WsbAffirmHr(WsbRegistryValueUlongAsString(NULL, HSM_ENGINE_REGISTRY_STRING, HSM_DONT_SAVE_DATABASES,
|
|
&l_value));
|
|
m_StoreDatabasesInBags = !l_value;
|
|
WsbTrace(OLESTR("CHsmWorkQueue::CheckRegistry: m_StoreDatabasesInBags = <%ls>\n"),
|
|
WsbBoolAsString(m_StoreDatabasesInBags));
|
|
|
|
// Queue length to pause scan
|
|
WsbAffirmHr(WsbRegistryValueUlongAsString(NULL, HSM_ENGINE_REGISTRY_STRING, HSM_QUEUE_ITEMS_TO_PAUSE,
|
|
&m_QueueItemsToPause));
|
|
WsbTrace(OLESTR("CHsmWorkQueue::CheckRegistry: m_QueueItemsToPause = %lu\n"),
|
|
m_QueueItemsToPause);
|
|
|
|
// Queue length to resume scan
|
|
WsbAffirmHr(WsbRegistryValueUlongAsString(NULL, HSM_ENGINE_REGISTRY_STRING, HSM_QUEUE_ITEMS_TO_RESUME,
|
|
&m_QueueItemsToResume));
|
|
WsbTrace(OLESTR("CHsmWorkQueue::CheckRegistry: m_QueueItemsToResume = %lu\n"),
|
|
m_QueueItemsToResume);
|
|
|
|
// See if the user defined a media base name to use
|
|
if (S_OK == WsbGetRegistryValueString(NULL, HSM_ENGINE_REGISTRY_STRING, HSM_MEDIA_BASE_NAME,
|
|
dataString, 100, &sizeGot)) {
|
|
m_MediaBaseName = dataString;
|
|
WsbTrace(OLESTR("CHsmWorkQueue::CheckRegistry: m_MediaBaseName = <%ls>\n"),
|
|
static_cast<OLECHAR *>(m_MediaBaseName));
|
|
}
|
|
|
|
// Check for change to number of errors to allow before cancelling
|
|
// a job
|
|
WsbAffirmHr(WsbRegistryValueUlongAsString(NULL, HSM_ENGINE_REGISTRY_STRING, HSM_JOB_ABORT_CONSECUTIVE_ERRORS,
|
|
&m_JobAbortMaxConsecutiveErrors));
|
|
WsbTrace(OLESTR("CHsmWorkQueue::CheckRegistry: m_JobAbortMaxConsecutiveErrors = %lu\n"),
|
|
m_JobAbortMaxConsecutiveErrors);
|
|
WsbAffirmHr(WsbRegistryValueUlongAsString(NULL, HSM_ENGINE_REGISTRY_STRING, HSM_JOB_ABORT_TOTAL_ERRORS,
|
|
&m_JobAbortMaxTotalErrors));
|
|
WsbTrace(OLESTR("CHsmWorkQueue::CheckRegistry: m_JobAbortMaxTotalErrors = %lu\n"),
|
|
m_JobAbortMaxTotalErrors);
|
|
|
|
// Check for amount of system disk space required for a manage job
|
|
WsbAffirmHr(WsbRegistryValueUlongAsString(NULL, HSM_ENGINE_REGISTRY_STRING, HSM_JOB_ABORT_SYS_DISK_SPACE,
|
|
&m_JobAbortSysDiskSpace));
|
|
WsbTrace(OLESTR("CHsmWorkQueue::CheckRegistry: m_JobAbortSysDiskSpace = %lu\n"),
|
|
m_JobAbortSysDiskSpace);
|
|
|
|
} WsbCatch( hr );
|
|
|
|
WsbTraceOut(OLESTR("CHsmWorkQueue::CheckRegistry"), OLESTR("hr = <%ls>"),
|
|
WsbHrAsString(hr));
|
|
|
|
return( hr );
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CHsmWorkQueue::CheckForDiskSpace(void)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Check system volume for sufficient space to complete a manage job.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
S_OK - There is enough space
|
|
WSB_E_SYSTEM_DISK_FULL - There isn't enough space
|
|
E_* - Some error occurred
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
ULARGE_INTEGER FreeBytesAvailableToCaller;
|
|
ULARGE_INTEGER TotalNumberOfBytes;
|
|
ULARGE_INTEGER TotalNumberOfFreeBytes;
|
|
|
|
WsbTraceIn(OLESTR("CHsmWorkQueue::CheckForDiskSpace"), OLESTR(""));
|
|
|
|
if (GetDiskFreeSpaceEx(NULL, &FreeBytesAvailableToCaller,
|
|
&TotalNumberOfBytes, &TotalNumberOfFreeBytes)) {
|
|
if (FreeBytesAvailableToCaller.QuadPart < m_JobAbortSysDiskSpace) {
|
|
hr = WSB_E_SYSTEM_DISK_FULL;
|
|
}
|
|
} else {
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
|
|
WsbTraceOut(OLESTR("CHsmWorkQueue::CheckForDiskSpace"), OLESTR("hr = <%ls>"),
|
|
WsbHrAsString(hr));
|
|
|
|
return( hr );
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CHsmWorkQueue::CommitWork(void)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
HRESULT hrComplete = S_OK;
|
|
HRESULT hrFlush = E_FAIL;
|
|
|
|
WsbTraceIn(OLESTR("CHsmWorkQueue::CommitWork"),OLESTR(""));
|
|
try {
|
|
LONGLONG lastByteWritten = -1;
|
|
ULONG numItems;
|
|
CWsbStringPtr path;
|
|
CComPtr<IHsmWorkItem> pWorkItem;
|
|
CComPtr<IFsaPostIt> pFsaWorkItem;
|
|
HSM_WORK_ITEM_TYPE workType;
|
|
BOOLEAN done = FALSE;
|
|
BOOL skipWork = FALSE;
|
|
|
|
// Do we actually have work to commit?
|
|
WsbAffirmHr(m_pWorkToCommit->GetEntries(&numItems));
|
|
if (0 == numItems) {
|
|
return(S_OK);
|
|
}
|
|
|
|
//
|
|
// We expect the data mover to be ready for work
|
|
//
|
|
WsbAffirm(m_pDataMover != 0, E_UNEXPECTED);
|
|
|
|
//
|
|
// If we never got a valid session going, we cannot
|
|
// commit the work. So check here to make sure the
|
|
// session is really established OK
|
|
if (S_OK == m_BeginSessionHr) {
|
|
CComPtr<IStream> pIStream;
|
|
ULARGE_INTEGER position;
|
|
LARGE_INTEGER zero = {0, 0};
|
|
|
|
// Force a flush of the buffers
|
|
//
|
|
hrFlush = m_pDataMover->FlushBuffers();
|
|
|
|
// Determine where we are on the tape
|
|
WsbAffirmHr(m_pDataMover->QueryInterface(IID_IStream,
|
|
(void **)&pIStream));
|
|
if (S_OK != pIStream->Seek(zero, STREAM_SEEK_END, &position)) {
|
|
// If we didn't get useful information
|
|
// about the amount of data written to media, we'll have
|
|
// to skip everything in the queue
|
|
skipWork = TRUE;
|
|
} else {
|
|
lastByteWritten = position.QuadPart;
|
|
}
|
|
} else {
|
|
// Skip all of the work - none of it gets committed
|
|
skipWork = TRUE;
|
|
}
|
|
WsbTrace(OLESTR("CHsmWorkQueue::CommitWork: hrFlush = <%ls>, lastByteWritten = %ls\n"),
|
|
WsbHrAsString(hrFlush), WsbLonglongAsString(lastByteWritten));
|
|
|
|
|
|
while ( (!done) && (S_OK == hr) ) {
|
|
//
|
|
// Get the next work item from the queue
|
|
//
|
|
hr = m_pWorkToCommit->First(IID_IHsmWorkItem, (void **)&pWorkItem);
|
|
if (hr == S_OK) {
|
|
//
|
|
// Find out about the work, should be FSA work
|
|
//
|
|
WsbAffirmHr(pWorkItem->GetWorkType(&workType));
|
|
|
|
if (HSM_WORK_ITEM_FSA_WORK == workType) {
|
|
|
|
try {
|
|
CComPtr<IFsaScanItem> pScanItem;
|
|
|
|
WsbAffirmHr(pWorkItem->GetFsaPostIt(&pFsaWorkItem));
|
|
WsbAffirmHr(GetScanItem(pFsaWorkItem, &pScanItem));
|
|
WsbAffirmHr(pFsaWorkItem->GetRequestAction(&m_RequestAction));
|
|
|
|
// If FlushBuffers failed, some items may not have
|
|
// gotten written to tape. This code assumes the items
|
|
// in the queue are in the same order they were written
|
|
// onto the media
|
|
if (!skipWork && S_OK != hrFlush) {
|
|
FSA_PLACEHOLDER placeholder;
|
|
|
|
WsbAffirmHr(pFsaWorkItem->GetPlaceholder(&placeholder));
|
|
if (((LONGLONG)m_RemoteDataSetStart.QuadPart + placeholder.fileStart +
|
|
placeholder.fileSize) > lastByteWritten) {
|
|
skipWork = TRUE;
|
|
}
|
|
}
|
|
|
|
(void) pFsaWorkItem->GetPath(&path, 0);
|
|
if (!skipWork) {
|
|
//
|
|
// Get the FSA Work Item and complete the work
|
|
//
|
|
hr = CompleteWorkItem(pWorkItem);
|
|
//
|
|
// Do the stats counts
|
|
//
|
|
(void)m_pSession->ProcessItem(m_JobPhase, m_JobAction,
|
|
pScanItem, hr);
|
|
|
|
//
|
|
// This is not a failure - change to OK
|
|
//
|
|
if ( FSA_E_REPARSE_NOT_WRITTEN_FILE_CHANGED == hr ) {
|
|
hr = S_OK;
|
|
}
|
|
|
|
//
|
|
// Quota error should be handled differently - we want to log only once
|
|
// and avoid abortint the job no matter how many such errors we got
|
|
//
|
|
if ( FSA_E_REPARSE_OWNER_PASS_QUOTA == hr ) {
|
|
if (! (m_uErrorReportFlags & QUEUE_REPORT_PASS_QUOTA_LIMIT_FLAG)) {
|
|
WsbLogEvent(HSM_MESSAGE_MANAGE_FAILED_USER_QUOTA,
|
|
0, NULL, WsbAbbreviatePath(path, 120), NULL);
|
|
m_uErrorReportFlags |= QUEUE_REPORT_PASS_QUOTA_LIMIT_FLAG;
|
|
}
|
|
hr = S_OK;
|
|
}
|
|
|
|
//
|
|
// Replace to HSM specific error for some error codes
|
|
//
|
|
switch (HRESULT_CODE(hr)) {
|
|
case ERROR_LOCK_VIOLATION:
|
|
hr = HSM_E_FILE_LOCK_VIOLATION;
|
|
break;
|
|
case ERROR_SHARING_VIOLATION:
|
|
hr = HSM_E_FILE_SHARING_VIOLATION;
|
|
break;
|
|
}
|
|
|
|
if (S_OK != hr) {
|
|
// Tell the session how things went if they didn't go well.
|
|
(void) m_pSession->ProcessHr(m_JobPhase, 0, 0, hr);
|
|
}
|
|
|
|
// Check if the job needs to be canceled
|
|
if (S_OK != ShouldJobContinue(hr)) {
|
|
// Log a message if the disk is full
|
|
if (FSA_E_REPARSE_NOT_CREATED_DISK_FULL == hr) {
|
|
WsbLogEvent(HSM_MESSAGE_MANAGE_FAILED_DISK_FULL,
|
|
0, NULL, WsbAbbreviatePath(path, 120), NULL);
|
|
}
|
|
hrComplete = hr;
|
|
skipWork = TRUE;
|
|
}
|
|
WsbAffirmHr(hr);
|
|
} else {
|
|
//
|
|
// Skip the work
|
|
//
|
|
WsbLogEvent(HSM_MESSAGE_WORK_SKIPPED_COMMIT_FAILED,
|
|
0, NULL, WsbAbbreviatePath(path, 120),
|
|
WsbHrAsString(hr), NULL);
|
|
(void)m_pSession->ProcessItem(m_JobPhase,
|
|
m_JobAction, pScanItem,
|
|
HSM_E_WORK_SKIPPED_COMMIT_FAILED);
|
|
}
|
|
} WsbCatchAndDo(hr, hr = S_OK;);
|
|
(void)m_pWorkToCommit->RemoveAndRelease(pWorkItem);
|
|
} else {
|
|
//
|
|
// Found non fsa work - don't expect that!
|
|
//
|
|
ULONG tmp;
|
|
tmp = (ULONG)workType;
|
|
WsbTrace(OLESTR("Expecting FSA work, found <%lu>\n"), tmp);
|
|
hr = E_UNEXPECTED;
|
|
}
|
|
} else if (WSB_E_NOTFOUND == hr) {
|
|
// There are no more entries in the queue so we are done
|
|
done = TRUE;
|
|
hr = S_OK;
|
|
m_DataCountBeforeCommit = 0;
|
|
m_FilesCountBeforeCommit = 0;
|
|
}
|
|
|
|
pWorkItem = 0;
|
|
pFsaWorkItem = 0;
|
|
}
|
|
} WsbCatch(hr);
|
|
|
|
if (S_OK != hrFlush) {
|
|
FailJob();
|
|
}
|
|
|
|
if (S_OK != hrComplete) {
|
|
hr = hrComplete;
|
|
}
|
|
|
|
WsbTraceOut(OLESTR("CHsmWorkQueue::CommitWork"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
|
|
return(hr);
|
|
}
|
|
|
|
HRESULT
|
|
CHsmWorkQueue::StartNewMedia(
|
|
IFsaPostIt *pFsaWorkItem
|
|
)
|
|
|
|
/*++
|
|
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
BOOL dummyBool;
|
|
CComPtr<IMediaInfo> pMediaInfo;
|
|
GUID storagePoolId;
|
|
|
|
WsbTraceIn(OLESTR("CHsmWorkQueue::StartNewMedia"),OLESTR(""));
|
|
try {
|
|
WsbAffirmHr(pFsaWorkItem->GetStoragePoolId(&storagePoolId));
|
|
WsbAffirmHr(GetMediaParameters());
|
|
|
|
WsbAffirmHr(m_pSegmentDb->GetEntity(m_pDbWorkSession, HSM_MEDIA_INFO_REC_TYPE, IID_IMediaInfo,
|
|
(void**)&pMediaInfo));
|
|
WsbAffirmHr(CoCreateGuid(&m_MediaId));
|
|
WsbAffirmHr(CoFileTimeNow(&m_MediaUpdate));
|
|
WsbAffirmHr(pMediaInfo->GetRecreate(&dummyBool));
|
|
WsbAffirmHr(pMediaInfo->SetMediaInfo(m_MediaId, m_MountedMedia, storagePoolId,
|
|
m_MediaFreeSpace, m_MediaCapacity, m_BadMedia,
|
|
1, m_MediaName, m_MediaType,
|
|
m_MediaBarCode, m_MediaReadOnly, m_MediaUpdate,
|
|
0, dummyBool));
|
|
WsbAffirmHr(pMediaInfo->MarkAsNew());
|
|
|
|
WsbAffirmHr(pMediaInfo->UpdateLastKnownGoodMaster());
|
|
WsbAffirmHr(pMediaInfo->Write());
|
|
} WsbCatch( hr );
|
|
|
|
WsbTraceOut(OLESTR("CHsmWorkQueue::StartNewMedia"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
|
|
return(hr);
|
|
|
|
}
|
|
|
|
HRESULT
|
|
CHsmWorkQueue::StartNewSession( void )
|
|
|
|
/*++
|
|
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
HRESULT hrSession = S_OK;
|
|
CComPtr<IMediaInfo> pMediaInfo;
|
|
|
|
WsbTraceIn(OLESTR("CHsmWorkQueue::StartNewSession"),OLESTR(""));
|
|
try {
|
|
|
|
CWsbStringPtr strGuid;
|
|
|
|
CWsbBstrPtr sessionName = HSM_BAG_NAME;
|
|
WsbAffirmHr(WsbSafeGuidAsString(m_BagId, strGuid));
|
|
sessionName.Append(strGuid);
|
|
|
|
CWsbBstrPtr sessionDescription = HSM_ENGINE_ID;
|
|
WsbAffirmHr(WsbSafeGuidAsString(m_HsmId, strGuid));
|
|
sessionDescription.Append(strGuid);
|
|
|
|
//
|
|
// Find the media record to know the next remote data set
|
|
//
|
|
WsbAffirmHr(m_pSegmentDb->GetEntity(m_pDbWorkSession, HSM_MEDIA_INFO_REC_TYPE, IID_IMediaInfo,
|
|
(void**)&pMediaInfo));
|
|
WsbAffirmHr(pMediaInfo->SetId(m_MediaId));
|
|
WsbAffirmHr(pMediaInfo->FindEQ());
|
|
WsbAffirmHr(pMediaInfo->GetNextRemoteDataSet(&m_RemoteDataSet));
|
|
|
|
//
|
|
// Now call the data mover to begin a session. If this doesn't work then
|
|
// we want to mark the media as read only so that we will not overwrite
|
|
// data.
|
|
//
|
|
m_BeginSessionHr = m_pDataMover->BeginSession(sessionName, sessionDescription, m_RemoteDataSet, MVR_SESSION_AS_LAST_DATA_SET);
|
|
if (S_OK != m_BeginSessionHr) {
|
|
try {
|
|
//
|
|
// Check the reason for the failure of the begin session. If it is
|
|
// MVR_E_DATA_SET_MISSING then the last begin session actually failed when
|
|
// it was committed. So, let's decrement the remote data set count and
|
|
// redo the begin session that failed.
|
|
//
|
|
if (MVR_E_DATA_SET_MISSING == m_BeginSessionHr) {
|
|
m_RemoteDataSet--;
|
|
|
|
//
|
|
// Try again...
|
|
m_BeginSessionHr = m_pDataMover->BeginSession(sessionName, sessionDescription, m_RemoteDataSet, MVR_SESSION_OVERWRITE_DATA_SET);
|
|
|
|
//
|
|
// !!! IMPORTANT NOTE !!!
|
|
//
|
|
// Update the media info to reflect new RemoteDataSet count.
|
|
// This will also correct any out of sync copies.
|
|
WsbAffirmHr(pMediaInfo->SetNextRemoteDataSet(m_RemoteDataSet));
|
|
}
|
|
switch (m_BeginSessionHr) {
|
|
case S_OK:
|
|
case MVR_E_BUS_RESET:
|
|
case MVR_E_MEDIA_CHANGED:
|
|
case MVR_E_NO_MEDIA_IN_DRIVE:
|
|
case MVR_E_DEVICE_REQUIRES_CLEANING:
|
|
case MVR_E_SHARING_VIOLATION:
|
|
case MVR_E_ERROR_IO_DEVICE:
|
|
case MVR_E_ERROR_DEVICE_NOT_CONNECTED:
|
|
case MVR_E_ERROR_NOT_READY:
|
|
break;
|
|
|
|
case MVR_E_INVALID_BLOCK_LENGTH:
|
|
case MVR_E_WRITE_PROTECT:
|
|
case MVR_E_CRC:
|
|
default:
|
|
// Note the error
|
|
WsbAffirmHr(pMediaInfo->SetLastError(m_BeginSessionHr));
|
|
// Mark media as read only
|
|
m_MediaReadOnly = TRUE;
|
|
WsbAffirmHr(pMediaInfo->SetRecallOnlyStatus(m_MediaReadOnly));
|
|
// Write this out
|
|
WsbAffirmHr(pMediaInfo->Write());
|
|
break;
|
|
}
|
|
} WsbCatch( hrSession );
|
|
}
|
|
|
|
// If the BeginSession() failed, skip everything else.
|
|
WsbAffirmHr(m_BeginSessionHr);
|
|
|
|
//
|
|
// Up the count of the remote data set and write it out
|
|
m_RemoteDataSet++;
|
|
WsbAffirmHr(pMediaInfo->SetNextRemoteDataSet(m_RemoteDataSet));
|
|
|
|
// Write all of this out
|
|
WsbAffirmHr(pMediaInfo->Write());
|
|
|
|
//
|
|
// Now set the Bag remote data set value
|
|
//
|
|
HSM_BAG_STATUS l_BagStatus;
|
|
LONGLONG l_BagLen;
|
|
USHORT l_BagType;
|
|
FILETIME l_BirthDate;
|
|
LONGLONG l_DeletedBagAmount;
|
|
SHORT l_RemoteDataSet;
|
|
GUID l_BagVolId;
|
|
GUID l_BagId;
|
|
CComPtr<IBagInfo> pBagInfo;
|
|
|
|
WsbAffirmHr(m_pSegmentDb->GetEntity(m_pDbWorkSession, HSM_BAG_INFO_REC_TYPE, IID_IBagInfo,
|
|
(void**)&pBagInfo));
|
|
|
|
GetSystemTimeAsFileTime(&l_BirthDate);
|
|
|
|
WsbAffirmHr(pBagInfo->SetBagInfo(HSM_BAG_STATUS_IN_PROGRESS, m_BagId, l_BirthDate,
|
|
0, 0, GUID_NULL, 0, 0 ));
|
|
WsbAffirmHr(pBagInfo->FindEQ());
|
|
WsbAffirmHr(pBagInfo->GetBagInfo(&l_BagStatus, &l_BagId, &l_BirthDate,
|
|
&l_BagLen, &l_BagType, &l_BagVolId, &l_DeletedBagAmount, &l_RemoteDataSet ));
|
|
WsbAffirmHr(pBagInfo->SetBagInfo(l_BagStatus, l_BagId, l_BirthDate,
|
|
l_BagLen, l_BagType, l_BagVolId, l_DeletedBagAmount, (SHORT)(m_RemoteDataSet - 1)));
|
|
WsbAffirmHr(pBagInfo->Write());
|
|
|
|
// Reset error counts
|
|
m_JobConsecutiveErrors = 0;
|
|
m_JobTotalErrors = 0;
|
|
|
|
} WsbCatchAndDo(hr,
|
|
FailJob();
|
|
);
|
|
|
|
WsbTraceOut(OLESTR("CHsmWorkQueue::StartNewSession"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
|
|
return(hr);
|
|
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CHsmWorkQueue::TranslateRmsMountHr(
|
|
HRESULT rmsMountHr
|
|
)
|
|
|
|
/*++
|
|
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
WsbTraceIn(OLESTR("CHsmWorkQueue::TranslateRmsMountHr"),OLESTR("rms hr = <%ls>"), WsbHrAsString(rmsMountHr));
|
|
try {
|
|
switch (rmsMountHr) {
|
|
case S_OK:
|
|
hr = S_OK;
|
|
ReportMediaProgress(HSM_JOB_MEDIA_STATE_MOUNTED, hr);
|
|
break;
|
|
case RMS_E_MEDIASET_NOT_FOUND:
|
|
if (m_RmsMediaSetId == GUID_NULL) {
|
|
hr = HSM_E_STG_PL_NOT_CFGD;
|
|
} else {
|
|
hr = HSM_E_STG_PL_INVALID;
|
|
}
|
|
ReportMediaProgress(HSM_JOB_MEDIA_STATE_UNAVAILABLE, hr);
|
|
break;
|
|
case RMS_E_SCRATCH_NOT_FOUND:
|
|
hr = HSM_E_NO_MORE_MEDIA;
|
|
ReportMediaProgress(HSM_JOB_MEDIA_STATE_UNAVAILABLE, hr);
|
|
break;
|
|
case RMS_E_SCRATCH_NOT_FOUND_FINAL:
|
|
hr = HSM_E_NO_MORE_MEDIA_FINAL;
|
|
ReportMediaProgress(HSM_JOB_MEDIA_STATE_UNAVAILABLE, hr);
|
|
break;
|
|
case RMS_E_SCRATCH_NOT_FOUND_TOO_SMALL:
|
|
hr = HSM_E_WORK_SKIPPED_FILE_TOO_BIG;
|
|
ReportMediaProgress(HSM_JOB_MEDIA_STATE_UNAVAILABLE, hr);
|
|
break;
|
|
case RMS_E_CARTRIDGE_UNAVAILABLE:
|
|
case RMS_E_RESOURCE_UNAVAILABLE:
|
|
case RMS_E_DRIVE_UNAVAILABLE:
|
|
case RMS_E_LIBRARY_UNAVAILABLE:
|
|
hr = HSM_E_MEDIA_NOT_AVAILABLE;
|
|
ReportMediaProgress(HSM_JOB_MEDIA_STATE_UNAVAILABLE, hr);
|
|
break;
|
|
case RMS_E_CARTRIDGE_BUSY:
|
|
case RMS_E_RESOURCE_BUSY:
|
|
case RMS_E_DRIVE_BUSY:
|
|
hr = HSM_E_MEDIA_BUSY;
|
|
ReportMediaProgress(HSM_JOB_MEDIA_STATE_BUSY, hr);
|
|
break;
|
|
case RMS_E_CARTRIDGE_NOT_FOUND:
|
|
case RMS_E_CARTRIDGE_DISABLED:
|
|
case RMS_E_TIMEOUT:
|
|
case RMS_E_CANCELLED:
|
|
case ERROR_REQUEST_REFUSED:
|
|
hr = rmsMountHr;
|
|
ReportMediaProgress(HSM_JOB_MEDIA_STATE_UNAVAILABLE, hr);
|
|
break;
|
|
case WSB_E_BAD_MEDIA:
|
|
case WSB_E_WRITE_PROTECTED:
|
|
case WSB_E_CANT_LOCK:
|
|
case WSB_E_BAD_LABEL:
|
|
case WSB_E_CANT_QUICK_FORMAT:
|
|
case WSB_E_IO_ERROR:
|
|
case WSB_E_VOLUME_TOO_SMALL:
|
|
case WSB_E_VOLUME_TOO_BIG:
|
|
case WSB_E_FORMAT_FAILED:
|
|
hr = rmsMountHr;
|
|
ReportMediaProgress(HSM_JOB_MEDIA_STATE_FAILED, hr);
|
|
break;
|
|
default:
|
|
hr = rmsMountHr;
|
|
(void) m_pSession->ProcessHr(m_JobPhase, __FILE__, __LINE__, rmsMountHr);
|
|
ReportMediaProgress(HSM_JOB_MEDIA_STATE_UNAVAILABLE, hr);
|
|
break;
|
|
}
|
|
} WsbCatch( hr );
|
|
|
|
WsbTraceOut(OLESTR("CHsmWorkQueue::TranslateRmsMountHr"),
|
|
OLESTR("hr = <%ls>"), WsbHrAsString(hr));
|
|
return(hr);
|
|
|
|
}
|
|
|
|
HRESULT
|
|
CHsmWorkQueue::StoreDatabasesOnMedia( void )
|
|
/*++
|
|
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
WsbTraceIn(OLESTR("CHsmWorkQueue::StoreDatabasesOnMedia"),OLESTR(""));
|
|
try {
|
|
//
|
|
// For ultimate disaster recovery, write some files to media. We want
|
|
// to save the engine metadata and collection, the rms colleciton, NTMS
|
|
// data and the fsa collection if it exists.
|
|
//
|
|
ULARGE_INTEGER remoteDataSetStart;
|
|
ULARGE_INTEGER remoteFileStart;
|
|
ULARGE_INTEGER remoteFileSize;
|
|
ULARGE_INTEGER remoteDataStart;
|
|
ULARGE_INTEGER remoteDataSize;
|
|
ULARGE_INTEGER remoteVerificationData;
|
|
ULONG remoteVerificationType;
|
|
ULARGE_INTEGER dataStreamCRC;
|
|
ULONG dataStreamCRCType;
|
|
ULARGE_INTEGER usn;
|
|
ULARGE_INTEGER localDataSize;
|
|
ULARGE_INTEGER localDataStart;
|
|
HANDLE handle = INVALID_HANDLE_VALUE;
|
|
WIN32_FIND_DATA findData;
|
|
CWsbStringPtr localName;
|
|
CWsbBstrPtr bStrLocalName;
|
|
CWsbStringPtr rootName;
|
|
BOOL foundFile = TRUE;
|
|
BOOL bFullMessage = TRUE;
|
|
LONG mediaType;
|
|
BOOL bNewSession = FALSE;
|
|
|
|
//
|
|
// Force a save of the persistent databases
|
|
// We are not doing FSA here
|
|
//
|
|
try {
|
|
hr = m_pRmsServer->SaveAll();
|
|
hr = m_pServer->SavePersistData();
|
|
} WsbCatch( hr );
|
|
|
|
|
|
//
|
|
// In case of direct-access media, we terminate the Mover Session and open
|
|
// an additional special metadata session
|
|
WsbAssert(m_pRmsCartridge != 0, E_UNEXPECTED);
|
|
WsbAffirmHr(m_pRmsCartridge->GetType(&mediaType));
|
|
switch (mediaType) {
|
|
case RmsMediaOptical:
|
|
case RmsMediaFixed:
|
|
case RmsMediaDVD:
|
|
bNewSession = TRUE;
|
|
break;
|
|
|
|
default:
|
|
bNewSession = FALSE;
|
|
break;
|
|
}
|
|
|
|
if (bNewSession) {
|
|
// End current session
|
|
m_BeginSessionHr = S_FALSE;
|
|
WsbAffirmHr(m_pDataMover->EndSession());
|
|
|
|
// Start a new one
|
|
CWsbBstrPtr sessionName = HSM_METADATA_NAME;
|
|
|
|
CWsbStringPtr strGuid;
|
|
CWsbBstrPtr sessionDescription = HSM_ENGINE_ID;
|
|
WsbAffirmHr(WsbSafeGuidAsString(m_HsmId, strGuid));
|
|
sessionDescription.Append(strGuid);
|
|
|
|
m_BeginSessionHr = m_pDataMover->BeginSession(
|
|
sessionName,
|
|
sessionDescription,
|
|
0,
|
|
MVR_SESSION_METADATA | MVR_SESSION_AS_LAST_DATA_SET);
|
|
|
|
if (S_OK != m_BeginSessionHr) {
|
|
HRESULT hrSession = S_OK;
|
|
CComPtr<IMediaInfo> pMediaInfo;
|
|
|
|
try {
|
|
// Check the error (some errors requires marking the media is Read Only
|
|
switch (m_BeginSessionHr) {
|
|
case S_OK:
|
|
case MVR_E_BUS_RESET:
|
|
case MVR_E_MEDIA_CHANGED:
|
|
case MVR_E_NO_MEDIA_IN_DRIVE:
|
|
case MVR_E_DEVICE_REQUIRES_CLEANING:
|
|
case MVR_E_SHARING_VIOLATION:
|
|
case MVR_E_ERROR_IO_DEVICE:
|
|
case MVR_E_ERROR_DEVICE_NOT_CONNECTED:
|
|
case MVR_E_ERROR_NOT_READY:
|
|
break;
|
|
|
|
case MVR_E_INVALID_BLOCK_LENGTH:
|
|
case MVR_E_WRITE_PROTECT:
|
|
case MVR_E_CRC:
|
|
default:
|
|
// Get the media record
|
|
WsbAffirmHr(m_pSegmentDb->GetEntity(m_pDbWorkSession, HSM_MEDIA_INFO_REC_TYPE,
|
|
IID_IMediaInfo, (void**)&pMediaInfo));
|
|
WsbAffirmHr(pMediaInfo->SetId(m_MediaId));
|
|
WsbAffirmHr(pMediaInfo->FindEQ());
|
|
// Note the error
|
|
WsbAffirmHr(pMediaInfo->SetLastError(m_BeginSessionHr));
|
|
// Mark media as read only
|
|
m_MediaReadOnly = TRUE;
|
|
WsbAffirmHr(pMediaInfo->SetRecallOnlyStatus(m_MediaReadOnly));
|
|
// Write this out
|
|
WsbAffirmHr(pMediaInfo->Write());
|
|
break;
|
|
}
|
|
} WsbCatch( hrSession );
|
|
} // end if BeginSession error
|
|
|
|
WsbAffirmHr(m_BeginSessionHr);
|
|
} // end if new mover session
|
|
|
|
//
|
|
// Start at the beginning of all files
|
|
//
|
|
localDataStart.LowPart = 0;
|
|
localDataStart.HighPart = 0;
|
|
|
|
//
|
|
// First go the the remote storage and save the collections
|
|
//
|
|
try {
|
|
// Get the name of the file
|
|
WsbAffirmHr(m_pServer->GetDbPath(&rootName, 0));
|
|
WsbAffirmHr(rootName.Append(OLESTR("\\")));
|
|
localName = rootName;
|
|
WsbAffirmHr(localName.Append(OLESTR("Rs*.bak")));
|
|
|
|
|
|
// Find out the file(s)
|
|
handle = FindFirstFile(localName, &findData);
|
|
localName = rootName;
|
|
WsbAffirmHr(localName.Append((OLECHAR *)(findData.cFileName)));
|
|
|
|
// Copy each file to tape
|
|
while ((INVALID_HANDLE_VALUE != handle) && (foundFile == TRUE)) {
|
|
if ((FILE_ATTRIBUTE_DIRECTORY & findData.dwFileAttributes) != FILE_ATTRIBUTE_DIRECTORY) {
|
|
localDataSize.LowPart = findData.nFileSizeLow;
|
|
localDataSize.HighPart = findData.nFileSizeHigh;
|
|
bStrLocalName = localName;
|
|
hr = StoreDataWithRetry( bStrLocalName,
|
|
localDataStart,
|
|
localDataSize,
|
|
MVR_FLAG_BACKUP_SEMANTICS,
|
|
&remoteDataSetStart,
|
|
&remoteFileStart,
|
|
&remoteFileSize,
|
|
&remoteDataStart,
|
|
&remoteDataSize,
|
|
&remoteVerificationType,
|
|
&remoteVerificationData,
|
|
&dataStreamCRCType,
|
|
&dataStreamCRC,
|
|
&usn,
|
|
&bFullMessage);
|
|
}
|
|
|
|
foundFile = FindNextFile(handle, &findData);
|
|
localName = rootName;
|
|
WsbAffirmHr(localName.Append((OLECHAR *)(findData.cFileName)));
|
|
}
|
|
|
|
} WsbCatch(hr);
|
|
if ( INVALID_HANDLE_VALUE != handle ) {
|
|
FindClose(handle);
|
|
handle = INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
//
|
|
// Next save the hsm metadata
|
|
//
|
|
try {
|
|
//
|
|
// First backup the databases since the backup files
|
|
// are the ones that are saved.
|
|
//
|
|
WsbAffirmHr(m_pServer->BackupSegmentDb());
|
|
|
|
// Create the search path
|
|
localName = "";
|
|
WsbAffirmHr(m_pServer->GetIDbPath(&rootName, 0));
|
|
WsbAffirmHr(rootName.Append(OLESTR(".bak\\")));
|
|
localName = rootName;
|
|
WsbAffirmHr(localName.Append(OLESTR("*.*")));
|
|
|
|
// Find the first file
|
|
handle = FindFirstFile(localName, &findData);
|
|
localName = rootName;
|
|
WsbAffirmHr(localName.Append((OLECHAR *)(findData.cFileName)));
|
|
|
|
// Copy each file to tape
|
|
foundFile = TRUE;
|
|
while ((INVALID_HANDLE_VALUE != handle) && (foundFile == TRUE)) {
|
|
if ((FILE_ATTRIBUTE_DIRECTORY & findData.dwFileAttributes) != FILE_ATTRIBUTE_DIRECTORY) {
|
|
localDataSize.LowPart = findData.nFileSizeLow;
|
|
localDataSize.HighPart = findData.nFileSizeHigh;
|
|
bStrLocalName = localName;
|
|
hr = StoreDataWithRetry( bStrLocalName,
|
|
localDataStart,
|
|
localDataSize,
|
|
MVR_FLAG_BACKUP_SEMANTICS,
|
|
&remoteDataSetStart,
|
|
&remoteFileStart,
|
|
&remoteFileSize,
|
|
&remoteDataStart,
|
|
&remoteDataSize,
|
|
&remoteVerificationType,
|
|
&remoteVerificationData,
|
|
&dataStreamCRCType,
|
|
&dataStreamCRC,
|
|
&usn,
|
|
&bFullMessage);
|
|
}
|
|
foundFile = FindNextFile(handle, &findData);
|
|
localName = rootName;
|
|
WsbAffirmHr(localName.Append((OLECHAR *)(findData.cFileName)));
|
|
}
|
|
} WsbCatch(hr);
|
|
if ( INVALID_HANDLE_VALUE != handle ) {
|
|
FindClose(handle);
|
|
handle = INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
//
|
|
// Next go the the NTMS databases and save them
|
|
//
|
|
try {
|
|
DWORD sizeGot;
|
|
//
|
|
// NTMS saves databases in a subdirectory parallel to the
|
|
// RemoteStorage subdirectory. So go there and just take
|
|
// the necessary files.
|
|
//
|
|
localName = "";
|
|
WsbAffirmHr(localName.Realloc(1024));
|
|
//
|
|
// Use the relocatable meta-data path if it's available,
|
|
// otherwise default to the %SystemRoot%\System32\RemoteStorage
|
|
//
|
|
hr = WsbGetRegistryValueString(NULL, WSB_RSM_CONTROL_REGISTRY_KEY, WSB_RSM_METADATA_REGISTRY_VALUE, localName, 256, &sizeGot);
|
|
if (hr == S_OK) {
|
|
WsbAffirmHr(localName.Append(OLESTR("NtmsData\\NTMSDATA.BAK")));
|
|
} else {
|
|
WsbAffirmHr(WsbEnsureRegistryKeyExists(NULL, WSB_CURRENT_VERSION_REGISTRY_KEY));
|
|
WsbAffirmHr(WsbGetRegistryValueString(NULL, WSB_CURRENT_VERSION_REGISTRY_KEY, WSB_SYSTEM_ROOT_REGISTRY_VALUE, localName, 256, &sizeGot));
|
|
WsbAffirmHr(localName.Append(OLESTR("\\system32\\NtmsData\\NTMSDATA.BAK")));
|
|
}
|
|
|
|
// Find the first one
|
|
handle = FindFirstFile(localName, &findData);
|
|
|
|
// Copy each file to tape
|
|
if (INVALID_HANDLE_VALUE != handle) {
|
|
localDataSize.LowPart = findData.nFileSizeLow;
|
|
localDataSize.HighPart = findData.nFileSizeHigh;
|
|
bStrLocalName = localName;
|
|
hr = StoreDataWithRetry( bStrLocalName,
|
|
localDataStart,
|
|
localDataSize,
|
|
MVR_FLAG_BACKUP_SEMANTICS,
|
|
&remoteDataSetStart,
|
|
&remoteFileStart,
|
|
&remoteFileSize,
|
|
&remoteDataStart,
|
|
&remoteDataSize,
|
|
&remoteVerificationType,
|
|
&remoteVerificationData,
|
|
&dataStreamCRCType,
|
|
&dataStreamCRC,
|
|
&usn,
|
|
&bFullMessage);
|
|
}
|
|
|
|
|
|
} WsbCatch(hr);
|
|
if ( INVALID_HANDLE_VALUE != handle ) {
|
|
FindClose(handle);
|
|
handle = INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
//
|
|
// Next save the NTMS Export files.
|
|
//
|
|
try {
|
|
DWORD sizeGot;
|
|
//
|
|
// NTMS saves Export files in the EXPORT directory. We take
|
|
// all the files in this dir. StoreData does the findFirst for us.
|
|
//
|
|
localName = "";
|
|
WsbAffirmHr(localName.Realloc(256));
|
|
WsbAffirmHr(WsbEnsureRegistryKeyExists(NULL, WSB_CURRENT_VERSION_REGISTRY_KEY));
|
|
WsbAffirmHr(WsbGetRegistryValueString(NULL, WSB_CURRENT_VERSION_REGISTRY_KEY, WSB_SYSTEM_ROOT_REGISTRY_VALUE, localName, 256, &sizeGot));
|
|
WsbAffirmHr(localName.Append(OLESTR("\\system32\\NtmsData\\Export\\*.*")));
|
|
|
|
bStrLocalName = localName;
|
|
localDataStart.QuadPart = 0;
|
|
localDataSize.QuadPart = 0;
|
|
hr = StoreDataWithRetry( bStrLocalName,
|
|
localDataStart,
|
|
localDataSize,
|
|
MVR_FLAG_BACKUP_SEMANTICS,
|
|
&remoteDataSetStart,
|
|
&remoteFileStart,
|
|
&remoteFileSize,
|
|
&remoteDataStart,
|
|
&remoteDataSize,
|
|
&remoteVerificationType,
|
|
&remoteVerificationData,
|
|
&dataStreamCRCType,
|
|
&dataStreamCRC,
|
|
&usn,
|
|
&bFullMessage);
|
|
|
|
|
|
} WsbCatch(hr);
|
|
|
|
} WsbCatch(hr);
|
|
|
|
//
|
|
// Whatever happens, return OK
|
|
//
|
|
hr = S_OK;
|
|
|
|
|
|
WsbTraceOut(OLESTR("CHsmWorkQueue::StoreDatabasesOnMedia"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CHsmWorkQueue::StoreDataWithRetry(
|
|
IN BSTR localName,
|
|
IN ULARGE_INTEGER localDataStart,
|
|
IN ULARGE_INTEGER localDataSize,
|
|
IN DWORD flags,
|
|
OUT ULARGE_INTEGER *pRemoteDataSetStart,
|
|
OUT ULARGE_INTEGER *pRemoteFileStart,
|
|
OUT ULARGE_INTEGER *pRemoteFileSize,
|
|
OUT ULARGE_INTEGER *pRemoteDataStart,
|
|
OUT ULARGE_INTEGER *pRemoteDataSize,
|
|
OUT DWORD *pRemoteVerificationType,
|
|
OUT ULARGE_INTEGER *pRemoteVerificationData,
|
|
OUT DWORD *pDatastreamCRCType,
|
|
OUT ULARGE_INTEGER *pDatastreamCRC,
|
|
OUT ULARGE_INTEGER *pUsn,
|
|
OUT BOOL *bFullMessage
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Calls StoreData with retries in case the file to write from is in use.
|
|
|
|
Arguments:
|
|
|
|
Same as StoreData
|
|
|
|
Return Value:
|
|
|
|
From StoreData
|
|
|
|
--*/
|
|
{
|
|
#define MAX_STOREDATA_RETRIES 3
|
|
|
|
HRESULT hr = S_OK;
|
|
LONG RetryCount = 0;
|
|
|
|
WsbTraceIn(OLESTR("CHsmWorkQueue::StoreDataWithRetry"), OLESTR("file <%ls>"),
|
|
static_cast<OLECHAR *>(localName));
|
|
|
|
for (RetryCount = 0; (RetryCount < MAX_STOREDATA_RETRIES) && (hr != E_ABORT) && (hr != MVR_E_MEDIA_ABORT); RetryCount++) {
|
|
if (RetryCount > 0) {
|
|
WsbLogEvent(HSM_MESSAGE_DATABASE_FILE_COPY_RETRY, 0, NULL,
|
|
WsbAbbreviatePath((WCHAR *) localName, 120), NULL);
|
|
}
|
|
// Make sure data mover is ready for work.
|
|
WsbAffirmPointer(m_pDataMover);
|
|
hr = m_pDataMover->StoreData(localName, localDataStart, localDataSize,
|
|
flags, pRemoteDataSetStart, pRemoteFileStart, pRemoteFileSize,
|
|
pRemoteDataStart, pRemoteDataSize, pRemoteVerificationType,
|
|
pRemoteVerificationData, pDatastreamCRCType, pDatastreamCRC,
|
|
pUsn);
|
|
WsbTrace(OLESTR("CHsmWorkQueue::StoreDataWithRetry: StoreData hr = <%ls>\n"),
|
|
WsbHrAsString(hr) );
|
|
if (S_OK == hr) break;
|
|
Sleep(1000);
|
|
}
|
|
|
|
if (hr != S_OK) {
|
|
if (*bFullMessage) {
|
|
WsbLogEvent(HSM_MESSAGE_GENERAL_DATABASE_FILE_NOT_COPIED, 0, NULL, WsbHrAsString(hr), NULL);
|
|
*bFullMessage = FALSE;
|
|
}
|
|
WsbLogEvent(HSM_MESSAGE_DATABASE_FILE_NOT_COPIED, 0, NULL,
|
|
WsbAbbreviatePath((WCHAR *) localName, 120), WsbHrAsString(hr), NULL);
|
|
}
|
|
|
|
WsbTraceOut(OLESTR("CHsmWorkQueue::StoreDataWithRetry"), OLESTR("hr = <%ls>"),
|
|
WsbHrAsString(hr) );
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CHsmWorkQueue::ShouldJobContinue(
|
|
HRESULT problemHr
|
|
)
|
|
|
|
/*++
|
|
|
|
Implements:
|
|
|
|
CHsmWorkQueue::ShouldJobContinue().
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
WsbTraceIn(OLESTR("CHsmWorkQueue::ShouldJobContinue"), OLESTR("<%ls>"), WsbHrAsString(problemHr));
|
|
try {
|
|
// Collect some error counts and check if we've had too many
|
|
if (S_OK == problemHr) {
|
|
// Reset consecutive error count
|
|
m_JobConsecutiveErrors = 0;
|
|
} else {
|
|
m_JobConsecutiveErrors++;
|
|
m_JobTotalErrors++;
|
|
if (m_JobConsecutiveErrors >= m_JobAbortMaxConsecutiveErrors) {
|
|
WsbLogEvent(HSM_MESSAGE_TOO_MANY_CONSECUTIVE_JOB_ERRORS,
|
|
0, NULL, WsbLongAsString(m_JobConsecutiveErrors), NULL);
|
|
hr = S_FALSE;
|
|
} else if (m_JobTotalErrors >= m_JobAbortMaxTotalErrors) {
|
|
WsbLogEvent(HSM_MESSAGE_TOO_MANY_TOTAL_JOB_ERRORS,
|
|
0, NULL, WsbLongAsString(m_JobTotalErrors), NULL);
|
|
hr = S_FALSE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Evaluate the input HR to decide if we should try to continue with the job or if
|
|
// we should abandon the job because the problem is not recoverable.
|
|
//
|
|
if (S_OK == hr) {
|
|
switch (problemHr) {
|
|
case E_ABORT:
|
|
case MVR_E_MEDIA_ABORT:
|
|
case FSA_E_REPARSE_NOT_CREATED_DISK_FULL:
|
|
case WSB_E_SYSTEM_DISK_FULL:
|
|
//
|
|
// we want to cancel the job
|
|
//
|
|
hr = S_FALSE;
|
|
break;
|
|
|
|
default:
|
|
// Be optimistic and try to keep going
|
|
hr = S_OK;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Abort the job if necessary
|
|
if (S_FALSE == hr) {
|
|
WsbAffirmHr(FailJob());
|
|
}
|
|
|
|
} WsbCatch(hr);
|
|
|
|
WsbTraceOut(OLESTR("CHsmWorkQueue::ShouldJobContinue"), OLESTR("hr = <%ls>"), WsbHrAsString(hr) );
|
|
return(hr);
|
|
}
|
|
|
|
HRESULT
|
|
CHsmWorkQueue::Remove(
|
|
IHsmWorkItem *pWorkItem
|
|
)
|
|
/*++
|
|
|
|
Implements:
|
|
|
|
IHsmFsaTskMgr::Remove
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
WsbTraceIn(OLESTR("CHsmWorkQueue::Remove"),OLESTR(""));
|
|
try {
|
|
//
|
|
// Remove the item from the queue and see if we need to
|
|
// resume the scanner (if it is paused)
|
|
//
|
|
(void)m_pWorkToDo->RemoveAndRelease(pWorkItem);
|
|
ULONG numItems;
|
|
WsbAffirmHr(m_pWorkToDo->GetEntries(&numItems));
|
|
WsbTrace(OLESTR("CHsmWorkQueue::Remove - num items in queue = <%lu>\n"),numItems);
|
|
if (numItems <= m_QueueItemsToResume) {
|
|
WsbAffirmHr(ResumeScanner());
|
|
}
|
|
} WsbCatch (hr);
|
|
|
|
WsbTraceOut(OLESTR("CHsmWorkQueue::Remove"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
|
|
return (hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CHsmWorkQueue::ChangeSysState(
|
|
IN OUT HSM_SYSTEM_STATE* pSysState
|
|
)
|
|
|
|
/*++
|
|
|
|
Implements:
|
|
|
|
IHsmSystemState::ChangeSysState().
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
WsbTraceIn(OLESTR("CHsmWorkQueue::ChangeSysState"), OLESTR(""));
|
|
|
|
try {
|
|
|
|
if (pSysState->State & HSM_STATE_SUSPEND) {
|
|
// Should have already been paused via the job
|
|
} else if (pSysState->State & HSM_STATE_RESUME) {
|
|
// Should have already been resumed via the job
|
|
} else if (pSysState->State & HSM_STATE_SHUTDOWN) {
|
|
|
|
// Release the thread (we assume it has been stopped already)
|
|
if (m_WorkerThread) {
|
|
CloseHandle(m_WorkerThread);
|
|
m_WorkerThread = 0;
|
|
}
|
|
|
|
if (m_pDataMover) {
|
|
//
|
|
// Cancel any active I/O
|
|
//
|
|
(void) m_pDataMover->Cancel();
|
|
}
|
|
|
|
// If Session is valid - unadvise and free session, otherwise, just try to
|
|
// dismount media if it is mounted (which we don't know at this point)
|
|
// Best effort dismount, no error checking so following resources will get released.
|
|
if (m_pSession != 0) {
|
|
EndSessions(FALSE, TRUE);
|
|
} else {
|
|
(void) DismountMedia(TRUE);
|
|
}
|
|
}
|
|
|
|
} WsbCatch(hr);
|
|
|
|
WsbTraceOut(OLESTR("CHsmWorkQueue::ChangeSysState"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
|
|
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CHsmWorkQueue::UnsetMediaInfo( void )
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Sets the media data members back to their default (unset) values.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
S_OK: Ok.
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
WsbTraceIn(OLESTR("CHsmWorkQueue::UnsetMediaInfo"), OLESTR(""));
|
|
|
|
m_MediaId = GUID_NULL;
|
|
m_MountedMedia = GUID_NULL;
|
|
m_MediaType = HSM_JOB_MEDIA_TYPE_UNKNOWN;
|
|
m_MediaName = OLESTR("");
|
|
m_MediaBarCode = OLESTR("");
|
|
m_MediaFreeSpace = 0;
|
|
m_MediaCapacity = 0;
|
|
m_MediaReadOnly = FALSE;
|
|
m_MediaUpdate = WsbLLtoFT(0);
|
|
m_BadMedia = S_OK;
|
|
m_RemoteDataSetStart.QuadPart = 0;
|
|
m_RemoteDataSet = 0;
|
|
|
|
WsbTraceOut(OLESTR("CHsmWorkQueue::UnsetMediaInfo"), OLESTR("hr = <%ls>"),WsbHrAsString(hr));
|
|
return(hr);
|
|
}
|
|
|
|
HRESULT
|
|
CHsmWorkQueue::UpdateMediaFreeSpace( void )
|
|
|
|
/*++
|
|
Routine Description:
|
|
Updates media free space in the database based on Mover current information.
|
|
This method should be called only while the current media is still mounted.
|
|
|
|
Arguments:
|
|
None.
|
|
|
|
Return Value:
|
|
S_OK: Ok.
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
WsbTraceIn(OLESTR("CHsmWorkQueue::UpdateMediaFreeSpace"), OLESTR(""));
|
|
|
|
try
|
|
{
|
|
CComPtr<IMediaInfo> pMediaInfo;
|
|
LONGLONG currentFreeSpace;
|
|
|
|
WsbAssert(GUID_NULL != m_MediaId, E_UNEXPECTED);
|
|
WsbAffirm(m_pDbWorkSession != 0, E_FAIL);
|
|
|
|
// Find media record
|
|
WsbAffirmHr(m_pSegmentDb->GetEntity(m_pDbWorkSession, HSM_MEDIA_INFO_REC_TYPE,
|
|
IID_IMediaInfo, (void**)&pMediaInfo));
|
|
|
|
WsbAffirmHr(pMediaInfo->SetId(m_MediaId));
|
|
WsbAffirmHr(pMediaInfo->FindEQ());
|
|
|
|
// Get updated free space
|
|
WsbAffirmHr(pMediaInfo->GetFreeBytes(¤tFreeSpace));
|
|
WsbAffirmHr(GetMediaParameters(currentFreeSpace));
|
|
|
|
// Update in the media table
|
|
WsbAffirmHr(pMediaInfo->SetFreeBytes(m_MediaFreeSpace));
|
|
|
|
WsbAffirmHr(pMediaInfo->UpdateLastKnownGoodMaster());
|
|
WsbAffirmHr(pMediaInfo->Write());
|
|
|
|
} WsbCatch( hr );
|
|
|
|
WsbTraceOut(OLESTR("CHsmWorkQueue::UpdateMediaFreeSpace"), OLESTR("hr = <%ls>"),WsbHrAsString(hr));
|
|
return(hr);
|
|
}
|
|
|
|
HRESULT
|
|
CHsmWorkQueue::GetMediaFreeSpace( LONGLONG *pFreeSpace )
|
|
|
|
/*++
|
|
Routine Description:
|
|
Retrieves internal free space from HSM DB (media table)
|
|
|
|
Arguments:
|
|
None.
|
|
|
|
Return Value:
|
|
S_OK: Ok.
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
WsbTraceIn(OLESTR("CHsmWorkQueue::GetMediaFreeSpace"), OLESTR(""));
|
|
|
|
try
|
|
{
|
|
CComPtr<IMediaInfo> pMediaInfo;
|
|
|
|
WsbAssert(GUID_NULL != m_MediaId, E_UNEXPECTED);
|
|
WsbAssert(m_pDbWorkSession != 0, E_UNEXPECTED);
|
|
WsbAssertPointer(pFreeSpace);
|
|
|
|
*pFreeSpace = 0;
|
|
|
|
// Update in the media table
|
|
WsbAffirmHr(m_pSegmentDb->GetEntity(m_pDbWorkSession, HSM_MEDIA_INFO_REC_TYPE,
|
|
IID_IMediaInfo, (void**)&pMediaInfo));
|
|
|
|
WsbAffirmHr(pMediaInfo->SetId(m_MediaId));
|
|
WsbAffirmHr(pMediaInfo->FindEQ());
|
|
WsbAffirmHr(pMediaInfo->GetFreeBytes(pFreeSpace));
|
|
|
|
} WsbCatch( hr );
|
|
|
|
WsbTraceOut(OLESTR("CHsmWorkQueue::GetMediaFreeSpace"), OLESTR("hr = <%ls>"),WsbHrAsString(hr));
|
|
return(hr);
|
|
}
|