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.

269 lines
9.8 KiB

  1. /*++
  2. Copyright (C) 2000-2001 Microsoft Corporation
  3. Module Name:
  4. VarObjHeap.H
  5. Abstract:
  6. Implements the storage of variable length objects over the top of of a fixed
  7. length page system. It keeps a set of admin pages for holding the pages active
  8. by this subsystem, along with how much space is used on each. When a page becomes
  9. empty it frees up the page to the page system. It also deals with blocks that span
  10. multiple pages
  11. History:
  12. paulall 02-Feb-2001 Created
  13. --*/
  14. #include <unk.h>
  15. #include <arrtempl.h>
  16. class CPageFile;
  17. class CPageSource;
  18. #define VAROBJ_VERSION 1
  19. //**************************************************************************************
  20. //VarObjAdminPageEntry - This is a structure that is stored within the
  21. //m_aAdminPages cache. It has an entry for each of the admin pages
  22. //that we cache. It stores the PageId (0 for the first one!),
  23. //pointer to the actual page, and a flag to determine if we need to
  24. //flush it next time around.
  25. //**************************************************************************************
  26. typedef struct _VarObjAdminPageEntry
  27. {
  28. DWORD dwPageId;
  29. BYTE *pbPage;
  30. bool bDirty;
  31. } VarObjAdminPageEntry;
  32. //**************************************************************************************
  33. //VarObjObjOffsetEntry: There is an array of these objects stored at the
  34. //start of the object page to point out where each object is stored.
  35. //If this is a continuation block we do not have one of these, however
  36. //continuation blocks have consecutive pageIds so it should be fairly easy
  37. //to conclude
  38. //**************************************************************************************
  39. typedef struct _VarObjObjOffsetEntry
  40. {
  41. DWORD dwOffsetId;
  42. DWORD dwPhysicalStartOffset;
  43. DWORD dwBlockLength;
  44. DWORD dwCRC;
  45. } VarObjObjOffsetEntry;
  46. //**************************************************************************************
  47. //VarObjHeapAdminPage - This is the header of each of the admin pages
  48. //that are stored in the object file. The version is only relevant
  49. //in the first page (page 0). The last entry is a buffer to make
  50. //it 4-DWORD structure rather than 3. May use it at a later date.
  51. //Should always set it to 0 for now.
  52. //**************************************************************************************
  53. typedef struct _VarObjHeapAdminPage
  54. {
  55. DWORD dwVersion;
  56. DWORD dwNextAdminPage;
  57. DWORD dwNumberEntriesOnPage;
  58. //VarObjHeapFreeList aFreeListEntries[dwNumberEntriesOnPage];
  59. } VarObjHeapAdminPage;
  60. //**************************************************************************************
  61. //VarObjHeapFreeList - This structure follows the admin page header
  62. //and there is an entry for each page we use to store objects. The
  63. //page may not be full, so we do not shuffle items on a second page
  64. //to this page when we delete an entry.
  65. //**************************************************************************************
  66. typedef struct _VarObjHeapFreeList
  67. {
  68. DWORD dwPageId;
  69. DWORD dwFreeSpace;
  70. DWORD dwCRC32;
  71. DWORD dwReserved;
  72. } VarObjHeapFreeList;
  73. //**************************************************************************************
  74. //CVarObjHeap - This is the implementation of the variable sized object store
  75. //over the top of the transacted fixed page manager. It tracks the admin pages
  76. //that hold all pages we use to store objects in (it caches these pages), and
  77. //also manages cases when an object is too big to fit on a single page.
  78. //**************************************************************************************
  79. class CVarObjHeap
  80. {
  81. private:
  82. //Current status of admin page
  83. enum
  84. {
  85. NoError = 0,
  86. AdminPageReadFailure = 1,
  87. RootAdminPageCreationFailure = 2,
  88. AdminPagesNeedReading = 3
  89. } m_dwStatus;
  90. //Pointer to the transacted file for the object storage
  91. CPageFile *m_pObjectFile;
  92. //Page size used within the object storage file.
  93. DWORD m_dwPageSize;
  94. //Admin page structure
  95. CLockableFlexArray m_aAdminPages;
  96. protected:
  97. //Adds an allocation to the end of the existing allocations
  98. DWORD AllocateFromPage(/* in */ DWORD dwPageId,
  99. /* in */ BYTE *pbPage,
  100. /* in */ ULONG ulBlockSize,
  101. /* in */ const BYTE *pBlock,
  102. /* out*/ ULONG *pdwNewOffset);
  103. //Allocates a multi-page entry in the object file. This requires
  104. //different algorithms to work things out so is a special case
  105. DWORD AllocateMultiPageBuffer(/* in */ ULONG ulBlockSize,
  106. /* in */ const BYTE *pBlock,
  107. /* out */ ULONG *pulPageId,
  108. /* out */ ULONG *pulOffsetId);
  109. //Given and offsetId and a page, calculate the physical pointer to the object and also
  110. //return the size of the block
  111. DWORD OffsetToPointer(/* in */ ULONG ulOffsetId,
  112. /* in */ BYTE *pbPage,
  113. /* out*/ BYTE **pOffsetPointer,
  114. /* out*/ ULONG *pdwBlockSize,
  115. /* out*/ DWORD *pdwCRC32);
  116. //Reads the admin pages into memory and marks them as clean (no changes)
  117. //setting bReReadPages to false has an affect of clearing the pages out
  118. DWORD ReadAdminPages(CPageSource *pTransactionManager, bool bReReadPages);
  119. //Writes each of the changed admin pages back to the object file
  120. DWORD FlushAdminPages();
  121. //Find a page form the admin pages that can accomodate a particular buffer size
  122. DWORD FindPageWithSpace(/* in */ DWORD dwRequiredSize,
  123. /* out*/ DWORD *pdwPageId);
  124. //Allocate a new page for use with objects. A buffer for the new page is passed
  125. //in, however the PageId of this page is passed out
  126. DWORD AllocateNewPage(/* in */ DWORD ulBlockSize,
  127. /* out*/ DWORD *dwPageId,
  128. /* in */ BYTE *pbNewObjectPage);
  129. //Deletes a page, and updates the admin pages as appropriage
  130. DWORD DeletePage(/* in */ DWORD ulPageId);
  131. //DeleteFromPage - removes an object from a specific object page
  132. DWORD RemoveFromPage(/* in */ ULONG ulPageId,
  133. /* in */ ULONG ulOffsetId,
  134. /* in */ BYTE *pbPage,
  135. /* out*/ DWORD *pdwSize);
  136. //MultiPageObject - returns true if the provided page is the first page
  137. //of a multi-page object
  138. bool MultiPageObject(/* in */ BYTE *pbPage) { return ((VarObjObjOffsetEntry*) pbPage)->dwBlockLength > (m_dwPageSize - (sizeof(VarObjObjOffsetEntry) * 2)); }
  139. //DeleteMultiPageBuffer - handles the deletion of an object when it spans
  140. //multiple pages
  141. DWORD DeleteMultiPageBuffer(/* in */ ULONG ulPageId,
  142. /* in */ ULONG ulOffsetId,
  143. /* in */ BYTE *pbPage);
  144. //UpdateAdminPageForAllocate - Updates the admin page to decrement the amount
  145. //of free space on a page by this amount ( + sizeof(VarObjObjOffsetEntry))
  146. DWORD UpdateAdminPageForAllocate(/* in */ ULONG ulPageId,
  147. /* in */ ULONG ulBlockSize,
  148. /* in */ DWORD dwCRC32);
  149. //UpdateAdminPageForDelete - Updates the admin page for giving space back. If
  150. //the page is totally empty we should delete the page altogether
  151. DWORD UpdateAdminPageForDelete(/* in */ ULONG ulPageId,
  152. /* in */ ULONG ulBlockSize,
  153. /* in */ DWORD dwCRC32,
  154. /* out */ bool *pbPageDeleted);
  155. //Removes an object page entry from an admin page, removing the
  156. //admin page if it is no longer needed
  157. DWORD RemoveEntryFromAdminPage(/* in */ DWORD dwAdminPageIndex,
  158. /* in */ DWORD dwAdminPageEntry);
  159. //Returns a CRC based on a given block of memory
  160. #define FINALIZE_CRC32(x) (x=~x)
  161. DWORD CreateCRC32(/* in */ const BYTE *pBlock,
  162. /* in */ DWORD dwSize,
  163. /* in */ DWORD dwPreviousCRC = (DWORD) -1); // Must be 0xFFFFFFFF if no previous CRC
  164. #ifdef DBG
  165. //Given a page we validate that there is in fact enough space
  166. //for this block. If there is not it asserts. This implies
  167. //that the admin page is not in sync with the actual pages.
  168. DWORD ValidatePageFreeSpace(/* in */ const BYTE *pbPage,
  169. /* in */ DWORD ulBlockSize);
  170. //Given a page and a page ID, it validates the amount of free space
  171. //on the page is equal to the amount the admin page thinks is on
  172. //there.
  173. DWORD ValidatePageFreeSpaceWithAdminPage(/* in */ const BYTE *pbPage,
  174. /* in */ DWORD ulPageId);
  175. //Dumps the offset table of a page to the debugger
  176. DWORD DumpPageOffsetTable(/* in */ DWORD dwPageId,
  177. /* in */ const BYTE *pbPage);
  178. //Checks the CRCs of all objects on a page (cannot do this
  179. //for a multi-page object though as we only have the first
  180. //page!)
  181. DWORD ValidateAllCRC32OnPage(/* in */ const BYTE *pbPage);
  182. //Validates the page check-sum with the admin page
  183. DWORD ValidatePageCRCWithAdminPage(/* in */ const BYTE *pbPage,
  184. /* in */ DWORD dwPageId);
  185. #endif /* DBG */
  186. public:
  187. CVarObjHeap();
  188. ~CVarObjHeap();
  189. DWORD Initialize(CPageSource *pPageManager);
  190. DWORD Shutdown(DWORD dwShutdownType);
  191. //Re-read admin pages
  192. DWORD InvalidateCache();
  193. //Discard admin pages
  194. DWORD FlushCaches();
  195. //ReadBuffer pages the virtual page and offset of the block and returns a new[]-ed block
  196. DWORD ReadBuffer(/* in */ ULONG ulPageId,
  197. /* in */ ULONG ulOffsetId,
  198. /* out */ BYTE **ppReturnedBlock,
  199. /* out */ DWORD *pdwBlockSize);
  200. //WriteNewBuffer will write a new page based on size of BYTE *, and return the
  201. //new virtual pageId and offsetId of the block.
  202. DWORD WriteNewBuffer(/* in */ ULONG ulBlockSize,
  203. /* in */ const BYTE *pBlock,
  204. /* out */ ULONG *pulPageId,
  205. /* out */ ULONG *pulOffsetId);
  206. //WriteExistingBuffer will update an existing block with new data. The old virtual page
  207. //and offset are passed in, and new ones are returned. They may or may not be the same
  208. //depending on if it still fits in the page or not.
  209. DWORD WriteExistingBuffer(/* in */ ULONG ulBlockSize,
  210. /* in */ const BYTE *pBlock,
  211. /* in */ ULONG ulOldPageId,
  212. /* in */ ULONG ulOldOffsetId,
  213. /* out */ ULONG *pulNewPageId,
  214. /* out */ ULONG *pulNewOffsetId);
  215. //DeleteBuffer is called to delete the item in the store given the virtual pageId and
  216. //offsetId.
  217. DWORD DeleteBuffer(/* in */ ULONG ulPageId,
  218. /* in */ ULONG ulOffsetId);
  219. };