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.

538 lines
16 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. VerfySup.c
  5. Abstract:
  6. This module implements consistency checking and structure comparisions
  7. on Lfs structures.
  8. Author:
  9. Brian Andrew [BrianAn] 20-June-1991
  10. Revision History:
  11. --*/
  12. #include "lfsprocs.h"
  13. #ifdef LFS_RAISE
  14. BOOLEAN LfsRaiseFull = FALSE;
  15. #endif
  16. #ifdef ALLOC_PRAGMA
  17. #pragma alloc_text(PAGE, LfsCurrentAvailSpace)
  18. #pragma alloc_text(PAGE, LfsFindCurrentAvail)
  19. #pragma alloc_text(PAGE, LfsVerifyLogSpaceAvail)
  20. #endif
  21. VOID
  22. LfsCurrentAvailSpace (
  23. IN PLFCB Lfcb,
  24. OUT PLONGLONG CurrentAvailSpace,
  25. OUT PULONG CurrentPageBytes
  26. )
  27. /*++
  28. Routine Description:
  29. This routine is called to determine the available log space in the log file.
  30. It returns the total number of free bytes and the number available on the
  31. active page if present. The total free bytes will reflect all of the empty
  32. pages as well as the number in the active page.
  33. Arguments:
  34. Lfcb - Lfcb for this log file.
  35. CurrentAvailSpace - This is the number of bytes available for log
  36. records.
  37. CurrentPageBytes - This is the number of bytes remaining on the
  38. current log page.
  39. Return Value:
  40. None.
  41. --*/
  42. {
  43. *CurrentPageBytes = 0;
  44. PAGED_CODE();
  45. DebugTrace( +1, Dbg, "LfsCurrentAvailSpace: Entered\n", 0 );
  46. //
  47. // Get the total number from the Lfcb.
  48. //
  49. *CurrentAvailSpace = Lfcb->CurrentAvailable;
  50. //
  51. // We now look to see if there are any bytes available on the Lbcb in
  52. // the active queue. We can add this to the bytes available in the
  53. // log pages and also give this back to the caller.
  54. //
  55. if (!IsListEmpty( &Lfcb->LbcbActive )) {
  56. PLBCB ThisLbcb;
  57. ThisLbcb = CONTAINING_RECORD( Lfcb->LbcbActive.Flink,
  58. LBCB,
  59. ActiveLinks );
  60. //
  61. // If the page is not empty or the page is empty but this is a
  62. // restart page then add the remaining bytes on this page.
  63. //
  64. if (FlagOn( ThisLbcb->LbcbFlags, LBCB_NOT_EMPTY | LBCB_FLUSH_COPY )) {
  65. *CurrentPageBytes = (ULONG)Lfcb->LogPageSize - (ULONG)ThisLbcb->BufferOffset;
  66. *CurrentAvailSpace = *CurrentAvailSpace + *CurrentPageBytes; //**** xxAdd( *CurrentAvailSpace, xxFromUlong( *CurrentPageBytes ));
  67. }
  68. }
  69. DebugTrace( +1, Dbg, "LfsCurrentAvailSpace: Exit\n", 0 );
  70. return;
  71. }
  72. BOOLEAN
  73. LfsVerifyLogSpaceAvail (
  74. IN PLFCB Lfcb,
  75. IN PLCH Lch,
  76. IN ULONG RemainingLogBytes,
  77. IN LONG UndoRequirement,
  78. IN BOOLEAN ForceToDisk
  79. )
  80. /*++
  81. Routine Description:
  82. This routine is called to verify that we may write this log record into the
  83. log file. We want to always leave room for each transaction to abort.
  84. We determine how much space the current log record will take and the
  85. worst case for its undo operation. If this space is available we
  86. update the corresponding values in the Lfcb and Lch for bookkeeping.
  87. Otherwise we raise a status indicating that the log file is full.
  88. The disk usage is different for the packed and unpacked cases. Make the
  89. following adjustments after finding the total available and amount still
  90. remaining on the last active page,
  91. Packed Case:
  92. Size needed for log record is data size plus header size.
  93. Undo requirement is the undo data size plus the header size.
  94. We have already taken into account the end of the pages
  95. except for the current page.
  96. Add the log record size to the undo requirement to get the
  97. log file usage. Compare this number with the actual available
  98. space (Available - CommittedUndo). If the space is not
  99. available, then raise LOG_FILE_FULL. Must take into account
  100. any unused bytes at the end of the current page.
  101. Unpacked Case:
  102. Size needed is initially header size plus data size.
  103. If the log record can't begin on the current page then
  104. add the bytes being thrown away to the log record size.
  105. If the page is being forced to disk then add any remaining
  106. bytes on the last page. To the bytes being used.
  107. Undo requirement is twice the sum of the header size and
  108. undo size. We double the requested size since the log
  109. record will always fit on a page. This can be a
  110. positive or negative number.
  111. Add the log record usage to the undo usage to get the log file
  112. usage. Compare this number with the actual available
  113. space (Available - CommittedUndo). If the space is not
  114. available, then raise LOG_FILE_FULL.
  115. Arguments:
  116. Lfcb - Lfcb for this log file.
  117. Lch - Client handle
  118. RemainingLogBytes - Number of bytes for the current log record
  119. UndoRequirement - User's requirement for the undo record.
  120. ForceToDisk - Indicates if this log record will be flushed to disk.
  121. Return Value:
  122. BOOLEAN - Advisory, indicates that there is less than 1/4 of the log file available.
  123. --*/
  124. {
  125. ULONG CurrentLogRecordSize;
  126. ULONG LogRecordStart;
  127. ULONG TailBytes;
  128. LONGLONG CurrentAvailSpace;
  129. ULONG CurrentPageBytes;
  130. LONGLONG LogFileUsage;
  131. PAGED_CODE();
  132. DebugTrace( +1, Dbg, "LfsVerifyLogSpaceAvail: Entered\n", 0 );
  133. DebugTrace( 0, Dbg, "Lfcb -> %08x\n", Lfcb );
  134. DebugTrace( 0, Dbg, "Lch -> %08lx\n", Lch );
  135. DebugTrace( 0, Dbg, "RemainingLogBytes -> %08lx\n", RemainingLogBytes );
  136. DebugTrace( 0, Dbg, "UndoRequirement -> %08lx\n", UndoRequirement );
  137. DebugTrace( 0, Dbg, "ForceToDisk -> %04x\n", ForceToDisk );
  138. //
  139. // Start by collecting the current data on the file.
  140. //
  141. LfsCurrentAvailSpace( Lfcb,
  142. &CurrentAvailSpace,
  143. &CurrentPageBytes );
  144. //
  145. // We compute the amount of space needed for the current log record by
  146. // adding up the following:
  147. //
  148. // Space at end of current log page which won't be used.
  149. // Size of header for log record.
  150. // Size of client data in log record.
  151. // Size of wasted portion of log page if this is forced to disk.
  152. //
  153. //
  154. // Start with the size of the header and the client data.
  155. //
  156. CurrentLogRecordSize = RemainingLogBytes + Lfcb->RecordHeaderLength;
  157. //
  158. // If the log is packed and there are bytes on the current page we need
  159. // to take into account any bytes at the end of the page which won't
  160. // be used. This will happen if the log record spills into the end of
  161. // the log page but doesn't use up the page. If the remaining bytes are
  162. // less than a record header size we must throw them away.
  163. //
  164. if (FlagOn( Lfcb->Flags, LFCB_PACK_LOG )) {
  165. if (CurrentPageBytes != 0
  166. && CurrentLogRecordSize < CurrentPageBytes
  167. && (CurrentPageBytes - CurrentLogRecordSize) < Lfcb->RecordHeaderLength) {
  168. CurrentLogRecordSize += (CurrentPageBytes - CurrentLogRecordSize);
  169. }
  170. //
  171. // If this is the unpacked case we need to check for bytes being thrown away
  172. // on the current page or the last page.
  173. //
  174. } else {
  175. //
  176. // If there is an active Lbcb, we need to add any bytes that
  177. // would be thrown away at the end.
  178. //
  179. if (CurrentPageBytes != 0) {
  180. //
  181. // We won't use this log page unless the new log record will fit or
  182. // unless this is the first log record in the page.
  183. //
  184. if ((CurrentPageBytes != (ULONG)Lfcb->LogPageDataSize)
  185. && (CurrentLogRecordSize > CurrentPageBytes)) {
  186. CurrentLogRecordSize += CurrentPageBytes;
  187. //
  188. // Remember that we will start this log record at the first
  189. // byte in the data portion of a page.
  190. //
  191. LogRecordStart = 0;
  192. //
  193. // Otherwise this will start at the current offset into the
  194. // data portion of the log page.
  195. //
  196. } else {
  197. LogRecordStart = (ULONG)Lfcb->LogPageDataSize - CurrentPageBytes;
  198. }
  199. //
  200. // If there was no Lbcb, then we know that we will start at the first
  201. // byte of the data portion.
  202. //
  203. } else {
  204. LogRecordStart = 0;
  205. }
  206. //
  207. // We always assume that we will use up the rest of the bytes on the last page
  208. // in computing whether the log record will fit in the available space. We
  209. // only subtract that space from the available space if this is a force write.
  210. //
  211. if (ForceToDisk) {
  212. //
  213. // We take into account where we start on a log page and continue
  214. // to subtract log pages until we know the amount on the last
  215. // page.
  216. //
  217. TailBytes = RemainingLogBytes + Lfcb->RecordHeaderLength + LogRecordStart;
  218. while (TailBytes > (ULONG)Lfcb->LogPageDataSize) {
  219. TailBytes -= (ULONG)Lfcb->LogPageDataSize;
  220. }
  221. TailBytes = (ULONG)Lfcb->LogPageDataSize - TailBytes;
  222. CurrentLogRecordSize += TailBytes;
  223. }
  224. }
  225. //
  226. // We now know the number of bytes needed for the current log page.
  227. // Next we compute the number of bytes being reserved by UndoRequirement.
  228. // If the UndoRequirement is positive, we will add to the amount reserved
  229. // in the log file. If it is negative, we will subtract from the amount
  230. // reserved in the log file.
  231. //
  232. //
  233. // When we have an actual reserve amount, we convert it to positive
  234. // and then reserve twice the space required to hold the data and
  235. // its header (up to the maximum of a single page.
  236. //
  237. if (UndoRequirement != 0) {
  238. if (!FlagOn( Lfcb->Flags, LFCB_PACK_LOG )) {
  239. UndoRequirement *= 2;
  240. }
  241. if (UndoRequirement < 0) {
  242. UndoRequirement -= (2 * Lfcb->RecordHeaderLength);
  243. } else {
  244. UndoRequirement += (2 * Lfcb->RecordHeaderLength);
  245. }
  246. }
  247. //
  248. // Now compute the net log file usage. The result may be positive or
  249. // negative.
  250. //
  251. LogFileUsage = ((LONG) CurrentLogRecordSize) + UndoRequirement; //**** xxFromLong( ((LONG) CurrentLogRecordSize) + UndoRequirement );
  252. //
  253. // The actual available space is the CurrentAvail minus the reserved
  254. // undo value in the Lfcb.
  255. //
  256. CurrentAvailSpace = CurrentAvailSpace - Lfcb->TotalUndoCommitment; //**** xxSub( CurrentAvailSpace, Lfcb->TotalUndoCommitment );
  257. //
  258. // If this log file usage is greater than the available log file space
  259. // then we raise a status code.
  260. //
  261. #ifdef LFS_RAISE
  262. if (LfsRaiseFull) {
  263. LfsRaiseFull = FALSE;
  264. DebugTrace( -1, Dbg, "LfsVerifyLogSpaceAvail: About to raise\n", 0 );
  265. ExRaiseStatus( STATUS_LOG_FILE_FULL );
  266. }
  267. #endif
  268. if (LogFileUsage > CurrentAvailSpace) {
  269. DebugTrace( -1, Dbg, "LfsVerifyLogSpaceAvail: About to raise\n", 0 );
  270. ExRaiseStatus( STATUS_LOG_FILE_FULL );
  271. }
  272. Lfcb->TotalUndoCommitment = Lfcb->TotalUndoCommitment + UndoRequirement; //**** xxAdd( Lfcb->TotalUndoCommitment, xxFromLong( UndoRequirement ));
  273. Lch->ClientUndoCommitment = Lch->ClientUndoCommitment + UndoRequirement; //**** xxAdd( Lch->ClientUndoCommitment, xxFromLong( UndoRequirement ));
  274. DebugTrace( -1, Dbg, "LfsVerifyLogSpaceAvail: Exit\n", 0 );
  275. //
  276. // Now check if the log file is almost used up.
  277. //
  278. if ((CurrentAvailSpace - LogFileUsage) < (Lfcb->TotalAvailable >> 2)) {
  279. return TRUE;
  280. }
  281. return FALSE;
  282. }
  283. VOID
  284. LfsFindCurrentAvail (
  285. IN PLFCB Lfcb
  286. )
  287. /*++
  288. Routine Description:
  289. This routine is called to calculate the number of bytes available for log
  290. records which are in completely empty log record pages. It ignores any
  291. partial pages in the active work queue and ignores any page which is
  292. going to be reused.
  293. Arguments:
  294. Lfcb - Lfcb for this log file.
  295. Return Value:
  296. None.
  297. --*/
  298. {
  299. LONGLONG OldestPageOffset;
  300. LONGLONG NextFreePageOffset;
  301. LONGLONG FreeBytes;
  302. PAGED_CODE();
  303. DebugTrace( +1, Dbg, "LfsFindCurrentAvail: Entered\n", 0 );
  304. DebugTrace( 0, Dbg, "Lfcb -> %08x\n", Lfcb );
  305. //
  306. // If there is a last lsn in the restart area then we know
  307. // that we will have to compute the free range.
  308. //
  309. if (!FlagOn( Lfcb->Flags, LFCB_NO_LAST_LSN )) {
  310. //
  311. // If there is no oldest Lsn then start at the
  312. // first page of the file.
  313. //
  314. if (FlagOn( Lfcb->Flags, LFCB_NO_OLDEST_LSN )) {
  315. OldestPageOffset = Lfcb->FirstLogPage;
  316. } else {
  317. LfsTruncateOffsetToLogPage( Lfcb,
  318. Lfcb->OldestLsnOffset,
  319. &OldestPageOffset );
  320. }
  321. //
  322. // We will use the next log page offset to compute the
  323. // next free page. If we are going to reuse this page
  324. // go to the next page, if we are at the first page then
  325. // use the end of the file.
  326. //
  327. if (FlagOn( Lfcb->Flags, LFCB_REUSE_TAIL )) {
  328. NextFreePageOffset = Lfcb->NextLogPage + Lfcb->LogPageSize; //**** xxAdd( Lfcb->NextLogPage, Lfcb->LogPageSize );
  329. } else if ( Lfcb->NextLogPage == Lfcb->FirstLogPage ) { //**** xxEql( Lfcb->NextLogPage, Lfcb->FirstLogPage )
  330. NextFreePageOffset = Lfcb->FileSize;
  331. } else {
  332. NextFreePageOffset = Lfcb->NextLogPage;
  333. }
  334. //
  335. // If the two offsets are the same then there is no available space.
  336. //
  337. if ( OldestPageOffset == NextFreePageOffset ) { //**** xxEql( OldestPageOffset, NextFreePageOffset )
  338. Lfcb->CurrentAvailable = 0;
  339. } else {
  340. //
  341. // If the free offset follows the oldest offset then subtract
  342. // this range from the total available pages.
  343. //
  344. if ( OldestPageOffset < NextFreePageOffset ) { //**** xxLtr( OldestPageOffset, NextFreePageOffset )
  345. FreeBytes = Lfcb->TotalAvailInPages - ( NextFreePageOffset - OldestPageOffset ); //**** xxSub( Lfcb->TotalAvailInPages, xxSub( NextFreePageOffset, OldestPageOffset ));
  346. } else {
  347. FreeBytes = OldestPageOffset - NextFreePageOffset; //**** xxSub( OldestPageOffset, NextFreePageOffset );
  348. }
  349. //
  350. // We now have the total bytes in the pages available. We
  351. // now have to subtract the size of the page header to get
  352. // the total available bytes.
  353. //
  354. // We will convert the bytes to pages and then multiple
  355. // by the data size of each page.
  356. //
  357. FreeBytes = Int64ShrlMod32(((ULONGLONG)(FreeBytes)), Lfcb->LogPageShift);
  358. Lfcb->CurrentAvailable = FreeBytes * (ULONG)Lfcb->ReservedLogPageSize; //**** xxXMul( FreeBytes, Lfcb->ReservedLogPageSize.LowPart );
  359. }
  360. //
  361. // Otherwise the entire file is available.
  362. //
  363. } else {
  364. Lfcb->CurrentAvailable = Lfcb->MaxCurrentAvail;
  365. }
  366. DebugTrace( -1, Dbg, "LfsFindCurrentAvail: Exit\n", 0 );
  367. return;
  368. }