507 lines
15 KiB
C++
507 lines
15 KiB
C++
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Copyright (c) 1996-2000 Microsoft Corporation
|
|
//
|
|
// Module Name:
|
|
// Cleanup.cpp
|
|
//
|
|
// Abstract:
|
|
// Implementation of the functions related to cleaning up a node that has
|
|
// been evicted.
|
|
//
|
|
// Author:
|
|
// Vijayendra Vasu (vvasu) 17-AUG-2000
|
|
//
|
|
// Revision History:
|
|
// None.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
#define UNICODE 1
|
|
#define _UNICODE 1
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Include files
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
#include "clusrtlp.h"
|
|
|
|
#include <objbase.h>
|
|
#include <ClusCfgGuids.h>
|
|
#include <ClusCfgServer.h>
|
|
#include <ClusCfgClient.h>
|
|
#include <clusrtl.h>
|
|
#include <clusudef.h>
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// ClRtlCleanupNode()
|
|
//
|
|
// Routine Description:
|
|
// Cleanup a node that has been evicted. This method tries to instantiate
|
|
// the cleanup COM component locally (even if a remote node is being cleaned up)
|
|
// and will therefore not work if called from computer which do not have this
|
|
// component registered.
|
|
//
|
|
// Arguments:
|
|
// const WCHAR * pcszEvictedNodeNameIn
|
|
// Name of the node on which cleanup is to be initiated. If this is NULL
|
|
// the local node is cleaned up.
|
|
//
|
|
// DWORD dwDelayIn
|
|
// Number of milliseconds that will elapse before cleanup is started
|
|
// on the target node. If some other process cleans up the target node while
|
|
// delay is in progress, the delay is terminated. If this value is zero,
|
|
// the node is cleaned up immediately.
|
|
//
|
|
// DWORD dwTimeoutIn
|
|
// Number of milliseconds that this method will wait for cleanup to complete.
|
|
// This timeout is independent of the delay above, so if dwDelayIn is greater
|
|
// than dwTimeoutIn, this method will most probably timeout. Once initiated,
|
|
// however, cleanup will run to completion - this method just may not wait for it
|
|
// to complete.
|
|
//
|
|
// Return Value:
|
|
// S_OK
|
|
// If the cleanup operations were successful
|
|
//
|
|
// RPC_S_CALLPENDING
|
|
// If cleanup is not complete in dwTimeoutIn milliseconds
|
|
//
|
|
// Other HRESULTS
|
|
// In case of error
|
|
//
|
|
//--
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
HRESULT ClRtlCleanupNode(
|
|
const WCHAR * pcszEvictedNodeNameIn
|
|
, DWORD dwDelayIn
|
|
, DWORD dwTimeoutIn
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
HRESULT hrInit;
|
|
IClusCfgEvictCleanup * pcceEvict = NULL;
|
|
ICallFactory * pcfCallFactory = NULL;
|
|
ISynchronize * psSync = NULL;
|
|
AsyncIClusCfgEvictCleanup * paicceAsyncEvict = NULL;
|
|
|
|
|
|
//
|
|
// Initialize COM - make sure it really init'ed or that we're just trying
|
|
// to change modes on the calling thread. Attempting to change to mode
|
|
// is not reason to fail this function.
|
|
//
|
|
hrInit = CoInitializeEx( NULL, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE );
|
|
if ( ( hrInit != S_OK ) && ( hrInit != S_FALSE ) && ( hrInit != RPC_E_CHANGED_MODE ) )
|
|
{
|
|
hr = hrInit;
|
|
goto Exit;
|
|
} // if:
|
|
|
|
hr = CoCreateInstance(
|
|
CLSID_ClusCfgEvictCleanup
|
|
, NULL
|
|
, CLSCTX_LOCAL_SERVER
|
|
, __uuidof( pcceEvict )
|
|
, reinterpret_cast< void ** >( &pcceEvict )
|
|
);
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if: we could not get a pointer to synchronous evict interface
|
|
|
|
hr = pcceEvict->QueryInterface( __uuidof( pcfCallFactory ), reinterpret_cast< void ** >( &pcfCallFactory ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if: we could not get a pointer to the call factory interface
|
|
|
|
hr = pcfCallFactory->CreateCall(
|
|
__uuidof( paicceAsyncEvict )
|
|
, NULL
|
|
, __uuidof( paicceAsyncEvict )
|
|
, reinterpret_cast< IUnknown ** >( &paicceAsyncEvict )
|
|
);
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if: we could not get a pointer to the asynchronous evict interface
|
|
|
|
hr = paicceAsyncEvict->QueryInterface< ISynchronize >( &psSync );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if: we could not get a pointer to the synchronization interface
|
|
|
|
// Initiate cleanup
|
|
if ( pcszEvictedNodeNameIn != NULL )
|
|
{
|
|
hr = paicceAsyncEvict->Begin_CleanupRemoteNode( pcszEvictedNodeNameIn, dwDelayIn );
|
|
} // if: we are cleaning up a remote node
|
|
else
|
|
{
|
|
hr = paicceAsyncEvict->Begin_CleanupLocalNode( dwDelayIn );
|
|
} // else: we are cleaning up the local node
|
|
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if: we could not initiate cleanup
|
|
|
|
// Wait for specified time.
|
|
hr = psSync->Wait( 0, dwTimeoutIn );
|
|
if ( FAILED( hr ) || ( hr == RPC_S_CALLPENDING ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if: we could not wait till cleanup completed
|
|
|
|
// Finish cleanup
|
|
if ( pcszEvictedNodeNameIn != NULL )
|
|
{
|
|
hr = paicceAsyncEvict->Finish_CleanupRemoteNode();
|
|
} // if: we are cleaning up a remote node
|
|
else
|
|
{
|
|
hr = paicceAsyncEvict->Finish_CleanupLocalNode();
|
|
} // else: we are cleaning up the local node
|
|
|
|
Cleanup:
|
|
|
|
//
|
|
// Free acquired resources
|
|
//
|
|
|
|
if ( pcceEvict != NULL )
|
|
{
|
|
pcceEvict->Release();
|
|
} // if: we had obtained a pointer to the synchronous evict interface
|
|
|
|
if ( pcfCallFactory != NULL )
|
|
{
|
|
pcfCallFactory->Release();
|
|
} // if: we had obtained a pointer to the call factory interface
|
|
|
|
if ( psSync != NULL )
|
|
{
|
|
psSync->Release();
|
|
} // if: we had obtained a pointer to the synchronization interface
|
|
|
|
if ( paicceAsyncEvict != NULL )
|
|
{
|
|
paicceAsyncEvict->Release();
|
|
} // if: we had obtained a pointer to the asynchronous evict interface
|
|
|
|
//
|
|
// Did the call to CoInitializeEx() above succeed? If it did then
|
|
// we need to call CoUnitialize(). Mode changed means we don't need
|
|
// to call CoUnitialize().
|
|
//
|
|
if ( hrInit != RPC_E_CHANGED_MODE )
|
|
{
|
|
CoUninitialize();
|
|
} // if:
|
|
|
|
Exit:
|
|
|
|
return hr;
|
|
|
|
} //*** ClRtlCleanupNode()
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// ClRtlAsyncCleanupNode()
|
|
//
|
|
// Routine Description:
|
|
// Cleanup a node that has been evicted. This method does not initiate
|
|
// any COM component on the machine on which this call is made and therefore,
|
|
// does not require the cleanup COM component to be registered on the local
|
|
// machine.
|
|
//
|
|
// Arguments:
|
|
// const WCHAR * pcszEvictedNodeNameIn
|
|
// Name of the node on which cleanup is to be initiated. If this is NULL
|
|
// the local node is cleaned up.
|
|
//
|
|
// DWORD dwDelayIn
|
|
// Number of milliseconds that will elapse before cleanup is started
|
|
// on the target node. If some other process cleans up the target node while
|
|
// delay is in progress, the delay is terminated. If this value is zero,
|
|
// the node is cleaned up immediately.
|
|
//
|
|
// DWORD dwTimeoutIn
|
|
// Number of milliseconds that this method will wait for cleanup to complete.
|
|
// This timeout is independent of the delay above, so if dwDelayIn is greater
|
|
// than dwTimeoutIn, this method will most probably timeout. Once initiated,
|
|
// however, cleanup will run to completion - this method just may not wait for it
|
|
// to complete.
|
|
//
|
|
// Return Value:
|
|
// S_OK
|
|
// If the cleanup operations were successful
|
|
//
|
|
// RPC_S_CALLPENDING
|
|
// If cleanup is not complete in dwTimeoutIn milliseconds
|
|
//
|
|
// Other HRESULTS
|
|
// In case of error
|
|
//
|
|
//--
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
HRESULT ClRtlAsyncCleanupNode(
|
|
const WCHAR * pcszEvictedNodeNameIn
|
|
, DWORD dwDelayIn
|
|
, DWORD dwTimeoutIn
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
HRESULT hrInit = S_OK;
|
|
IDispatch * pDisp = NULL;
|
|
|
|
//
|
|
// Initialize COM - make sure it really init'ed or that we're just trying
|
|
// to change modes on the calling thread. Attempting to change to mode
|
|
// is not reason to fail this function.
|
|
//
|
|
hrInit = CoInitializeEx( NULL, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE );
|
|
if ( ( hrInit != S_OK ) && ( hrInit != S_FALSE ) && ( hrInit != RPC_E_CHANGED_MODE ) )
|
|
{
|
|
hr = hrInit;
|
|
goto Exit;
|
|
} // if:
|
|
|
|
MULTI_QI mqiInterfaces[] =
|
|
{
|
|
{ &IID_IDispatch, NULL, S_OK },
|
|
};
|
|
|
|
COSERVERINFO csiServerInfo;
|
|
COSERVERINFO * pcsiServerInfoPtr = &csiServerInfo;
|
|
|
|
if ( pcszEvictedNodeNameIn == NULL )
|
|
{
|
|
pcsiServerInfoPtr = NULL;
|
|
} // if: we have to cleanup the local node
|
|
else
|
|
{
|
|
csiServerInfo.dwReserved1 = 0;
|
|
csiServerInfo.pwszName = const_cast< LPWSTR >( pcszEvictedNodeNameIn );
|
|
csiServerInfo.pAuthInfo = NULL;
|
|
csiServerInfo.dwReserved2 = 0;
|
|
} // else: we have to clean up a remote node
|
|
|
|
//
|
|
// Instantiate this component on the evicted node.
|
|
//
|
|
hr = CoCreateInstanceEx(
|
|
CLSID_ClusCfgAsyncEvictCleanup
|
|
, NULL
|
|
, CLSCTX_LOCAL_SERVER
|
|
, pcsiServerInfoPtr
|
|
, sizeof( mqiInterfaces ) / sizeof( mqiInterfaces[0] )
|
|
, mqiInterfaces
|
|
);
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if: we could not instantiate the evict processing component
|
|
|
|
pDisp = reinterpret_cast< IDispatch * >( mqiInterfaces[ 0 ].pItf );
|
|
|
|
{
|
|
OLECHAR * pszMethodName = L"CleanupNode";
|
|
DISPID dispidCleanupNode;
|
|
VARIANT vResult;
|
|
|
|
VARIANTARG rgvaCleanupNodeArgs[ 3 ];
|
|
|
|
DISPPARAMS dpCleanupNodeParams = {
|
|
rgvaCleanupNodeArgs
|
|
, NULL
|
|
, sizeof( rgvaCleanupNodeArgs ) / sizeof( rgvaCleanupNodeArgs[ 0 ] )
|
|
, 0
|
|
};
|
|
|
|
// Get the dispatch id of the CleanupNode() method.
|
|
hr = pDisp->GetIDsOfNames( IID_NULL, &pszMethodName, 1, LOCALE_SYSTEM_DEFAULT, &dispidCleanupNode );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if: we could not get the dispid of the CleanupNode() method
|
|
|
|
//
|
|
// Initialize the arguments. Note, the parameters are stored in the reverse order in the array.
|
|
//
|
|
|
|
// Initialize the return value.
|
|
VariantInit( &vResult );
|
|
|
|
// The first parameter is the name of the node.
|
|
VariantInit( &rgvaCleanupNodeArgs[ 2 ] );
|
|
rgvaCleanupNodeArgs[ 2 ].vt = VT_BSTR;
|
|
rgvaCleanupNodeArgs[ 2 ].bstrVal = NULL;
|
|
|
|
// The second parameter is the delay.
|
|
VariantInit( &rgvaCleanupNodeArgs[ 1 ] );
|
|
rgvaCleanupNodeArgs[ 1 ].vt = VT_UI4;
|
|
rgvaCleanupNodeArgs[ 1 ].ulVal = dwDelayIn;
|
|
|
|
// The third parameter is the timeout.
|
|
VariantInit( &rgvaCleanupNodeArgs[ 0 ] );
|
|
rgvaCleanupNodeArgs[ 0 ].vt = VT_UI4;
|
|
rgvaCleanupNodeArgs[ 0 ].ulVal = dwTimeoutIn;
|
|
|
|
//
|
|
// Invoke the CleanupNode() method.
|
|
//
|
|
hr = pDisp->Invoke(
|
|
dispidCleanupNode
|
|
, IID_NULL
|
|
, LOCALE_SYSTEM_DEFAULT
|
|
, DISPATCH_METHOD
|
|
, &dpCleanupNodeParams
|
|
, &vResult
|
|
, NULL
|
|
, NULL
|
|
);
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if: we could not invoke the CleanupNode() method
|
|
|
|
hr = vResult.scode;
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if: CleanupNode() failed
|
|
} // block:
|
|
|
|
Cleanup:
|
|
|
|
//
|
|
// Free acquired resources
|
|
//
|
|
|
|
if ( pDisp != NULL )
|
|
{
|
|
pDisp->Release();
|
|
} // if: we had obtained a pointer to the IDispatch interface
|
|
|
|
//
|
|
// Did the call to CoInitializeEx() above succeed? If it did then
|
|
// we need to call CoUnitialize(). Mode changed means we don't need
|
|
// to call CoUnitialize().
|
|
//
|
|
if ( hrInit != RPC_E_CHANGED_MODE )
|
|
{
|
|
CoUninitialize();
|
|
} // if:
|
|
|
|
Exit:
|
|
|
|
return hr;
|
|
|
|
} //*** ClRtlAsyncCleanupNode()
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// ClRtlHasNodeBeenEvicted()
|
|
//
|
|
// Routine Description:
|
|
// Finds out if a registry value indicating that this node has been
|
|
// evicted, is set or not
|
|
//
|
|
// Arguments:
|
|
// BOOL * pfNodeEvictedOut
|
|
// Pointer to the boolean variable that will be set to TRUE if
|
|
// the node has been evicted, but not cleaned up and FALSE
|
|
// otherwise
|
|
//
|
|
// Return Value:
|
|
// ERROR_SUCCESS
|
|
// If the eviction state could be successfully determined.
|
|
//
|
|
// Other Win32 error codes
|
|
// In case of error
|
|
//
|
|
//--
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
DWORD ClRtlHasNodeBeenEvicted( BOOL * pfNodeEvictedOut )
|
|
{
|
|
DWORD dwError = ERROR_SUCCESS;
|
|
HKEY hNodeStateKey = NULL;
|
|
|
|
do
|
|
{
|
|
DWORD dwEvictState = 0;
|
|
DWORD dwType;
|
|
DWORD dwSize;
|
|
|
|
// Validate parameter
|
|
if ( pfNodeEvictedOut == NULL )
|
|
{
|
|
dwError = ERROR_INVALID_PARAMETER;
|
|
break;
|
|
} // if: the output parameter is invalid
|
|
|
|
// Initialize output.
|
|
*pfNodeEvictedOut = FALSE;
|
|
|
|
// Open a registry key that holds a value indicating that this node has been evicted.
|
|
dwError = RegOpenKeyEx(
|
|
HKEY_LOCAL_MACHINE
|
|
, CLUSREG_KEYNAME_NODE_DATA
|
|
, 0
|
|
, KEY_ALL_ACCESS
|
|
, &hNodeStateKey
|
|
);
|
|
|
|
if ( dwError != ERROR_SUCCESS )
|
|
{
|
|
break;
|
|
} // if: RegOpenKeyEx() has failed
|
|
|
|
// Read the required registry value
|
|
dwSize = sizeof( dwEvictState );
|
|
dwError = RegQueryValueEx(
|
|
hNodeStateKey
|
|
, CLUSREG_NAME_EVICTION_STATE
|
|
, 0
|
|
, &dwType
|
|
, reinterpret_cast< BYTE * >( &dwEvictState )
|
|
, &dwSize
|
|
);
|
|
|
|
if ( dwError == ERROR_FILE_NOT_FOUND )
|
|
{
|
|
// This is ok - absence of the value indicates that this node has not been evicted.
|
|
dwEvictState = 0;
|
|
dwError = ERROR_SUCCESS;
|
|
} // if: RegQueryValueEx did not find the value
|
|
else if ( dwError != ERROR_SUCCESS )
|
|
{
|
|
break;
|
|
} // else if: RegQueryValueEx() has failed
|
|
|
|
*pfNodeEvictedOut = ( dwEvictState == 0 ) ? FALSE : TRUE;
|
|
}
|
|
while( false ); // dummy do-while loop to avoid gotos
|
|
|
|
//
|
|
// Free acquired resources
|
|
//
|
|
|
|
if ( hNodeStateKey != NULL )
|
|
{
|
|
RegCloseKey( hNodeStateKey );
|
|
} // if: we had opened the node state registry key
|
|
|
|
return dwError;
|
|
} //*** ClRtlHasNodeBeenEvicted()
|