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.

839 lines
25 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. ClRtlLogPrint(LOG_NOISE,
  127. "[LM] LogStartXsaction : Exit returning=0x%1!08lx!\r\n",
  128. Lsn);
  129. if (dwError != ERROR_SUCCESS)
  130. {
  131. if (pXsaction) {
  132. LocalFree(pXsaction);
  133. pXsaction = NULL;
  134. }
  135. SetLastError(dwError);
  136. }
  137. LeaveCriticalSection(&pLog->Lock);
  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. ClRtlLogPrint(LOG_NOISE,
  241. "[LM] LogWriteXsaction : Exit returning=0x%1!08lx!\r\n",
  242. Lsn);
  243. if (dwError != ERROR_SUCCESS)
  244. SetLastError(dwError);
  245. LeaveCriticalSection(&pLog->Lock);
  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. if ( dwError == ERROR_SUCCESS )
  288. {
  289. ClRtlLogPrint(LOG_NOISE, "[LM] LogCommitXsaction: Exit with success\n");
  290. } else
  291. {
  292. ClRtlLogPrint(LOG_CRITICAL, "[LM] LogCommitXsaction: Exit, dwError=0x%1!08lx!\n",
  293. dwError);
  294. }
  295. return(dwError);
  296. }
  297. /****
  298. @func DWORD | LogAbortXsaction | Marks a given transaction as aborted in the
  299. quorum log file.
  300. @parm IN HLOG | hLog | Supplies the handle to the log.
  301. @parm IN HXSACTION | hXsaction | Supplies the handle to the transaction.
  302. @parm IN RMTYPE | ResourceFlags | A dword of flags that the resource
  303. manager may use to store any data it wants with this record.
  304. @comm An abort transaction is written to the quorum log. This is used in
  305. identifying aborted transactions during roll back. The hXsaction
  306. handle is invalidated at this point and should not be used after this.
  307. @rdesc ERROR_SUCCESS if successful. Win32 error code if something horrible happened.
  308. @xref <f LogStartXsaction> <f LogCommitXsaction>
  309. ****/
  310. DWORD
  311. LogAbortXsaction(
  312. IN HLOG hLog,
  313. IN HXSACTION hXsaction,
  314. IN RMTYPE ResourceFlags
  315. )
  316. {
  317. PXSACTION pXsaction;
  318. LSN Lsn;
  319. DWORD dwError = ERROR_SUCCESS;
  320. ClRtlLogPrint(LOG_NOISE,
  321. "[LM] LogAbortXsaction : Entry, hXsaction=0x%1!08lx!\r\n",
  322. hXsaction);
  323. GETXSACTION(pXsaction, hXsaction);
  324. Lsn = LogWrite(hLog, pXsaction->TrId, TTAbortXsaction, pXsaction->RmId,
  325. ResourceFlags, NULL, 0);
  326. if (Lsn == NULL_LSN)
  327. {
  328. dwError = GetLastError();
  329. goto FnExit;
  330. }
  331. FnExit:
  332. ZeroMemory(pXsaction, sizeof(XSACTION)); // just in case somebody tries to
  333. LocalFree(pXsaction);
  334. if ( dwError == ERROR_SUCCESS )
  335. {
  336. ClRtlLogPrint(LOG_NOISE, "[LM] LogAbortXsaction: Exit with success\n");
  337. } else
  338. {
  339. ClRtlLogPrint(LOG_CRITICAL, "[LM] LogAbortXsaction: Exit, dwError=0x%1!08lx!\n",
  340. dwError);
  341. }
  342. return(dwError);
  343. }
  344. /****
  345. @func LSN | LogFindXsactionState | This fuctions scans the record and finds
  346. the state of a given transaction.
  347. @parm IN HLOG | hLog | Supplies the identifier of the log.
  348. @parm IN LSN | StartXsactionLsn | The LSN of the start transaction record.
  349. @parm IN TRID | XsactionId | The transaction id of the transaction.
  350. @parm OUT TRSTATE | *pXsactionState | The state of the transaction.
  351. @comm Transaction state is set to XsactionCommitted, XsactionAborted or XsactionUnknown.
  352. depending on whether a commit record, or abort record or no record is found
  353. for this record in the log.
  354. @rdesc ERROR_SUCCESS, else returns the error code if something horrible happens.
  355. @xref <f LogScanXsaction>
  356. ****/
  357. DWORD
  358. LogFindXsactionState(
  359. IN HLOG hLog,
  360. IN LSN StartXsactionLsn,
  361. IN TRID XsactionId,
  362. OUT TRSTATE *pXsactionState)
  363. {
  364. PLOG pLog;
  365. PLOGRECORD pRecord, pEopRecord;
  366. DWORD dwError = ERROR_SUCCESS;
  367. int PageIndex, OldPageIndex;
  368. RMID Resource;
  369. TRID TrId;
  370. TRTYPE TrType;
  371. LSN Lsn, EopLsn;
  372. PLOGPAGE pPage = NULL,pLargeBuffer = NULL;
  373. DWORD dwBytesRead;
  374. RMTYPE ResourceFlags;
  375. BOOL bFound = FALSE;
  376. GETLOG(pLog, hLog);
  377. ClRtlLogPrint(LOG_NOISE,
  378. "[LM] LogWrite : Entry StartXLsn=0x%1!08lx! StartXId=%2!u!\r\n",
  379. StartXsactionLsn, XsactionId);
  380. EnterCriticalSection(&pLog->Lock);
  381. if (StartXsactionLsn >= pLog->NextLsn)
  382. {
  383. dwError = ERROR_INVALID_PARAMETER;
  384. goto FnExit;
  385. }
  386. //read this record
  387. dwBytesRead = 0;
  388. if ((Lsn = LogRead( hLog, StartXsactionLsn, &Resource, &ResourceFlags, &TrId, &TrType,
  389. NULL, &dwBytesRead)) == NULL_LSN)
  390. {
  391. dwError = GetLastError();
  392. goto FnExit;
  393. }
  394. //check the record
  395. if ((TrType != TTStartXsaction) ||
  396. (TrId != XsactionId))
  397. {
  398. dwError = ERROR_INVALID_PARAMETER;
  399. goto FnExit;
  400. }
  401. pPage = (PLOGPAGE)AlignAlloc(SECTOR_SIZE);
  402. if (pPage == NULL) {
  403. CL_UNEXPECTED_ERROR( ERROR_NOT_ENOUGH_MEMORY );
  404. }
  405. //Lsn is now set to the next Lsn after the start
  406. //initialize this to -1 so that the first page is always read
  407. OldPageIndex = -1;
  408. while (Lsn < pLog->NextLsn && !bFound)
  409. {
  410. //
  411. // Scan From Next record to find either the commit or abort record
  412. //
  413. PageIndex = LSNTOPAGE(Lsn);
  414. if (PageIndex != OldPageIndex)
  415. {
  416. //read the page
  417. pLog->Overlapped.Offset = PageIndex * pLog->SectorSize;
  418. pLog->Overlapped.OffsetHigh = 0;
  419. dwError = LogpRead(pLog, pPage, pLog->SectorSize, &dwBytesRead);
  420. if (dwError)
  421. {
  422. goto FnExit;
  423. }
  424. //read was successful, no need to read the page unless the
  425. //record falls on a different page
  426. OldPageIndex = PageIndex;
  427. }
  428. pRecord = LSNTORECORD(pPage, Lsn);
  429. //skip other log management records
  430. //these are small records by definition
  431. if (pRecord->ResourceManager < RMAny)
  432. {
  433. Lsn = GETNEXTLSN(pRecord, TRUE);
  434. continue;
  435. }
  436. //if the transaction id is the same, check the xsaction type
  437. if (pRecord->Transaction == XsactionId)
  438. {
  439. if ((pRecord->XsactionType == TTCommitXsaction) ||
  440. (pRecord->XsactionType == TTStartXsaction))
  441. {
  442. bFound = TRUE;
  443. continue;
  444. }
  445. }
  446. //handle large records
  447. if (pRecord->NumPages > 0)
  448. {
  449. EopLsn = GETNEXTLSN(pRecord,TRUE);
  450. PageIndex = LSNTOPAGE(EopLsn);
  451. //read the page
  452. pLog->Overlapped.Offset = PageIndex * pLog->SectorSize;
  453. pLog->Overlapped.OffsetHigh = 0;
  454. dwError = LogpRead(pLog, pPage, pLog->SectorSize, &dwBytesRead);
  455. if (dwError)
  456. {
  457. goto FnExit;
  458. }
  459. OldPageIndex = PageIndex;
  460. pEopRecord = (PLOGRECORD)((ULONG_PTR) pPage +
  461. (EopLsn - (pLog->Overlapped).Offset));
  462. //move to the next page
  463. Lsn = GETNEXTLSN(pEopRecord, TRUE);
  464. }
  465. else
  466. {
  467. Lsn = GETNEXTLSN(pRecord, TRUE);
  468. }
  469. }
  470. if (bFound)
  471. {
  472. if (pRecord->XsactionType == TTCommitXsaction)
  473. *pXsactionState = XsactionCommitted;
  474. else
  475. *pXsactionState = XsactionAborted;
  476. }
  477. else
  478. {
  479. *pXsactionState = XsactionUnknown;
  480. }
  481. ClRtlLogPrint(LOG_NOISE,
  482. "[LM] LogFindXsactionState : Exit,State=%1!u!\r\n",
  483. *pXsactionState);
  484. FnExit:
  485. LeaveCriticalSection(&pLog->Lock);
  486. if (pPage) AlignFree(pPage);
  487. return(dwError);
  488. }
  489. /****
  490. @func LSN | LogScanXsaction | This fuctions scans the multiple units
  491. of a transaction.
  492. @parm IN HLOG | hLog | Supplies the identifier of the log.
  493. @parm IN LSN | StartXsacionLsn | The LSN of the start transaction record.
  494. @parm IN TRID | XsactionId | The transaction id of the transaction.
  495. @parm IN PLOG_SCANXSACTION_CALLBACK | CallbackRoutine | The routine to call
  496. for every unit of a transaction.
  497. @parm IN PVOID | pContext | The context to be passed to state of the transaction.
  498. @comm Stops enumerating the transaction units if the callback function returns
  499. FALSE, or if the abort or commit record for this transaction is found or
  500. if the next transacion is found.
  501. @rdesc ERROR_SUCCESS if the state is found, else returns the error code.
  502. @xref <f LogFindXsactionState>
  503. ****/
  504. DWORD
  505. LogScanXsaction(
  506. IN HLOG hLog,
  507. IN LSN StartXsactionLsn,
  508. IN TRID XsactionId,
  509. IN PLOG_SCANXSACTION_CALLBACK CallbackRoutine,
  510. IN PVOID pContext)
  511. {
  512. PLOG pLog;
  513. PLOGRECORD pRecord;
  514. DWORD dwError = ERROR_SUCCESS;
  515. int PageIndex, OldPageIndex;
  516. RMID Resource;
  517. TRID TrId;
  518. TRTYPE TrType;
  519. LSN Lsn;
  520. PLOGPAGE pPage = NULL;
  521. PUCHAR pLargeBuffer;
  522. DWORD dwBytesRead;
  523. RMTYPE ResourceFlags;
  524. GETLOG(pLog, hLog);
  525. ClRtlLogPrint(LOG_NOISE,
  526. "[LM] LogScanXsaction : Entry StartXLsn=0x%1!08lx! StartXId=%2!u!\r\n",
  527. StartXsactionLsn, XsactionId);
  528. Lsn = StartXsactionLsn;
  529. if (Lsn >= pLog->NextLsn)
  530. {
  531. dwError = ERROR_INVALID_PARAMETER;
  532. goto FnExit;
  533. }
  534. //read this record
  535. dwBytesRead = 0;
  536. if (LogRead( hLog, Lsn, &Resource, &ResourceFlags, &TrId, &TrType,
  537. NULL, &dwBytesRead) == NULL_LSN)
  538. {
  539. dwError = GetLastError();
  540. goto FnExit;
  541. }
  542. //check the record
  543. if ((TrType != TTStartXsaction) ||
  544. (TrId != XsactionId))
  545. {
  546. dwError = ERROR_INVALID_PARAMETER;
  547. goto FnExit;
  548. }
  549. pPage = (PLOGPAGE)AlignAlloc(SECTOR_SIZE);
  550. if (pPage == NULL) {
  551. CL_UNEXPECTED_ERROR( ERROR_NOT_ENOUGH_MEMORY );
  552. }
  553. //initialize this to -1 so that the first page is always read
  554. OldPageIndex = -1;
  555. while (Lsn < pLog->NextLsn)
  556. {
  557. //
  558. // Scan From Next record to find either the commit or abort record
  559. //
  560. PageIndex = LSNTOPAGE(Lsn);
  561. if (PageIndex != OldPageIndex)
  562. {
  563. //read the page
  564. pLog->Overlapped.Offset = PageIndex * pLog->SectorSize;
  565. pLog->Overlapped.OffsetHigh = 0;
  566. dwError = LogpRead(pLog, pPage, pLog->SectorSize, &dwBytesRead);
  567. if (dwError)
  568. {
  569. goto FnExit;
  570. }
  571. //read was successful, no need to read the page unless the
  572. //record falls on a different page
  573. OldPageIndex = PageIndex;
  574. }
  575. pRecord = LSNTORECORD(pPage, Lsn);
  576. //skip other log management records
  577. if (pRecord->ResourceManager < RMAny)
  578. {
  579. Lsn = GETNEXTLSN(pRecord, TRUE);
  580. continue;
  581. }
  582. //stop if next transaction record is encountered
  583. if (pRecord->Transaction > XsactionId)
  584. {
  585. break;
  586. }
  587. //stop when a commit or abort record is found
  588. if ((pRecord->Transaction == XsactionId) &&
  589. ((pRecord->XsactionType == TTCommitXsaction) ||
  590. (pRecord->XsactionType == TTAbortXsaction)))
  591. {
  592. break;
  593. }
  594. //handle large records
  595. if (pRecord->NumPages > 0)
  596. {
  597. //if the transaction id is the same
  598. if ((pRecord->Transaction == XsactionId) &&
  599. (pRecord->XsactionType == TTXsactionUnit))
  600. {
  601. //read the whole record
  602. //for a large record you need to read in the entire data
  603. pLargeBuffer = AlignAlloc(pRecord->NumPages * SECTOR_SIZE);
  604. if (pLargeBuffer == NULL)
  605. {
  606. dwError = ERROR_NOT_ENOUGH_MEMORY ;
  607. CL_LOGFAILURE(ERROR_NOT_ENOUGH_MEMORY);
  608. break;
  609. }
  610. //read the pages
  611. pLog->Overlapped.Offset = PageIndex * pLog->SectorSize;
  612. pLog->Overlapped.OffsetHigh = 0;
  613. dwError = LogpRead(pLog, pLargeBuffer, pRecord->NumPages *
  614. pLog->SectorSize, &dwBytesRead);
  615. //if it is the last page, then set the new page as the active
  616. //page
  617. if (dwError != ERROR_SUCCESS)
  618. {
  619. CL_LOGFAILURE(dwError);
  620. AlignFree(pLargeBuffer);
  621. break;
  622. }
  623. pRecord = LSNTORECORD((PLOGPAGE)pLargeBuffer, Lsn);
  624. ClRtlLogPrint(LOG_NOISE,
  625. "[LM] LogScanXsaction::Calling the scancb for Lsn=0x%1!08lx! Trid=%2!u! RecordSize=%3!u!\r\n",
  626. Lsn, pRecord->Transaction, pRecord->DataSize);
  627. //if the callback requests to stop scan
  628. if (!(*CallbackRoutine)(pContext, Lsn, pRecord->ResourceManager,
  629. pRecord->Flags, pRecord->Transaction,
  630. pRecord->Data, pRecord->DataSize))
  631. {
  632. AlignFree(pLargeBuffer);
  633. break;
  634. }
  635. }
  636. //read the last page of the large record and advance
  637. Lsn = GETNEXTLSN(pRecord,TRUE);
  638. AlignFree(pLargeBuffer);
  639. PageIndex = LSNTOPAGE(Lsn);
  640. //read the page
  641. pLog->Overlapped.Offset = PageIndex * pLog->SectorSize;
  642. pLog->Overlapped.OffsetHigh = 0;
  643. dwError = LogpRead(pLog, pPage, pLog->SectorSize, &dwBytesRead);
  644. if (dwError)
  645. {
  646. goto FnExit;
  647. }
  648. OldPageIndex = PageIndex;
  649. pRecord = (PLOGRECORD)((ULONG_PTR) pPage +
  650. (Lsn - (pLog->Overlapped).Offset));
  651. CL_ASSERT(pRecord->ResourceManager == RMPageEnd);
  652. //move to the next page
  653. Lsn = GETNEXTLSN(pRecord, TRUE);
  654. }
  655. else
  656. {
  657. if ((pRecord->Transaction == XsactionId) &&
  658. (pRecord->XsactionType == TTXsactionUnit))
  659. {
  660. ClRtlLogPrint(LOG_NOISE,
  661. "[LM] LogScanXsaction: Calling the scancb for Lsn=0x%1!08lx! Trid=%2!u! RecordSize=%3!u!\r\n",
  662. Lsn, pRecord->Transaction, pRecord->DataSize);
  663. //call the callback
  664. if (!(*CallbackRoutine)(pContext, Lsn, pRecord->ResourceManager,
  665. pRecord->Flags, pRecord->Transaction,
  666. pRecord->Data, pRecord->DataSize))
  667. {
  668. break;
  669. }
  670. }
  671. Lsn = GETNEXTLSN(pRecord, TRUE);
  672. }
  673. }
  674. FnExit:
  675. if (pPage) AlignFree(pPage);
  676. return(dwError);
  677. }