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.
 
 
 
 
 
 

1518 lines
51 KiB

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1991 - 2002.
//
// File: PrpStMgr.cxx
//
// Contents: A two-level property store.
//
// Classes: CPropStoreManager
//
// History: 24-Oct-1997 KrishnaN Created
//
//----------------------------------------------------------------------------
#include <pch.cxx>
#pragma hdrstop
#include <prpstmgr.hxx>
#include <propobj.hxx>
#include <eventlog.hxx>
#include <catalog.hxx>
#include <imprsnat.hxx>
#include <propiter.hxx>
//+---------------------------------------------------------------------------
//
// Member: CPropStoreManager::CPropStoreManager, public
//
// Synopsis: Constructs the class.
//
// History: 24-Oct-97 KrishnaN Created.
// 01-Nov-98 KLam Added cMegToLeaveOnDisk to constructor
//
//----------------------------------------------------------------------------
CPropStoreManager::CPropStoreManager( ULONG cMegToLeaveOnDisk )
: _pStorage( 0 ),
_xPrimaryStore( 0 ),
_xSecondaryStore( 0 ),
_dwXctionStoreLevel( INVALID_STORE_LEVEL ),
_cMegToLeaveOnDisk( cMegToLeaveOnDisk )
{
_xPrimaryStore.Set(new CPropertyStore(*this, PRIMARY_STORE));
_xSecondaryStore.Set(new CPropertyStore(*this, SECONDARY_STORE));
}
//+---------------------------------------------------------------------------
//
// Member: CPropStoreManager::CPropStoreManager, public
//
// Synopsis: Constructs the class.
//
// History: 24-Oct-97 KrishnaN Created.
// 01-Nov-98 KLam Added cMegToLeaveOnDisk to constructor
//
//----------------------------------------------------------------------------
CPropStoreManager::CPropStoreManager(CiStorage * pStorage,
CPropertyStore *pPrimaryStore,
CPropertyStore *pSecondaryStore,
ULONG cMegToLeaveOnDisk )
: _pStorage( pStorage ),
_dwXctionStoreLevel( INVALID_STORE_LEVEL ),
_cMegToLeaveOnDisk( cMegToLeaveOnDisk )
{
_xPrimaryStore.Set( pPrimaryStore );
_xSecondaryStore.Set( pSecondaryStore );
}
//+---------------------------------------------------------------------------
//
// Member: CPropStoreManager::~CPropStoreManager, public
//
// Synopsis: Destructs the class.
//
// History: 24-Oct-97 KrishnaN Created.
//
//----------------------------------------------------------------------------
CPropStoreManager::~CPropStoreManager()
{
if ( !_xpsNew.IsNull() )
{
//
// The property stores in xpsnew are owned by the property stores
// in this instance (the one being destructed) of the property
// stores. They're in smart pointers but you can't delete them.
//
_xpsNew->_xPrimaryStore.Acquire();
_xpsNew->_xSecondaryStore.Acquire();
_xpsNew.Free();
}
}
//+---------------------------------------------------------------------------
//
// Member: CPropStoreManager::Empty
//
// Synopsis: Empties out the intitialized members and prepares for a
// re-init.
//
// History: 22-Oct-97 KrishnaN Created
//
//----------------------------------------------------------------------------
void CPropStoreManager::Empty()
{
_xPrimaryStore->Empty();
_xSecondaryStore->Empty();
_pStorage = 0;
}
//+---------------------------------------------------------------------------
//
// Member: CPropStoreManager::FastInit, public
//
// Synopsis: Initialize property store (two-phase construction)
//
// Arguments: [pStorage] -- Storage object.
//
// History: 22-Oct-97 KrishnaN Created
//
//----------------------------------------------------------------------------
void CPropStoreManager::FastInit( CiStorage * pStorage )
{
_pStorage = pStorage;
_xPrimaryStore->FastInit(pStorage);
_xSecondaryStore->FastInit(pStorage);
}
//+---------------------------------------------------------------------------
//
// Member: CPropStoreManager::LongInit
//
// Synopsis: If the propstore was dirty when shut down, run the recovery
// operation.
//
// Arguments: [fWasDirty] -- dirty flag is returned here
// [cInconsistencies] -- returns number of inconsistencies found
// [pfnUpdateCallback]-- Callback to be called to update docs during
// recovery. the prop store has no knowledge of
// doc store, so this callback is needed.
// [pUserData] -- will be echoed back through callback.
//
// Returns:
//
// History: 22-Oct-97 KrishnaN Created
//
// Notes: The propstore is locked for write during recovery, but
// reads are still permitted.
//
//----------------------------------------------------------------------------
void CPropStoreManager::LongInit( BOOL & fWasDirty, ULONG & cInconsistencies,
T_UpdateDoc pfnUpdateCallback, void const *pUserData )
{
//
// If at least one of the two stores is dirty, consider both to be dirty
// and recover from both.
//
ciDebugOut(( DEB_ITRACE, "is primary dirty: %d, is secondary dirty %d\n",
_xPrimaryStore->IsDirty(), _xSecondaryStore->IsDirty() ));
ciDebugOut(( DEB_ITRACE, "is backedup mode: %d\n", IsBackedUpMode() ));
if (IsDirty())
{
_xPrimaryStore->_PropStoreInfo.MarkDirty();
_xSecondaryStore->_PropStoreInfo.MarkDirty();
}
//
// If at least one of them recovered with inconsistencies, both should be
// considered to be corrupt!
//
_xPrimaryStore->LongInit(fWasDirty, cInconsistencies, pfnUpdateCallback, pUserData);
ciDebugOut(( DEB_ITRACE, "fWas, cIncon: %d, %d\n", fWasDirty, cInconsistencies ));
if (fWasDirty && cInconsistencies)
{
// Propstore is considered corrupt. No point attempting recovery on
// secondary.
return;
}
_xSecondaryStore->LongInit(fWasDirty, cInconsistencies, pfnUpdateCallback, pUserData);
ciDebugOut(( DEB_ITRACE, "2nd: fWas, cIncon: %d, %d\n", fWasDirty, cInconsistencies ));
if (fWasDirty && cInconsistencies)
{
// Propstore is still corrupt.
return;
}
// Are both the stores in sync
// First line defense
if (_xPrimaryStore->CountRecordsInUse() != _xSecondaryStore->CountRecordsInUse())
{
Win4Assert(fWasDirty);
cInconsistencies = abs((LONG)_xPrimaryStore->CountRecordsInUse() -
(LONG)_xSecondaryStore->CountRecordsInUse());
return;
}
// We have done our best to recover from a dirty shutdown. However, in at least one
// case (bug 132655), it was detected that there was an inconsistency between the
// two stores. Ensure that we catch such inconsistencies.
if (IsDirty())
{
CPropertyStoreWids iter(*this);
ULONG iRec = 0;
const ULONG cTotal = _xPrimaryStore->CountRecordsInUse();
for ( WORKID wid = iter.WorkId();
!cInconsistencies && wid != widInvalid;
wid = iter.LokNextWorkId() )
{
iRec++;
// get the physical store pointed to by the primary top-level record
CBorrowed BorrowedTopLevel( *(_xSecondaryStore->PhysStore()),
GetSecondaryTopLevelWid(wid),
_xSecondaryStore->RecordsPerPage(),
_xSecondaryStore->RecordSize() );
COnDiskPropertyRecord * prec = BorrowedTopLevel.Get();
if (!prec->IsInUse())
cInconsistencies++;
}
if (cInconsistencies)
return;
}
#if 0 // this is really expensive... CIDBG == 1
else
{
ULONG iRec = 0;
const ULONG cTotal = _xPrimaryStore->CountRecordsInUse();
CPropertyStoreWids iter(*this);
for ( WORKID wid = iter.WorkId(); wid != widInvalid; wid = iter.LokNextWorkId() )
{
iRec++;
// get the physical store pointed to by the primary top-level record
CBorrowed BorrowedTopLevel( *(_xSecondaryStore->PhysStore()),
GetSecondaryTopLevelWid(wid),
_xSecondaryStore->RecordsPerPage(),
_xSecondaryStore->RecordSize() );
COnDiskPropertyRecord * prec = BorrowedTopLevel.Get();
Win4Assert(prec->IsInUse());
}
}
#endif // CIDBG
// All is well. Flush and get on with the business of indexing and searching
Flush();
} //LongInit
//+---------------------------------------------------------------------------
//
// Member: CPropStoreManager::BeginTransaction, public
//
// Synopsis: Begins a schema transaction. Any existing transaction will be
// aborted.
//
// Returns: Token representing transaction.
//
// History: 24-Oct-97 KrishnaN Created.
// 02-Nov-98 KLam Passed _cMegToLeaveOnDisk to
// CPropStoreManager
//
//----------------------------------------------------------------------------
ULONG_PTR CPropStoreManager::BeginTransaction()
{
CLock lock( _mtxWrite );
// we are not committing, so the fixed pids are ignored.
if ( !_xpsNew.IsNull() )
EndTransaction( (ULONG_PTR)_xpsNew.Acquire(), FALSE, pidInvalid, pidInvalid);
ULONG_PTR ulPrimaryXctionToken = _xPrimaryStore->BeginTransaction();
ULONG_PTR ulSecondaryXctionToken = _xSecondaryStore->BeginTransaction();
_xpsNew.Set( new CPropStoreManager( _pStorage,
(CPropertyStore *)ulPrimaryXctionToken,
(CPropertyStore *)ulSecondaryXctionToken,
_cMegToLeaveOnDisk ) );
// init storelevel used in transaction to unknown.
_dwXctionStoreLevel = INVALID_STORE_LEVEL;
return (ULONG_PTR)_xpsNew.GetPointer();
}
//+---------------------------------------------------------------------------
//
// Member: CPropStoreManager::Setup, public
//
// Synopsis: Setup a property description. Property may already exist
// in the cache.
//
// Arguments: [pid] -- Propid
// [vt] -- Datatype of property. VT_VARIANT if unknown.
// [cbMaxLen] -- Soft-maximum length for variable length
// properties. This much space is pre-allocated
// in original record.
// [ulToken] -- Token of transaction
// [fCanBeModified]-- Can the prop meta info be modified once set?
//
// History: 22-Oct-97 KrishnaN Created.
//
//----------------------------------------------------------------------------
void CPropStoreManager::Setup( PROPID pid,
ULONG vt,
DWORD cbMaxLen,
ULONG_PTR ulToken,
BOOL fCanBeModified,
DWORD dwStoreLevel )
{
if ( ulToken != (ULONG_PTR)_xpsNew.GetPointer() )
{
ciDebugOut(( DEB_ERROR, "Transaction mismatch: 0x%x vs. 0x%x\n", ulToken, _xpsNew.GetPointer() ));
THROW( CException( STATUS_TRANSACTION_NO_MATCH ) );
}
//
// Currently we only allow operations on one store during a transaction.
// Remember that or enforce that, as appropriate.
//
if (INVALID_STORE_LEVEL == _dwXctionStoreLevel)
_dwXctionStoreLevel = dwStoreLevel;
else
{
Win4Assert(PRIMARY_STORE == dwStoreLevel || SECONDARY_STORE == dwStoreLevel);
// should be primary or secondary
if (PRIMARY_STORE != dwStoreLevel && SECONDARY_STORE != dwStoreLevel)
{
THROW( CException( STATUS_TRANSACTION_INVALID_TYPE ) );
}
// should be the same as the first store used in the transaction
if (_dwXctionStoreLevel != dwStoreLevel)
{
THROW( CException( STATUS_TRANSACTION_NO_MATCH ) );
}
}
// Before placing the pid in a store, assert that it doesn't
// exist in the other store.
CLock lock( _mtxWrite );
CPropStoreManager *pStoreMgr = (CPropStoreManager *)ulToken;
if (PRIMARY_STORE == dwStoreLevel)
{
Win4Assert(_xSecondaryStore->CanStore(pid) == FALSE);
if (_xSecondaryStore->CanStore(pid))
{
THROW( CException( STATUS_TRANSACTION_NO_MATCH ) );
}
_xPrimaryStore->Setup(pid, vt, cbMaxLen,
(ULONG_PTR)pStoreMgr->_xPrimaryStore.GetPointer(),
fCanBeModified);
}
else
{
Win4Assert(_xPrimaryStore->CanStore(pid) == FALSE);
if (_xPrimaryStore->CanStore(pid))
{
THROW( CException( STATUS_TRANSACTION_NO_MATCH ) );
}
_xSecondaryStore->Setup(pid, vt, cbMaxLen,
(ULONG_PTR)pStoreMgr->_xSecondaryStore.GetPointer(),
fCanBeModified);
}
}
//+---------------------------------------------------------------------------
//
// Member: CPropStoreManager::EndTransaction, public
//
// Synopsis: End property transaction, and maybe commit changes.
//
// Arguments: [ulToken] -- Token of transaction
// [fCommit] -- TRUE --> Commit transaction
// [pidFixedPrimary] -- Every workid with this pid will move to the
// same workid in the new property cache.
// [pidFixedSecondary] -- Every workid with this pid will move to the
// same workid in the new property cache.
//
// History: 22-Oct-97 KrishnaN Created.
//
//----------------------------------------------------------------------------
void CPropStoreManager::EndTransaction( ULONG_PTR ulToken, BOOL fCommit,
PROPID pidFixedPrimary,
PROPID pidFixedSecondary )
{
Win4Assert(ulToken);
CLock lock( _mtxWrite );
if ( ulToken != (ULONG_PTR)_xpsNew.GetPointer() )
{
ciDebugOut(( DEB_ERROR,
"PropStMgr: Transaction mismatch: 0x%x vs. 0x%x\n",
ulToken, _xpsNew.GetPointer() ));
THROW( CException( STATUS_TRANSACTION_NO_MATCH ) );
}
_xPrimaryStore->EndTransaction((ULONG_PTR)_xpsNew->_xPrimaryStore.GetPointer(),
fCommit, pidFixedPrimary);
_xSecondaryStore->EndTransaction((ULONG_PTR)_xpsNew->_xSecondaryStore.GetPointer(),
fCommit, pidFixedSecondary);
// The primary and secondary ptrs are already deleted in EndTransaction
// calls. Cleanup to reflect them prior to deleting _xpsNew.
_xpsNew->_xPrimaryStore.Acquire();
_xpsNew->_xSecondaryStore.Acquire();
_xpsNew.Free();
} //EndTransaction
//+---------------------------------------------------------------------------
//
// Member: CPropStoreManager::MakeBackupCopy
//
// Synopsis: Makes a backup copy of the property storage. It makes a
// full copy if the pIEnumWorkids is NULL. Otherwise, it makes
// a copy of only the changed workids.
//
// Arguments: [pIProgressEnum] - Progress indication
// [pfAbort] - Caller initiated abort flag
// [dstStorage] - Destination storage to use
// [pIEnumWorkids] - List of workids to copy. If null, all the
// workids are copied.
// [ppFileList] - List of propstore files copied.
//
// History: 22-Oct-97 KrishnaN Created
//
// Notes: Incremental not implemented yet
//
//----------------------------------------------------------------------------
void CPropStoreManager::MakeBackupCopy( IProgressNotify * pIProgressEnum,
BOOL & fAbort,
CiStorage & dstStorage,
ICiEnumWorkids * pIEnumWorkids,
IEnumString **ppFileList )
{
CLock lock( _mtxWrite );
Flush();
// fill in an array of sizes to pass into CCompositeProgressNotifier
DWORD *pdwStoreSizes = new DWORD[2];
pdwStoreSizes[0] = _xPrimaryStore->GetTotalSizeInKB();
pdwStoreSizes[1] = _xSecondaryStore->GetTotalSizeInKB();
CCompositeProgressNotifier ProgressNotifier( pIProgressEnum, pdwStoreSizes );
_xPrimaryStore->MakeBackupCopy(&ProgressNotifier, fAbort, dstStorage,
pIEnumWorkids, ppFileList);
ProgressNotifier.IncrementFinishedComponents();
ICiEnumWorkids *pIEnumSecondaryWorkids = pIEnumWorkids;
_xSecondaryStore->MakeBackupCopy(&ProgressNotifier, fAbort, dstStorage,
pIEnumSecondaryWorkids, ppFileList);
}
//+---------------------------------------------------------------------------
//
// Member: CPropStoreManager::WriteProperty, public
//
// Synopsis: Write a property to the cache.
//
// Arguments: [wid] -- Workid
// [pid] -- Propid
// [var] -- Value
//
// Returns: Scode propagated from underlying store.
//
// History: 24-Oct-97 KrishnaN Created.
//
//----------------------------------------------------------------------------
SCODE CPropStoreManager::WriteProperty( WORKID wid,
PROPID pid,
CStorageVariant const & var )
{
if ( _xPrimaryStore->CanStore( pid ) )
{
return WritePrimaryProperty( wid, pid, var );
}
else
{
CCompositePropRecordForWrites PropRecord( wid, *this, _mtxWrite );
return _xSecondaryStore->WriteProperty( PropRecord.GetSecondaryPropRecord(),
pid,
var,
IsBackedUpMode() );
}
} //WriteProperty
//+---------------------------------------------------------------------------
//
// Member: CPropStoreManager::WriteProperty, public
//
// Synopsis: Write a property to the specified cache.
//
// Arguments: [dwStoreLevle] -- level of the property store to write to
// [PropRecord] -- Previously opened property record.
// [pid] -- Propid
// [var] -- Value
//
// Returns: SCODE propagated from underlying store.
//
// History: 23-Oct-2000 KitmanH Created.
//
//----------------------------------------------------------------------------
SCODE CPropStoreManager::WriteProperty( DWORD dwStoreLevel,
CCompositePropRecordForWrites & PropRecord,
PROPID pid,
CStorageVariant const & var )
{
Win4Assert( PRIMARY_STORE == dwStoreLevel || SECONDARY_STORE == dwStoreLevel );
if ( PRIMARY_STORE == dwStoreLevel )
{
if ( _xPrimaryStore->CanStore( pid ) )
return WritePrimaryProperty( PropRecord, pid, var );
}
else
{
if ( _xSecondaryStore->CanStore( pid ) )
return WriteSecondaryProperty( PropRecord, pid, var );
}
return E_INVALIDARG;
} //WriteProperty
//+---------------------------------------------------------------------------
//
// Member: CPropStoreManager::WritePrimaryProperty, public
//
// Synopsis: Write a property from the cache. Triggers CoTaskMemAlloc
//
// Arguments: [wid] -- Workid
// [pid] -- Propid
// [var] -- Place to return the value
//
// History: 22-Oct-97 KrishnaN Created.
//
//----------------------------------------------------------------------------
SCODE CPropStoreManager::WritePrimaryProperty( WORKID wid,
PROPID pid,
CStorageVariant const & var )
{
CPrimaryPropRecordForWrites PropRecord( wid, *this, _mtxWrite );
return WritePrimaryProperty( PropRecord, pid, var );
}
//+---------------------------------------------------------------------------
//
// Member: CPropStoreManager::WriteProperty, public
//
// Synopsis: Write a property to the cache.
//
// Arguments: [PropRecord] -- Previously opened property record.
// [pid] -- Propid
// [var] -- Value
//
// Returns: Scode propagated from underlying store.
//
// History: 24-Oct-97 KrishnaN Created.
//
//----------------------------------------------------------------------------
SCODE CPropStoreManager::WriteProperty( CCompositePropRecordForWrites & PropRecord,
PROPID pid, CStorageVariant const & var )
{
ciDebugOut(( DEB_PROPSTORE, "WRITE: proprecord = 0x%x, pid = 0x%x, type = %d\n", &PropRecord, pid, var.Type() ));
if (_xPrimaryStore->CanStore(pid))
return _xPrimaryStore->WriteProperty(PropRecord.GetPrimaryPropRecord(), pid, var, IsBackedUpMode() );
else
return _xSecondaryStore->WriteProperty(PropRecord.GetSecondaryPropRecord(), pid, var, IsBackedUpMode() );
}
//+---------------------------------------------------------------------------
//
// Member: CPropStoreManager::WritePrimaryProperty, public
//
// Synopsis: Write a property from the cache. Triggers CoTaskMemAlloc
//
// Arguments: [PropRecord] -- Previously opened property record
// [pid] -- Propid
// [var] -- Place to return the value
//
// History: 17-Mar-98 KrishnaN Created.
//
//----------------------------------------------------------------------------
SCODE CPropStoreManager::WritePrimaryProperty( CCompositePropRecordForWrites & PropRecord,
PROPID pid, CStorageVariant const & var )
{
// Has to be used only to Write pids in the primary store.
Win4Assert(_xPrimaryStore->CanStore(pid) == TRUE);
return _xPrimaryStore->WriteProperty( PropRecord.GetPrimaryPropRecord(), pid, var, IsBackedUpMode() );
}
//+---------------------------------------------------------------------------
//
// Member: CPropStoreManager::WritePrimaryProperty, public
//
// Synopsis: Write a property from the cache. Triggers CoTaskMemAlloc
//
// Arguments: [PropRecord] -- Previously opened property record
// [pid] -- Propid
// [var] -- Place to return the value
//
// History: 17-Mar-98 KrishnaN Created.
//
//----------------------------------------------------------------------------
SCODE CPropStoreManager::WritePrimaryProperty( CPrimaryPropRecordForWrites & PropRecord,
PROPID pid,
CStorageVariant const & var )
{
// Has to be used only to Write pids in the primary store.
Win4Assert(_xPrimaryStore->CanStore(pid) == TRUE);
return _xPrimaryStore->WriteProperty( PropRecord.GetPrimaryPropRecord(), pid, var, IsBackedUpMode() );
}
//+---------------------------------------------------------------------------
//
// Member: CPropStoreManager::WriteSecondaryProperty, public
//
// Synopsis: Write a property from the cache. Triggers CoTaskMemAlloc
//
// Arguments: [PropRecord] -- Previously opened property record
// [pid] -- Propid
// [var] -- Place to return the value
//
// History: 23-Oct-2000 KitmanH Created.
//
//----------------------------------------------------------------------------
SCODE CPropStoreManager::WriteSecondaryProperty( CCompositePropRecordForWrites & PropRecord,
PROPID pid, CStorageVariant const & var )
{
Win4Assert(_xSecondaryStore->CanStore(pid) == TRUE);
return _xSecondaryStore->WriteProperty( PropRecord.GetSecondaryPropRecord(), pid, var, IsBackedUpMode() );
}
//+---------------------------------------------------------------------------
//
// Member: CPropStoreManager::ReadProperty, public
//
// Synopsis: Read a property from the cache.
//
// Arguments: [wid] -- Workid
// [pid] -- Propid
// [pbData] -- Place to return the value
// [pcb] -- On input, the maximum number of bytes to
// write at pbData. On output, the number of
// bytes written if the call was successful,
// else the number of bytes required.
//
// History: 22-Oct-97 KrishnaN Created.
//
//----------------------------------------------------------------------------
BOOL CPropStoreManager::ReadProperty( WORKID wid, PROPID pid,
PROPVARIANT * pbData, unsigned * pcb )
{
unsigned cb = *pcb - sizeof (PROPVARIANT);
BOOL fOk = ReadProperty( wid, pid, *pbData, (BYTE *)(pbData + 1), &cb );
*pcb = cb + sizeof (PROPVARIANT);
return fOk;
}
//+---------------------------------------------------------------------------
//
// Member: CPropStoreManager::ReadProperty, public
//
// Synopsis: Read a property from the cache. Version which uses property
// record.
//
// Arguments: [PropRec] -- Pre-opened property record
// [pid] -- Propid
// [pbData] -- Place to return the value
// [pcb] -- On input, the maximum number of bytes to
// write at pbData. On output, the number of
// bytes written if the call was successful,
// else the number of bytes required.
//
// History: 22-Oct-97 KrishnaN Created.
//
//----------------------------------------------------------------------------
BOOL CPropStoreManager::ReadProperty( CCompositePropRecord & PropRec,
PROPID pid,
PROPVARIANT * pbData,
unsigned * pcb )
{
unsigned cb = *pcb - sizeof (PROPVARIANT);
BOOL fOk = ReadProperty( PropRec, pid, *pbData, (BYTE *)(pbData + 1), &cb );
*pcb = cb + sizeof (PROPVARIANT);
return fOk;
}
//+---------------------------------------------------------------------------
//
// Member: CPropStoreManager::ReadProperty, public
//
// Synopsis: Read a property from the cache. Version which uses property
// record.
//
// Arguments: [PropRec] -- Pre-opened property record
// [pid] -- Propid
// [var] -- Place to return the value
//
// History: 19-Dec-97 dlee Created.
//
//----------------------------------------------------------------------------
BOOL CPropStoreManager::ReadProperty(
CCompositePropRecord & PropRec,
PROPID pid,
PROPVARIANT & var )
{
unsigned cb = 0xFFFFFFFF;
return ReadProperty( PropRec, pid, var, 0, &cb );
}
//+---------------------------------------------------------------------------
//
// Member: CPropStoreManager::ReadProperty, public
//
// Synopsis: Read a property from the cache. Version which uses property
// record.
//
// Arguments: [PropRec] -- Pre-opened property record
// [pid] -- Propid
// [var] -- Place to return the value
//
// History: 19-Dec-97 dlee Created.
//
//----------------------------------------------------------------------------
BOOL CPropStoreManager::ReadProperty(
CPrimaryPropRecord & PropRec,
PROPID pid,
PROPVARIANT & var )
{
unsigned cb = 0xFFFFFFFF;
return ReadProperty( PropRec, pid, var, 0, &cb );
}
//+---------------------------------------------------------------------------
//
// Member: CPropStoreManager::ReadProperty, public
//
// Synopsis: Read a property from the cache. Triggers CoTaskMemAlloc
//
// Arguments: [wid] -- Workid
// [pid] -- Propid
// [var] -- Place to return the value
//
// History: 22-Oct-97 KrishnaN Created.
//
//----------------------------------------------------------------------------
BOOL CPropStoreManager::ReadProperty(
WORKID wid,
PROPID pid,
PROPVARIANT & var )
{
unsigned cb = 0xFFFFFFFF;
return ReadProperty( wid, pid, var, 0, &cb );
}
//+---------------------------------------------------------------------------
//
// Member: CPropStoreManager::ReadProperty, public
//
// Synopsis: Read a property from the cache. Triggers CoTaskMemAlloc
//
// Arguments: [wid] -- Workid
// [pid] -- Propid
// [var] -- Place to return the value
//
// History: 22-Oct-97 KrishnaN Created.
//
//----------------------------------------------------------------------------
BOOL CPropStoreManager::ReadPrimaryProperty( WORKID wid, PROPID pid, PROPVARIANT & var )
{
// Has to be used only to read pids in the primary store.
Win4Assert(_xPrimaryStore->CanStore(pid) == TRUE);
unsigned cb = 0xFFFFFFFF;
BOOL fOk = _xPrimaryStore->ReadProperty( wid, pid, var, 0, &cb );
return fOk;
}
//+---------------------------------------------------------------------------
//
// Member: CPropStoreManager::ReadProperty, public
//
// Synopsis: Read a property from the cache. Separate variable buffer.
//
// Arguments: [wid] -- Workid
// [pid] -- Propid
// [var] -- Variant written here
// [pbExtra] -- Place to store additional pointer(s).
// [pcbExtra] -- On input, the maximum number of bytes to
// write at pbExtra. On output, the number of
// bytes written if the call was successful,
// else the number of bytes required.
//
// History: 24-Oct-97 KrishnaN Created.
//
//----------------------------------------------------------------------------
BOOL CPropStoreManager::ReadProperty( WORKID wid,
PROPID pid,
PROPVARIANT & var,
BYTE * pbExtra,
unsigned * pcbExtra )
{
if ( _xPrimaryStore->CanStore( pid ) )
{
CPrimaryPropRecord PropRecord( wid, *this );
return ReadProperty( PropRecord, pid, var, pbExtra, pcbExtra );
}
else
{
// the constructor seeds the constituent proprecords
// with the right wid, based on the wid we pass in.
CCompositePropRecord PropRecord( wid, *this );
return _xSecondaryStore->ReadProperty( PropRecord.GetSecondaryPropRecord(),
pid, var, pbExtra, pcbExtra);
}
} //ReadProperty
//+---------------------------------------------------------------------------
//
// Member: CPropStoreManager::ReadProperty, public
//
// Synopsis: Read a property from the cache. Separate variable buffer.
// Uses pre-opened property record.
//
// Arguments: [PropRec] -- Pre-opened property record.
// [pid] -- Propid
// [var] -- Variant written here
// [pbExtra] -- Place to store additional pointer(s).
// [pcbExtra] -- On input, the maximum number of bytes to
// write at pbExtra. On output, the number of
// bytes written if the call was successful,
// else the number of bytes required.
//
// History: 03-Apr-96 KyleP Created.
//
//----------------------------------------------------------------------------
BOOL CPropStoreManager::ReadProperty( CCompositePropRecord & PropRecord,
PROPID pid,
PROPVARIANT & var,
BYTE * pbExtra,
unsigned * pcbExtra )
{
if (_xPrimaryStore->CanStore(pid))
{
return _xPrimaryStore->ReadProperty(PropRecord.GetPrimaryPropRecord(),
pid, var, pbExtra, pcbExtra);
}
else
{
return _xSecondaryStore->ReadProperty(PropRecord.GetSecondaryPropRecord(),
pid, var, pbExtra, pcbExtra);
}
}
//+---------------------------------------------------------------------------
//
// Member: CPropStoreManager::ReadProperty, public
//
// Synopsis: Read a property from the cache. Separate variable buffer.
// Uses pre-opened property record.
//
// Arguments: [PropRec] -- Pre-opened property record.
// [pid] -- Propid
// [var] -- Variant written here
// [pbExtra] -- Place to store additional pointer(s).
// [pcbExtra] -- On input, the maximum number of bytes to
// write at pbExtra. On output, the number of
// bytes written if the call was successful,
// else the number of bytes required.
//
// History: 03-Apr-96 KyleP Created.
//
//----------------------------------------------------------------------------
BOOL CPropStoreManager::ReadProperty( CPrimaryPropRecord & PropRecord,
PROPID pid,
PROPVARIANT & var,
BYTE * pbExtra,
unsigned * pcbExtra )
{
Win4Assert( _xPrimaryStore->CanStore(pid) );
return _xPrimaryStore->ReadProperty(PropRecord.GetPrimaryPropRecord(),
pid, var, pbExtra, pcbExtra);
}
//+---------------------------------------------------------------------------
//
// Member: CPropStoreManager::OpenRecord, public
//
// Synopsis: Opens record (for multiple reads)
//
// Arguments: [wid] -- Workid
// [pb] -- Storage for record
//
// Returns: Pointer to open property record. Owned by caller.
//
// History: 03-Apr-96 KyleP Created.
//
//----------------------------------------------------------------------------
CCompositePropRecord * CPropStoreManager::OpenRecord( WORKID wid, BYTE * pb )
{
Win4Assert( sizeof(CCompositePropRecord) <= sizeof_CCompositePropRecord );
return new( pb ) CCompositePropRecord( wid, *this );
}
//+---------------------------------------------------------------------------
//
// Member: CPropStoreManager::CloseRecord, public
//
// Synopsis: Closes record.
//
// Arguments: [pRec] -- Property record
//
// History: 03-Apr-96 KyleP Created.
//
//----------------------------------------------------------------------------
void CPropStoreManager::CloseRecord( CCompositePropRecord * pRec )
{
delete pRec;
}
//+---------------------------------------------------------------------------
//
// Member: CPropStoreManager::OpenPrimaryRecord, public
//
// Synopsis: Opens record (for multiple reads)
//
// Arguments: [wid] -- Workid
// [pb] -- Storage for record
//
// Returns: Pointer to open property record. Owned by caller.
//
// History: 03-Apr-96 KyleP Created.
//
//----------------------------------------------------------------------------
CPrimaryPropRecord * CPropStoreManager::OpenPrimaryRecord( WORKID wid, BYTE * pb )
{
Win4Assert( sizeof(CPrimaryPropRecord) <= sizeof_CPropRecord );
return new( pb ) CPrimaryPropRecord( wid, *this );
}
//+---------------------------------------------------------------------------
//
// Member: CPropStoreManager::CloseRecord, public
//
// Synopsis: Closes record.
//
// Arguments: [pRec] -- Property record
//
// History: 03-Apr-96 KyleP Created.
//
//----------------------------------------------------------------------------
void CPropStoreManager::CloseRecord( CPrimaryPropRecord * pRec )
{
delete pRec;
}
//+---------------------------------------------------------------------------
//
// Member: CPropStoreManager::OpenRecordForWrites, public
//
// Synopsis: Opens record (for multiple writes)
//
// Arguments: [wid] -- Workid
// [pb] -- Storage for record
//
// Returns: Pointer to open property record. Owned by caller.
//
// History: 17-Mar-98 KrishnaN Created.
//
//----------------------------------------------------------------------------
CCompositePropRecordForWrites * CPropStoreManager::OpenRecordForWrites( WORKID wid, BYTE * pb )
{
Win4Assert( sizeof(CCompositePropRecordForWrites) <= sizeof_CCompositePropRecord );
return new( pb ) CCompositePropRecordForWrites( wid, *this, _mtxWrite );
}
//+---------------------------------------------------------------------------
//
// Member: CPropStoreManager::OpenPrimaryRecordForWrites, public
//
// Synopsis: Opens record (for multiple writes)
//
// Arguments: [wid] -- Workid
// [pb] -- Storage for record
//
// Returns: Pointer to open property record. Owned by caller.
//
// History: 17-Mar-98 KrishnaN Created.
//
//----------------------------------------------------------------------------
CPrimaryPropRecordForWrites * CPropStoreManager::OpenPrimaryRecordForWrites( WORKID wid, BYTE * pb )
{
Win4Assert( sizeof(CPrimaryPropRecordForWrites) <= sizeof_CPropRecord );
return new( pb ) CPrimaryPropRecordForWrites( wid, *this, _mtxWrite );
}
//+---------------------------------------------------------------------------
//
// Member: CPropStoreManager::CloseRecord, public
//
// Synopsis: Closes record.
//
// Arguments: [pRec] -- Property record
//
// History: 17-Mar-98 KrishnaN Created.
//
//----------------------------------------------------------------------------
void CPropStoreManager::CloseRecord( CCompositePropRecordForWrites * pRec )
{
delete pRec;
}
//+---------------------------------------------------------------------------
//
// Member: CPropStoreManager::CloseRecord, public
//
// Synopsis: Closes record.
//
// Arguments: [pRec] -- Property record
//
// History: 17-Mar-98 KrishnaN Created.
//
//----------------------------------------------------------------------------
void CPropStoreManager::CloseRecord( CPrimaryPropRecordForWrites * pRec )
{
delete pRec;
}
//+---------------------------------------------------------------------------
//
// Member: CPropStoreManager::DeleteRecord, public
//
// Synopsis: Free a record and any records chained off it.
//
// Arguments: [wid] -- Workid
//
// History: 24-Oct-97 KrishnaN Created.
//
//----------------------------------------------------------------------------
void CPropStoreManager::DeleteRecord( WORKID wid )
{
CLock lock( _mtxWrite );
ciDebugOut(( DEB_PROPSTORE, "DELETE: wid = 0x%x\n", wid ));
//
// Get the secondary store's top-level wid before getting rid
// of the wid in the primary store.
//
//
// The secondary wid can certainly be bogus if we couldn't write
// it to the primary store after allocating it when creating the
// records.
//
WORKID widSec = GetSecondaryTopLevelWid(wid);
if ( widInvalid != widSec && 0 != widSec )
_xSecondaryStore->DeleteRecord( widSec,
IsBackedUpMode() );
_xPrimaryStore->DeleteRecord( wid, IsBackedUpMode() );
}
//+---------------------------------------------------------------------------
//
// Member: CPropStoreManager::Flush
//
// Synopsis: Flushes the data in the property store and marks it clean.
//
// History: 3-20-96 srikants Created
//
//----------------------------------------------------------------------------
void CPropStoreManager::Flush()
{
CLock mtxLock( _mtxWrite );
// Flush both the stores. Only when both are successful
// do we consider the entire flush to be successful.
// Don't reset the backup streams until the flush is
// completely successful.
BOOL fFlushOK = _xPrimaryStore->Flush();
if (fFlushOK)
fFlushOK = _xSecondaryStore->Flush();
// Reset the primary and the secondary backup stores
if (fFlushOK)
{
if (_xPrimaryStore->BackupStream())
_xPrimaryStore->BackupStream()->Reset(_xPrimaryStore->GetDesiredBackupSize());
if (_xSecondaryStore->BackupStream())
_xSecondaryStore->BackupStream()->Reset(_xSecondaryStore->GetDesiredBackupSize());
}
}
//+---------------------------------------------------------------------------
//
// Member: CPropStoreManager::WritePropertyInNewRecord, public
//
// Synopsis: Like WriteProperty, but also allocates record.
//
// Arguments: [pid] -- Propid to write.
// [var] -- Property value
//
// Returns: Workid of new record.
//
// History: 22-Oct-97 KrishnaN Created.
//
//----------------------------------------------------------------------------
WORKID CPropStoreManager::WritePropertyInNewRecord( PROPID pid,
CStorageVariant const & var )
{
CLock lock( _mtxWrite );
//
// Get new wids from the primary and the secondary store.
// Write the property.
// Increment records in use for both the stores.
//
WORKID widPrimary = widInvalid;
WORKID widSecondary = widInvalid;
TRY
{
widPrimary = _xPrimaryStore->NewWorkId( 1, IsBackedUpMode() );
widSecondary = _xSecondaryStore->NewWorkId( 1, IsBackedUpMode() );
}
CATCH(CException, e)
{
// cleanup if widSecondary is invalid
if (widInvalid == widSecondary && widInvalid != widPrimary)
_xPrimaryStore->DeleteRecord( widPrimary, IsBackedUpMode() );
// Let the caller do what it normally does to handle exceptions
RETHROW();
}
END_CATCH
ciDebugOut(( DEB_PROPSTORE, "New record at primary: %d, secondary: %d\n",
widPrimary, widSecondary ));
//
// The primary's top-level record has a pointer to the
// top-level record in the secondary store. Fill that now!
//
VARIANT newVar;
newVar.vt = VT_UI4;
newVar.ulVal = widSecondary;
CStorageVariant *pVar = CastToStorageVariant(newVar);
SCODE sc;
sc = WritePrimaryProperty( widPrimary, pidSecondaryStorage, *pVar );
if (FAILED(sc))
THROW(CException(sc));
sc = WriteProperty( widPrimary, pid, var );
//
// DLee add this assert to find out why this is failing sometimes.
// Did the caller pass a bogus variant?
//
Win4Assert( HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ) != sc );
if (FAILED(sc))
THROW(CException(sc));
_xPrimaryStore->IncRecordsInUse();
_xSecondaryStore->IncRecordsInUse();
// To the outside world, the primary wid is the one that matters.
return widPrimary;
}
//
// get and set parameters
// If incorrect parameter, default to the primary store.
//
//+---------------------------------------------------------------------------
//
// Member: CPropStoreManager::SetBackupSize, public
//
// Synopsis: Sets backup size for a given property store.
//
// Arguments: [ulBackupSizeInPages] -- Size of the backup file.
// [dwStoreLevel] -- Primary or secondary store?
//
// History: 22-Oct-97 KrishnaN Created.
//
//----------------------------------------------------------------------------
void CPropStoreManager::SetBackupSize(ULONG ulBackupSizeInPages,
DWORD dwStoreLevel)
{
if (SECONDARY_STORE == dwStoreLevel)
_xSecondaryStore->SetBackupSize(ulBackupSizeInPages);
else
{
Win4Assert(PRIMARY_STORE == dwStoreLevel);
_xPrimaryStore->SetBackupSize(ulBackupSizeInPages);
}
}
//+---------------------------------------------------------------------------
//
// Member: CPropStoreManager::GetBackupSize, public
//
// Synopsis: Gets backup size of a given property store.
//
// Arguments: [dwStoreLevel] -- Primary or secondary store?
//
// History: 22-Oct-97 KrishnaN Created.
//
//----------------------------------------------------------------------------
ULONG CPropStoreManager::GetBackupSize(DWORD dwStoreLevel)
{
if ( SECONDARY_STORE == dwStoreLevel)
return _xSecondaryStore->GetActualBackupSize();
else
{
Win4Assert( PRIMARY_STORE == dwStoreLevel);
return _xPrimaryStore->GetActualBackupSize();
}
}
//+---------------------------------------------------------------------------
//
// Member: CPropStoreManager::SetMappedCacheSize, public
//
// Synopsis: Gets backup size of a given property store.
//
// Arguments: [dwStoreLevel] -- Primary or secondary store?
//
// History: 22-Oct-97 KrishnaN Created.
//
//----------------------------------------------------------------------------
void CPropStoreManager::SetMappedCacheSize(ULONG ulPSMappedCache,
DWORD dwStoreLevel)
{
if ( SECONDARY_STORE == dwStoreLevel)
_xSecondaryStore->SetMappedCacheSize(ulPSMappedCache);
else
{
Win4Assert( PRIMARY_STORE== dwStoreLevel);
_xPrimaryStore->SetMappedCacheSize(ulPSMappedCache);
}
}
//+---------------------------------------------------------------------------
//
// Member: CPropStoreManager::GetMappedCacheSize, public
//
// Synopsis: Gets mapped cache size of a given property store.
//
// Arguments: [dwStoreLevel] -- Primary or secondary store?
//
// History: 22-Oct-97 KrishnaN Created.
//
//----------------------------------------------------------------------------
ULONG CPropStoreManager::GetMappedCacheSize(DWORD dwStoreLevel)
{
if (SECONDARY_STORE == dwStoreLevel)
return _xSecondaryStore->GetMappedCacheSize();
else
{
Win4Assert(PRIMARY_STORE == dwStoreLevel);
return _xPrimaryStore->GetMappedCacheSize();
}
}
//+---------------------------------------------------------------------------
//
// Member: CPropStoreManager::GetTotalSizeInKB, public
//
// Synopsis: Gets total size of the property store.
//
// Arguments:
//
// History: 22-Oct-97 KrishnaN Created.
//
//----------------------------------------------------------------------------
ULONG CPropStoreManager::GetTotalSizeInKB()
{
return _xPrimaryStore->GetTotalSizeInKB() +
_xSecondaryStore->GetTotalSizeInKB();
}
PStorage& CPropStoreManager::GetStorage(DWORD dwStoreLevel)
{
Win4Assert(&(_xPrimaryStore->GetStorage()) == _pStorage);
Win4Assert(&(_xSecondaryStore->GetStorage()) == _pStorage);
return *_pStorage;
}
void CPropStoreManager::Shutdown()
{
Flush();
_xPrimaryStore->Shutdown();
_xSecondaryStore->Shutdown();
}
void CPropStoreManager::ClearNonStorageProperties( CCompositePropRecordForWrites & rec )
{
_xPrimaryStore->ClearNonStorageProperties( rec );
_xSecondaryStore->ClearNonStorageProperties( rec );
}
// CSvcQuery methods
//+-------------------------------------------------------------------------
//
// Member: CCompositeProgressNotifier::QueryInterface, public
//
// Arguments: [ifid] -- Interface id
// [ppiuk] -- Interface return pointer
//
// Returns: Error. No rebind from this class is supported.
//
// History: Nov-14-97 KrishnaN Created
//
//--------------------------------------------------------------------------
STDMETHODIMP CCompositeProgressNotifier::QueryInterface(
REFIID ifid,
void ** ppiuk )
{
if ( IID_IUnknown == ifid )
{
AddRef();
*ppiuk = (void *)((IUnknown *)this);
return S_OK;
}
else
{
*ppiuk = 0;
return E_NOINTERFACE;
}
} //QueryInterface
//+-------------------------------------------------------------------------
//
// Member: CCompositeProgressNotifier::AddRef, public
//
// Synopsis: Reference the virtual table.
//
// History: Nov-14-97 KrishnaN Created
//
//--------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CCompositeProgressNotifier::AddRef()
{
InterlockedIncrement( &_ref );
return (ULONG)_ref;
} //AddRef
//+-------------------------------------------------------------------------
//
// Member: CCompositeProgressNotifier::Release, public
//
// Synopsis: De-Reference the virtual table.
//
// Effects: If the ref count goes to 0 then the table is deleted.
//
// History: Nov-14-97 KrishnaN Created
//
//--------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CCompositeProgressNotifier::Release()
{
unsigned long uTmp = InterlockedDecrement( &_ref );
if ( 0 == uTmp )
delete this;
return(uTmp);
} //Release
//+-------------------------------------------------------------------------
//
// Member: CCompositeProgressNotifier::OnProgress, public
//
// Synopsis: Report progress.
//
// Effects: Progress reporting accounts for the presence of multiple
// independently operating constituents in the property store.
//
// History: Nov-14-97 KrishnaN Created
//
//--------------------------------------------------------------------------
STDMETHODIMP CCompositeProgressNotifier::OnProgress
(
DWORD dwProgressCurrent,
DWORD dwProgressMaximum,
BOOL fAccurate,
BOOL fOwner
)
{
if (0 == _xComponentProgressNotifier.GetPointer())
return S_OK;
Win4Assert(_cFinishedComponents < _cComponents);
Win4Assert(dwProgressMaximum == _aulMaxSizes[_cFinishedComponents]);
//
// Present a unified view of progress reports. The composite progress
// report is 100% done only when all components are 100% done.
//
return _xComponentProgressNotifier->OnProgress
(dwProgressCurrent*1000/dwProgressMaximum + _dwCumMaxSize,
_dwTotalMaxSize,
fAccurate,
fOwner);
} //OnProgress