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.

773 lines
21 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. #if !defined( __PROPSTOR_HXX__ )
  16. #define __PROPSTOR_HXX__
  17. #include <prcstob.hxx>
  18. #include <phystr.hxx>
  19. #include <readwrit.hxx>
  20. #include <proplock.hxx>
  21. #include <rcstxact.hxx>
  22. class CiStorage;
  23. class COnDiskPropertyRecord;
  24. class CBorrowed;
  25. class CPropRecord;
  26. //+-------------------------------------------------------------------------
  27. //
  28. // Class: CPropDesc
  29. //
  30. // Purpose: Description of metadata for a single property
  31. //
  32. // History: 27-Dec-95 KyleP Created
  33. //
  34. //--------------------------------------------------------------------------
  35. class CPropDesc
  36. {
  37. public:
  38. CPropDesc() { _pid = pidInvalid; }
  39. void Init( PROPID pid,
  40. ULONG vt,
  41. DWORD oStart,
  42. DWORD cbMax,
  43. DWORD ordinal,
  44. DWORD rec )
  45. {
  46. _pid = pid;
  47. _vt = vt;
  48. _oStart = oStart;
  49. _cbMax = cbMax;
  50. _ordinal = ordinal;
  51. _mask = 1 << ((ordinal % 16) * 2);
  52. _rec = rec;
  53. }
  54. PROPID Pid() const { return _pid; }
  55. ULONG Type() const { return _vt; }
  56. DWORD Offset() const { return _oStart; }
  57. DWORD Size() const { return _cbMax; }
  58. DWORD Ordinal() const { return _ordinal; }
  59. DWORD Mask() const { return _mask; }
  60. DWORD Record() const { return _rec; }
  61. BOOL IsInUse() const { return (_pid != pidInvalid); }
  62. void Free() { _pid = pidInvalid - 1; }
  63. BOOL IsFree() const { return (_pid == (pidInvalid - 1) || _pid == pidInvalid); }
  64. BOOL IsFixedSize() const { return (_oStart != 0xFFFFFFFF); }
  65. void SetOrdinal( DWORD ordinal ) { _ordinal = ordinal; _mask = 1 << ((ordinal % 16) * 2); }
  66. void SetOffset( DWORD oStart ) { _oStart = oStart; }
  67. void SetRecord( DWORD rec ) { _rec = rec; }
  68. private:
  69. PROPID _pid; // Propid
  70. ULONG _vt; // Data type (fixed types only)
  71. DWORD _oStart; // Offset in fixed area to property (fixed types only)
  72. DWORD _cbMax; // Max size of property (used to compute record size)
  73. DWORD _ordinal; // Position of property in record. Zero based.
  74. DWORD _mask; // 1 << Ordinal. Stored for efficiency
  75. DWORD _rec; // Position of metadata object in metadata stream.
  76. };
  77. //+-------------------------------------------------------------------------
  78. //
  79. // Class: CPropStoreInfo
  80. //
  81. // Purpose: Global persistent state for property store
  82. //
  83. // History: 27-Dec-95 KyleP Created
  84. //
  85. //--------------------------------------------------------------------------
  86. class CPropStoreInfo : INHERIT_UNWIND
  87. {
  88. INLINE_UNWIND( CPropStoreInfo )
  89. public:
  90. //
  91. // Constructors and destructor
  92. //
  93. CPropStoreInfo();
  94. CPropStoreInfo( CPropStoreInfo const & psi );
  95. ~CPropStoreInfo();
  96. void Init( XPtr<PRcovStorageObj> & xObj );
  97. void Empty();
  98. //
  99. // Global metadata
  100. //
  101. WORKID WorkId() { return _info.widStream; }
  102. WORKID NextWorkId(CiStorage & storage);
  103. WORKID MaxWorkId() const { return _info.widMax; }
  104. WORKID FreeListHead() const { return _info.widFreeHead; }
  105. WORKID FreeListTail() const { return _info.widFreeTail; }
  106. ULONG RecordSize() const { return _info.culRecord; }
  107. ULONG RecordsPerPage() const { return _cRecPerPage; }
  108. ULONG FixedRecordSize() const { return _info.culFixed; }
  109. ULONG CountProps() const { return _info.cTotal; }
  110. ULONG CountFixedProps() const { return _info.cFixed; }
  111. BOOL IsDirty() const { return _info.fDirty; }
  112. inline void MarkDirty();
  113. inline void MarkClean();
  114. void SetMaxWorkId( WORKID wid ) { _info.widMax = wid; MarkDirty(); }
  115. void SetFreeListHead( WORKID wid ) { _info.widFreeHead = wid; MarkDirty(); }
  116. void SetFreeListTail( WORKID wid ) { _info.widFreeTail = wid; MarkDirty(); }
  117. ULONG CountRecordsInUse() const { return _info.cTopLevel; }
  118. void IncRecordsInUse() { _info.cTopLevel++; }
  119. void DecRecordsInUse() { _info.cTopLevel--; }
  120. void SetRecordsInUse( ULONG count ) { _info.cTopLevel = count; }
  121. //
  122. // Per-property metadata
  123. //
  124. inline BOOL CanStore( PROPID pid );
  125. inline unsigned Size( PROPID pid );
  126. inline ULONG Type( PROPID pid );
  127. inline CPropDesc const * GetDescription( PROPID pid );
  128. inline CPropDesc const * GetDescriptionByOrdinal( ULONG ordinal );
  129. BOOL Add( PROPID pid, ULONG vt, unsigned cbMaxLen, CiStorage & storage );
  130. BOOL Delete( PROPID pid, CiStorage & storage );
  131. void Commit( CPropStoreInfo & psi, CRcovStrmWriteTrans & xact );
  132. PRcovStorageObj * GetRcovObj() { return _prsoPropStore; }
  133. private:
  134. void ChangeDirty( BOOL fDirty );
  135. unsigned Lookup( PROPID pid );
  136. unsigned LookupNew( PROPID pid );
  137. struct SPropInfo
  138. {
  139. ULONG Version;
  140. ULONG culRecord;
  141. ULONG culFixed;
  142. BOOL fDirty;
  143. ULONG cTotal;
  144. ULONG cFixed;
  145. ULONG cHash;
  146. WORKID widStream;
  147. WORKID widMax;
  148. WORKID widFreeHead;
  149. ULONG cTopLevel;
  150. WORKID widFreeTail;
  151. };
  152. ULONG _cRecPerPage; // # records per 64K page
  153. SPropInfo _info; // Non-repeated info, stored in header
  154. PRcovStorageObj * _prsoPropStore; // The persistent storage itself
  155. BOOL _fOwned; // Set to TRUE if propstore is owned.
  156. XArray<CPropDesc> _aProp;
  157. };
  158. //+-------------------------------------------------------------------------
  159. //
  160. // Class: CPhysPropertyStore
  161. //
  162. // Purpose: Persistent property store
  163. //
  164. // History: 27-Dec-95 KyleP Created
  165. //
  166. //--------------------------------------------------------------------------
  167. class CPhysPropertyStore : public CPhysStorage
  168. {
  169. INLINE_UNWIND( CPhysPropertyStore );
  170. public:
  171. inline CPhysPropertyStore( PStorage & storage,
  172. PStorageObject& obj,
  173. WORKID objectId,
  174. PMmStream * stream,
  175. PStorage::EOpenMode mode );
  176. private:
  177. virtual void ReOpenStream();
  178. int _dummy;
  179. };
  180. //+-------------------------------------------------------------------------
  181. //
  182. // Class: CPropertyStore
  183. //
  184. // Purpose: Persistent property store
  185. //
  186. // History: 27-Dec-95 KyleP Created
  187. //
  188. //--------------------------------------------------------------------------
  189. class CPropertyStore : INHERIT_UNWIND
  190. {
  191. INLINE_UNWIND( CPropertyStore )
  192. public:
  193. //
  194. // Two phase construction (to accomadate late-bound storage)
  195. //
  196. CPropertyStore();
  197. ~CPropertyStore();
  198. void FastInit( CiStorage * pStorage );
  199. void LongInit( BOOL & fWasDirty, ULONG & cInconsistencies );
  200. BOOL IsDirty() const { return _PropStoreInfo.IsDirty(); }
  201. void Empty();
  202. //
  203. // Schema manipulation
  204. //
  205. inline BOOL CanStore( PROPID pid );
  206. inline unsigned Size( PROPID pid );
  207. inline ULONG Type( PROPID pid );
  208. ULONG BeginTransaction();
  209. void Setup( PROPID pid, ULONG vt, DWORD cbMaxLen, ULONG ulToken );
  210. void EndTransaction( ULONG ulToken, BOOL fCommit, PROPID pidFixed );
  211. //
  212. // Property storage/retrieval.
  213. //
  214. BOOL WriteProperty( WORKID wid, PROPID pid, CStorageVariant const & var );
  215. inline WORKID WritePropertyInNewRecord( PROPID pid, CStorageVariant const & var );
  216. BOOL ReadProperty( WORKID wid, PROPID pid, PROPVARIANT * pbData, unsigned * pcb);
  217. BOOL ReadProperty( WORKID wid, PROPID pid, PROPVARIANT & var, BYTE * pbExtra, unsigned * pcbExtra );
  218. BOOL ReadProperty( CPropRecord & PropRecord, PROPID pid, PROPVARIANT & var, BYTE * pbExtra, unsigned * pcbExtra );
  219. BOOL ReadProperty( CPropRecord & PropRecord, PROPID pid, PROPVARIANT * pbData, unsigned * pcb);
  220. BOOL ReadProperty( WORKID wid, PROPID pid, PROPVARIANT & var );
  221. CPropRecord * OpenRecord( WORKID wid, BYTE * pb );
  222. void CloseRecord( CPropRecord * pRec );
  223. //
  224. // Special path/wid support
  225. //
  226. inline WORKID MaxWorkId();
  227. inline ULONG RecordsPerPage() const
  228. {
  229. return _PropStoreInfo.RecordsPerPage();
  230. }
  231. void DeleteRecord( WORKID wid );
  232. inline ULONG CountRecordsInUse() const;
  233. void Shutdown()
  234. {
  235. _fAbort = TRUE;
  236. }
  237. void Flush();
  238. private:
  239. friend class CPropertyStoreWids;
  240. friend class CLockRecordForRead;
  241. friend class CLockRecordForWrite;
  242. friend class CPropRecord;
  243. friend class CPropertyStoreRecovery;
  244. CPropertyStore( CPropertyStore & psi );
  245. WORKID CreateStorage();
  246. //
  247. // Record locking.
  248. //
  249. void AcquireRead( CPropertyLockRecord & record );
  250. void SyncRead( CPropertyLockRecord & record, BOOL fDecrementRead = FALSE );
  251. void ReleaseRead( CPropertyLockRecord & record );
  252. void AcquireWrite( CPropertyLockRecord & record );
  253. void ReleaseWrite( CPropertyLockRecord & record );
  254. CPropertyLockMgr & LockMgr() { return _lockMgr; }
  255. CReadWriteAccess & GetReadWriteAccess() { return _rwAccess; }
  256. void InitNewRecord( WORKID wid,
  257. ULONG cWid,
  258. COnDiskPropertyRecord * prec,
  259. BOOL fTopLevel );
  260. void InitFreeList( );
  261. void RecycleFreeList( WORKID wid );
  262. void LokFreeRecord( WORKID wid, ULONG cFree, COnDiskPropertyRecord * prec );
  263. WORKID LokAllocRecord( ULONG cFree );
  264. void WritePropertyInSpecificNewRecord( WORKID wid, PROPID pid, CStorageVariant const & var );
  265. WORKID NewWorkId( ULONG cWid )
  266. {
  267. CLock lock( _mtxWrite );
  268. return LokNewWorkId( cWid, TRUE );
  269. }
  270. WORKID LokNewWorkId( ULONG cWid, BOOL fTopLevel );
  271. void Transfer( CPropertyStore & Target, PROPID pidFixed );
  272. CiStorage * _pStorage; // Persistent storage object.
  273. CPropStoreInfo _PropStoreInfo; // Global persistent state for property store.
  274. WORKID * _aFreeBlocks; // Pointers into free list by rec. size
  275. BOOL _fAbort; // Set to TRUE when aborting
  276. BOOL _fIsConsistent; // Set to TRUE as long as the data is
  277. // consistent
  278. //
  279. // Record locking
  280. //
  281. CMutexSem _mtxWrite; // Taken to add/remove/modify records
  282. CMutexSem _mtxRW; // Sometimes used during per-record locking
  283. CEventSem _evtRead; // Sometimes used during per-record locking
  284. CEventSem _evtWrite; // Sometimes used during per-record locking
  285. XPtr<CPhysPropertyStore> _xPhysStore; // Main data stream.
  286. CPropertyLockMgr _lockMgr; // arbitrates record-level locking
  287. CReadWriteAccess _rwAccess; // Controls access to resources
  288. //
  289. // For multi-property changes to metadata
  290. //
  291. CPropertyStore * _ppsNew; // New metadata stored here
  292. BOOL _fNew; // TRUE if something really changed
  293. #if CIDBG==1
  294. _int64 _sigPSDebug;
  295. DWORD _tidReadSet;
  296. DWORD _tidReadReset;
  297. DWORD _tidWriteSet;
  298. DWORD _tidWriteReset;
  299. void _SetReadTid()
  300. {
  301. _tidReadSet = GetCurrentThreadId();
  302. }
  303. void _ReSetReadTid()
  304. {
  305. _tidReadReset = GetCurrentThreadId();
  306. }
  307. void _SetWriteTid()
  308. {
  309. _tidWriteSet = GetCurrentThreadId();
  310. }
  311. void _ReSetWriteTid()
  312. {
  313. _tidWriteReset = GetCurrentThreadId();
  314. }
  315. //
  316. // Deadlock detection for the first 256 threads.
  317. //
  318. enum { cTrackThreads = 256 };
  319. long * _aPerThreadReadCount;
  320. long * _aPerThreadWriteCount;
  321. #else
  322. void _SetReadTid() { }
  323. void _ReSetReadTid() { }
  324. void _SetWriteTid() { }
  325. void _ReSetWriteTid() { }
  326. #endif // CIDBG==1
  327. };
  328. //+---------------------------------------------------------------------------
  329. //
  330. // Member: CPropStoreInfo::CanStore, public
  331. //
  332. // Arguments: [pid] -- Propid to check.
  333. //
  334. // Returns: TRUE if [pid] can exist in property store (e.g. has been
  335. // registered).
  336. //
  337. // History: 27-Dec-95 KyleP Created.
  338. //
  339. //----------------------------------------------------------------------------
  340. inline BOOL CPropStoreInfo::CanStore( PROPID pid )
  341. {
  342. return (0 != _info.cHash) && _aProp[Lookup(pid)].IsInUse();
  343. }
  344. //+---------------------------------------------------------------------------
  345. //
  346. // Member: CPropStoreInfo::Size, public
  347. //
  348. // Synopsis: Returns size in cache for this property.
  349. //
  350. // Arguments: [pid] -- Propid to check.
  351. //
  352. // Returns: TRUE if [pid] can exist in property store (e.g. has been
  353. // registered).
  354. //
  355. // History: 27-Dec-95 KyleP Created.
  356. //
  357. //----------------------------------------------------------------------------
  358. inline unsigned CPropStoreInfo::Size( PROPID pid )
  359. {
  360. if (0 == _info.cHash)
  361. return 0;
  362. unsigned hash = Lookup(pid);
  363. if ( _aProp[hash].IsInUse() )
  364. return _aProp[hash].Size();
  365. else
  366. return 0;
  367. }
  368. //+---------------------------------------------------------------------------
  369. //
  370. // Member: CPropStoreInfo::Type, public
  371. //
  372. // Synopsis: Returns type in cache for this property.
  373. //
  374. // Arguments: [pid] -- Propid to check.
  375. //
  376. // Returns: TRUE if [pid] can exist in property store (e.g. has been
  377. // registered).
  378. //
  379. // History: 27-Dec-95 KyleP Created.
  380. //
  381. //----------------------------------------------------------------------------
  382. inline ULONG CPropStoreInfo::Type( PROPID pid )
  383. {
  384. if (0 == _info.cHash)
  385. return VT_EMPTY;
  386. unsigned hash = Lookup(pid);
  387. if ( _aProp[hash].IsInUse() )
  388. return _aProp[hash].Type();
  389. else
  390. return VT_EMPTY;
  391. }
  392. void CPropStoreInfo::MarkDirty()
  393. {
  394. if ( !_info.fDirty )
  395. ChangeDirty( TRUE );
  396. }
  397. void CPropStoreInfo::MarkClean()
  398. {
  399. if ( _info.fDirty )
  400. ChangeDirty( FALSE );
  401. }
  402. inline CPhysPropertyStore::CPhysPropertyStore( PStorage & storage,
  403. PStorageObject& obj,
  404. WORKID objectId,
  405. PMmStream * stream,
  406. PStorage::EOpenMode mode )
  407. : CPhysStorage( storage, obj, objectId, stream, mode,
  408. TheUserCiParams.GetPropertyStoreMappedCache() )
  409. {
  410. END_CONSTRUCTION( CPhysPropertyStore );
  411. }
  412. //+---------------------------------------------------------------------------
  413. //
  414. // Member: CPropertyStore::CanStore, public
  415. //
  416. // Arguments: [pid] -- Propid to check.
  417. //
  418. // Returns: TRUE if [pid] can exist in property store (e.g. has been
  419. // registered).
  420. //
  421. // History: 27-Dec-95 KyleP Created.
  422. //
  423. //----------------------------------------------------------------------------
  424. inline BOOL CPropertyStore::CanStore( PROPID pid )
  425. {
  426. return _PropStoreInfo.CanStore( pid );
  427. }
  428. //+---------------------------------------------------------------------------
  429. //
  430. // Member: CPropertyStore::Size, public
  431. //
  432. // Arguments: [pid] -- Propid to check.
  433. //
  434. // Returns: Size of property in store, or 0 if it isn't in store.
  435. //
  436. // History: 27-Dec-95 KyleP Created.
  437. //
  438. //----------------------------------------------------------------------------
  439. inline unsigned CPropertyStore::Size( PROPID pid )
  440. {
  441. return _PropStoreInfo.Size( pid );
  442. }
  443. //+---------------------------------------------------------------------------
  444. //
  445. // Member: CPropertyStore::Type, public
  446. //
  447. // Arguments: [pid] -- Propid to check.
  448. //
  449. // Returns: Type of property in store, or VT_EMPTY if it isn't in store.
  450. //
  451. // History: 27-Dec-95 KyleP Created.
  452. //
  453. //----------------------------------------------------------------------------
  454. inline ULONG CPropertyStore::Type( PROPID pid )
  455. {
  456. return _PropStoreInfo.Type( pid );
  457. }
  458. //+---------------------------------------------------------------------------
  459. //
  460. // Member: CPropertyStore::WritePropertyInNewRecord, public
  461. //
  462. // Synopsis: Like WriteProperty, but also allocates record.
  463. //
  464. // Arguments: [pid] -- Propid to write.
  465. // [var] -- Property value
  466. //
  467. // Returns: Workid of new record.
  468. //
  469. // History: 27-Dec-95 KyleP Created.
  470. //
  471. //----------------------------------------------------------------------------
  472. inline WORKID CPropertyStore::WritePropertyInNewRecord( PROPID pid,
  473. CStorageVariant const & var )
  474. {
  475. CLock lock( _mtxWrite );
  476. WORKID wid = NewWorkId( 1 );
  477. ciDebugOut(( DEB_PROPSTORE, "New short record at %d\n", wid ));
  478. WriteProperty( wid, pid, var );
  479. _PropStoreInfo.IncRecordsInUse();
  480. return wid;
  481. }
  482. //+---------------------------------------------------------------------------
  483. //
  484. // Member: CPropertyStore::CountRecordsInUse, public
  485. //
  486. // Returns: Count of 'top level' records (correspond to user wids)
  487. //
  488. // History: 15-Feb-96 KyleP Created.
  489. //
  490. //----------------------------------------------------------------------------
  491. inline ULONG CPropertyStore::CountRecordsInUse() const
  492. {
  493. return _PropStoreInfo.CountRecordsInUse();
  494. }
  495. //+---------------------------------------------------------------------------
  496. //
  497. // Member: CPropertyStore::MaxWorkId, public
  498. //
  499. // Returns: Maximum workid which has been allocated.
  500. //
  501. // History: 28-Dec-95 KyleP Created.
  502. //
  503. //----------------------------------------------------------------------------
  504. inline WORKID CPropertyStore::MaxWorkId()
  505. {
  506. return _PropStoreInfo.MaxWorkId();
  507. }
  508. //+---------------------------------------------------------------------------
  509. //
  510. // Member: CPropertyStoreInfo::GetDescription, public
  511. //
  512. // Arguments: [pid] -- Propid to check.
  513. //
  514. // Returns: Metadata descriptor for specified property.
  515. //
  516. // History: 28-Dec-95 KyleP Created.
  517. //
  518. //----------------------------------------------------------------------------
  519. inline CPropDesc const * CPropStoreInfo::GetDescription( PROPID pid )
  520. {
  521. if (0 == _info.cHash)
  522. return 0;
  523. unsigned hash = Lookup( pid );
  524. if ( _aProp[hash].IsInUse() )
  525. return &_aProp[hash];
  526. else
  527. return 0;
  528. }
  529. //+---------------------------------------------------------------------------
  530. //
  531. // Member: CPropertyStoreInfo::GetDescriptionByOrdinal, public
  532. //
  533. // Arguments: [ordinal] -- Ordinal
  534. //
  535. // Returns: Metadata descriptor for specified property.
  536. //
  537. // History: 16-Jan-96 KyleP Created.
  538. //
  539. //----------------------------------------------------------------------------
  540. inline CPropDesc const * CPropStoreInfo::GetDescriptionByOrdinal( ULONG ordinal )
  541. {
  542. Win4Assert( 0 != _info.cHash );
  543. for ( unsigned i = 0; i < _aProp.Count(); i++ )
  544. {
  545. if ( _aProp[i].Pid() != pidInvalid && _aProp[i].Ordinal() == ordinal )
  546. return &_aProp[i];
  547. }
  548. return 0;
  549. }
  550. //+---------------------------------------------------------------------------
  551. //
  552. // Class: CPropertyStoreRecovery
  553. //
  554. // Purpose: Recovers the property store from a dirty shutdown
  555. //
  556. // History: 4-10-96 srikants Created
  557. //
  558. // Notes:
  559. //
  560. //----------------------------------------------------------------------------
  561. class CPropertyStoreRecovery : INHERIT_UNWIND
  562. {
  563. INLINE_UNWIND( CPropertyStoreRecovery )
  564. public:
  565. CPropertyStoreRecovery( CPropertyStore & propStore );
  566. ~CPropertyStoreRecovery( );
  567. void DoRecovery();
  568. ULONG GetInconsistencyCount() const { return _cInconsistencies; }
  569. private:
  570. void _Pass1();
  571. void _Pass2();
  572. void _Complete();
  573. void _SetFree();
  574. BOOL _CheckOverflowChain();
  575. void _FreeChain();
  576. WORKID AddToFreeList( WORKID widFree,
  577. ULONG cFree,
  578. COnDiskPropertyRecord * precFree,
  579. WORKID widListHead );
  580. CPropertyStore & _propStore;
  581. CPropStoreInfo & _PropStoreInfo;
  582. CPhysPropertyStore * _pPhysStore;
  583. WORKID _wid; // Wid being processed currently
  584. COnDiskPropertyRecord * _pRec; // Pointer to _wid's on disk rec
  585. WORKID _cRec; // Count of records for this wid
  586. //
  587. // Cumulative values during recovery.
  588. //
  589. WORKID * _aFreeBlocks; // Array of free lists by size
  590. WORKID _widMax; // Current wid max
  591. ULONG _cTopLevel; // Total top level records
  592. ULONG _cRecPerPage; // Records per long page
  593. ULONG _cInconsistencies;
  594. // Number of inconsistencies.
  595. ULONG _cForceFreed; // Number of records forecefully
  596. // freed.
  597. };
  598. #endif // __PROPSTOR_HXX__