Source code of Windows XP (NT5)
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.

1168 lines
33 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1991 - 2000.
  5. //
  6. // File: PropStor.hxx
  7. //
  8. // Contents: Persistent property store (external to docfile)
  9. //
  10. // Classes: CPropertyStore
  11. //
  12. // History: 27-Dec-19 KyleP Created
  13. //
  14. //----------------------------------------------------------------------------
  15. #pragma once
  16. #include <prcstob.hxx>
  17. #include <phystr.hxx>
  18. #include <rcstxact.hxx>
  19. #include <propdesc.hxx>
  20. #include <proplock.hxx>
  21. #include <cistore.hxx>
  22. #include <propbkp.hxx>
  23. #include <fsciexps.hxx>
  24. #include <enumstr.hxx>
  25. #include <imprsnat.hxx>
  26. class COnDiskPropertyRecord;
  27. class CBorrowed;
  28. class CPropRecordNoLock;
  29. class CPropRecord;
  30. class CPropRecordForWrites;
  31. class CEnumString;
  32. class CPropStoreBackupStream;
  33. class CPropStoreManager;
  34. class CCompositePropRecordForWrites;
  35. enum ERecordFormat {
  36. eNormal = 0,
  37. eLean = 1
  38. };
  39. //+-------------------------------------------------------------------------
  40. //
  41. // Class: CPropStoreInfo
  42. //
  43. // Purpose: Global persistent state for property store
  44. //
  45. // History: 27-Dec-95 KyleP Created
  46. //
  47. //--------------------------------------------------------------------------
  48. class CPropStoreInfo
  49. {
  50. public:
  51. enum
  52. {
  53. fDirtyPropStore = 1,
  54. fNotBackedUp = 2,
  55. };
  56. //
  57. // Constructors and destructor
  58. //
  59. CPropStoreInfo(DWORD dwStoreLevel);
  60. CPropStoreInfo( CPropStoreInfo const & psi );
  61. ~CPropStoreInfo() { Shutdown( FALSE ); }
  62. void Init( XPtr<PRcovStorageObj> & xObj,
  63. DWORD dwStoreLevel );
  64. void Empty();
  65. void FastTransfer( CPropStoreInfo const & psi );
  66. void Accept( XPtr<PRcovStorageObj> & xObj )
  67. {
  68. Win4Assert( _xrsoPropStore.IsNull() );
  69. _xrsoPropStore.Set( xObj.Acquire() );
  70. _fOwned = TRUE;
  71. }
  72. void Shutdown( BOOL fMarkClean = TRUE )
  73. {
  74. if ( _fOwned && !_xrsoPropStore.IsNull() )
  75. {
  76. if ( fMarkClean )
  77. MarkClean();
  78. _xrsoPropStore.Free();
  79. }
  80. else
  81. {
  82. _xrsoPropStore.Acquire();
  83. }
  84. }
  85. //
  86. // Global metadata
  87. //
  88. WORKID WorkId() { return _info.widStream; }
  89. WORKID NextWorkId(CiStorage & storage);
  90. WORKID InitWorkId(CiStorage & storage);
  91. WORKID MaxWorkId() const { return _info.widMax; }
  92. WORKID FreeListHead() const { return _info.widFreeHead; }
  93. WORKID FreeListTail() const { return _info.widFreeTail; }
  94. ULONG RecordSize() const { return _info.culRecord; }
  95. ULONG RecordsPerPage() const { return _cRecPerPage; }
  96. ULONG FixedRecordSize() const { return _info.culFixed; }
  97. ULONG CountProps() const { return _info.cTotal; }
  98. ULONG CountFixedProps() const { return _info.cFixed; }
  99. BOOL IsDirty() const
  100. {
  101. return ( 0 != ( _info.fDirty & fDirtyPropStore ) );
  102. }
  103. BOOL IsBackedUp() const
  104. {
  105. return ( 0 == ( _info.fDirty & fNotBackedUp ) );
  106. }
  107. ULONG OSPageSize() const { return _ulOSPageSize; }
  108. ULONG OSPagesPerPage() const { return _cOSPagesPerLargePage; }
  109. inline void MarkDirty();
  110. inline void MarkClean();
  111. inline void MarkNotBackedUp();
  112. inline void MarkBackedUp();
  113. void SetMaxWorkId( WORKID wid ) { _info.widMax = wid; MarkDirty(); }
  114. void SetFreeListHead( WORKID wid ) { _info.widFreeHead = wid; MarkDirty(); }
  115. void SetFreeListTail( WORKID wid ) { _info.widFreeTail = wid; MarkDirty(); }
  116. ULONG CountRecordsInUse() const { return _info.cTopLevel; }
  117. void IncRecordsInUse() { _info.cTopLevel++; }
  118. void DecRecordsInUse() { _info.cTopLevel--; }
  119. void SetRecordsInUse( ULONG count ) { _info.cTopLevel = count; }
  120. void SetStoreLevel(DWORD dwLevel) { _info.dwStoreLevel = dwLevel; }
  121. DWORD GetStoreLevel() { return _info.dwStoreLevel; }
  122. //
  123. // Lean record support
  124. //
  125. ERecordFormat GetRecordFormat() const { return _info.eRecordFormat; }
  126. void SetRecordFormat(ERecordFormat type) { _info.eRecordFormat = type; }
  127. //
  128. // Per-property metadata
  129. //
  130. inline BOOL CanStore( PROPID pid );
  131. inline unsigned Size( PROPID pid );
  132. inline ULONG Type( PROPID pid );
  133. inline BOOL CanBeModified( PROPID pid );
  134. inline CPropDesc const * GetDescription( PROPID pid );
  135. inline CPropDesc const * GetDescriptionByOrdinal( ULONG ordinal );
  136. BOOL Add( PROPID pid, ULONG vt, unsigned cbMaxLen,
  137. BOOL fCanBeModified, CiStorage & storage );
  138. BOOL Delete( PROPID pid, CiStorage & storage );
  139. void Commit( CPropStoreInfo & psi, CRcovStrmWriteTrans & xact );
  140. PRcovStorageObj * GetRcovObj() { return _xrsoPropStore.GetPointer(); }
  141. void DetectFormat();
  142. private:
  143. friend class CPropertyStore;
  144. void ChangeDirty( int fDirty );
  145. unsigned Lookup( PROPID pid );
  146. unsigned LookupNew( PROPID pid );
  147. inline CPropDesc const * GetDescription( unsigned i );
  148. ULONG CountDescription() { return _aProp.Count(); }
  149. struct SPropInfo
  150. {
  151. ULONG Version;
  152. ULONG culRecord;
  153. ULONG culFixed;
  154. int fDirty;
  155. ULONG cTotal;
  156. ULONG cFixed;
  157. ULONG cHash;
  158. WORKID widStream;
  159. WORKID widMax;
  160. WORKID widFreeHead;
  161. ULONG cTopLevel;
  162. WORKID widFreeTail;
  163. DWORD dwStoreLevel;
  164. ERecordFormat eRecordFormat;
  165. };
  166. ULONG _cRecPerPage; // # records per 64K page
  167. SPropInfo _info; // Non-repeated info, stored in header
  168. XPtr<PRcovStorageObj> _xrsoPropStore; // The persistent storage itself
  169. BOOL _fOwned; // Set to TRUE if propstore is owned.
  170. XArray<CPropDesc> _aProp;
  171. ULONG _ulOSPageSize; // GetSystemInfo returns this
  172. ULONG _cOSPagesPerLargePage;// number of OS pages per COMMON_PAGE_SIZE sized large page
  173. };
  174. //+-------------------------------------------------------------------------
  175. //
  176. // Class: CPhysPropertyStore
  177. //
  178. // Purpose: Persistent property store
  179. //
  180. // History: 27-Dec-95 KyleP Created
  181. //
  182. //--------------------------------------------------------------------------
  183. class CPhysPropertyStore : public CPhysStorage
  184. {
  185. public:
  186. inline CPhysPropertyStore( PStorage & storage,
  187. PStorageObject& obj,
  188. WORKID objectId,
  189. PMmStream * stream,
  190. PStorage::EOpenMode mode,
  191. unsigned cMappedItems );
  192. private:
  193. virtual void ReOpenStream();
  194. };
  195. // Backup support
  196. enum EField { eFieldNone = 0,
  197. eTopLevelField = 1};
  198. //+-------------------------------------------------------------------------
  199. //
  200. // Class: CPropertyStore
  201. //
  202. // Purpose: Persistent property store
  203. //
  204. // History: 27-Dec-95 KyleP Created
  205. //
  206. //--------------------------------------------------------------------------
  207. class CPropertyStore
  208. {
  209. public:
  210. CPropertyStore(CPropStoreManager& propStoreMgr, DWORD dwLevel);
  211. ~CPropertyStore();
  212. //
  213. // Two phase construction (to accomadate late-bound storage)
  214. //
  215. void FastInit( CiStorage * pStorage);
  216. void LongInit( BOOL & fWasDirty, ULONG & cInconsistencies,
  217. T_UpdateDoc pfnUpdateCallback, void const *pUserData );
  218. BOOL IsDirty() const { return _PropStoreInfo.IsDirty(); }
  219. void Empty();
  220. //
  221. // Schema manipulation
  222. //
  223. inline BOOL CanStore( PROPID pid );
  224. inline unsigned Size( PROPID pid );
  225. inline ULONG Type( PROPID pid );
  226. inline BOOL CanBeModified( PROPID pid );
  227. ULONG_PTR BeginTransaction();
  228. void Setup( PROPID pid, ULONG vt, DWORD cbMaxLen,
  229. ULONG_PTR ulToken, BOOL fModifiable = TRUE );
  230. void EndTransaction( ULONG_PTR ulToken, BOOL fCommit,
  231. PROPID pidFixed );
  232. //
  233. // Backup/Load
  234. //
  235. void MakeBackupCopy( IProgressNotify * pIProgressNotify,
  236. BOOL & fAbort,
  237. CiStorage & dstStorage,
  238. ICiEnumWorkids * pIWorkIds,
  239. IEnumString **ppFileList);
  240. //
  241. // Property storage/retrieval.
  242. //
  243. SCODE WriteProperty( WORKID wid,
  244. PROPID pid,
  245. CStorageVariant const & var,
  246. BOOL fBackup = TRUE);
  247. SCODE WriteProperty( CPropRecordForWrites &PropRecord, PROPID pid,
  248. CStorageVariant const & var, BOOL fBackup);
  249. inline WORKID WritePropertyInNewRecord( PROPID pid,
  250. CStorageVariant const & var,
  251. BOOL fBackup = TRUE);
  252. BOOL ReadProperty( WORKID wid, PROPID pid, PROPVARIANT & var );
  253. BOOL ReadProperty( WORKID wid, PROPID pid, PROPVARIANT & var, BYTE * pbExtra, unsigned * pcbExtra );
  254. BOOL ReadProperty( CPropRecordNoLock & PropRecord, PROPID pid, PROPVARIANT * pbData, unsigned * pcb);
  255. BOOL ReadProperty( COnDiskPropertyRecord *prec, PROPID pid, PROPVARIANT & var,
  256. BYTE * pbExtra, unsigned * pcbExtra );
  257. BOOL ReadProperty( CPropRecordNoLock & PropRecord, PROPID pid, PROPVARIANT & var,
  258. BYTE * pbExtra, unsigned * pcbExtra );
  259. //
  260. // Special path/wid support
  261. //
  262. inline WORKID MaxWorkId();
  263. inline ULONG RecordsPerPage() const
  264. {
  265. return _PropStoreInfo.RecordsPerPage();
  266. }
  267. void DeleteRecord( WORKID wid, BOOL fBackup = TRUE );
  268. inline ULONG CountRecordsInUse() const;
  269. void Shutdown()
  270. {
  271. _fAbort = TRUE;
  272. _PropStoreInfo.Shutdown();
  273. }
  274. BOOL Flush();
  275. PStorage & GetStorage()
  276. {
  277. Win4Assert ( 0 != _pStorage );
  278. return *_pStorage;
  279. }
  280. CiStorage & GetCiStorage()
  281. {
  282. Win4Assert ( 0 != _pStorage );
  283. return *_pStorage;
  284. }
  285. //
  286. // Some info from CPropertyStoreInfo
  287. //
  288. inline ULONG OSPagesPerPage() const
  289. {
  290. return _PropStoreInfo.OSPagesPerPage();
  291. }
  292. inline ULONG OSPageSize() const
  293. {
  294. return _PropStoreInfo.OSPageSize();
  295. }
  296. inline ULONG RecordSize() const
  297. {
  298. return _PropStoreInfo.RecordSize();
  299. }
  300. inline CPropStoreBackupStream * BackupStream()
  301. {
  302. return _xPSBkpStrm.GetPointer();
  303. }
  304. inline CPhysPropertyStore * PhysStore()
  305. {
  306. return _xPhysStore.GetPointer();
  307. }
  308. inline WORKID MaxWorkId() const
  309. {
  310. return _PropStoreInfo.MaxWorkId();
  311. }
  312. inline void IncRecordsInUse()
  313. {
  314. _PropStoreInfo.IncRecordsInUse();
  315. }
  316. //
  317. // get and set parameters
  318. //
  319. void SetBackupSize(ULONG ulBackupSizeInPages)
  320. {
  321. // range will be enforced when it is actually
  322. // used.
  323. _ulBackupSizeInPages = ulBackupSizeInPages;
  324. }
  325. ULONG GetDesiredBackupSize()
  326. {
  327. return _ulBackupSizeInPages;
  328. }
  329. ULONG GetActualBackupSize()
  330. {
  331. Win4Assert(!_xPSBkpStrm.IsNull());
  332. return _xPSBkpStrm->MaxPages();
  333. }
  334. void SetMappedCacheSize(ULONG ulPSMappedCache)
  335. {
  336. // Enforce ranges
  337. C_ASSERT(CI_PROPERTY_STORE_MAPPED_CACHE_MIN == 0);
  338. if (ulPSMappedCache > CI_PROPERTY_STORE_MAPPED_CACHE_MAX)
  339. _ulPSMappedCache = CI_PROPERTY_STORE_MAPPED_CACHE_MAX;
  340. else
  341. _ulPSMappedCache = ulPSMappedCache;
  342. }
  343. ULONG GetMappedCacheSize() { return _ulPSMappedCache; };
  344. ULONG GetTotalSizeInKB();
  345. inline DWORD GetStoreLevel() { return _PropStoreInfo.GetStoreLevel(); }
  346. //
  347. // Lean record support
  348. //
  349. ERecordFormat GetRecordFormat() const { return _PropStoreInfo.GetRecordFormat(); }
  350. void SetRecordFormat(ERecordFormat type) { _PropStoreInfo.SetRecordFormat( type ); }
  351. void MarkBackedUpMode()
  352. {
  353. _PropStoreInfo.MarkBackedUp();
  354. }
  355. void MarkNotBackedUpMode()
  356. {
  357. _PropStoreInfo.MarkNotBackedUp();
  358. }
  359. BOOL IsBackedUpMode() { return _PropStoreInfo.IsBackedUp(); }
  360. //
  361. // Clean Up
  362. //
  363. void ClearNonStorageProperties( CCompositePropRecordForWrites & rec );
  364. private:
  365. friend class CPropertyStoreWids;
  366. friend class CPropRecordNoLock;
  367. friend class CPropRecord;
  368. friend class CPropRecordForWrites;
  369. friend class CPropertyStoreRecovery;
  370. friend class CPropStoreManager;
  371. friend class CLockRecordForRead;
  372. friend class CLockRecordForWrite;
  373. friend class CLockAllRecordsForWrite;
  374. friend class CBackupWid;
  375. CPropertyStore( CPropertyStore & psi, CiStorage * pStorage );
  376. WORKID CreateStorage( WORKID wid = widInvalid );
  377. void InitNewRecord( WORKID wid,
  378. ULONG cWid,
  379. COnDiskPropertyRecord * prec,
  380. BOOL fTopLevel,
  381. BOOL fBackup);
  382. void InitFreeList( );
  383. void RecycleFreeList( WORKID wid );
  384. void LokFreeRecord( WORKID wid, ULONG cFree,
  385. COnDiskPropertyRecord * prec, BOOL fBackup );
  386. WORKID LokAllocRecord( ULONG cFree );
  387. void WritePropertyInSpecificNewRecord( WORKID wid, PROPID pid,
  388. CStorageVariant const & var,
  389. BOOL fBackup = TRUE );
  390. WORKID NewWorkId( ULONG cWid, BOOL fBackup )
  391. {
  392. return LokNewWorkId( cWid, TRUE, fBackup );
  393. }
  394. WORKID LokNewWorkId( ULONG cWid, BOOL fTopLevel, BOOL fBackup );
  395. //
  396. // Record locking.
  397. //
  398. void AcquireRead( CReadWriteLockRecord & record );
  399. void SyncRead( CReadWriteLockRecord & record );
  400. void SyncReadDecrement( CReadWriteLockRecord & record );
  401. void ReleaseRead( CReadWriteLockRecord & record );
  402. void AcquireWrite( CReadWriteLockRecord & record );
  403. void ReleaseWrite( CReadWriteLockRecord & record );
  404. void AcquireWrite2( CReadWriteLockRecord & record );
  405. void ReleaseWrite2( CReadWriteLockRecord & record );
  406. void AcquireWriteOnAllRecords();
  407. void ReleaseWriteOnAllRecords();
  408. CPropertyLockMgr & LockMgr() { return _lockMgr; }
  409. CReadWriteAccess & GetReadWriteAccess() { return _rwAccess; }
  410. void Transfer( CPropertyStore & Target,
  411. PROPID pidFixed,
  412. BOOL & fAbort,
  413. IProgressNotify * pProgress = 0 );
  414. void FastTransfer( CPropertyStore & Target,
  415. BOOL & fAbort,
  416. IProgressNotify * pProgress = 0 );
  417. CiStorage * _pStorage; // Persistent storage object.
  418. CPropStoreInfo _PropStoreInfo; // Global persistent state for property store.
  419. WORKID * _aFreeBlocks; // Pointers into free list by rec. size
  420. BOOL _fAbort; // Set to TRUE when aborting
  421. BOOL _fIsConsistent; // Set to TRUE as long as the data is
  422. // consistent
  423. //
  424. // Record locking
  425. //
  426. CMutexSem _mtxWrite; // Taken to add/remove/modify records
  427. CMutexSem _mtxRW; // Sometimes used during per-record locking
  428. CEventSem _evtRead; // Sometimes used during per-record locking
  429. CEventSem _evtWrite; // Sometimes used during per-record locking
  430. CPropertyLockMgr _lockMgr; // arbitrates record-level locking
  431. CReadWriteAccess _rwAccess; // Controls access to resources
  432. XPtr<CPhysPropertyStore> _xPhysStore; // Main data stream.
  433. //
  434. // For multi-property changes to metadata
  435. //
  436. CPropertyStore * _ppsNew; // New metadata stored here
  437. BOOL _fNew; // TRUE if something really changed
  438. XPtr<CPropStoreBackupStream> _xPSBkpStrm; // prop store backup stream
  439. ULONG _ulBackupSizeInPages; // backup size in pages
  440. ULONG _ulPSMappedCache; // size of the mapped cache
  441. DWORD _dwStoreLevel; // primary or secondary?
  442. CPropStoreManager& _propStoreMgr; // Manager controlling this.
  443. #if CIDBG==1
  444. _int64 _sigPSDebug;
  445. DWORD _tidReadSet;
  446. DWORD _tidReadReset;
  447. DWORD _tidWriteSet;
  448. DWORD _tidWriteReset;
  449. BYTE * _pbRecordLockTracker; // tracks write locking for en masse record lockup
  450. void _SetReadTid()
  451. {
  452. _tidReadSet = GetCurrentThreadId();
  453. }
  454. void _ReSetReadTid()
  455. {
  456. _tidReadReset = GetCurrentThreadId();
  457. }
  458. void _SetWriteTid()
  459. {
  460. _tidWriteSet = GetCurrentThreadId();
  461. }
  462. void _ReSetWriteTid()
  463. {
  464. _tidWriteReset = GetCurrentThreadId();
  465. }
  466. //
  467. // Deadlock detection for the first 256 threads.
  468. //
  469. enum { cTrackThreads = 2048 };
  470. XArray<long> _xPerThreadReadCounts;
  471. XArray<long> _xPerThreadWriteCounts;
  472. #else
  473. void _SetReadTid() { }
  474. void _ReSetReadTid() { }
  475. void _SetWriteTid() { }
  476. void _ReSetWriteTid() { }
  477. #endif // CIDBG==1
  478. };
  479. //+---------------------------------------------------------------------------
  480. //
  481. // Member: CPropStoreInfo::CanStore, public
  482. //
  483. // Arguments: [pid] -- Propid to check.
  484. //
  485. // Returns: TRUE if [pid] can exist in property store (e.g. has been
  486. // registered).
  487. //
  488. // History: 27-Dec-95 KyleP Created.
  489. //
  490. //----------------------------------------------------------------------------
  491. inline BOOL CPropStoreInfo::CanStore( PROPID pid )
  492. {
  493. return (0 != _info.cHash) && _aProp[Lookup(pid)].IsInUse();
  494. }
  495. //+---------------------------------------------------------------------------
  496. //
  497. // Member: CPropStoreInfo::Size, public
  498. //
  499. // Synopsis: Returns size in cache for this property.
  500. //
  501. // Arguments: [pid] -- Propid to check.
  502. //
  503. // Returns: TRUE if [pid] can exist in property store (e.g. has been
  504. // registered).
  505. //
  506. // History: 27-Dec-95 KyleP Created.
  507. //
  508. //----------------------------------------------------------------------------
  509. inline unsigned CPropStoreInfo::Size( PROPID pid )
  510. {
  511. if (0 == _info.cHash)
  512. return 0;
  513. unsigned hash = Lookup(pid);
  514. if ( _aProp[hash].IsInUse() )
  515. return _aProp[hash].Size();
  516. else
  517. return 0;
  518. }
  519. inline BOOL CPropStoreInfo::CanBeModified( PROPID pid )
  520. {
  521. if (0 == _info.cHash)
  522. return TRUE;
  523. unsigned hash = Lookup(pid);
  524. if ( _aProp[hash].IsInUse() )
  525. return _aProp[hash].Modifiable();
  526. else
  527. { // if it not in the store, it doesn't matter what the
  528. // reply is. But we will return TRUE so clients like Admin know that
  529. // they can allow the property metadata to be modified.
  530. return TRUE;
  531. }
  532. }
  533. //+---------------------------------------------------------------------------
  534. //
  535. // Member: CPropStoreInfo::Type, public
  536. //
  537. // Synopsis: Returns type in cache for this property.
  538. //
  539. // Arguments: [pid] -- Propid to check.
  540. //
  541. // Returns: TRUE if [pid] can exist in property store (e.g. has been
  542. // registered).
  543. //
  544. // History: 27-Dec-95 KyleP Created.
  545. //
  546. //----------------------------------------------------------------------------
  547. inline ULONG CPropStoreInfo::Type( PROPID pid )
  548. {
  549. if (0 == _info.cHash)
  550. return VT_EMPTY;
  551. unsigned hash = Lookup(pid);
  552. if ( _aProp[hash].IsInUse() )
  553. return _aProp[hash].Type();
  554. else
  555. return VT_EMPTY;
  556. }
  557. void CPropStoreInfo::MarkDirty()
  558. {
  559. #if 0 // there are too many clients who get this wrong...
  560. CImpersonateSystem impersonate(FALSE); // FALSE = don't impersonate
  561. Win4Assert(!impersonate.IsImpersonated());
  562. #endif // cidbg == 1
  563. if ( 0 == ( _info.fDirty & fDirtyPropStore ) )
  564. {
  565. CImpersonateSystem impersonate;
  566. ChangeDirty( _info.fDirty | fDirtyPropStore );
  567. }
  568. }
  569. void CPropStoreInfo::MarkClean()
  570. {
  571. if ( 0 != ( _info.fDirty & fDirtyPropStore ) )
  572. {
  573. CImpersonateSystem impersonate;
  574. ChangeDirty( _info.fDirty & ~fDirtyPropStore );
  575. }
  576. }
  577. void CPropStoreInfo::MarkNotBackedUp()
  578. {
  579. if ( 0 == ( _info.fDirty & fNotBackedUp ) )
  580. ChangeDirty( _info.fDirty | fNotBackedUp );
  581. }
  582. void CPropStoreInfo::MarkBackedUp()
  583. {
  584. if ( 0 != ( _info.fDirty & fNotBackedUp ) )
  585. ChangeDirty( _info.fDirty & ~fNotBackedUp );
  586. }
  587. inline CPhysPropertyStore::CPhysPropertyStore( PStorage & storage,
  588. PStorageObject& obj,
  589. WORKID objectId,
  590. PMmStream * stream,
  591. PStorage::EOpenMode mode,
  592. unsigned cMappedItems )
  593. : CPhysStorage( storage,
  594. obj,
  595. objectId,
  596. stream,
  597. mode,
  598. TRUE,
  599. cMappedItems )
  600. {
  601. }
  602. //+---------------------------------------------------------------------------
  603. //
  604. // Member: CPropertyStore::CanStore, public
  605. //
  606. // Arguments: [pid] -- Propid to check.
  607. //
  608. // Returns: TRUE if [pid] can exist in property store (e.g. has been
  609. // registered).
  610. //
  611. // History: 27-Dec-95 KyleP Created.
  612. //
  613. //----------------------------------------------------------------------------
  614. inline BOOL CPropertyStore::CanStore( PROPID pid )
  615. {
  616. return _PropStoreInfo.CanStore( pid );
  617. }
  618. //+---------------------------------------------------------------------------
  619. //
  620. // Member: CPropertyStore::Size, public
  621. //
  622. // Arguments: [pid] -- Propid to check.
  623. //
  624. // Returns: Size of property in store, or 0 if it isn't in store.
  625. //
  626. // History: 27-Dec-95 KyleP Created.
  627. //
  628. //----------------------------------------------------------------------------
  629. inline unsigned CPropertyStore::Size( PROPID pid )
  630. {
  631. return _PropStoreInfo.Size( pid );
  632. }
  633. //+---------------------------------------------------------------------------
  634. //
  635. // Member: CPropertyStore::Type, public
  636. //
  637. // Arguments: [pid] -- Propid to check.
  638. //
  639. // Returns: Type of property in store, or VT_EMPTY if it isn't in store.
  640. //
  641. // History: 27-Dec-95 KyleP Created.
  642. //
  643. //----------------------------------------------------------------------------
  644. inline ULONG CPropertyStore::Type( PROPID pid )
  645. {
  646. return _PropStoreInfo.Type( pid );
  647. }
  648. //+---------------------------------------------------------------------------
  649. //
  650. // Member: CPropertyStore::WritePropertyInNewRecord, public
  651. //
  652. // Synopsis: Like WriteProperty, but also allocates record.
  653. //
  654. // Arguments: [pid] -- Propid to write.
  655. // [var] -- Property value
  656. //
  657. // Returns: Workid of new record.
  658. //
  659. // History: 27-Dec-95 KyleP Created.
  660. //
  661. //----------------------------------------------------------------------------
  662. inline WORKID CPropertyStore::WritePropertyInNewRecord( PROPID pid,
  663. CStorageVariant const & var,
  664. BOOL fBackup )
  665. {
  666. WORKID wid = NewWorkId( 1, fBackup );
  667. ciDebugOut(( DEB_PROPSTORE, "New short record at %d\n", wid ));
  668. WriteProperty( wid, pid, var, fBackup );
  669. _PropStoreInfo.IncRecordsInUse();
  670. return wid;
  671. }
  672. //+---------------------------------------------------------------------------
  673. //
  674. // Member: CPropertyStore::CountRecordsInUse, public
  675. //
  676. // Returns: Count of 'top level' records (correspond to user wids)
  677. //
  678. // History: 15-Feb-96 KyleP Created.
  679. //
  680. //----------------------------------------------------------------------------
  681. inline ULONG CPropertyStore::CountRecordsInUse() const
  682. {
  683. return _PropStoreInfo.CountRecordsInUse();
  684. }
  685. //+---------------------------------------------------------------------------
  686. //
  687. // Member: CPropertyStore::MaxWorkId, public
  688. //
  689. // Returns: Maximum workid which has been allocated.
  690. //
  691. // History: 28-Dec-95 KyleP Created.
  692. //
  693. //----------------------------------------------------------------------------
  694. inline WORKID CPropertyStore::MaxWorkId()
  695. {
  696. return _PropStoreInfo.MaxWorkId();
  697. }
  698. //+---------------------------------------------------------------------------
  699. //
  700. // Member: CPropertyStore::CanBeModified, public
  701. //
  702. // Returns: Can the property info be modifed for the given property?
  703. //
  704. // History: 28-Dec-95 KyleP Created.
  705. //
  706. //----------------------------------------------------------------------------
  707. inline BOOL CPropertyStore::CanBeModified( PROPID pid )
  708. {
  709. return _PropStoreInfo.CanBeModified( pid );
  710. }
  711. //+---------------------------------------------------------------------------
  712. //
  713. // Member: CPropertyStoreInfo::GetDescription, public
  714. //
  715. // Arguments: [pid] -- Propid to check.
  716. //
  717. // Returns: Metadata descriptor for specified property.
  718. //
  719. // History: 28-Dec-95 KyleP Created.
  720. //
  721. //----------------------------------------------------------------------------
  722. inline CPropDesc const * CPropStoreInfo::GetDescription( PROPID pid )
  723. {
  724. if (0 == _info.cHash)
  725. return 0;
  726. unsigned hash = Lookup( pid );
  727. if ( _aProp[hash].IsInUse() )
  728. return &_aProp[hash];
  729. else
  730. return 0;
  731. }
  732. //+---------------------------------------------------------------------------
  733. //
  734. // Member: CPropertyStoreInfo::GetDescription, public
  735. //
  736. // Arguments: [i] -- the index position in the array.
  737. //
  738. // Returns: Metadata descriptor for the i-th property in the schema.
  739. //
  740. // History: 17-Oct-2000 KitmanH Created.
  741. //
  742. //----------------------------------------------------------------------------
  743. inline CPropDesc const * CPropStoreInfo::GetDescription( unsigned i )
  744. {
  745. if (0 == _info.cHash)
  746. return 0;
  747. if ( i < _aProp.Count() )
  748. {
  749. if ( pidInvalid != _aProp[i].Pid() )
  750. return &_aProp[i];
  751. }
  752. return 0;
  753. }
  754. //+---------------------------------------------------------------------------
  755. //
  756. // Member: CPropertyStoreInfo::GetDescriptionByOrdinal, public
  757. //
  758. // Arguments: [ordinal] -- Ordinal
  759. //
  760. // Returns: Metadata descriptor for specified property.
  761. //
  762. // History: 16-Jan-96 KyleP Created.
  763. //
  764. //----------------------------------------------------------------------------
  765. inline CPropDesc const * CPropStoreInfo::GetDescriptionByOrdinal( ULONG ordinal )
  766. {
  767. Win4Assert( 0 != _info.cHash );
  768. for ( unsigned i = 0; i < _aProp.Count(); i++ )
  769. {
  770. if ( _aProp[i].Pid() != pidInvalid && _aProp[i].Ordinal() == ordinal )
  771. return &_aProp[i];
  772. }
  773. return 0;
  774. }
  775. //+---------------------------------------------------------------------------
  776. //
  777. // Class: CPropertyStoreRecovery
  778. //
  779. // Purpose: Recovers the property store from a dirty shutdown
  780. //
  781. // History: 4-10-96 srikants Created
  782. //
  783. // Notes:
  784. //
  785. //----------------------------------------------------------------------------
  786. class CPropertyStoreRecovery
  787. {
  788. public:
  789. CPropertyStoreRecovery( CPropertyStore & propStore,
  790. T_UpdateDoc pfnUpdateCallback,
  791. void const *pUserData );
  792. ~CPropertyStoreRecovery( );
  793. void DoRecovery();
  794. ULONG GetInconsistencyCount() const { return _cInconsistencies; }
  795. private:
  796. void Pass0();
  797. void Pass1();
  798. void Pass2();
  799. void Complete();
  800. void SetFree();
  801. BOOL CheckOverflowChain();
  802. void FreeChain();
  803. WORKID AddToFreeList( WORKID widFree,
  804. ULONG cFree,
  805. COnDiskPropertyRecord * precFree,
  806. WORKID widListHead );
  807. CPropertyStore & _propStore;
  808. CPropStoreInfo & _PropStoreInfo;
  809. CPhysPropertyStore * _pPhysStore;
  810. WORKID _wid; // Wid being processed currently
  811. COnDiskPropertyRecord * _pRec; // Pointer to _wid's on disk rec
  812. WORKID _cRec; // Count of records for this wid
  813. XPtr<CPropStoreBackupStream> _xPSBkpStrm; // prop store backup stream
  814. //
  815. // Cumulative values during recovery.
  816. //
  817. WORKID * _aFreeBlocks; // Array of free lists by size
  818. WORKID _widMax; // Current wid max
  819. ULONG _cTopLevel; // Total top level records
  820. ULONG _cRecPerPage; // Records per long page
  821. ULONG _cInconsistencies;
  822. // Number of inconsistencies.
  823. ULONG _cForceFreed; // Number of records forecefully
  824. // freed.
  825. THashTable<ULONG> _pageTable; // Table of pages in backup.
  826. T_UpdateDoc _fnUpdateCallback; // callback to update the wid
  827. void const * _pUserData; // user data echoed back along with callback
  828. class CGraftPage
  829. {
  830. public:
  831. ~CGraftPage()
  832. {
  833. _pPhysStore->ReturnLargeBuffer(_ulPageInPS / _cPagesPerLargePage);
  834. }
  835. CGraftPage(ULONG ulPageInBkp, ULONG ulPageInPS, ULONG cPageSize,
  836. ULONG cCustomPagesPerLargePage, CPhysPropertyStore *pPhysStore,
  837. CPropStoreBackupStream *pPSBkpStrm):
  838. _cPagesPerLargePage( cCustomPagesPerLargePage ),
  839. _ulPageInPS( ulPageInPS ),
  840. _pPhysStore( pPhysStore )
  841. {
  842. PBYTE pLargePage = (PBYTE)pPhysStore->BorrowLargeBuffer(
  843. ulPageInPS/cCustomPagesPerLargePage,
  844. TRUE);
  845. BYTE *pbPageLoc = (pLargePage + cPageSize*(ulPageInPS%cCustomPagesPerLargePage));
  846. // Zap the page from backup file to property store
  847. pPSBkpStrm->ReadPage(ulPageInBkp, &ulPageInPS, pbPageLoc);
  848. ciDebugOut((DEB_PROPSTORE, "Successfully grafted backup page %d to %d in PS at location 0x%8x.\n",
  849. ulPageInBkp, ulPageInPS, pbPageLoc));
  850. }
  851. private:
  852. ULONG _cPagesPerLargePage;
  853. ULONG _ulPageInPS;
  854. CPhysPropertyStore *_pPhysStore;
  855. };
  856. };
  857. //+---------------------------------------------------------------------------
  858. //
  859. // Class: CBackupWid
  860. //
  861. // Purpose: Backs up a wid to the backup
  862. //
  863. // History: 6-20-97 KrishnaN Created
  864. //
  865. // Notes:
  866. //
  867. //----------------------------------------------------------------------------
  868. class CBackupWid
  869. {
  870. public:
  871. CBackupWid(CPropertyStore *pPropStor,
  872. WORKID wid,
  873. ULONG cRecsInWid):
  874. _pPropStor( pPropStor ),
  875. _nLargePage( 0xFFFFFFFF ),
  876. _ulFirstPage( 0xFFFFFFFF ),
  877. _ulLastPage( 0xFFFFFFFF ),
  878. _pbFirstPage( 0 )
  879. {
  880. BackupWid(wid, cRecsInWid);
  881. }
  882. CBackupWid(CPropertyStore *pPropStor,
  883. WORKID wid,
  884. ULONG cRecsInWid,
  885. EField FieldToCommit,
  886. ULONG ulValue,
  887. COnDiskPropertyRecord const *pRec):
  888. _pPropStor( pPropStor ),
  889. _nLargePage( 0xFFFFFFFF ),
  890. _ulFirstPage( 0xFFFFFFFF ),
  891. _ulLastPage( 0xFFFFFFFF ),
  892. _pbFirstPage( 0 )
  893. {
  894. BackupWid(wid, cRecsInWid,
  895. FieldToCommit, ulValue, pRec);
  896. }
  897. ~CBackupWid()
  898. {
  899. _pPropStor->PhysStore()->ReturnLargeBuffer(_nLargePage);
  900. }
  901. private:
  902. //
  903. // TryDescribeWidInAPage should be called first even when you
  904. // know that you may not be able to describe the wid in a single
  905. // page. This figures out the large page and borrows it. It also
  906. // figures out how many pages you might need, so you can allocate
  907. // the size and pass it to DescribeWid
  908. //
  909. inline ULONG TryDescribeWidInAPage(WORKID wid,
  910. ULONG cRecsInWid);
  911. inline void DescribeWid( WORKID wid,
  912. ULONG cRecsInWid,
  913. CDynArrayInPlace<ULONG> &pulPages,
  914. CDynArrayInPlace<void *> &ppvPages);
  915. void BackupWid(WORKID wid,
  916. ULONG cRecsInWid,
  917. EField FieldToCommit = eFieldNone,
  918. ULONG ulValue = 0,
  919. COnDiskPropertyRecord const *pRec = 0);
  920. BOOL BackupPages(ULONG cPages,
  921. ULONG const *pSlots,
  922. void const * const * ppvPages);
  923. ULONG DescribeField( EField FieldToCommit,
  924. COnDiskPropertyRecord const *pRec,
  925. ULONG cPages,
  926. void const * const* ppvPages,
  927. ULONG &pulOffset);
  928. inline void ComputeOSPageLocations(WORKID wid, ULONG cRecsInWid,
  929. ULONG *pFirstPage, ULONG *pLastPage);
  930. inline BYTE * GetOSPagePointer(ULONG ulPage);
  931. CPropertyStore * _pPropStor;
  932. ULONG _nLargePage; // large page containing this wid
  933. ULONG _ulFirstPage, _ulLastPage; // OS pages spanned by this wid
  934. BYTE * _pbFirstPage; // address of the first page
  935. };