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.

832 lines
24 KiB

  1. /*++
  2. Copyright (c) 1992-1997 Microsoft Corporation
  3. Module Name:
  4. xsaction.c
  5. Abstract:
  6. Provides basic xscational services for cluster logging.
  7. Author:
  8. Sunita Shrivastava (sunitas) 17-Mar-1997
  9. Revision History:
  10. --*/
  11. #include "service.h"
  12. #include "lmp.h"
  13. /****
  14. @doc EXTERNAL INTERFACES CLUSSVC LM
  15. ****/
  16. /****
  17. @func HXSACTION | LogStartXsaction| Write a start transaction record to
  18. the log.
  19. @parm IN HLOG | hLog | Supplies the handle to the log.
  20. @parm IN TRID | TrId | Supplies the transaction id.
  21. @parm IN RMID | ResourceId | The resource id that identifies the
  22. resource manager.
  23. @parm IN RMTYPE | ResourceFlags | A dword of flags that the resource
  24. manager may use to store any data it wants with this record.
  25. @rdesc Returns a handle suitable for use in subsequent log calls.
  26. NUll in case failure. Call GetLastError() to get the error.
  27. @xref <f LogCommitXsaction> <f LogAbortXsaction>
  28. ****/
  29. HXSACTION
  30. LogStartXsaction(
  31. IN HLOG hLog,
  32. IN TRID TrId,
  33. IN RMID ResourceId,
  34. IN RMTYPE ResourceFlags
  35. )
  36. {
  37. PLOG pLog;
  38. DWORD dwError=ERROR_SUCCESS;
  39. LSN Lsn = NULL_LSN;
  40. PLOGRECORD pLogRecord;
  41. DWORD dwNumPages;
  42. PLOGPAGE pPage;
  43. DWORD dwTotalSize;
  44. BOOL bMaxFileSizeReached;
  45. PXSACTION pXsaction = NULL;
  46. GETLOG(pLog, hLog);
  47. //write the record, dont allow resets to happen
  48. ClRtlLogPrint(LOG_NOISE,
  49. "[LM] LogStartXsaction : Entry TrId=%1!u! RmId=%2!u! RmType = %3!u!\r\n",
  50. TrId, ResourceId, ResourceFlags);
  51. EnterCriticalSection(&pLog->Lock);
  52. pXsaction = (PXSACTION)LocalAlloc(LMEM_FIXED, sizeof(XSACTION));
  53. if (!pXsaction)
  54. {
  55. dwError = ERROR_NOT_ENOUGH_MEMORY;
  56. goto FnExit;
  57. }
  58. #if DBG
  59. {
  60. DWORD dwOldProtect;
  61. DWORD Status;
  62. BOOL VPWorked;
  63. VPWorked = VirtualProtect(pLog->ActivePage, pLog->SectorSize, PAGE_READWRITE, &dwOldProtect);
  64. Status = GetLastError();
  65. CL_ASSERT( VPWorked );
  66. }
  67. #endif
  68. //reset the file
  69. dwError = LogReset(hLog);
  70. if (dwError != ERROR_SUCCESS)
  71. {
  72. ClRtlLogPrint(LOG_NOISE,
  73. "[LM] LogStartXsaction : LogReset failed\r\n");
  74. goto FnExit;
  75. }
  76. #if DBG
  77. {
  78. DWORD dwOldProtect;
  79. DWORD Status;
  80. BOOL VPWorked;
  81. VPWorked = VirtualProtect(pLog->ActivePage, pLog->SectorSize, PAGE_READWRITE, &dwOldProtect);
  82. Status = GetLastError();
  83. CL_ASSERT( VPWorked );
  84. }
  85. #endif
  86. CL_ASSERT(ResourceId > RMAny); // reserved for logger's use
  87. dwTotalSize = sizeof(LOGRECORD) + 7 & ~7; // round up to qword size
  88. pPage = LogpAppendPage(pLog, dwTotalSize, &pLogRecord, &bMaxFileSizeReached, &dwNumPages);
  89. //we just reset the file, if it cant take the new startxsaction
  90. //record, something is awfully wrong !!!
  91. if (pPage == NULL)
  92. {
  93. dwError = GetLastError();
  94. ClRtlLogPrint(LOG_NOISE,
  95. "[LM] LogStartXsaction : LogpAppendPage failed.\r\n");
  96. goto FnExit;
  97. }
  98. CL_ASSERT(((ULONG_PTR)pLogRecord & 0x7) == 0); // ensure qword alignment
  99. Lsn = MAKELSN(pPage, pLogRecord);
  100. //
  101. // Fill in log record.
  102. //
  103. pLogRecord->Signature = LOGREC_SIG;
  104. pLogRecord->ResourceManager = ResourceId;
  105. pLogRecord->Transaction = TrId;
  106. pLogRecord->XsactionType = TTStartXsaction;
  107. pLogRecord->Flags = ResourceFlags;
  108. GetSystemTimeAsFileTime(&pLogRecord->Timestamp);
  109. pLogRecord->NumPages = dwNumPages;
  110. pLogRecord->DataSize = 0;
  111. pXsaction->XsactionSig = XSACTION_SIG;
  112. pXsaction->TrId = TrId;
  113. pXsaction->StartLsn = Lsn;
  114. pXsaction->RmId = ResourceId;
  115. FnExit:
  116. #if DBG
  117. {
  118. DWORD dwOldProtect;
  119. DWORD Status;
  120. BOOL VPWorked;
  121. VPWorked = VirtualProtect(pLog->ActivePage, pLog->SectorSize, PAGE_READONLY, & dwOldProtect);
  122. Status = GetLastError();
  123. CL_ASSERT( VPWorked );
  124. }
  125. #endif
  126. if (dwError != ERROR_SUCCESS)
  127. {
  128. if (pXsaction) {
  129. LocalFree(pXsaction);
  130. pXsaction = NULL;
  131. }
  132. SetLastError(dwError);
  133. }
  134. LeaveCriticalSection(&pLog->Lock);
  135. ClRtlLogPrint(LOG_NOISE,
  136. "[LM] LogStartXsaction : Exit returning=0x%1!08lx!\r\n",
  137. Lsn);
  138. return((HXSACTION)pXsaction);
  139. }
  140. /****
  141. @func LSN | LogWriteXsaction| Write a transaction unit record to
  142. the log.
  143. @parm IN HLOG | hLog | Supplies the handle to the log.
  144. @parm IN HXSACTION | hXsaction | Supplies the handle to the transaction.
  145. @parm IN RMTYPE | ResourceFlags | A dword of flags that the resource
  146. manager may use to store any data it wants with this record.
  147. @parm IN PVOID | LogData | Supplies a pointer to the data to be logged.
  148. @parm DWORD | DataSize | Supplies the number of bytes of data pointed to by LogData
  149. @rdesc The LSN of the log record that was created. NULL_LSN if something terrible happened.
  150. GetLastError() will provide the error code.
  151. @comm This should use a transaction handle obtained from LogStartXsaction. This
  152. call is used to write the parts of a transaction to the quorum log.
  153. @xref <f LogStartXsaction>
  154. ****/
  155. LSN
  156. LogWriteXsaction(
  157. IN HLOG hLog,
  158. IN HXSACTION hXsaction,
  159. IN RMTYPE ResourceFlags,
  160. IN PVOID pLogData,
  161. IN DWORD dwDataSize)
  162. {
  163. PLOG pLog;
  164. DWORD dwError=ERROR_SUCCESS;
  165. LSN Lsn = NULL_LSN;
  166. PLOGRECORD pLogRecord;
  167. DWORD dwNumPages;
  168. PLOGPAGE pPage;
  169. DWORD dwTotalSize;
  170. BOOL bMaxFileSizeReached;
  171. PXSACTION pXsaction = NULL;
  172. GETLOG(pLog, hLog);
  173. GETXSACTION(pXsaction, hXsaction);
  174. //write the record, dont allow resets to happen
  175. ClRtlLogPrint(LOG_NOISE,
  176. "[LM] LogWriteXsaction : Entry TrId=%1!u! RmId=%2!u! RmType = %3!u!\r\n",
  177. pXsaction->TrId, pXsaction->RmId, ResourceFlags);
  178. #if DBG
  179. {
  180. DWORD dwOldProtect;
  181. DWORD Status;
  182. BOOL VPWorked;
  183. VPWorked = VirtualProtect(pLog->ActivePage, pLog->SectorSize, PAGE_READWRITE, &dwOldProtect);
  184. Status = GetLastError();
  185. CL_ASSERT( VPWorked );
  186. }
  187. #endif
  188. CL_ASSERT(pXsaction->RmId > RMAny); // reserved for logger's use
  189. dwTotalSize = sizeof(LOGRECORD) + (dwDataSize+ 7) & ~7; // round up to qword size
  190. EnterCriticalSection(&pLog->Lock);
  191. pPage = LogpAppendPage(pLog, dwTotalSize, &pLogRecord, &bMaxFileSizeReached, &dwNumPages);
  192. //we reset the file in logstartxsaction, if it cant take the new startxsaction
  193. //record, something is awfully wrong !!!
  194. if (pPage == NULL)
  195. {
  196. dwError = GetLastError();
  197. //assert if a complete local xsaction extends the log beyond its max size
  198. CL_ASSERT( dwError != ERROR_CLUSTERLOG_EXCEEDS_MAXSIZE);
  199. ClRtlLogPrint(LOG_NOISE,
  200. "[LM] LogWriteXsaction : LogpAppendPage failed.\r\n");
  201. goto FnExit;
  202. }
  203. CL_ASSERT(((ULONG_PTR)pLogRecord & 0x7) == 0); // ensure qword alignment
  204. Lsn = MAKELSN(pPage, pLogRecord);
  205. //
  206. // Fill in log record.
  207. //
  208. pLogRecord->Signature = LOGREC_SIG;
  209. pLogRecord->ResourceManager = pXsaction->RmId;
  210. pLogRecord->Transaction = pXsaction->TrId;
  211. pLogRecord->XsactionType = TTXsactionUnit;
  212. pLogRecord->Flags = ResourceFlags;
  213. GetSystemTimeAsFileTime(&pLogRecord->Timestamp);
  214. pLogRecord->NumPages = dwNumPages;
  215. pLogRecord->DataSize = dwDataSize;
  216. if (dwNumPages < 1)
  217. CopyMemory(&pLogRecord->Data, pLogData, dwDataSize);
  218. else
  219. {
  220. if (LogpWriteLargeRecordData(pLog, pLogRecord, pLogData, dwDataSize)
  221. != ERROR_SUCCESS)
  222. {
  223. ClRtlLogPrint(LOG_NOISE,
  224. "[LM] LogWriteXsaction : LogpWriteLargeRecordData failed. Lsn=0x%1!08lx!\r\n",
  225. Lsn);
  226. Lsn = NULL_LSN;
  227. }
  228. }
  229. FnExit:
  230. #if DBG
  231. {
  232. DWORD dwOldProtect;
  233. DWORD Status;
  234. BOOL VPWorked;
  235. VPWorked = VirtualProtect(pLog->ActivePage, pLog->SectorSize, PAGE_READONLY, & dwOldProtect);
  236. Status = GetLastError();
  237. CL_ASSERT( VPWorked );
  238. }
  239. #endif
  240. if (dwError != ERROR_SUCCESS)
  241. SetLastError(dwError);
  242. LeaveCriticalSection(&pLog->Lock);
  243. ClRtlLogPrint(LOG_NOISE,
  244. "[LM] LogWriteXsaction : Exit returning=0x%1!08lx!\r\n",
  245. Lsn);
  246. return(Lsn);
  247. }
  248. /****
  249. @func DWORD | LogCommitXsaction | This writes the commit transaction
  250. record to the log and flushes it.
  251. @parm IN HLOG | hLog | Supplies the handle to the log.
  252. @parm IN TRID | TrId | Supplies the transaction id.
  253. @parm IN RMID | ResourceId | The resource id that identifies the
  254. resource manager.
  255. @parm IN RMTYPE | ResourceFlags | A dword of flags that the resource
  256. manager may use to store any data it wants with this record.
  257. @comm A commit record is written to the quorum log. The hXsaction handle
  258. is invalidated at this point and should not be used after this call has
  259. been made. The commit is record is used to identify committed transactions
  260. during rollback.
  261. @rdesc ERROR_SUCCESS if successful. Win32 error code if something horrible happened.
  262. @xref <f LogStartXsaction>
  263. ****/
  264. DWORD WINAPI LogCommitXsaction(
  265. IN HLOG hLog,
  266. IN HXSACTION hXsaction,
  267. IN RMTYPE ResourceFlags)
  268. {
  269. DWORD dwError = ERROR_SUCCESS;
  270. LSN Lsn;
  271. PXSACTION pXsaction;
  272. ClRtlLogPrint(LOG_NOISE,
  273. "[LM] LogCommitXsaction : Entry, hXsaction=0x%1!08lx!\r\n",
  274. hXsaction);
  275. GETXSACTION(pXsaction, hXsaction);
  276. Lsn = LogWrite(hLog, pXsaction->TrId, TTCommitXsaction,
  277. pXsaction->RmId, ResourceFlags, NULL, 0);
  278. if (Lsn == NULL_LSN)
  279. {
  280. dwError = GetLastError();
  281. goto FnExit;
  282. }
  283. FnExit:
  284. //free up the transation memory
  285. ZeroMemory(pXsaction, sizeof(XSACTION)); // just in case somebody tries to
  286. LocalFree(pXsaction);
  287. ClRtlLogPrint(LOG_NOISE,
  288. "[LM] LogCommitXsaction : Exit, dwError=0x%1!08lx!\r\n",
  289. dwError);
  290. return(dwError);
  291. }
  292. /****
  293. @func DWORD | LogAbortXsaction | Marks a given transaction as aborted in the
  294. quorum log file.
  295. @parm IN HLOG | hLog | Supplies the handle to the log.
  296. @parm IN HXSACTION | hXsaction | Supplies the handle to the transaction.
  297. @parm IN RMTYPE | ResourceFlags | A dword of flags that the resource
  298. manager may use to store any data it wants with this record.
  299. @comm An abort transaction is written to the quorum log. This is used in
  300. identifying aborted transactions during roll back. The hXsaction
  301. handle is invalidated at this point and should not be used after this.
  302. @rdesc ERROR_SUCCESS if successful. Win32 error code if something horrible happened.
  303. @xref <f LogStartXsaction> <f LogCommitXsaction>
  304. ****/
  305. DWORD
  306. LogAbortXsaction(
  307. IN HLOG hLog,
  308. IN HXSACTION hXsaction,
  309. IN RMTYPE ResourceFlags
  310. )
  311. {
  312. PXSACTION pXsaction;
  313. LSN Lsn;
  314. DWORD dwError = ERROR_SUCCESS;
  315. ClRtlLogPrint(LOG_NOISE,
  316. "[LM] LogAbortXsaction : Entry, hXsaction=0x%1!08lx!\r\n",
  317. hXsaction);
  318. GETXSACTION(pXsaction, hXsaction);
  319. Lsn = LogWrite(hLog, pXsaction->TrId, TTAbortXsaction, pXsaction->RmId,
  320. ResourceFlags, NULL, 0);
  321. if (Lsn == NULL_LSN)
  322. {
  323. dwError = GetLastError();
  324. goto FnExit;
  325. }
  326. FnExit:
  327. ZeroMemory(pXsaction, sizeof(XSACTION)); // just in case somebody tries to
  328. LocalFree(pXsaction);
  329. ClRtlLogPrint(LOG_NOISE,
  330. "[LM] LogAbortXsaction : Exit, returning, dwError=0x%1!08lx!\r\n",
  331. dwError);
  332. return(dwError);
  333. }
  334. /****
  335. @func LSN | LogFindXsactionState | This fuctions scans the record and finds
  336. the state of a given transaction.
  337. @parm IN HLOG | hLog | Supplies the identifier of the log.
  338. @parm IN LSN | StartXsactionLsn | The LSN of the start transaction record.
  339. @parm IN TRID | XsactionId | The transaction id of the transaction.
  340. @parm OUT TRSTATE | *pXsactionState | The state of the transaction.
  341. @comm Transaction state is set to XsactionCommitted, XsactionAborted or XsactionUnknown.
  342. depending on whether a commit record, or abort record or no record is found
  343. for this record in the log.
  344. @rdesc ERROR_SUCCESS, else returns the error code if something horrible happens.
  345. @xref <f LogScanXsaction>
  346. ****/
  347. DWORD
  348. LogFindXsactionState(
  349. IN HLOG hLog,
  350. IN LSN StartXsactionLsn,
  351. IN TRID XsactionId,
  352. OUT TRSTATE *pXsactionState)
  353. {
  354. PLOG pLog;
  355. PLOGRECORD pRecord, pEopRecord;
  356. DWORD dwError = ERROR_SUCCESS;
  357. int PageIndex, OldPageIndex;
  358. RMID Resource;
  359. TRID TrId;
  360. TRTYPE TrType;
  361. LSN Lsn, EopLsn;
  362. PLOGPAGE pPage = NULL,pLargeBuffer = NULL;
  363. DWORD dwBytesRead;
  364. RMTYPE ResourceFlags;
  365. BOOL bFound = FALSE;
  366. GETLOG(pLog, hLog);
  367. ClRtlLogPrint(LOG_NOISE,
  368. "[LM] LogWrite : Entry StartXLsn=0x%1!08lx! StartXId=%2!u!\r\n",
  369. StartXsactionLsn, XsactionId);
  370. EnterCriticalSection(&pLog->Lock);
  371. if (StartXsactionLsn >= pLog->NextLsn)
  372. {
  373. dwError = ERROR_INVALID_PARAMETER;
  374. goto FnExit;
  375. }
  376. //read this record
  377. dwBytesRead = 0;
  378. if ((Lsn = LogRead( hLog, StartXsactionLsn, &Resource, &ResourceFlags, &TrId, &TrType,
  379. NULL, &dwBytesRead)) == NULL_LSN)
  380. {
  381. dwError = GetLastError();
  382. goto FnExit;
  383. }
  384. //check the record
  385. if ((TrType != TTStartXsaction) ||
  386. (TrId != XsactionId))
  387. {
  388. dwError = ERROR_INVALID_PARAMETER;
  389. goto FnExit;
  390. }
  391. pPage = (PLOGPAGE)AlignAlloc(SECTOR_SIZE);
  392. if (pPage == NULL) {
  393. CL_UNEXPECTED_ERROR( ERROR_NOT_ENOUGH_MEMORY );
  394. }
  395. //Lsn is now set to the next Lsn after the start
  396. //initialize this to -1 so that the first page is always read
  397. OldPageIndex = -1;
  398. while (Lsn < pLog->NextLsn && !bFound)
  399. {
  400. //
  401. // Scan From Next record to find either the commit or abort record
  402. //
  403. PageIndex = LSNTOPAGE(Lsn);
  404. if (PageIndex != OldPageIndex)
  405. {
  406. //read the page
  407. pLog->Overlapped.Offset = PageIndex * pLog->SectorSize;
  408. pLog->Overlapped.OffsetHigh = 0;
  409. dwError = LogpRead(pLog, pPage, pLog->SectorSize, &dwBytesRead);
  410. if (dwError)
  411. {
  412. goto FnExit;
  413. }
  414. //read was successful, no need to read the page unless the
  415. //record falls on a different page
  416. OldPageIndex = PageIndex;
  417. }
  418. pRecord = LSNTORECORD(pPage, Lsn);
  419. //skip other log management records
  420. //these are small records by definition
  421. if (pRecord->ResourceManager < RMAny)
  422. {
  423. Lsn = GETNEXTLSN(pRecord, TRUE);
  424. continue;
  425. }
  426. //if the transaction id is the same, check the xsaction type
  427. if (pRecord->Transaction == XsactionId)
  428. {
  429. if ((pRecord->XsactionType == TTCommitXsaction) ||
  430. (pRecord->XsactionType == TTStartXsaction))
  431. {
  432. bFound = TRUE;
  433. continue;
  434. }
  435. }
  436. //handle large records
  437. if (pRecord->NumPages > 0)
  438. {
  439. EopLsn = GETNEXTLSN(pRecord,TRUE);
  440. PageIndex = LSNTOPAGE(EopLsn);
  441. //read the page
  442. pLog->Overlapped.Offset = PageIndex * pLog->SectorSize;
  443. pLog->Overlapped.OffsetHigh = 0;
  444. dwError = LogpRead(pLog, pPage, pLog->SectorSize, &dwBytesRead);
  445. if (dwError)
  446. {
  447. goto FnExit;
  448. }
  449. OldPageIndex = PageIndex;
  450. pEopRecord = (PLOGRECORD)((ULONG_PTR) pPage +
  451. (EopLsn - (pLog->Overlapped).Offset));
  452. //move to the next page
  453. Lsn = GETNEXTLSN(pEopRecord, TRUE);
  454. }
  455. else
  456. {
  457. Lsn = GETNEXTLSN(pRecord, TRUE);
  458. }
  459. }
  460. if (bFound)
  461. {
  462. if (pRecord->XsactionType == TTCommitXsaction)
  463. *pXsactionState = XsactionCommitted;
  464. else
  465. *pXsactionState = XsactionAborted;
  466. }
  467. else
  468. {
  469. *pXsactionState = XsactionUnknown;
  470. }
  471. ClRtlLogPrint(LOG_NOISE,
  472. "[LM] LogFindXsactionState : Exit,State=%1!u!\r\n",
  473. *pXsactionState);
  474. FnExit:
  475. LeaveCriticalSection(&pLog->Lock);
  476. if (pPage) AlignFree(pPage);
  477. return(dwError);
  478. }
  479. /****
  480. @func LSN | LogScanXsaction | This fuctions scans the multiple units
  481. of a transaction.
  482. @parm IN HLOG | hLog | Supplies the identifier of the log.
  483. @parm IN LSN | StartXsacionLsn | The LSN of the start transaction record.
  484. @parm IN TRID | XsactionId | The transaction id of the transaction.
  485. @parm IN PLOG_SCANXSACTION_CALLBACK | CallbackRoutine | The routine to call
  486. for every unit of a transaction.
  487. @parm IN PVOID | pContext | The context to be passed to state of the transaction.
  488. @comm Stops enumerating the transaction units if the callback function returns
  489. FALSE, or if the abort or commit record for this transaction is found or
  490. if the next transacion is found.
  491. @rdesc ERROR_SUCCESS if the state is found, else returns the error code.
  492. @xref <f LogFindXsactionState>
  493. ****/
  494. DWORD
  495. LogScanXsaction(
  496. IN HLOG hLog,
  497. IN LSN StartXsactionLsn,
  498. IN TRID XsactionId,
  499. IN PLOG_SCANXSACTION_CALLBACK CallbackRoutine,
  500. IN PVOID pContext)
  501. {
  502. PLOG pLog;
  503. PLOGRECORD pRecord;
  504. DWORD dwError = ERROR_SUCCESS;
  505. int PageIndex, OldPageIndex;
  506. RMID Resource;
  507. TRID TrId;
  508. TRTYPE TrType;
  509. LSN Lsn;
  510. PLOGPAGE pPage = NULL;
  511. PUCHAR pLargeBuffer;
  512. DWORD dwBytesRead;
  513. RMTYPE ResourceFlags;
  514. GETLOG(pLog, hLog);
  515. ClRtlLogPrint(LOG_NOISE,
  516. "[LM] LogScanXsaction : Entry StartXLsn=0x%1!08lx! StartXId=%2!u!\r\n",
  517. StartXsactionLsn, XsactionId);
  518. Lsn = StartXsactionLsn;
  519. if (Lsn >= pLog->NextLsn)
  520. {
  521. dwError = ERROR_INVALID_PARAMETER;
  522. goto FnExit;
  523. }
  524. //read this record
  525. dwBytesRead = 0;
  526. if (LogRead( hLog, Lsn, &Resource, &ResourceFlags, &TrId, &TrType,
  527. NULL, &dwBytesRead) == NULL_LSN)
  528. {
  529. dwError = GetLastError();
  530. goto FnExit;
  531. }
  532. //check the record
  533. if ((TrType != TTStartXsaction) ||
  534. (TrId != XsactionId))
  535. {
  536. dwError = ERROR_INVALID_PARAMETER;
  537. goto FnExit;
  538. }
  539. pPage = (PLOGPAGE)AlignAlloc(SECTOR_SIZE);
  540. if (pPage == NULL) {
  541. CL_UNEXPECTED_ERROR( ERROR_NOT_ENOUGH_MEMORY );
  542. }
  543. //initialize this to -1 so that the first page is always read
  544. OldPageIndex = -1;
  545. while (Lsn < pLog->NextLsn)
  546. {
  547. //
  548. // Scan From Next record to find either the commit or abort record
  549. //
  550. PageIndex = LSNTOPAGE(Lsn);
  551. if (PageIndex != OldPageIndex)
  552. {
  553. //read the page
  554. pLog->Overlapped.Offset = PageIndex * pLog->SectorSize;
  555. pLog->Overlapped.OffsetHigh = 0;
  556. dwError = LogpRead(pLog, pPage, pLog->SectorSize, &dwBytesRead);
  557. if (dwError)
  558. {
  559. goto FnExit;
  560. }
  561. //read was successful, no need to read the page unless the
  562. //record falls on a different page
  563. OldPageIndex = PageIndex;
  564. }
  565. pRecord = LSNTORECORD(pPage, Lsn);
  566. //skip other log management records
  567. if (pRecord->ResourceManager < RMAny)
  568. {
  569. Lsn = GETNEXTLSN(pRecord, TRUE);
  570. continue;
  571. }
  572. //stop if next transaction record is encountered
  573. if (pRecord->Transaction > XsactionId)
  574. {
  575. break;
  576. }
  577. //stop when a commit or abort record is found
  578. if ((pRecord->Transaction == XsactionId) &&
  579. ((pRecord->XsactionType == TTCommitXsaction) ||
  580. (pRecord->XsactionType == TTAbortXsaction)))
  581. {
  582. break;
  583. }
  584. //handle large records
  585. if (pRecord->NumPages > 0)
  586. {
  587. //if the transaction id is the same
  588. if ((pRecord->Transaction == XsactionId) &&
  589. (pRecord->XsactionType == TTXsactionUnit))
  590. {
  591. //read the whole record
  592. //for a large record you need to read in the entire data
  593. pLargeBuffer = AlignAlloc(pRecord->NumPages * SECTOR_SIZE);
  594. if (pLargeBuffer == NULL)
  595. {
  596. dwError = ERROR_NOT_ENOUGH_MEMORY ;
  597. CL_LOGFAILURE(ERROR_NOT_ENOUGH_MEMORY);
  598. break;
  599. }
  600. //read the pages
  601. pLog->Overlapped.Offset = PageIndex * pLog->SectorSize;
  602. pLog->Overlapped.OffsetHigh = 0;
  603. dwError = LogpRead(pLog, pLargeBuffer, pRecord->NumPages *
  604. pLog->SectorSize, &dwBytesRead);
  605. //if it is the last page, then set the new page as the active
  606. //page
  607. if (dwError != ERROR_SUCCESS)
  608. {
  609. CL_LOGFAILURE(dwError);
  610. AlignFree(pLargeBuffer);
  611. break;
  612. }
  613. pRecord = LSNTORECORD((PLOGPAGE)pLargeBuffer, Lsn);
  614. ClRtlLogPrint(LOG_NOISE,
  615. "[LM] LogScanXsaction::Calling the scancb for Lsn=0x%1!08lx! Trid=%2!u! RecordSize=%3!u!\r\n",
  616. Lsn, pRecord->Transaction, pRecord->DataSize);
  617. //if the callback requests to stop scan
  618. if (!(*CallbackRoutine)(pContext, Lsn, pRecord->ResourceManager,
  619. pRecord->Flags, pRecord->Transaction,
  620. pRecord->Data, pRecord->DataSize))
  621. {
  622. AlignFree(pLargeBuffer);
  623. break;
  624. }
  625. }
  626. //read the last page of the large record and advance
  627. Lsn = GETNEXTLSN(pRecord,TRUE);
  628. AlignFree(pLargeBuffer);
  629. PageIndex = LSNTOPAGE(Lsn);
  630. //read the page
  631. pLog->Overlapped.Offset = PageIndex * pLog->SectorSize;
  632. pLog->Overlapped.OffsetHigh = 0;
  633. dwError = LogpRead(pLog, pPage, pLog->SectorSize, &dwBytesRead);
  634. if (dwError)
  635. {
  636. goto FnExit;
  637. }
  638. OldPageIndex = PageIndex;
  639. pRecord = (PLOGRECORD)((ULONG_PTR) pPage +
  640. (Lsn - (pLog->Overlapped).Offset));
  641. CL_ASSERT(pRecord->ResourceManager == RMPageEnd);
  642. //move to the next page
  643. Lsn = GETNEXTLSN(pRecord, TRUE);
  644. }
  645. else
  646. {
  647. if ((pRecord->Transaction == XsactionId) &&
  648. (pRecord->XsactionType == TTXsactionUnit))
  649. {
  650. ClRtlLogPrint(LOG_NOISE,
  651. "[LM] LogScanXsaction: Calling the scancb for Lsn=0x%1!08lx! Trid=%2!u! RecordSize=%3!u!\r\n",
  652. Lsn, pRecord->Transaction, pRecord->DataSize);
  653. //call the callback
  654. if (!(*CallbackRoutine)(pContext, Lsn, pRecord->ResourceManager,
  655. pRecord->Flags, pRecord->Transaction,
  656. pRecord->Data, pRecord->DataSize))
  657. {
  658. break;
  659. }
  660. }
  661. Lsn = GETNEXTLSN(pRecord, TRUE);
  662. }
  663. }
  664. FnExit:
  665. if (pPage) AlignFree(pPage);
  666. return(dwError);
  667. }