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.

1220 lines
29 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. QueryLog.c
  5. Abstract:
  6. This module implements the user routines which query for log records
  7. in a log file.
  8. Author:
  9. Brian Andrew [BrianAn] 20-June-1991
  10. Revision History:
  11. --*/
  12. #include "lfsprocs.h"
  13. //
  14. // The debug trace level
  15. //
  16. #define Dbg (DEBUG_TRACE_QUERY)
  17. #undef MODULE_POOL_TAG
  18. #define MODULE_POOL_TAG ('QsfL')
  19. VOID
  20. LfsFindLogRecord (
  21. IN PLFCB Lfcb,
  22. IN OUT PLEB Leb,
  23. IN LSN Lsn,
  24. OUT PLFS_RECORD_TYPE RecordType,
  25. OUT TRANSACTION_ID *TransactionId,
  26. OUT PLSN UndoNextLsn,
  27. OUT PLSN PreviousLsn,
  28. OUT PULONG BufferLength,
  29. OUT PVOID *Buffer
  30. );
  31. BOOLEAN
  32. LfsFindClientNextLsn (
  33. IN PLFCB Lfcb,
  34. IN PLEB Leb,
  35. OUT PLSN Lsn
  36. );
  37. BOOLEAN
  38. LfsSearchForwardByClient (
  39. IN PLFCB Lfcb,
  40. IN OUT PLEB Leb,
  41. OUT PLSN Lsn
  42. );
  43. #ifdef ALLOC_PRAGMA
  44. #pragma alloc_text(PAGE, LfsFindClientNextLsn)
  45. #pragma alloc_text(PAGE, LfsFindLogRecord)
  46. #pragma alloc_text(PAGE, LfsQueryLastLsn)
  47. #pragma alloc_text(PAGE, LfsReadLogRecord)
  48. #pragma alloc_text(PAGE, LfsReadNextLogRecord)
  49. #pragma alloc_text(PAGE, LfsSearchForwardByClient)
  50. #pragma alloc_text(PAGE, LfsTerminateLogQuery)
  51. #endif
  52. VOID
  53. LfsReadLogRecord (
  54. IN LFS_LOG_HANDLE LogHandle,
  55. IN LSN FirstLsn,
  56. IN LFS_CONTEXT_MODE ContextMode,
  57. OUT PLFS_LOG_CONTEXT Context,
  58. OUT PLFS_RECORD_TYPE RecordType,
  59. OUT TRANSACTION_ID *TransactionId,
  60. OUT PLSN UndoNextLsn,
  61. OUT PLSN PreviousLsn,
  62. OUT PULONG BufferLength,
  63. OUT PVOID *Buffer
  64. )
  65. /*++
  66. Routine Description:
  67. This routine initiates the query operation. It returns the log record
  68. in question and a context structure used by the Lfs to return related
  69. log records. The caller specifies what mode of query to use. He may
  70. walk backwards through the file by Undo records or all records for
  71. this client linked through the previous Lsn fields. He may also look
  72. forwards through the file for all records for the issuing client.
  73. Arguments:
  74. LogHandle - Pointer to private Lfs structure used to identify this
  75. client.
  76. FirstLsn - Starting record for this query operation.
  77. ContextMode - Method of query.
  78. Context - Supplies the address to store a pointer to the Lfs created
  79. context structure.
  80. RecordType - Supplies the address to store the record type of this
  81. log record.
  82. TransactionId - Supplies the address to store the transaction Id of
  83. this log record.
  84. UndoNextLsn - Supplies the address to store the Undo Next Lsn for this
  85. log record.
  86. PreviousLsn - Supplies the address to store the Previous Lsn for this
  87. log record.
  88. BufferLength - This is the length of the log data.
  89. Buffer - This is a pointer to the start of the log data.
  90. Return Value:
  91. None
  92. --*/
  93. {
  94. PLFS_CLIENT_RECORD ClientRecord;
  95. PLCH Lch;
  96. PLFCB Lfcb;
  97. PLEB Leb = NULL;
  98. PAGED_CODE();
  99. DebugTrace( +1, Dbg, "LfsReadLogRecord: Entered\n", 0 );
  100. DebugTrace( 0, Dbg, "Log Handle -> %08lx\n", LogHandle );
  101. DebugTrace( 0, Dbg, "First Lsn (Low) -> %08lx\n", FirstLsn.LowPart );
  102. DebugTrace( 0, Dbg, "First Lsn (High) -> %08lx\n", FirstLsn.HighPart );
  103. DebugTrace( 0, Dbg, "Context Mode -> %08lx\n", ContextMode );
  104. Lch = (PLCH) LogHandle;
  105. //
  106. // Check that the context mode is valid.
  107. //
  108. switch (ContextMode) {
  109. case LfsContextUndoNext :
  110. case LfsContextPrevious :
  111. case LfsContextForward :
  112. break;
  113. default:
  114. DebugTrace( 0, Dbg, "Invalid context mode -> %08x\n", ContextMode );
  115. ExRaiseStatus( STATUS_INVALID_PARAMETER );
  116. }
  117. //
  118. // Check that the structure is a valid log handle structure.
  119. //
  120. LfsValidateLch( Lch );
  121. //
  122. // Use a try-except to catch errors.
  123. //
  124. //
  125. // Use a try-finally to facilitate cleanup.
  126. //
  127. try {
  128. //
  129. // Acquire the log file control block for this log file.
  130. //
  131. LfsAcquireLchExclusive( Lch );
  132. Lfcb = Lch->Lfcb;
  133. //
  134. // If the Log file has been closed then refuse access.
  135. //
  136. if (Lfcb == NULL) {
  137. ExRaiseStatus( STATUS_ACCESS_DENIED );
  138. }
  139. //
  140. // Check that the client Id is valid.
  141. //
  142. LfsValidateClientId( Lfcb, Lch );
  143. //
  144. // Check that the given Lsn is in the legal range for this client.
  145. //
  146. ClientRecord = Add2Ptr( Lfcb->ClientArray,
  147. Lch->ClientArrayByteOffset,
  148. PLFS_CLIENT_RECORD );
  149. if (!LfsVerifyClientLsnInRange( Lfcb, ClientRecord, FirstLsn )) {
  150. ExRaiseStatus( STATUS_DISK_CORRUPT_ERROR );
  151. }
  152. //
  153. // We can give up the Lfcb as we know the Lsn is within the file.
  154. //
  155. LfsReleaseLch( Lch );
  156. //
  157. // Allocate and initialize an enumeration structure.
  158. //
  159. LfsAllocateLeb( Lfcb, &Leb );
  160. LfsInitializeLeb( Leb,
  161. Lch->ClientId,
  162. ContextMode );
  163. //
  164. // Find the log record indicated by the given Lsn.
  165. //
  166. LfsFindLogRecord( Lfcb,
  167. Leb,
  168. FirstLsn,
  169. RecordType,
  170. TransactionId,
  171. UndoNextLsn,
  172. PreviousLsn,
  173. BufferLength,
  174. Buffer );
  175. //
  176. // Update the client's arguments.
  177. //
  178. *Context = Leb;
  179. Leb = NULL;
  180. } finally {
  181. DebugUnwind( LfsReadLogRecord );
  182. //
  183. // Release the log file control block if held.
  184. //
  185. LfsReleaseLch( Lch );
  186. //
  187. // Deallocate the enumeration block if an error occurred.
  188. //
  189. if (Leb != NULL) {
  190. LfsDeallocateLeb( Lfcb, Leb );
  191. }
  192. DebugTrace( 0, Dbg, "Context -> %08lx\n", *Context );
  193. DebugTrace( 0, Dbg, "Buffer Length -> %08lx\n", *BufferLength );
  194. DebugTrace( 0, Dbg, "Buffer -> %08lx\n", *Buffer );
  195. DebugTrace( -1, Dbg, "LfsReadLogRecord: Exit\n", 0 );
  196. }
  197. return;
  198. }
  199. BOOLEAN
  200. LfsReadNextLogRecord (
  201. IN LFS_LOG_HANDLE LogHandle,
  202. IN OUT LFS_LOG_CONTEXT Context,
  203. OUT PLFS_RECORD_TYPE RecordType,
  204. OUT TRANSACTION_ID *TransactionId,
  205. OUT PLSN UndoNextLsn,
  206. OUT PLSN PreviousLsn,
  207. OUT PLSN Lsn,
  208. OUT PULONG BufferLength,
  209. OUT PVOID *Buffer
  210. )
  211. /*++
  212. Routine Description:
  213. This routine is called to continue a query operation. The Lfs uses
  214. private information stored in the enumeration structure to determine the
  215. next log record to return to the caller.
  216. Arguments:
  217. LogHandle - Pointer to private Lfs structure used to identify this
  218. client.
  219. Context - Supplies the address to store a pointer to the Lfs created
  220. enumeration structure.
  221. Lsn - Lsn for this log record.
  222. RecordType - Supplies the address to store the record type of this
  223. log record.
  224. TransactionId - Supplies the address to store the transaction Id of
  225. this log record.
  226. UndoNextLsn - Supplies the address to store the Undo Next Lsn for this
  227. log record.
  228. PreviousLsn - Supplies the address to store the Previous Lsn for this
  229. log record.
  230. BufferLength - This is the length of the log data.
  231. Buffer - This is a pointer to the start of the log data.
  232. Return Value:
  233. None
  234. --*/
  235. {
  236. PLCH Lch;
  237. PLFCB Lfcb;
  238. PLEB Leb;
  239. BOOLEAN FoundNextLsn;
  240. BOOLEAN UnwindRememberLebFields;
  241. PBCB UnwindRecordHeaderBcb;
  242. PLFS_RECORD_HEADER UnwindRecordHeader;
  243. PVOID UnwindCurrentLogRecord;
  244. BOOLEAN UnwindAuxilaryBuffer;
  245. PAGED_CODE();
  246. DebugTrace( +1, Dbg, "LfsReadNextLogRecord: Entered\n", 0 );
  247. DebugTrace( 0, Dbg, "Log Handle -> %08lx\n", LogHandle );
  248. DebugTrace( 0, Dbg, "Context -> %08lx\n", Context );
  249. FoundNextLsn = FALSE;
  250. UnwindRememberLebFields = FALSE;
  251. Lch = (PLCH) LogHandle;
  252. Leb = (PLEB) Context;
  253. //
  254. // Check that the structure is a valid log handle structure.
  255. //
  256. LfsValidateLch( Lch );
  257. //
  258. // Use a try-finally to facilitate cleanup.
  259. //
  260. try {
  261. //
  262. // Acquire the log file control block for this log file.
  263. //
  264. LfsAcquireLchExclusive( Lch );
  265. Lfcb = Lch->Lfcb;
  266. //
  267. // If the Log file has been closed then refuse access.
  268. //
  269. if (Lfcb == NULL) {
  270. ExRaiseStatus( STATUS_ACCESS_DENIED );
  271. }
  272. //
  273. // Check that the client Id is valid.
  274. //
  275. LfsValidateClientId( Lfcb, Lch );
  276. //
  277. // Check that the enumeration structure is valid.
  278. //
  279. LfsValidateLeb( Leb, Lch );
  280. //
  281. // Remember any enumeration fields to be overwritten.
  282. //
  283. UnwindRememberLebFields = TRUE;
  284. UnwindRecordHeaderBcb = Leb->RecordHeaderBcb;
  285. Leb->RecordHeaderBcb = NULL;
  286. UnwindRecordHeader = Leb->RecordHeader;
  287. UnwindCurrentLogRecord = Leb->CurrentLogRecord;
  288. UnwindAuxilaryBuffer = Leb->AuxilaryBuffer;
  289. Leb->AuxilaryBuffer = FALSE;
  290. //
  291. // Find the next Lsn number based on the current Lsn number in
  292. // the enumeration block.
  293. //
  294. if (LfsFindClientNextLsn( Lfcb, Leb, Lsn )) {
  295. //
  296. // We can give up the Lfcb as we know the Lsn is within the file.
  297. //
  298. LfsReleaseLfcb( Lfcb );
  299. //
  300. // Cleanup the enumeration block so we can do the next search.
  301. //
  302. Leb->CurrentLogRecord = NULL;
  303. Leb->AuxilaryBuffer = FALSE;
  304. //
  305. // Perform the work of getting the log record.
  306. //
  307. LfsFindLogRecord( Lfcb,
  308. Leb,
  309. *Lsn,
  310. RecordType,
  311. TransactionId,
  312. UndoNextLsn,
  313. PreviousLsn,
  314. BufferLength,
  315. Buffer );
  316. FoundNextLsn = TRUE;
  317. }
  318. } finally {
  319. DebugUnwind( LfsReadNextLogRecord );
  320. //
  321. // If we exited due to an error, we have to restore the enumeration
  322. // block.
  323. //
  324. if (UnwindRememberLebFields) {
  325. if (AbnormalTermination()) {
  326. //
  327. // If the record header in the enumeration block is not
  328. // the same as we started with. Then we unpin that
  329. // data.
  330. //
  331. if (Leb->RecordHeaderBcb != NULL) {
  332. CcUnpinData( Leb->RecordHeaderBcb );
  333. }
  334. if (Leb->CurrentLogRecord != NULL
  335. && Leb->AuxilaryBuffer == TRUE) {
  336. LfsFreeSpanningBuffer( Leb->CurrentLogRecord );
  337. }
  338. Leb->RecordHeaderBcb = UnwindRecordHeaderBcb;
  339. Leb->RecordHeader = UnwindRecordHeader;
  340. Leb->CurrentLogRecord = UnwindCurrentLogRecord;
  341. Leb->AuxilaryBuffer = UnwindAuxilaryBuffer;
  342. //
  343. // Otherwise, if we have successfully found the next Lsn,
  344. // we free up any resources being held from the previous search.
  345. //
  346. } else if (FoundNextLsn ) {
  347. if (UnwindRecordHeaderBcb != NULL) {
  348. CcUnpinData( UnwindRecordHeaderBcb );
  349. }
  350. if (UnwindCurrentLogRecord != NULL
  351. && UnwindAuxilaryBuffer == TRUE) {
  352. LfsFreeSpanningBuffer( UnwindCurrentLogRecord );
  353. }
  354. //
  355. // Restore the Bcb and auxilary buffer field for the final
  356. // cleanup.
  357. //
  358. } else {
  359. if (UnwindRecordHeaderBcb != NULL) {
  360. if (Leb->RecordHeaderBcb != NULL) {
  361. CcUnpinData( UnwindRecordHeaderBcb );
  362. } else {
  363. Leb->RecordHeaderBcb = UnwindRecordHeaderBcb;
  364. }
  365. }
  366. if (UnwindAuxilaryBuffer) {
  367. if (Leb->CurrentLogRecord == UnwindCurrentLogRecord) {
  368. Leb->AuxilaryBuffer = TRUE;
  369. } else {
  370. LfsFreeSpanningBuffer( UnwindCurrentLogRecord );
  371. }
  372. }
  373. }
  374. }
  375. //
  376. // Release the log file control block if held.
  377. //
  378. LfsReleaseLch( Lch );
  379. DebugTrace( 0, Dbg, "Lsn (Low) -> %08lx\n", Lsn->LowPart );
  380. DebugTrace( 0, Dbg, "Lsn (High) -> %08lx\n", Lsn->HighPart );
  381. DebugTrace( 0, Dbg, "Buffer Length -> %08lx\n", *BufferLength );
  382. DebugTrace( 0, Dbg, "Buffer -> %08lx\n", *Buffer );
  383. DebugTrace( -1, Dbg, "LfsReadNextLogRecord: Exit\n", 0 );
  384. }
  385. return FoundNextLsn;
  386. }
  387. VOID
  388. LfsTerminateLogQuery (
  389. IN LFS_LOG_HANDLE LogHandle,
  390. IN LFS_LOG_CONTEXT Context
  391. )
  392. /*++
  393. Routine Description:
  394. This routine is called when a client has completed his query operation
  395. and wishes to deallocate any resources acquired by the Lfs to
  396. perform the log file query.
  397. Arguments:
  398. LogHandle - Pointer to private Lfs structure used to identify this
  399. client.
  400. Context - Supplies the address to store a pointer to the Lfs created
  401. enumeration structure.
  402. Return Value:
  403. None
  404. --*/
  405. {
  406. PLCH Lch;
  407. PLEB Leb;
  408. PLFCB Lfcb;
  409. PAGED_CODE();
  410. DebugTrace( +1, Dbg, "LfsTerminateLogQuery: Entered\n", 0 );
  411. DebugTrace( 0, Dbg, "Log Handle -> %08lx\n", LogHandle );
  412. DebugTrace( 0, Dbg, "Context -> %08lx\n", Context );
  413. Lch = (PLCH) LogHandle;
  414. Leb = (PLEB) Context;
  415. //
  416. // Check that the structure is a valid log handle structure.
  417. //
  418. LfsValidateLch( Lch );
  419. //
  420. // Use a try-finally to facilitate cleanup.
  421. //
  422. try {
  423. //
  424. // Acquire the log file control block for this log file.
  425. //
  426. LfsAcquireLchExclusive( Lch );
  427. Lfcb = Lch->Lfcb;
  428. //
  429. // If the Log file has been closed then refuse access.
  430. //
  431. if (Lfcb == NULL) {
  432. try_return( NOTHING );
  433. }
  434. //
  435. // Check that the client Id is valid.
  436. //
  437. LfsValidateClientId( Lfcb, Lch );
  438. //
  439. // Check that the enumeration structure is valid.
  440. //
  441. LfsValidateLeb( Leb, Lch );
  442. //
  443. // Deallocate the enumeration block.
  444. //
  445. LfsDeallocateLeb( Lfcb, Leb );
  446. try_exit: NOTHING;
  447. } finally {
  448. DebugUnwind( LfsTerminateLogQuery );
  449. //
  450. // Release the Lfcb if acquired.
  451. //
  452. LfsReleaseLch( Lch );
  453. DebugTrace( -1, Dbg, "LfsTerminateLogQuery: Exit\n", 0 );
  454. }
  455. return;
  456. }
  457. LSN
  458. LfsQueryLastLsn (
  459. IN LFS_LOG_HANDLE LogHandle
  460. )
  461. /*++
  462. Routine Description:
  463. This routine will return the most recent Lsn for this log record.
  464. Arguments:
  465. LogHandle - Pointer to private Lfs structure used to identify this
  466. client.
  467. Return Value:
  468. LSN - This is the last Lsn assigned in this log file.
  469. --*/
  470. {
  471. PLCH Lch;
  472. PLFCB Lfcb;
  473. LSN LastLsn;
  474. PAGED_CODE();
  475. DebugTrace( +1, Dbg, "LfsQueryLastLsn: Entered\n", 0 );
  476. DebugTrace( 0, Dbg, "Log Handle -> %08lx\n", LogHandle );
  477. Lch = (PLCH) LogHandle;
  478. //
  479. // Check that the structure is a valid log handle structure.
  480. //
  481. LfsValidateLch( Lch );
  482. //
  483. // Use a try-finally to facilitate cleanup.
  484. //
  485. try {
  486. //
  487. // Acquire the log file control block for this log file.
  488. //
  489. LfsAcquireLchExclusive( Lch );
  490. Lfcb = Lch->Lfcb;
  491. //
  492. // If the Log file has been closed then refuse access.
  493. //
  494. if (Lfcb == NULL) {
  495. ExRaiseStatus( STATUS_ACCESS_DENIED );
  496. }
  497. //
  498. // Check that the client Id is valid.
  499. //
  500. LfsValidateClientId( Lfcb, Lch );
  501. //
  502. // Copy the last Lsn out of the Lfcb. If the last Lsn is
  503. // does not correspond to a log record, we will return the
  504. // zero Lsn.
  505. //
  506. if (FlagOn( Lfcb->Flags, LFCB_NO_LAST_LSN )) {
  507. LastLsn = LfsZeroLsn;
  508. } else {
  509. LastLsn = Lfcb->RestartArea->CurrentLsn;
  510. }
  511. } finally {
  512. DebugUnwind( LfsQueryLastLsn );
  513. //
  514. // Release the Lfcb if acquired.
  515. //
  516. LfsReleaseLch( Lch );
  517. DebugTrace( 0, Dbg, "Last Lsn (Low) -> %08lx\n", LastLsn.LowPart );
  518. DebugTrace( 0, Dbg, "Last Lsn (High) -> %08lx\n", LastLsn.HighPart );
  519. DebugTrace( -1, Dbg, "LfsQueryLastLsn: Exit\n", 0 );
  520. }
  521. return LastLsn;
  522. }
  523. //
  524. // Local support routine.
  525. //
  526. VOID
  527. LfsFindLogRecord (
  528. IN PLFCB Lfcb,
  529. IN OUT PLEB Leb,
  530. IN LSN Lsn,
  531. OUT PLFS_RECORD_TYPE RecordType,
  532. OUT TRANSACTION_ID *TransactionId,
  533. OUT PLSN UndoNextLsn,
  534. OUT PLSN PreviousLsn,
  535. OUT PULONG BufferLength,
  536. OUT PVOID *Buffer
  537. )
  538. /*++
  539. Routine Description:
  540. This routine is called recover a log record for a client.
  541. Arguments:
  542. Lfcb - Log file control block for this file.
  543. Leb - Pointer to the enumeration block to update.
  544. Lsn - This is the Lsn for the log record.
  545. RecordType - Supplies the address to store the record type of this
  546. log record.
  547. TransactionId - Supplies the address to store the transaction Id of
  548. this log record.
  549. UndoNextLsn - Supplies the address to store the Undo Next Lsn for this
  550. log record.
  551. PreviousLsn - Supplies the address to store the Previous Lsn for this
  552. log record.
  553. BufferLength - Pointer to address to store the length in bytes of the
  554. log record.
  555. Buffer - Pointer to store the address where the log record data begins.
  556. Return Value:
  557. None
  558. --*/
  559. {
  560. PCHAR NewBuffer;
  561. BOOLEAN UsaError;
  562. LONGLONG LogRecordLength;
  563. ULONG PageOffset;
  564. PAGED_CODE();
  565. DebugTrace( +1, Dbg, "LfsFindLogRecord: Entered\n", 0 );
  566. DebugTrace( 0, Dbg, "Lfcb -> %08lx\n", Lfcb );
  567. DebugTrace( 0, Dbg, "Enumeration Block -> %08lx\n", Leb );
  568. DebugTrace( 0, Dbg, "Lsn (Low) -> %08lx\n", Lsn.LowPart );
  569. NewBuffer = NULL;
  570. //
  571. // Use a try-finally to facilitate cleanup.
  572. //
  573. try {
  574. //
  575. // Map the record header for this Lsn if we haven't already.
  576. //
  577. if (Leb->RecordHeader == NULL) {
  578. LfsPinOrMapLogRecordHeader( Lfcb,
  579. Lsn,
  580. FALSE,
  581. FALSE,
  582. &UsaError,
  583. &Leb->RecordHeader,
  584. &Leb->RecordHeaderBcb );
  585. }
  586. //
  587. // We now have the log record desired. If the Lsn in the
  588. // log record doesn't match the desired Lsn then the disk is
  589. // corrupt.
  590. //
  591. if ( Lsn.QuadPart != Leb->RecordHeader->ThisLsn.QuadPart ) { //**** xxNeq( Lsn, Leb->RecordHeader->ThisLsn )
  592. ExRaiseStatus( STATUS_DISK_CORRUPT_ERROR );
  593. }
  594. //
  595. // Check that the length field isn't greater than the total available space
  596. // in the log file.
  597. //
  598. LogRecordLength = Leb->RecordHeader->ClientDataLength + Lfcb->RecordHeaderLength; //**** xxFromUlong( Leb->RecordHeader->ClientDataLength + Lfcb->RecordHeaderLength );
  599. if ( LogRecordLength >= Lfcb->TotalAvailable ) { //**** xxGeq( LogRecordLength, Lfcb->TotalAvailable )
  600. ExRaiseStatus( STATUS_DISK_CORRUPT_ERROR );
  601. }
  602. //
  603. // If the entire log record is on this log page, put a pointer to
  604. // the log record in the enumeration block.
  605. //
  606. if (!FlagOn( Leb->RecordHeader->Flags, LOG_RECORD_MULTI_PAGE )) {
  607. //
  608. // If client size indicates that we have to go beyond the end of the current
  609. // page, we raise an error.
  610. //
  611. PageOffset = LfsLsnToPageOffset( Lfcb, Lsn );
  612. if ((PageOffset + Leb->RecordHeader->ClientDataLength + Lfcb->RecordHeaderLength)
  613. > (ULONG)Lfcb->LogPageSize) {
  614. ExRaiseStatus( STATUS_DISK_CORRUPT_ERROR );
  615. }
  616. Leb->CurrentLogRecord = Add2Ptr( Leb->RecordHeader, LFS_RECORD_HEADER_SIZE, PVOID );
  617. Leb->AuxilaryBuffer = FALSE;
  618. //
  619. // Else we copy the data and remember that we allocated a buffer.
  620. //
  621. } else {
  622. NewBuffer = LfsAllocateSpanningBuffer( Lfcb, Leb->RecordHeader->ClientDataLength );
  623. //
  624. // Copy the data into the buffer returned.
  625. //
  626. LfsCopyReadLogRecord( Lfcb,
  627. Leb->RecordHeader,
  628. NewBuffer );
  629. Leb->CurrentLogRecord = NewBuffer;
  630. Leb->AuxilaryBuffer = TRUE;
  631. NewBuffer = NULL;
  632. }
  633. //
  634. // We need to update the caller's parameters and the enumeration block.
  635. //
  636. *RecordType = Leb->RecordHeader->RecordType;
  637. *TransactionId = Leb->RecordHeader->TransactionId;
  638. *UndoNextLsn = Leb->RecordHeader->ClientUndoNextLsn;
  639. *PreviousLsn = Leb->RecordHeader->ClientPreviousLsn;
  640. *Buffer = Leb->CurrentLogRecord;
  641. *BufferLength = Leb->RecordHeader->ClientDataLength;
  642. } finally {
  643. DebugUnwind( LfsFindLogRecord );
  644. //
  645. // If an error occurred we unpin the record header and the log
  646. // We also free the buffer if allocated by us.
  647. //
  648. if (NewBuffer != NULL) {
  649. LfsFreeSpanningBuffer( NewBuffer );
  650. }
  651. DebugTrace( 0, Dbg, "Buffer Length -> %08lx\n", *BufferLength );
  652. DebugTrace( 0, Dbg, "Buffer -> %08lx\n", *Buffer );
  653. DebugTrace( -1, Dbg, "LfsFindLogRecord: Exit\n", 0 );
  654. }
  655. return;
  656. }
  657. //
  658. // Local support routine.
  659. //
  660. BOOLEAN
  661. LfsFindClientNextLsn (
  662. IN PLFCB Lfcb,
  663. IN PLEB Leb,
  664. OUT PLSN Lsn
  665. )
  666. /*++
  667. Routine Description:
  668. This routine will attempt to find the next Lsn to return to a client
  669. based on the context mode.
  670. Arguments:
  671. Lfcb - File control block for this log file.
  672. Leb - Pointer to the enumeration block for this query operation.
  673. Lsn - Pointer to store the Lsn found (if any)
  674. Return Value:
  675. BOOLEAN - TRUE if an Lsn is found, FALSE otherwise.
  676. --*/
  677. {
  678. LSN NextLsn;
  679. BOOLEAN NextLsnFound;
  680. PLFS_CLIENT_RECORD ClientRecord;
  681. PAGED_CODE();
  682. DebugTrace( +1, Dbg, "LfsFindClientNextLsn: Entered\n", 0 );
  683. DebugTrace( 0, Dbg, "Leb -> %08lx\n", Leb );
  684. ClientRecord = Lfcb->ClientArray + Leb->ClientId.ClientIndex;
  685. //
  686. // The enumeration block has the last Lsn returned. If the user wanted
  687. // one of the Lsn's in that log header then our job is simple.
  688. //
  689. switch (Leb->ContextMode) {
  690. case LfsContextUndoNext:
  691. case LfsContextPrevious:
  692. NextLsn = (Leb->ContextMode == LfsContextUndoNext
  693. ? Leb->RecordHeader->ClientUndoNextLsn
  694. : Leb->RecordHeader->ClientPreviousLsn);
  695. if ( NextLsn.QuadPart == 0 ) { //**** xxEqlZero( NextLsn )
  696. NextLsnFound = FALSE;
  697. } else if (LfsVerifyClientLsnInRange( Lfcb, ClientRecord, NextLsn )) {
  698. BOOLEAN UsaError;
  699. LfsPinOrMapLogRecordHeader( Lfcb,
  700. NextLsn,
  701. FALSE,
  702. FALSE,
  703. &UsaError,
  704. &Leb->RecordHeader,
  705. &Leb->RecordHeaderBcb );
  706. NextLsnFound = TRUE;
  707. } else {
  708. NextLsnFound = FALSE;
  709. }
  710. break;
  711. case LfsContextForward:
  712. //
  713. // We search forward for the next log record for this client.
  714. //
  715. NextLsnFound = LfsSearchForwardByClient( Lfcb, Leb, &NextLsn );
  716. break;
  717. default:
  718. NextLsnFound = FALSE;
  719. break;
  720. }
  721. if (NextLsnFound) {
  722. *Lsn = NextLsn;
  723. }
  724. DebugTrace( 0, Dbg, "NextLsn (Low) -> %08lx\n", NextLsn.LowPart );
  725. DebugTrace( 0, Dbg, "NextLsn (High) -> %08lx\n", NextLsn.HighPart );
  726. DebugTrace( -1, Dbg, "LfsFindClientNextLsn: Exit -> %08x\n", NextLsnFound );
  727. return NextLsnFound;
  728. }
  729. //
  730. // Local support routine.
  731. //
  732. BOOLEAN
  733. LfsSearchForwardByClient (
  734. IN PLFCB Lfcb,
  735. IN OUT PLEB Leb,
  736. OUT PLSN Lsn
  737. )
  738. /*++
  739. Routine Description:
  740. This routine will attempt to find the next Lsn for this client by searching
  741. forward in the file, looking for a match.
  742. Arguments:
  743. Lfcb - Pointer to the file control block for this log file.
  744. Leb - Pointer to the enumeration block for this query operation.
  745. Lsn - Points to the location to store the next Lsn if found.
  746. Return Value:
  747. BOOLEAN - TRUE if another Lsn for this client is found. FALSE otherwise.
  748. --*/
  749. {
  750. PLFS_RECORD_HEADER CurrentRecordHeader;
  751. PBCB CurrentBcb;
  752. BOOLEAN FoundNextLsn;
  753. LSN CurrentLsn;
  754. PAGED_CODE();
  755. DebugTrace( +1, Dbg, "LfsSearchForwardByClient: Entered\n", 0 );
  756. DebugTrace( 0, Dbg, "Leb -> %08lx\n", Leb );
  757. //
  758. // The log record header is in the log enumeration
  759. // block. We set the current Bcb to NULL so that we don't
  760. // unpin the log record in the enumeration block until we're sure
  761. // of success.
  762. //
  763. CurrentRecordHeader = Leb->RecordHeader;
  764. CurrentBcb = NULL;
  765. //
  766. // We use a try-finally to facilitate cleanup.
  767. //
  768. try {
  769. //
  770. // We assume we won't find another Lsn.
  771. //
  772. FoundNextLsn = FALSE;
  773. //
  774. // Loop as long as another Lsn can be found.
  775. //
  776. while (LfsFindNextLsn( Lfcb, CurrentRecordHeader, &CurrentLsn )) {
  777. BOOLEAN UsaError;
  778. //
  779. // Unpin the previous log record header.
  780. //
  781. if (CurrentBcb != NULL) {
  782. CcUnpinData( CurrentBcb );
  783. CurrentBcb = NULL;
  784. }
  785. //
  786. // Pin the log record header for this Lsn.
  787. //
  788. LfsPinOrMapLogRecordHeader( Lfcb,
  789. CurrentLsn,
  790. FALSE,
  791. FALSE,
  792. &UsaError,
  793. &CurrentRecordHeader,
  794. &CurrentBcb );
  795. //
  796. // If the client values match, then we update the
  797. // enumeration block and exit.
  798. //
  799. if (LfsClientIdMatch( &CurrentRecordHeader->ClientId,
  800. &Leb->ClientId )
  801. && CurrentRecordHeader->RecordType == LfsClientRecord) {
  802. //
  803. // We remember this one.
  804. //
  805. Leb->RecordHeader = CurrentRecordHeader;
  806. Leb->RecordHeaderBcb = CurrentBcb;
  807. CurrentBcb = NULL;
  808. FoundNextLsn = TRUE;
  809. *Lsn = CurrentLsn;
  810. break;
  811. }
  812. }
  813. } finally {
  814. DebugUnwind( LfsSearchForwardByClient );
  815. //
  816. // Unpin any log record headers still pinned for no reason.
  817. //
  818. if (CurrentBcb != NULL) {
  819. CcUnpinData( CurrentBcb );
  820. }
  821. DebugTrace( 0, Dbg, "NextLsn (Low) -> %08lx\n", Lsn->LowPart );
  822. DebugTrace( 0, Dbg, "NextLsn (High) -> %08lx\n", Lsn->HighPart );
  823. DebugTrace( -1, Dbg, "LfsSearchForwardByClient: Exit -> %08x\n", FoundNextLsn );
  824. }
  825. return FoundNextLsn;
  826. }