|
|
/*++
Copyright (c) 1999 Microsoft Corporation
Abstract:
@doc @module async.cxx | Implementation of CVssAsyncBackup object @end
Author:
brian berkowitz [brianb] 04/10/2000
Revision History:
Name Date Comments brianb 04/10/2000 Created
--*/
/////////////////////////////////////////////////////////////////////////////
// Includes
#include "stdafx.hxx"
#include "vs_inc.hxx"
#include "vs_sec.hxx"
#include "vs_idl.hxx"
#include "vswriter.h"
#include "vsbackup.h"
#include "vs_wmxml.hxx"
#include "vs_cmxml.hxx"
#include "worker.hxx"
#include "async.hxx"
#include "vssmsg.h"
////////////////////////////////////////////////////////////////////////
// Standard foo for file name aliasing. This code block must be after
// all includes of VSS header files.
//
#ifdef VSS_FILE_ALIAS
#undef VSS_FILE_ALIAS
#endif
#define VSS_FILE_ALIAS "BUEASYNC"
//
////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// CVssAsyncBackup
// constructor
CVssAsyncBackup::CVssAsyncBackup(): m_hrState(S_OK), m_state(VSS_AS_UNDEFINED), m_pBackupComponents(NULL), m_bOwned(NULL) { CVssFunctionTracer ft(VSSDBG_XML, L"CVssAsyncBackup::CVssAsyncBackup");
m_bcsInitialized = false; try { // Initialize the critical section
m_cs.Init(); m_bcsInitialized = true; } VSS_STANDARD_CATCH(ft) }
// destructor
CVssAsyncBackup::~CVssAsyncBackup() { CVssFunctionTracer ft(VSSDBG_XML, L"CVssAsyncBackup::~CVssAsyncBackup");
try { // Wait for the worker thread to finish, if running.
// WARNING: FinalReleaseWorkerThreadObject uses virtual methods!
// Virtual methods in classes derived from CVssAsync are now inaccessible!
FinalReleaseWorkerThreadObject(); } VSS_STANDARD_CATCH(ft) }
// do operation by creating a thread to do it and return an IVssAsync object
// for backup to use
IVssAsync* CVssAsyncBackup::CreateInstanceAndStartJob ( IN CVssBackupComponents * pBackupComponents, VSS_ASYNC_STATE state ) { CVssFunctionTracer ft(VSSDBG_XML, L"CVssAsyncBackup::CreateInstanceAndStartJob" ); CComPtr<IVssAsync> pAsync;
try { BS_ASSERT(state == VSS_AS_PREPARE_FOR_BACKUP || state == VSS_AS_BACKUP_COMPLETE || state == VSS_AS_RESTORE || state == VSS_AS_GATHER_WRITER_METADATA || state == VSS_AS_GATHER_WRITER_STATUS);
BS_ASSERT(pBackupComponents);
// Allocate the COM object.
CComObject<CVssAsyncBackup>* pObject; ft.hr = CComObject<CVssAsyncBackup>::CreateInstance(&pObject); if (ft.HrFailed()) ft.Throw ( VSSDBG_XML, E_OUTOFMEMORY, L"Error creating the CVssAsync instance. hr = 0x%08lx", ft.hr );
if (!pObject->m_bcsInitialized) ft.Throw ( VSSDBG_XML, E_OUTOFMEMORY, L"Error initializing critical section" );
BS_ASSERT(pObject);
// Setting async object internal data
pObject->m_pBackupComponents = pBackupComponents; pObject->m_pvbcReference = pBackupComponents; pObject->m_state = state;
// Querying the IVssSnapshot interface. Now the ref count becomes 1.
CComPtr<IUnknown> pUnknown = pObject->GetUnknown(); BS_ASSERT(pUnknown); ft.hr = pUnknown->SafeQI(IVssAsync, &pAsync); // The ref count is 2.
if (ft.HrFailed()) { ft.LogError(VSS_ERROR_QI_IVSSASYNC_FAILED, VSSDBG_XML << ft.hr); ft.Throw ( VSSDBG_XML, E_UNEXPECTED, L"Error querying the IVssAsync interface. hr = 0x%08lx", ft.hr ); }
BS_ASSERT(pAsync);
// Prepare job (thread created in resume state)
ft.hr = pObject->PrepareJob(); if (ft.HrFailed()) ft.Throw ( VSSDBG_XML, ft.hr, L"CVssAsyncBackup::PrepareJob failed. hr = 0x%08lx.", ft.hr );
// increment reference count so that it lives throughout lifetime
// of async thread
pObject->GetUnknown()->AddRef(); pObject->SetOwned();
// Start job
ft.hr = pObject->StartJob(); if (ft.HrFailed()) { // release reference held for thread
pObject->ClearOwned(); pObject->GetUnknown()->Release(); ft.Throw ( VSSDBG_XML, ft.hr, L"Error starting the job. hr = 0x%08lx", ft.hr ); }
// Now the background thread related members (m_hrState, m_nPercentDone) begin to update.
} VSS_STANDARD_CATCH(ft)
return pAsync.Detach(); // The ref count remains 1.
}
/////////////////////////////////////////////////////////////////////////////
// CVssWorkerThread overrides
// do basic initialization
bool CVssAsyncBackup::OnInit() { CVssFunctionTracer ft(VSSDBG_XML, L"CVssAsyncBackup::OnInit");
try { if (m_pBackupComponents != NULL) { BS_ASSERT(m_hrState == S_OK); m_hrState = VSS_S_ASYNC_PENDING; } } VSS_STANDARD_CATCH(ft)
return m_pBackupComponents != NULL; }
// execute PrepareForBackup or BackupComplete
void CVssAsyncBackup::OnRun() { CVssFunctionTracer ft(VSSDBG_XML, L"CVssAsyncBackup::OnRun");
bool bCoInitializeSucceeded = false;
try { // Check if the backup components object is created.
if (m_pBackupComponents == NULL) { ft.LogError(VSS_ERROR_BACKUPCOMPONENTS_NULL, VSSDBG_XML); ft.Throw(VSSDBG_XML, E_UNEXPECTED, L"BackupComponents object is NULL."); }
ft.hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); ft.CheckForError(VSSDBG_XML, L"CoInitializeEx");
bCoInitializeSucceeded = true; // We assume that the async object is not yet released.
// (the wait in destructor should ensure that).
m_timestamp = m_pBackupComponents->m_timestampOperation + 1;
// Call StartSnapshotSet on the given object.
if (m_state == VSS_AS_PREPARE_FOR_BACKUP) { ft.hr = m_pBackupComponents->InternalPrepareForBackup(); if (ft.HrFailed()) ft.Trace ( VSSDBG_XML, L"Internal PrepareBackup failed. 0x%08lx", ft.hr ); } else if (m_state == VSS_AS_BACKUP_COMPLETE) { ft.hr = m_pBackupComponents->InternalBackupComplete(); if (ft.hr != S_OK) ft.Trace ( VSSDBG_XML, L"Internal BackupComplete failed. 0x%08lx", ft.hr ); } else if (m_state == VSS_AS_RESTORE) { ft.hr = m_pBackupComponents->InternalPostRestore(); if (ft.hr != S_OK) ft.Trace ( VSSDBG_XML, L"Internal BackupComplete failed. 0x%08lx", ft.hr ); } else if (m_state == VSS_AS_GATHER_WRITER_METADATA) { // save previous state and timestamp that will be used
// for gather writer metadata. It is passed into
// PostGatherWriterMetadata if Cancel is called.
m_stateSaved = m_pBackupComponents->m_state; ft.hr = m_pBackupComponents->InternalGatherWriterMetadata(); if (ft.hr != S_OK) ft.Trace ( VSSDBG_XML, L"Internal GatherWriterMetadata failed. 0x%08lx", ft.hr ); } else { BS_ASSERT(m_state == VSS_AS_GATHER_WRITER_STATUS);
// save previous state and timestamp that will be used
// for gather writer metadata. It is passed into
// PostGatherWriterStatus if Cancel is called.
m_stateSaved = m_pBackupComponents->m_state;
ft.hr = m_pBackupComponents->InternalGatherWriterStatus(); if (ft.hr != S_OK) ft.Trace ( VSSDBG_XML, L"Internal GatherWriterStatus failed. 0x%08lx", ft.hr ); }
if (ft.hr != S_OK) // Put the error code into the
m_hrState = ft.hr; } VSS_STANDARD_CATCH(ft)
if (bCoInitializeSucceeded) CoUninitialize(); }
void CVssAsyncBackup::OnFinish() { CVssFunctionTracer ft(VSSDBG_XML, L"CVssAsyncBackup::OnFinish");
try { if (m_hrState == VSS_S_ASYNC_PENDING) m_hrState = VSS_S_ASYNC_FINISHED;
// Mark the thread as finished, as the last operation
MarkAsFinished(); } VSS_STANDARD_CATCH(ft)
// release interface pointer owned by the thread
BS_ASSERT(m_bOwned); m_bOwned = false; Release(); }
void CVssAsyncBackup::OnTerminate() { CVssFunctionTracer ft( VSSDBG_COORD, L"CVssAsyncBackup::OnTerminate" ); }
/////////////////////////////////////////////////////////////////////////////
// IVssAsync implementation
STDMETHODIMP CVssAsyncBackup::Cancel() { CVssFunctionTracer ft(VSSDBG_XML, L"CVssAsyncBackup::Cancel");
try { // The critical section will be left automatically at the end of scope.
CVssSafeAutomaticLock lock(m_cs);
// Safety check
if (m_pBackupComponents == NULL) { ft.LogError(VSS_ERROR_BACKUPCOMPONENTS_NULL, VSSDBG_XML); ft.Throw(VSSDBG_XML, E_UNEXPECTED, L"BackupComponents object is NULL"); }
// If thread is already finished, return correct code.
if (m_hrState == VSS_S_ASYNC_FINISHED || m_hrState == VSS_S_ASYNC_CANCELLED) ft.hr = m_hrState; else { m_hrState = VSS_S_ASYNC_CANCELLED; switch(m_state) { default: BS_ASSERT(FALSE && "Invalid ASYNC state"); break;
case VSS_AS_PREPARE_FOR_BACKUP: m_pBackupComponents->PostPrepareForBackup(m_timestamp); break;
case VSS_AS_BACKUP_COMPLETE: m_pBackupComponents->PostBackupComplete(m_timestamp); break;
case VSS_AS_RESTORE: m_pBackupComponents->PostPostRestore(m_timestamp); break;
case VSS_AS_GATHER_WRITER_STATUS: m_pBackupComponents->PostGatherWriterStatus ( m_timestamp, m_stateSaved );
break;
case VSS_AS_GATHER_WRITER_METADATA: ft.hr = m_pBackupComponents->PostGatherWriterMetadata ( m_timestamp, m_stateSaved );
if (FAILED(ft.hr)) m_hrState = ft.hr;
break; } } } VSS_STANDARD_CATCH(ft)
return ft.hr; }
STDMETHODIMP CVssAsyncBackup::Wait(DWORD dwMilliseconds) { UNREFERENCED_PARAMETER(dwMilliseconds); CVssFunctionTracer ft( VSSDBG_XML, L"CVssAsyncBackup::Wait" );
try { // Safety check
if (m_pBackupComponents == NULL) { BS_ASSERT(false); ft.LogError(VSS_ERROR_BACKUPCOMPONENTS_NULL, VSSDBG_XML); ft.Throw( VSSDBG_XML, E_UNEXPECTED, L"BackupComponents object is NULL."); }
// wait for thread to terminate
HANDLE hThread = GetThreadHandle(); if (hThread == NULL) { ft.LogError(VSS_ERROR_THREADHANDLE_NULL, VSSDBG_XML); ft.Throw( VSSDBG_XML, E_UNEXPECTED, L"invalid hThread"); }
if (::WaitForSingleObject(hThread, INFINITE) == WAIT_FAILED) { ft.LogError(VSS_ERROR_WAITFORSINGLEOBJECT, VSSDBG_XML << HRESULT_FROM_WIN32(GetLastError())); ft.Throw( VSSDBG_XML, E_UNEXPECTED, L"Wait failed. [0x%08lx]", ::GetLastError()); } } VSS_STANDARD_CATCH(ft)
return ft.hr; }
STDMETHODIMP CVssAsyncBackup::QueryStatus ( OUT HRESULT* pHrResult, OUT INT* pnReserved ) { CVssFunctionTracer ft( VSSDBG_XML, L"CVssAsyncBackup::QueryStatus" );
try { VssZeroOut(pHrResult); VssZeroOut(pnReserved); // Argument check
if (pHrResult == NULL) ft.Throw( VSSDBG_XML, E_INVALIDARG, L"Output parameter is NULL.");
// The critical section will be left automatically at the end of scope.
CVssSafeAutomaticLock lock(m_cs);
// Safety check
if (m_pBackupComponents == NULL) { ft.LogError(VSS_ERROR_BACKUPCOMPONENTS_NULL, VSSDBG_XML); ft.Throw( VSSDBG_XML, E_UNEXPECTED, L"BackupComponents object is NULL."); }
(*pHrResult) = m_hrState; ft.Trace( VSSDBG_XML, L"Returning *pHrResult: 0x%08x", *pHrResult ); } VSS_STANDARD_CATCH(ft)
return ft.hr; }
/////////////////////////////////////////////////////////////////////////////
// IVssAsync Cover implementation
void CVssAsyncCover::CreateInstance( IN CVssBackupComponents* pBackupComponents, IN IVssAsync* pAsyncInternal, OUT IVssAsync** ppAsync ) throw(HRESULT)
/*++
Description:
Creates a cover for a given IVssAsync and a backup components object.
Comments:
This object is used to intercept all calls to the internal async QueryStatus
--*/
{ CVssFunctionTracer ft(VSSDBG_XML, L"CVssAsyncCover::CreateInstance");
BS_ASSERT(pBackupComponents); BS_ASSERT(pAsyncInternal); BS_ASSERT(ppAsync && (*ppAsync == NULL)); // create cover async object
CComObject<CVssAsyncCover>* pObject; ft.hr = CComObject<CVssAsyncCover>::CreateInstance(&pObject); if (ft.HrFailed()) ft.Throw ( VSSDBG_XML, E_OUTOFMEMORY, L"Error creating the CVssAsync instance. hr = 0x%08lx", ft.hr );
// Fill out the data members (the ref counts are incremented)
pObject->m_pvbc = pBackupComponents; pObject->m_pvbcReference = pBackupComponents; pObject->m_pAsync = pAsyncInternal;
// Get the IVssAsync interface
CComPtr<IUnknown> pUnknown = pObject->GetUnknown(); BS_ASSERT(pUnknown); CComPtr<IVssAsync> ptrAsync; ft.hr = pUnknown->SafeQI(IVssAsync, &ptrAsync); if (ft.HrFailed()) { BS_ASSERT(FALSE && "QI shouldn't fail"); ft.LogError(VSS_ERROR_QI_IVSSASYNC_FAILED, VSSDBG_XML << ft.hr); ft.Throw ( VSSDBG_XML, E_UNEXPECTED, L"Error querying the IVssAsync interface. hr = 0x%08lx", ft.hr ); }
// Copy the interface to the out parameter
ptrAsync.CopyTo(ppAsync); }
STDMETHODIMP CVssAsyncCover::Cancel() { CVssFunctionTracer ft(VSSDBG_XML, L"CVssAsyncCover::Cancel");
BS_ASSERT(m_pAsync); BS_ASSERT(m_pvbc);
ft.hr = m_pAsync->Cancel(); if (ft.hr == VSS_S_ASYNC_FINISHED) m_pvbc->m_state = x_StateDoSnapshotSucceeded; else m_pvbc->m_state = x_StateDoSnapshotFailed;
return ft.hr; }
STDMETHODIMP CVssAsyncCover::Wait(DWORD dwMilliseconds) { CVssFunctionTracer ft(VSSDBG_XML, L"CVssAsyncCover::Wait");
BS_ASSERT(m_pAsync); BS_ASSERT(m_pvbc);
ft.hr = m_pAsync->Wait(dwMilliseconds);
return ft.hr; }
STDMETHODIMP CVssAsyncCover::QueryStatus ( OUT HRESULT* pHrResult, OUT INT* pnPercentDone ) { CVssFunctionTracer ft(VSSDBG_XML, L"CVssAsyncCover::QueryStatus");
if (pHrResult == NULL) return E_INVALIDARG;
BS_ASSERT(m_pAsync); BS_ASSERT(m_pvbc);
try { ft.hr = m_pAsync->QueryStatus(pHrResult, pnPercentDone); if (*pHrResult == VSS_E_BAD_STATE) m_pvbc->m_state = x_StateDoSnapshotFailedWithoutSendingAbort; else if (FAILED(ft.hr) || FAILED(*pHrResult) || *pHrResult == VSS_S_ASYNC_CANCELLED) m_pvbc->m_state = x_StateDoSnapshotFailed; else if (*pHrResult == VSS_S_ASYNC_FINISHED) m_pvbc->m_state = x_StateDoSnapshotSucceeded; } VSS_STANDARD_CATCH(ft)
return ft.hr; }
|