317 lines
8.8 KiB
C++
317 lines
8.8 KiB
C++
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Copyright (C) 2000, Microsoft Corporation
|
|
//
|
|
// File: DfsFolder.cxx
|
|
//
|
|
// Contents: implements the base DFS Folder class
|
|
//
|
|
// Classes: DfsFolder.
|
|
//
|
|
// History: Dec. 8 2000, Author: udayh
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#include "DfsFolder.hxx"
|
|
#include "DfsFolderReferralData.hxx"
|
|
#include "DfsInit.hxx"
|
|
|
|
//
|
|
// logging specific includes
|
|
//
|
|
|
|
#include "DfsFolder.tmh"
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: GetReferralData - get the referral data
|
|
//
|
|
// Arguments: ppReferralData - the referral data for this folder
|
|
// pCacheHit - did we find it already loaded?
|
|
//
|
|
// Returns: Status
|
|
// ERROR_SUCCESS if we could get the referral data
|
|
// error status otherwise.
|
|
//
|
|
//
|
|
// Description: This routine returns a reference DfsFolderReferralDAta
|
|
// for the folder. If one does not already exist in this
|
|
// folder, we create a new one. If someone is in the process
|
|
// of loading the referral, we wait on the event in
|
|
// the referral data which gets signalled when the thread
|
|
// responsible for loading is done with the load.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
DFSSTATUS
|
|
DfsFolder::GetReferralData(
|
|
OUT DfsFolderReferralData **ppReferralData,
|
|
OUT BOOLEAN *pCacheHit )
|
|
{
|
|
DfsFolderReferralData *pRefData;
|
|
DFSSTATUS Status = STATUS_SUCCESS;
|
|
|
|
*pCacheHit = FALSE;
|
|
|
|
Status = AcquireWriteLock();
|
|
if ( Status != STATUS_SUCCESS )
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// WE take difference action depending on the load state.
|
|
//
|
|
switch ( _LoadState )
|
|
{
|
|
case DfsFolderLoaded:
|
|
|
|
DFS_TRACE_HIGH(REFERRAL_SERVER, " Get Referral Data: Cache hit\n");
|
|
//
|
|
// we are dealing with a loaded folder. Just acquire a reference
|
|
// and return the loaded referral data.
|
|
//
|
|
ASSERT (_pReferralData != NULL);
|
|
|
|
pRefData = _pReferralData;
|
|
|
|
pRefData->Timeout = _Timeout;
|
|
pRefData->AcquireReference();
|
|
|
|
ReleaseLock();
|
|
|
|
*pCacheHit = TRUE;
|
|
*ppReferralData = pRefData;
|
|
|
|
break;
|
|
|
|
case DfsFolderNotLoaded:
|
|
|
|
//
|
|
// The folder is not loaded. Make sure that the referral data is
|
|
// indeed empty. Create a new instance of the referral data
|
|
// and set the state to load in progress.
|
|
// The create reference of the folder referral data is inherited
|
|
// by the folder. (we are holding a reference to the referral
|
|
// data in _pReferralData). This reference is released when
|
|
// we RemoveReferralData at a later point.
|
|
//
|
|
ASSERT(_pReferralData == NULL);
|
|
DFS_TRACE_HIGH(REFERRAL_SERVER, " Get Referral Data: not loaded\n");
|
|
|
|
_pReferralData = new DfsFolderReferralData( &Status,
|
|
this );
|
|
if ( _pReferralData != NULL )
|
|
{
|
|
_LoadState = DfsFolderLoadInProgress;
|
|
|
|
if (IsFolderRoot() == TRUE)
|
|
{
|
|
_pReferralData->SetRootReferral();
|
|
}
|
|
|
|
_pReferralData->Timeout = _Timeout;
|
|
|
|
//
|
|
// Acquire a reference on the new referral data, since we
|
|
// have to return a referenced referral data to the caller.
|
|
//
|
|
pRefData = _pReferralData;
|
|
pRefData->AcquireReference();
|
|
} else
|
|
{
|
|
Status = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
//
|
|
// We no longer need the lock. We have allocate the referral
|
|
// data and marked the state accordingly. No other thread can
|
|
// interfere with our load now.
|
|
//
|
|
ReleaseLock();
|
|
|
|
//
|
|
// Now we load the referral data, and save the status of the
|
|
// load in both our load status as well as the load status
|
|
// in the referral data.
|
|
// If the load was successful, we add this to the loaded list
|
|
// of referral data that can be scavenged later. We set the load
|
|
// state to loaded, and signal the event so that all waiting
|
|
// threads can now be woken up.
|
|
//
|
|
|
|
if ( Status == ERROR_SUCCESS )
|
|
{
|
|
DFSLOG(" Load called on link %wZ (%wZ)\n",
|
|
GetFolderMetadataName(),
|
|
GetFolderLogicalName() );
|
|
|
|
|
|
Status = LoadReferralData( _pReferralData );
|
|
|
|
_LoadStatus = Status;
|
|
_pReferralData->LoadStatus = Status;
|
|
|
|
|
|
if ( Status == ERROR_SUCCESS )
|
|
{
|
|
_LoadState = DfsFolderLoaded;
|
|
DfsAddReferralDataToLoadedList( _pReferralData );
|
|
*ppReferralData = pRefData;
|
|
pRefData->Signal();
|
|
} else
|
|
{
|
|
_LoadState = DfsFolderLoadFailed;
|
|
pRefData->Signal();
|
|
pRefData->ReleaseReference();
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case DfsFolderLoadInProgress:
|
|
|
|
//
|
|
// The load is in progress. We acquire a reference on the
|
|
// referral data being loaded and wait for the event in the
|
|
// referral data to be signalled. The return status of the wait
|
|
// indicates if we can return the referral data or we fail
|
|
// this request with an error.
|
|
//
|
|
DFS_TRACE_HIGH(REFERRAL_SERVER, " Get Referral Data: load in progress\n");
|
|
ASSERT(_pReferralData != NULL);
|
|
pRefData = _pReferralData;
|
|
pRefData->AcquireReference();
|
|
|
|
ReleaseLock();
|
|
|
|
DFSLOG("Thread: Waiting for referral load\n");
|
|
|
|
Status = pRefData->Wait();
|
|
|
|
if ( Status == ERROR_SUCCESS )
|
|
{
|
|
*ppReferralData = pRefData;
|
|
} else
|
|
{
|
|
pRefData->ReleaseReference();
|
|
}
|
|
DFS_TRACE_HIGH(REFERRAL_SERVER, " Get Referral Data: load in progress done\n");
|
|
break;
|
|
|
|
case DfsFolderLoadFailed:
|
|
//
|
|
// The Load failed. REturn error. We need to setup a time
|
|
// after which we need to reattempt the load.
|
|
//
|
|
Status = _LoadStatus;
|
|
ReleaseLock();
|
|
*ppReferralData = NULL;
|
|
break;
|
|
|
|
default:
|
|
//
|
|
// We should never get here. Its an invalid state.
|
|
//
|
|
ASSERT(TRUE);
|
|
Status = ERROR_INVALID_STATE;
|
|
ReleaseLock();
|
|
|
|
break;
|
|
}
|
|
|
|
if ((Status == ERROR_SUCCESS) &&
|
|
(*ppReferralData == NULL))
|
|
{
|
|
DbgBreakPoint();
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: RemoveReferralData - remove the referral data from folder
|
|
//
|
|
// Arguments: NONE
|
|
//
|
|
// Returns: Status
|
|
// ERROR_SUCCESS if we could remove the referral data
|
|
// error status otherwise.
|
|
//
|
|
//
|
|
// Description: This routine removes the cached reference to the loaded
|
|
// referral data in the folder, and releases its reference
|
|
// on it.
|
|
// This causes all future GetREferralDAta to be loaded
|
|
// back from the store.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
DFSSTATUS
|
|
DfsFolder::RemoveReferralData(
|
|
DfsFolderReferralData *pRemoveReferralData,
|
|
PBOOLEAN pRemoved )
|
|
{
|
|
DFSSTATUS Status;
|
|
DfsFolderReferralData *pRefData = NULL;
|
|
|
|
//
|
|
// Get tnhe exclusive lock on the folder
|
|
//
|
|
if (pRemoved != NULL)
|
|
{
|
|
*pRemoved = FALSE;
|
|
}
|
|
|
|
Status = AcquireWriteLock();
|
|
if ( Status != ERROR_SUCCESS )
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// make sure _LoadState indicates that it is loaded.
|
|
// Set the referralData to null, and state to NotLoaded.
|
|
//
|
|
if (_LoadState == DfsFolderLoaded)
|
|
{
|
|
|
|
pRefData = _pReferralData;
|
|
if ( (pRemoveReferralData == NULL) ||
|
|
(pRemoveReferralData == pRefData) )
|
|
{
|
|
_pReferralData = NULL;
|
|
_LoadState = DfsFolderNotLoaded;
|
|
}
|
|
else {
|
|
pRefData = NULL;
|
|
}
|
|
}
|
|
|
|
ReleaseLock();
|
|
|
|
//
|
|
// Release reference on the referral data. This is the reference
|
|
// we had taken when we had cached the referral data in this folder.
|
|
//
|
|
if (pRefData != NULL)
|
|
{
|
|
pRefData->ReleaseReference();
|
|
if (pRemoved != NULL)
|
|
{
|
|
*pRemoved = TRUE;
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
|