Leaked source code of windows server 2003
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.
 
 
 
 
 
 

632 lines
15 KiB

/*++
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;
}