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.

1521 lines
42 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1991 - 2000.
  5. //
  6. // File: RCSTXACT.CXX
  7. //
  8. // Contents: RecoverableStream Transactions
  9. //
  10. // Classes: CRcovStrmTrans,
  11. // CRcovStrmReadTrans,
  12. // CRcovStrmWriteTrans,
  13. // CRcovStrmAppendTrans,
  14. // CRcovStrmMDTrans
  15. //
  16. //
  17. // History: 28-Jan-1994 SrikantS Created
  18. //
  19. //----------------------------------------------------------------------------
  20. #include <pch.cxx>
  21. #pragma hdrstop
  22. #include <rcstxact.hxx>
  23. #include <cifailte.hxx>
  24. #include <eventlog.hxx>
  25. #ifndef FACB_MAPPING_GRANULARITY
  26. #define VACB_MAPPING_GRANULARITY 262144
  27. #endif
  28. #define CI_PAGES_IN_CACHE_PAGE (VACB_MAPPING_GRANULARITY/CI_PAGE_SIZE)
  29. #define CACHE_PAGE_TO_CI_PAGE_SHIFT 6 // 64
  30. //+---------------------------------------------------------------------------
  31. //
  32. // Function: CiPagesFromCachePages
  33. //
  34. // Synopsis: Given a number in "cache" page units, it converts into
  35. // "ci" pages. A cache page is 256K in size and a ci page is
  36. // 4K in size.
  37. //
  38. // Arguments: [cachePage] - A number in cache page units
  39. //
  40. // History: 10-17-95 srikants Created
  41. //
  42. // Notes:
  43. //
  44. //----------------------------------------------------------------------------
  45. inline LONGLONG CiPagesFromCachePages( const LONGLONG & cachePage )
  46. {
  47. Win4Assert( (1 << CACHE_PAGE_TO_CI_PAGE_SHIFT) == CI_PAGES_IN_CACHE_PAGE );
  48. return cachePage << CACHE_PAGE_TO_CI_PAGE_SHIFT;
  49. }
  50. inline
  51. ULONG PgCachePgTrunc(ULONG x)
  52. {
  53. return x & ~(VACB_MAPPING_GRANULARITY - 1);
  54. }
  55. inline BOOL IsHighBitSet( ULONG ul )
  56. {
  57. return ul & 0x80000000;
  58. }
  59. //+---------------------------------------------------------------------------
  60. //
  61. // Member: CRcovStrmTrans::CRcovStrmTrans
  62. //
  63. // Synopsis:
  64. //
  65. // Arguments: [obj] -
  66. // [op] -
  67. //
  68. // Returns:
  69. //
  70. // Modifies:
  71. //
  72. // History: 1-28-94 srikants Created
  73. // 3-13-98 kitmanh Don't Open backup mmstreams if catalog
  74. // is read-only
  75. //
  76. // Notes:
  77. //
  78. //----------------------------------------------------------------------------
  79. CRcovStrmTrans::CRcovStrmTrans( PRcovStorageObj &obj,
  80. RcovOpType op
  81. ) : _obj(obj),
  82. _hdr(obj.GetHeader()),
  83. _sObj(_obj)
  84. {
  85. Win4Assert( opNone != op );
  86. //
  87. // Read the header from the disk.
  88. //
  89. _obj.ReadHeader();
  90. _iPrim = _hdr.GetPrimary();
  91. _iBack = _hdr.GetBackup();
  92. _iCurr = _iBack;
  93. //
  94. // Check if the backup is clean or not.
  95. //
  96. if ( !_hdr.IsBackupClean() )
  97. {
  98. ciDebugOut(( DEB_WARN, "CRcovStrmTrans::Cleaning up a Failed Previous Trans\n" ));
  99. //
  100. // Open the streams and create memory mapped streams for
  101. // accessing the backup in write mode and the primary in
  102. // read mode.
  103. //
  104. _obj.Open( _hdr.GetPrimary(), FALSE );
  105. // We can't cleanup if the catalog is read only, so just fail
  106. if ( obj.IsReadOnly() )
  107. {
  108. PStorage & storage = _obj.GetStorage();
  109. storage.ReportCorruptComponent( L"RcovStorageTrans2" );
  110. THROW (CException( CI_CORRUPT_DATABASE ) );
  111. }
  112. _obj.Open( _hdr.GetBackup(), TRUE );
  113. //
  114. // There is an assumption here that the primary stream
  115. // is as big as the header says but it was not true in a corrupt
  116. // shutdown.
  117. //
  118. PMmStream & primStrm = _obj.GetMmStream( _iPrim );
  119. LONGLONG llcbMinimum = _hdr.GetCbToSkip(_iPrim) +
  120. _hdr.GetUserDataSize(_iPrim);
  121. if ( llcbMinimum > primStrm.Size() )
  122. {
  123. ciDebugOut((DEB_ERROR, "**** CI MAY HAVE LOST IMPORTANT INFO ***\n" ));
  124. ciDebugOut((DEB_ERROR, "**** EMPTYING CI RCOV OBJECT ***** \n" ));
  125. PStorage & storage = _obj.GetStorage();
  126. Win4Assert( !"Corrupt catalog" );
  127. storage.ReportCorruptComponent( L"RcovStorageTrans1" );
  128. Win4Assert( !"Recoverable object corrupt" );
  129. THROW (CException( CI_CORRUPT_DATABASE ) );
  130. }
  131. CleanupAndSynchronize();
  132. }
  133. Win4Assert( _hdr.IsBackupClean() );
  134. Win4Assert( _hdr.GetCbToSkip(_iPrim) == _hdr.GetCbToSkip(_iBack) );
  135. Win4Assert( _hdr.IsBackupClean() );
  136. _hdr.SetRcovOp( op );
  137. //
  138. // Open the stream(s) for read/write access as needed.
  139. //
  140. if ( opRead == op )
  141. {
  142. _obj.Open( _hdr.GetPrimary(), FALSE );
  143. _iCurr = _iPrim;
  144. }
  145. else
  146. {
  147. // Win4Assert( !obj.IsReadOnly() );
  148. // We can get here if adding a property to the property map when
  149. // the catalog is read-only by issuing a query on a property we
  150. // haven't seen before.
  151. if ( obj.IsReadOnly() )
  152. THROW( CException( E_ACCESSDENIED ) );
  153. _obj.Open( _hdr.GetBackup(), TRUE );
  154. _obj.WriteHeader();
  155. }
  156. Win4Assert( _obj.IsOpen(_iCurr) );
  157. Seek( 0 );
  158. END_CONSTRUCTION( CRcovStrmTrans );
  159. }
  160. //+---------------------------------------------------------------------------
  161. //
  162. // Member: CRcovStrmTrans::CleanupAndSynchronize
  163. //
  164. // Synopsis:
  165. //
  166. // Returns:
  167. //
  168. // Modifies:
  169. //
  170. // History: 9-12-95 srikants Created
  171. //
  172. // Notes:
  173. //
  174. //----------------------------------------------------------------------------
  175. void CRcovStrmTrans::CleanupAndSynchronize()
  176. {
  177. Win4Assert( !_hdr.IsBackupClean() );
  178. if ( 0 != _hdr.GetCbToSkip(_iBack) )
  179. {
  180. //
  181. // Get rid of the bytes to be skipped in the front.
  182. //
  183. EmptyBackupStream();
  184. }
  185. Win4Assert( 0 == _hdr.GetCbToSkip(_iBack) );
  186. SetStrmSize( _iBack, _hdr.GetUserDataSize(_iPrim) );
  187. _hdr.SetUserDataSize( _iBack, _hdr.GetUserDataSize(_iPrim) );
  188. _hdr.SetCount( _iBack, _hdr.GetCount(_iPrim) );
  189. CopyToBack( 0, 0, _hdr.GetUserDataSize(_iPrim) );
  190. if ( _hdr.GetCbToSkip(_iPrim) != _hdr.GetCbToSkip(_iBack) )
  191. {
  192. Unmap( _iPrim );
  193. _obj.Close( _iPrim );
  194. CommitPh1();
  195. Win4Assert( 0 != _hdr.GetCbToSkip(_iBack) );
  196. EmptyBackupStream();
  197. SetStrmSize( _iBack, _hdr.GetUserDataSize(_iPrim) );
  198. _hdr.SetUserDataSize( _iBack, _hdr.GetUserDataSize(_iPrim) );
  199. CopyToBack( 0, 0, _hdr.GetUserDataSize(_iPrim) );
  200. }
  201. Win4Assert( _hdr.GetCbToSkip(_iBack) == _hdr.GetCbToSkip(_iBack) );
  202. Win4Assert( 0 == _hdr.GetCbToSkip(_iBack) );
  203. CommitPh2();
  204. }
  205. inline LONGLONG llCommonPageTrunc ( LONGLONG cb )
  206. {
  207. return (cb & ~(COMMON_PAGE_SIZE-1));
  208. }
  209. inline LONGLONG llCommonPageRound ( LONGLONG cb )
  210. {
  211. return ( cb + (COMMON_PAGE_SIZE-1) ) & ~(COMMON_PAGE_SIZE-1);
  212. }
  213. //+---------------------------------------------------------------------------
  214. //
  215. // Member: CRcovStrmTrans::Seek
  216. //
  217. // Synopsis: Seeks to the specified offset. This is an exported function
  218. // the offset is the offset visible to the user, ie, offset
  219. // after the "bytes to skip" in the front of the stream.
  220. //
  221. // Arguments: [offset] - offset into the stream. If offset is ENDOFSTRM,
  222. // it will be positioned after the last "user" byte.
  223. //
  224. // Returns: BOOL - FALSE if seek is to beyond end of data, TRUE otherwise
  225. //
  226. // History: 9-19-95 srikants Created
  227. //
  228. // Notes:
  229. //
  230. //----------------------------------------------------------------------------
  231. BOOL CRcovStrmTrans::Seek( ULONG offset )
  232. {
  233. PMmStream & mmStrm = _obj.GetMmStream( _iCurr );
  234. //
  235. // Compute the length of the committed part of the stream.
  236. // (Excluding the hole in the front).
  237. //
  238. Win4Assert( mmStrm.Size() >= _hdr.GetCbToSkip(_iCurr) );
  239. ULONG cbStrmMax = _GetCommittedStrmSize(_iCurr);
  240. if ( ENDOFSTRM == offset )
  241. {
  242. offset = _hdr.GetUserDataSize(_iCurr);
  243. }
  244. else if ( offset >= _hdr.GetUserDataSize(_iCurr) )
  245. {
  246. Win4Assert( 0 == offset ||
  247. _hdr.GetUserDataSize(_iCurr) == offset );
  248. return FALSE;
  249. }
  250. //
  251. // Add the offset of the starting of user data from the beginning
  252. // of the "present but invisible to user" range of bytes.
  253. //
  254. offset += _hdr.GetUserDataStart(_iCurr);
  255. _Seek( offset );
  256. return TRUE;
  257. }
  258. //+---------------------------------------------------------------------------
  259. //
  260. // Function: _Seek
  261. //
  262. // Synopsis: Seeks the current stream to the specified offset.
  263. // If the offset specified is ENDOFSTRM, it will be
  264. // positioned after the last valid byte.
  265. //
  266. // Effects: As long as the current offset is < the full size
  267. // of the stream ( not the valid size in the header but
  268. // the actual size of the strm ), it will be mapped.
  269. //
  270. // Arguments: [offset] -- byte offset from the beginning of the
  271. // "hole".
  272. //
  273. // History: 2-02-94 srikants Created
  274. //
  275. // Notes:
  276. //
  277. //----------------------------------------------------------------------------
  278. void CRcovStrmTrans::_Seek( ULONG offset )
  279. {
  280. Win4Assert( ENDOFSTRM != offset );
  281. Win4Assert( offset >= _hdr.GetUserDataStart(_iCurr) );
  282. Win4Assert( offset <= _hdr.GetFullSize(_iCurr) );
  283. CStrmInfo & si = _aStrmInfo[_iCurr];
  284. PMmStream & mmStrm = _obj.GetMmStream( _iCurr );
  285. //
  286. // Compute the length of the committed part of the stream.
  287. // (Excluding the hole in the front).
  288. //
  289. Win4Assert( mmStrm.Size() >= _hdr.GetCbToSkip(_iCurr) );
  290. si._oCurrent = offset;
  291. if ( IsMapped(si._oCurrent) ||
  292. _GetCommittedStrmSize( mmStrm, _iCurr) <= si._oCurrent )
  293. {
  294. return;
  295. }
  296. Win4Assert( _GetCommittedStrmSize( mmStrm, _iCurr) > si._oCurrent );
  297. //
  298. // Since the current offset is within the valid range of bytes
  299. // and it is not mapped, we have to unmap the currently mapped
  300. // range (if any) and map the new range.
  301. //
  302. CMmStreamBuf & sbuf = _obj.GetMmStreamBuf( _iCurr );
  303. if ( sbuf.Get() )
  304. {
  305. mmStrm.Flush( sbuf, sbuf.Size() );
  306. mmStrm.Unmap( sbuf );
  307. }
  308. //
  309. // We always map on page boundaries.
  310. //
  311. si._oMapLow = CommonPageTrunc( si._oCurrent );
  312. si._oMapHigh = si._oMapLow + (COMMON_PAGE_SIZE-1);
  313. LONGLONG llOffset = _hdr.GetHoleLength(_iCurr) + si._oMapLow;
  314. mmStrm.Map( sbuf, COMMON_PAGE_SIZE,
  315. lltoLowPart(llOffset),
  316. (ULONG) lltoHighPart(llOffset),
  317. mmStrm.isWritable() // Map for writing only if the stream
  318. // is writable.
  319. );
  320. #if CIDBG==1
  321. LONGLONG llHighMap = llOffset+COMMON_PAGE_SIZE-1;
  322. Win4Assert( llHighMap < mmStrm.Size() );
  323. #endif // CIDBG==1
  324. Win4Assert( IsMapped( si._oCurrent ) );
  325. }
  326. //+---------------------------------------------------------------------------
  327. //
  328. // Function: Advance
  329. //
  330. // Synopsis: Advances the current offset by the specified number of
  331. // bytes.
  332. //
  333. // Arguments: [cb] -- Number of bytes by which to increment the
  334. // current position.
  335. //
  336. // History: 2-02-94 srikants Created
  337. //
  338. // Notes:
  339. //
  340. //----------------------------------------------------------------------------
  341. void CRcovStrmTrans::Advance( ULONG cb )
  342. {
  343. CStrmInfo & si = _aStrmInfo[_iCurr];
  344. Win4Assert( !IsHighBitSet(si._oCurrent) );
  345. ULONG offset = si._oCurrent + cb;
  346. _Seek( offset );
  347. }
  348. //+---------------------------------------------------------------------------
  349. //
  350. // Function: Read
  351. //
  352. // Synopsis: Reads the specified number of bytes from the current
  353. // stream into the given buffer.
  354. //
  355. // Effects: The current pointer will be advanced by the number of
  356. // bytes read.
  357. //
  358. // Arguments: [pvBuf] -- Buffer to read the data into.
  359. // [cbToRead] -- Number of bytes to read.
  360. //
  361. // Returns: The number of bytes read. It will not read beyond the
  362. // end of valid bytes (end of stream).
  363. //
  364. // History: 2-02-94 srikants Created
  365. //
  366. // Notes:
  367. //
  368. //----------------------------------------------------------------------------
  369. ULONG CRcovStrmTrans::Read( void *pvBuf, ULONG cbToRead )
  370. {
  371. CStrmInfo & si = _aStrmInfo[_iCurr];
  372. ULONG cbRead = 0;
  373. BYTE * pbDst = (BYTE *) pvBuf;
  374. while ( (cbToRead > 0) && (si._oCurrent < _hdr.GetFullSize(_iCurr)) )
  375. {
  376. _Seek( si._oCurrent );
  377. ULONG cbMapped = si._oMapHigh - si._oCurrent + 1;
  378. ULONG cbCopy = min ( cbToRead, cbMapped );
  379. Win4Assert( cbMapped && cbCopy );
  380. ULONG oStart = si._oCurrent - si._oMapLow;
  381. CMmStreamBuf & sbuf = _obj.GetMmStreamBuf( _iCurr );
  382. BYTE * pbSrc = (BYTE *)sbuf.Get() + oStart;
  383. memcpy( pbDst, pbSrc, cbCopy );
  384. pbDst += cbCopy;
  385. cbToRead -= cbCopy;
  386. cbRead += cbCopy;
  387. si._oCurrent += cbCopy;
  388. }
  389. return cbRead;
  390. }
  391. //+---------------------------------------------------------------------------
  392. //
  393. // Function: Write
  394. //
  395. // Synopsis: Writes the given bytes to the current backup stream
  396. //
  397. // Effects: The current pointer will be advanced by the number
  398. // of bytes written. If necessary, the stream will be
  399. // grown to accommodate the given bytes.
  400. //
  401. // Arguments: [pvBuf] -- Buffer containing the data.
  402. // [cbToWrite] -- Number of bytes to write.
  403. //
  404. // History: 2-02-94 srikants Created
  405. //
  406. // Notes:
  407. //
  408. //----------------------------------------------------------------------------
  409. void CRcovStrmTrans::Write( const void *pvBuf, ULONG cbToWrite )
  410. {
  411. Win4Assert( cbToWrite && pvBuf || !cbToWrite );
  412. Win4Assert( _iCurr == _iBack );
  413. CStrmInfo & si = _aStrmInfo[_iCurr];
  414. if ( si._oCurrent+ cbToWrite > _hdr.GetFullSize(_iCurr) )
  415. {
  416. //
  417. // Grow the stream for writing the given bytes.
  418. //
  419. ULONG cbDelta = (si._oCurrent + cbToWrite) -
  420. _hdr.GetFullSize(_iCurr);
  421. Grow( _iCurr, cbDelta );
  422. }
  423. BYTE * pbSrc = (BYTE *) pvBuf;
  424. while (cbToWrite > 0)
  425. {
  426. Win4Assert( si._oCurrent < _hdr.GetFullSize( _iCurr ) );
  427. _Seek( si._oCurrent );
  428. ULONG cbMapped = si._oMapHigh - si._oCurrent + 1;
  429. ULONG cbCopy = min ( cbToWrite, cbMapped );
  430. Win4Assert( cbCopy && cbMapped );
  431. ULONG oStart = si._oCurrent - si._oMapLow;
  432. CMmStreamBuf & sbuf = _obj.GetMmStreamBuf( _iCurr );
  433. BYTE * pbDst = (BYTE *)sbuf.Get() + oStart;
  434. memcpy( pbDst, pbSrc, cbCopy );
  435. pbSrc += cbCopy;
  436. si._oCurrent += cbCopy;
  437. cbToWrite -= cbCopy;
  438. }
  439. }
  440. //+---------------------------------------------------------------------------
  441. //
  442. // Function: Unmap
  443. //
  444. // Synopsis: Unmaps the currently mapped region of the specified
  445. // stream.
  446. //
  447. // Effects: _aStrmInfo[nCopy] will be updated to indicate that
  448. // nothing is mapped.
  449. //
  450. // Arguments: [nCopy] -- Stream to unmap.
  451. //
  452. // History: 2-02-94 srikants Created
  453. //
  454. // Notes:
  455. //
  456. //----------------------------------------------------------------------------
  457. void CRcovStrmTrans::Unmap( CRcovStorageHdr::DataCopyNum nCopy )
  458. {
  459. CStrmInfo & si = _aStrmInfo[nCopy];
  460. if ( ENDOFSTRM == si._oMapLow )
  461. {
  462. Win4Assert( ENDOFSTRM == si._oMapHigh );
  463. return;
  464. }
  465. PMmStream & mmStrm = _obj.GetMmStream( nCopy );
  466. CMmStreamBuf & sbuf = _obj.GetMmStreamBuf( nCopy );
  467. if ( sbuf.Get() )
  468. {
  469. mmStrm.Flush( sbuf, sbuf.Size() );
  470. mmStrm.Unmap( sbuf );
  471. }
  472. //
  473. // Reset the high and low end points of the mapping info.
  474. //
  475. si.Reset();
  476. return;
  477. }
  478. //+---------------------------------------------------------------------------
  479. //
  480. // Function: Grow
  481. //
  482. // Synopsis: Grows the current stream to accommodate "cbDelta" more
  483. // bytes in the stream.
  484. //
  485. // Effects: The valid size entry in the header for the current
  486. // stream will be updated to indicate the new size.
  487. //
  488. // Arguments: [nCopy] -- The stream which needs to be grown.
  489. // [cbDelta] -- Number of bytes to grow by.
  490. //
  491. // History: 2-02-94 srikants Created
  492. //
  493. // Notes:
  494. //
  495. //----------------------------------------------------------------------------
  496. inline void CRcovStrmTrans::Grow(
  497. CRcovStorageHdr::DataCopyNum nCopy, ULONG cbDelta )
  498. {
  499. //
  500. // We don't want to do overflow checking or use 64bit arithmetic.
  501. // 2GB for a changelog is huge enough!
  502. //
  503. Win4Assert( !IsHighBitSet( _hdr.GetUserDataSize(nCopy) ) );
  504. ULONG cbNew = _hdr.GetUserDataSize(nCopy) + cbDelta;
  505. PMmStream & mmStrm = _obj.GetMmStream(nCopy);
  506. Win4Assert( mmStrm.Size() >= _hdr.GetCbToSkip(nCopy) );
  507. ULONG ulCommittedSize = lltoul( mmStrm.Size() - _hdr.GetCbToSkip(nCopy) );
  508. //
  509. // Check if the stream is big enough to accommodate the additional
  510. // bytes.
  511. //
  512. if ( ulCommittedSize >= cbNew )
  513. {
  514. _hdr.SetUserDataSize(nCopy, cbNew);
  515. return;
  516. }
  517. //
  518. // We have to grow the stream also.
  519. //
  520. SetStrmSize( nCopy, cbNew );
  521. _hdr.SetUserDataSize(nCopy, cbNew );
  522. }
  523. //+---------------------------------------------------------------------------
  524. //
  525. // Function: SetStrmSize
  526. //
  527. // Synopsis: Sets the size of the given stream to be the specified
  528. // number of bytes. The size will be rounded up to the
  529. // nearest COMMON_PAGE_SIZE. However, the stream will
  530. // never be reduced below COMMON_PAGE_SIZE, ie, the minimum
  531. // size of the stream will be adjusted to be COMMON_PAGE_SIZE.
  532. //
  533. // Effects: The stream will be unmapped after this operation.
  534. //
  535. // Arguments: [nCopy] -- The stream whose size must be set.
  536. // [cbNew] -- New size of the stream.
  537. //
  538. // History: 2-03-94 srikants Created
  539. //
  540. // Notes: This is an internal function and it is assumed that the
  541. // necessary transaction protocol is being followed. Also
  542. // note that the size in the header is NOT set by this
  543. // method.
  544. //
  545. //----------------------------------------------------------------------------
  546. void CRcovStrmTrans::SetStrmSize(
  547. CRcovStorageHdr::DataCopyNum nCopy, ULONG cbNew )
  548. {
  549. PMmStream & mmStrm = _obj.GetMmStream( nCopy );
  550. //
  551. // Size must be atleast one OFS page in size.
  552. //
  553. if ( 0 == cbNew )
  554. cbNew = COMMON_PAGE_SIZE;
  555. Unmap( nCopy );
  556. LONGLONG llTotalLen = cbNew + _hdr.GetCbToSkip(nCopy);
  557. llTotalLen = llCommonPageRound( llTotalLen );
  558. if ( mmStrm.Size() != llTotalLen ) // optimization.
  559. {
  560. mmStrm.SetSize( _obj.GetStorage(),
  561. lltoLowPart(llTotalLen),
  562. (ULONG) lltoHighPart(llTotalLen) );
  563. }
  564. }
  565. //+---------------------------------------------------------------------------
  566. //
  567. // Function: EmptyBackupStream
  568. //
  569. // Synopsis: Empties the contents of the backup stream by setting its
  570. // size to "0" (in user space to COMMON_PAGE_SIZE).
  571. //
  572. // History: 10-18-95 srikants Created
  573. //
  574. // Notes: When there is a hole in a sparse stream, we have to first
  575. // set its size to 0 to remove the sparseness completely.
  576. // Otherwise, we will try writing/reading into decommitted
  577. // space.
  578. //
  579. // For example, if there is a 256K hole in a 1M stream, setting
  580. // the size of the stream to 64K will leave a 64K hole in the
  581. // front. To avoid this, we first set the size to 0 and then
  582. // set size to 64K to get committed 64K stream.
  583. //
  584. //----------------------------------------------------------------------------
  585. void CRcovStrmTrans::EmptyBackupStream()
  586. {
  587. ciDebugOut(( DEB_ITRACE, "Emptying contents of backup stream\n" ));
  588. PMmStream & mmStrm = _obj.GetMmStream( _iBack );
  589. Unmap( _iBack );
  590. //
  591. // In use space we cannot have a 0 length stream because mapping
  592. // of a zero length stream fails. Also, there are no "holes" in
  593. // user space.
  594. //
  595. ULONG cbLow = COMMON_PAGE_SIZE;
  596. mmStrm.SetSize( _obj.GetStorage(),
  597. cbLow,
  598. 0 );
  599. _hdr.SetUserDataSize(_iBack,0);
  600. _hdr.SetCbToSkip(_iBack,0);
  601. _obj.WriteHeader();
  602. }
  603. //+---------------------------------------------------------------------------
  604. //
  605. // Function: CopyToBack
  606. //
  607. // Synopsis: Copies the specified number of bytes from the current
  608. // primary stream to the backup stream.
  609. //
  610. // Effects:
  611. //
  612. // Arguments: [oSrc] -- Starting byte offset in the primary where
  613. // to start the copying from (Offset from the beginning of the
  614. // user data).
  615. // [oDst] -- Starting byte offset in the backup where
  616. // to copy the data to. (Offset from the beginning of the user
  617. // data.)
  618. // [cbToCopy] -- Number of bytes to copy.
  619. //
  620. // History: 2-03-94 srikants Created
  621. //
  622. // Notes: This does not modify the "valid size" of the backup
  623. // stream - it is upto the caller to change it. Also, it
  624. // is assumed that the backup stream is big enough to
  625. // hold all the data and the primary data is big enough
  626. // to give the data.
  627. //
  628. //----------------------------------------------------------------------------
  629. void CRcovStrmTrans::CopyToBack( ULONG oSrc, ULONG oDst, ULONG cbToCopy )
  630. {
  631. //
  632. // Transform the offsets to the offset from the beginning of the
  633. // hole.
  634. //
  635. Win4Assert( oSrc != ENDOFSTRM );
  636. Win4Assert( oDst != ENDOFSTRM );
  637. oSrc += _hdr.GetUserDataStart(_iPrim);
  638. oDst += _hdr.GetUserDataStart(_iBack);
  639. ULONG cbLeft = cbToCopy;
  640. const CRcovStorageHdr::DataCopyNum iStartCurr = _iCurr;
  641. CStrmInfo & siPrim = _aStrmInfo[_iPrim];
  642. CStrmInfo & siBack = _aStrmInfo[_iBack];
  643. while ( cbLeft > 0 )
  644. {
  645. SetCurrentStrm( _iPrim );
  646. _Seek( oSrc );
  647. Win4Assert( IsMapped( oSrc ) );
  648. SetCurrentStrm( _iBack );
  649. _Seek( oDst );
  650. Win4Assert( IsMapped( oDst ) );
  651. PMmStream & mmPrimStrm = _obj.GetMmStream( _iPrim );
  652. PMmStream & mmBackStrm = _obj.GetMmStream( _iBack );
  653. CMmStreamBuf & sPrimBuf = _obj.GetMmStreamBuf( _iPrim );
  654. CMmStreamBuf & sBackBuf = _obj.GetMmStreamBuf( _iBack );
  655. const BYTE *pbSrc = (const BYTE *) sPrimBuf.Get();
  656. pbSrc += ( oSrc - siPrim._oMapLow);
  657. BYTE * pbDst = (BYTE *) sBackBuf.Get();
  658. pbDst += ( oDst - siBack._oMapLow);
  659. ULONG cbMapRead = siPrim._oMapHigh - oSrc + 1;
  660. ULONG cbMapWrite = siBack._oMapHigh - oDst + 1;
  661. Win4Assert( cbMapRead && cbMapWrite );
  662. ULONG cbCopy = min( cbLeft, min(cbMapRead, cbMapWrite) );
  663. Win4Assert( cbCopy );
  664. memcpy( pbDst, pbSrc, cbCopy );
  665. oSrc += cbCopy;
  666. oDst += cbCopy;
  667. cbLeft -= cbCopy;
  668. }
  669. //
  670. // Restore the current index stream to be the same as the
  671. // original.
  672. //
  673. _iCurr = iStartCurr;
  674. }
  675. //+---------------------------------------------------------------------------
  676. //
  677. // Function: CommitPh1
  678. //
  679. // Synopsis: Commits the changes to the current backup stream and
  680. // makes it the primary. It also opens the new backup
  681. // stream in a write mode for making changes to the new backup
  682. // stream in the phase 2 of the commit process.
  683. //
  684. // Effects: The backup stream gets flushed to the disk.
  685. //
  686. // Arguments: (none)
  687. //
  688. // History: 2-05-94 srikants Created
  689. //
  690. // Notes:
  691. //
  692. //----------------------------------------------------------------------------
  693. void CRcovStrmTrans::CommitPh1()
  694. {
  695. //
  696. // Flush the backup stream.
  697. //
  698. PMmStream & mmStrm = _obj.GetMmStream( _iBack );
  699. CMmStreamBuf & sbuf = _obj.GetMmStreamBuf( _iBack );
  700. Unmap( _iBack ); // Should unmap before flushing.
  701. //
  702. // Swap the primary and backup in the header and write
  703. // out the header.
  704. //
  705. _hdr.SwitchPrimary();
  706. _obj.WriteHeader();
  707. Win4Assert( _iPrim == _hdr.GetBackup() );
  708. //
  709. // Swap the primary and backup streams and make
  710. // _iCurr the new backup. This is to prepare for
  711. // the phase 2 of the commit process.
  712. //
  713. _iCurr = _iPrim;
  714. _iPrim = _iBack;
  715. _iBack = _iCurr;
  716. //
  717. // Now open the current backup stream for writing.
  718. //
  719. _obj.Open( _iBack, TRUE );
  720. }
  721. //+---------------------------------------------------------------------------
  722. //
  723. // Function: CommitPh2
  724. //
  725. // Synopsis: Commits the phase 2 of the transaction. It writes out
  726. // the changes to the backup stream. Upon successful
  727. // completion, it marks that both streams are clean in
  728. // the header and closes the streams.
  729. //
  730. // Effects: After this returns, the streams are no longer accessible
  731. // as they are closed. They should be re-opened for another
  732. // transaction.
  733. //
  734. // Arguments: (none)
  735. //
  736. // History: 2-10-94 srikants Created
  737. //
  738. // Notes:
  739. //
  740. //----------------------------------------------------------------------------
  741. void CRcovStrmTrans::CommitPh2()
  742. {
  743. //
  744. // Close the primary stream and mark that it has been unmapped.
  745. //
  746. _obj.Close( _iPrim ); // close automatically unmaps if it is
  747. // mapped.
  748. _aStrmInfo[_iPrim].Reset();
  749. //
  750. // Now Flush the backup and close it.
  751. //
  752. PMmStream & mmStrm = _obj.GetMmStream( _iBack );
  753. CMmStreamBuf & sbuf = _obj.GetMmStreamBuf( _iBack );
  754. Unmap( _iBack ); // Must unmap before flushing.
  755. _obj.Close( _iBack );
  756. //
  757. // Update the header that the object is now clean.
  758. //
  759. _hdr.SyncBackup();
  760. _obj.WriteHeader();
  761. }
  762. #if 0
  763. void CRcovStrmTrans::Compare()
  764. {
  765. #if CIDBG == 1
  766. Win4Assert( !_obj.IsOpen( _hdr.GetPrimary() ) );
  767. Win4Assert( !_obj.IsOpen( _hdr.GetBackup() ) );
  768. if( _hdr.GetUserDataSize( _hdr.GetPrimary() ) != _hdr.GetUserDataSize( _hdr.GetBackup() ) )
  769. {
  770. ciDebugOut(( DEB_ERROR, "Primary (%u) = 0x%x, Secondary (%u) = 0x%x\n",
  771. _hdr.GetPrimary(), _hdr.GetUserDataSize( _hdr.GetPrimary() ),
  772. _hdr.GetBackup(), _hdr.GetUserDataSize( _hdr.GetBackup() ) ));
  773. Win4Assert( _hdr.GetUserDataSize( _hdr.GetPrimary() ) == _hdr.GetUserDataSize( _hdr.GetBackup() ) );
  774. }
  775. _obj.Open( _hdr.GetPrimary(), FALSE );
  776. _obj.Open( _hdr.GetBackup(), FALSE );
  777. ULONG oSrc = _hdr.GetUserDataStart( _hdr.GetPrimary() );
  778. ULONG oDst = _hdr.GetUserDataStart( _hdr.GetBackup() );
  779. if ( oSrc != oDst )
  780. {
  781. ciDebugOut(( DEB_ERROR, "Primary (%u) = 0x%x, Secondary (%u) = 0x%x\n",
  782. _hdr.GetPrimary(), oSrc,
  783. _hdr.GetBackup(), oDst ));
  784. Win4Assert( oSrc == oDst );
  785. }
  786. if ( _hdr.GetUserDataSize( _hdr.GetPrimary() ) != _hdr.GetUserDataSize( _hdr.GetBackup() ) )
  787. {
  788. ciDebugOut(( DEB_ERROR, "Primary (%u) = 0x%x, Secondary (%u) = 0x%x\n",
  789. _hdr.GetPrimary(), _hdr.GetUserDataSize( _hdr.GetPrimary() ),
  790. _hdr.GetBackup(), _hdr.GetUserDataSize( _hdr.GetBackup() ) ));
  791. Win4Assert( _hdr.GetUserDataSize( _hdr.GetPrimary() ) == _hdr.GetUserDataSize( _hdr.GetBackup() ) );
  792. }
  793. ULONG cbLeft = _hdr.GetUserDataSize( _hdr.GetPrimary() );
  794. CStrmInfo & siPrim = _aStrmInfo[_hdr.GetPrimary()];
  795. CStrmInfo & siBack = _aStrmInfo[_hdr.GetBackup()];
  796. while ( cbLeft > 0 )
  797. {
  798. SetCurrentStrm( _hdr.GetPrimary() );
  799. _Seek( oSrc );
  800. Win4Assert( IsMapped( oSrc ) );
  801. SetCurrentStrm( _hdr.GetBackup() );
  802. _Seek( oDst );
  803. Win4Assert( IsMapped( oDst ) );
  804. PMmStream & mmPrimStrm = _obj.GetMmStream( _hdr.GetPrimary() );
  805. PMmStream & mmBackStrm = _obj.GetMmStream( _hdr.GetBackup() );
  806. CMmStreamBuf & sPrimBuf = _obj.GetMmStreamBuf( _hdr.GetPrimary() );
  807. CMmStreamBuf & sBackBuf = _obj.GetMmStreamBuf( _hdr.GetBackup() );
  808. const BYTE *pbSrc = (const BYTE *) sPrimBuf.Get();
  809. pbSrc += ( oSrc - siPrim._oMapLow);
  810. BYTE * pbDst = (BYTE *) sBackBuf.Get();
  811. pbDst += ( oDst - siBack._oMapLow);
  812. ULONG cbMapRead = siPrim._oMapHigh - oSrc + 1;
  813. ULONG cbMapWrite = siBack._oMapHigh - oDst + 1;
  814. Win4Assert( cbMapRead && cbMapWrite );
  815. ULONG cbCopy = min( cbLeft, min(cbMapRead, cbMapWrite) );
  816. Win4Assert( cbCopy );
  817. if ( 0 != memcmp( pbDst, pbSrc, cbCopy ) )
  818. {
  819. ciDebugOut(( DEB_ERROR, "CRcovStrmTrans::Compare -- mismatch\n" ));
  820. ciDebugOut(( DEB_ERROR | DEB_NOCOMPNAME, " Primary (%u) offset 0x%x, pb = 0x%x\n",
  821. _hdr.GetPrimary(), oSrc, pbSrc ));
  822. ciDebugOut(( DEB_ERROR | DEB_NOCOMPNAME, " Backup (%u) offset 0x%x, pb = 0x%x\n",
  823. _hdr.GetBackup(), oDst, pbDst ));
  824. Win4Assert( !"CRcovStrmTrans::Compare -- mismatch" );
  825. }
  826. oSrc += cbCopy;
  827. oDst += cbCopy;
  828. cbLeft -= cbCopy;
  829. }
  830. _obj.Close( _hdr.GetPrimary() );
  831. _obj.Close( _hdr.GetBackup() );
  832. #endif // CIDBG
  833. }
  834. #endif
  835. void CRcovStrmWriteTrans::Commit()
  836. {
  837. Win4Assert( XActAbort == CTransaction::GetStatus() );
  838. CommitPh1();
  839. //
  840. // After phase1 is successfully committed, the transaction will be
  841. // completed by making "forward progress". So, we should not throw
  842. // now even if the phase2 fails. Even if phase2 fails now, it will
  843. // be eventually completed later when a new transaction is created
  844. // for this object.
  845. //
  846. TRY
  847. {
  848. //
  849. // Copy the entire contents from the new primary to the
  850. // new backup.
  851. //
  852. SetStrmSize( _iBack, GetStorageHdr().GetUserDataSize(_iPrim) );
  853. GetStorageHdr().SetUserDataSize( _iBack,
  854. GetStorageHdr().GetUserDataSize(_iPrim) );
  855. CopyToBack( 0, 0, GetStorageHdr().GetUserDataSize(_iPrim));
  856. CommitPh2();
  857. Win4Assert( GetStorageHdr().IsBackupClean() );
  858. }
  859. CATCH( CException, e )
  860. {
  861. GetRcovObj().Close( _iPrim );
  862. GetRcovObj().Close( _iBack );
  863. ciDebugOut(( DEB_ERROR, "Phase2 of CRcomStrmWriteTrans failed 0x%X\n",
  864. e.GetErrorCode() ));
  865. }
  866. END_CATCH
  867. CRcovStrmTrans::Commit();
  868. }
  869. void CRcovStrmWriteTrans::Empty()
  870. {
  871. Win4Assert( _iCurr == _iBack );
  872. SetStrmSize( _iBack, 0 );
  873. GetStorageHdr().SetUserDataSize( _iBack, 0 );
  874. Seek(0);
  875. }
  876. CRcovStrmAppendTrans::CRcovStrmAppendTrans( PRcovStorageObj & obj )
  877. : CRcovStrmTrans( obj, opAppend )
  878. {
  879. //
  880. // Seek to end of file.
  881. //
  882. Seek( ENDOFSTRM );
  883. END_CONSTRUCTION( CRcovStrmAppendTrans );
  884. }
  885. void CRcovStrmAppendTrans::Commit()
  886. {
  887. Win4Assert( XActAbort == CTransaction::GetStatus() );
  888. Win4Assert( GetStorageHdr().GetUserDataSize(_iPrim) <=
  889. GetStorageHdr().GetUserDataSize(_iBack) );
  890. CTransaction::_status = XActAbort;
  891. CommitPh1();
  892. //
  893. // After phase1 is successfully committed, the transaction will be
  894. // completed by making "forward progress". So, we should not throw
  895. // now even if the phase2 fails. Even if phase2 fails now, it will
  896. // be eventually completed later when a new transaction is created
  897. // for this object.
  898. //
  899. TRY
  900. {
  901. //
  902. // Now copy the contents of the primary to the backup
  903. // from the point where append started.
  904. //
  905. ULONG cbToCopy = GetStorageHdr().GetUserDataSize(_iPrim) -
  906. GetStorageHdr().GetUserDataSize(_iBack);
  907. ULONG offset = GetStorageHdr().GetUserDataSize(_iBack);
  908. ciFAILTEST( STATUS_DISK_FULL );
  909. Grow(_iBack, cbToCopy);
  910. ciFAILTEST( STATUS_DISK_FULL );
  911. CopyToBack( offset, offset, cbToCopy );
  912. ciFAILTEST( STATUS_DISK_FULL );
  913. CommitPh2();
  914. ciFAILTEST( STATUS_DISK_FULL );
  915. }
  916. CATCH ( CException, e )
  917. {
  918. GetRcovObj().Close( _iPrim );
  919. GetRcovObj().Close( _iBack );
  920. ciDebugOut(( DEB_ERROR, "Phase2 of CRcomStrmAppendTrans failed 0x%X\n",
  921. e.GetErrorCode() ));
  922. }
  923. END_CATCH
  924. CRcovStrmTrans::Commit();
  925. }
  926. CRcovStrmMDTrans::CRcovStrmMDTrans( PRcovStorageObj & obj,
  927. MDOp op, ULONG cb )
  928. : CRcovStrmTrans( obj, opMetaData ),
  929. _op(op), _cbOp(cb)
  930. {
  931. END_CONSTRUCTION( CRcovStrmMDTrans );
  932. }
  933. void CRcovStrmMDTrans::Commit()
  934. {
  935. Win4Assert( XActAbort == CTransaction::GetStatus() );
  936. switch ( _op )
  937. {
  938. case mdopSetSize:
  939. SetSize( _cbOp );
  940. break;
  941. case mdopGrow:
  942. Grow( _cbOp );
  943. break;
  944. case mdopFrontShrink:
  945. ShrinkFromFront( _cbOp );
  946. break;
  947. case mdopBackCompact:
  948. CompactFromEnd( _cbOp );
  949. break;
  950. default:
  951. Win4Assert( ! "Control Should Not Come Here" );
  952. break;
  953. }
  954. CRcovStrmTrans::Commit();
  955. }
  956. void CRcovStrmMDTrans::SetSize( ULONG cbNew )
  957. {
  958. //
  959. // set the size on the backup first.
  960. //
  961. Win4Assert( _iCurr == _iBack );
  962. CRcovStrmTrans::SetStrmSize( _iBack, cbNew );
  963. GetStorageHdr().SetUserDataSize( _iBack, cbNew );
  964. //
  965. // Do the phase1 commit now.
  966. //
  967. CommitPh1();
  968. //
  969. // After phase1 is successfully committed, the transaction will be
  970. // completed by making "forward progress". So, we should not throw
  971. // now even if the phase2 fails. Even if phase2 fails now, it will
  972. // be eventually completed later when a new transaction is created
  973. // for this object.
  974. //
  975. TRY
  976. {
  977. //
  978. // Apply the same operation on the new backup.
  979. //
  980. Win4Assert( _iCurr == _iBack );
  981. CRcovStrmTrans::SetStrmSize( _iBack, cbNew );
  982. CommitPh2();
  983. Win4Assert( GetStorageHdr().IsBackupClean() );
  984. }
  985. CATCH( CException,e )
  986. {
  987. GetRcovObj().Close( _iPrim );
  988. GetRcovObj().Close( _iBack );
  989. ciDebugOut(( DEB_ERROR, "Phase2 of CRcovStrmMDTrans failed 0x%X\n",
  990. e.GetErrorCode() ));
  991. }
  992. END_CATCH
  993. }
  994. void CRcovStrmMDTrans::Grow( ULONG cbDelta )
  995. {
  996. const ULONG cbNew = GetStorageHdr().GetUserDataSize(_iCurr)+cbDelta;
  997. CRcovStrmMDTrans::SetSize( cbNew );
  998. }
  999. void CRcovStrmMDTrans::CompactFromEnd( ULONG cbDelta )
  1000. {
  1001. Win4Assert( cbDelta <= GetStorageHdr().GetUserDataSize( _iCurr ) );
  1002. Win4Assert( _iCurr == _iBack );
  1003. cbDelta = min (cbDelta, GetStorageHdr().GetUserDataSize( _iCurr ));
  1004. const ULONG cbNew = GetStorageHdr().GetUserDataSize(_iCurr) - cbDelta;
  1005. CRcovStrmMDTrans::SetSize( cbNew );
  1006. }
  1007. //+---------------------------------------------------------------------------
  1008. //
  1009. // Member: CRcovStrmMDTrans::IncreaseBytesToSkip
  1010. //
  1011. // Synopsis: Increases the number of bytes to be "skipped" in the front
  1012. // by the specified amount.
  1013. //
  1014. // Arguments: [cbDelta] - Number of additional bytes to skip.
  1015. //
  1016. // History: 9-19-95 srikants Created
  1017. //
  1018. // Notes:
  1019. //
  1020. //----------------------------------------------------------------------------
  1021. void CRcovStrmMDTrans::IncreaseBytesToSkip( ULONG cbDelta )
  1022. {
  1023. CRcovStorageHdr & hdr = GetStorageHdr();
  1024. //
  1025. // Update the hole length and the valid data length.
  1026. //
  1027. Win4Assert( hdr.GetUserDataSize(_iBack) >= cbDelta );
  1028. const ULONG cbNewValid = hdr.GetUserDataSize(_iPrim) - cbDelta;
  1029. hdr.SetUserDataSize( _iBack, cbNewValid );
  1030. Win4Assert( hdr.GetCbToSkip(_iPrim) == hdr.GetCbToSkip(_iBack) );
  1031. const LONGLONG llcbNewSkip = hdr.GetCbToSkip(_iBack)+cbDelta;
  1032. hdr.SetCbToSkip( _iBack, llcbNewSkip );
  1033. // Phase1 complete - just set the values for the backup.
  1034. hdr.SwitchPrimary();
  1035. Win4Assert( _iPrim == hdr.GetBackup() );
  1036. _iCurr = _iPrim;
  1037. _iPrim = _iBack;
  1038. _iBack = _iCurr;
  1039. // phase 2 complete. Commit the changes
  1040. hdr.SyncBackup();
  1041. GetRcovObj().WriteHeader();
  1042. }
  1043. //+---------------------------------------------------------------------------
  1044. //
  1045. // Member: CRcovStrmMDTrans::CopyShrinkFromFront
  1046. //
  1047. // Synopsis: Implements a shrink from front by copying bytes.
  1048. //
  1049. // Arguments: [cbNew] - Number of bytes that will be in the stream after
  1050. // doing a shrink from front.
  1051. // [cbDelta] - Number of bytes to shrink in the front.
  1052. //
  1053. // History: 10-02-95 srikants Created ( Moved from ShrinkFromFront()
  1054. // methoed )
  1055. //
  1056. // Notes:
  1057. //
  1058. //----------------------------------------------------------------------------
  1059. void CRcovStrmMDTrans::CopyShrinkFromFront( ULONG cbNew,
  1060. ULONG cbDelta )
  1061. {
  1062. CRcovStorageHdr & hdr = GetStorageHdr();
  1063. ULONG oDst = 0;
  1064. ULONG oSrc = cbDelta;
  1065. // this check is an optimization
  1066. if ( hdr.GetHoleLength(_iBack) > SHRINK_FROM_FRONT_PAGE_SIZE )
  1067. {
  1068. //
  1069. // If the hole in front is <= SHRINK_FROM_FRONT_PAGE_SIZE, then
  1070. // this there is no "sparseness" in the front.
  1071. //
  1072. EmptyBackupStream();
  1073. }
  1074. //
  1075. // Open the Primary in a read-only mode and close it before
  1076. // calling CommitPh1().
  1077. // Copy the contents from oSrc in the primary to oDst in the
  1078. // backup stream.
  1079. //
  1080. hdr.SetCbToSkip(_iBack,0);
  1081. CRcovStrmTrans::SetStrmSize( _iBack, cbNew );
  1082. hdr.SetUserDataSize( _iBack, cbNew );
  1083. GetRcovObj().Open( _iPrim, FALSE );
  1084. CopyToBack( oSrc, oDst, cbNew );
  1085. Unmap( _iPrim );
  1086. GetRcovObj().Close( _iPrim );
  1087. //
  1088. // Commit the phase1 changes now.
  1089. //
  1090. CommitPh1();
  1091. //
  1092. // After phase1 is successfully committed, the transaction will be
  1093. // completed by making "forward progress". So, we should not throw
  1094. // now even if the phase2 fails. Even if phase2 fails now, it will
  1095. // be eventually completed later when a new transaction is created
  1096. // for this object.
  1097. //
  1098. TRY
  1099. {
  1100. //
  1101. // We have to synchronize the new backup with the new primary.
  1102. //
  1103. Win4Assert( _iCurr == _iBack );
  1104. // this check is an optimization
  1105. if ( hdr.GetHoleLength(_iBack) > SHRINK_FROM_FRONT_PAGE_SIZE )
  1106. {
  1107. //
  1108. // If the hole in front is <= SHRINK_FROM_FRONT_PAGE_SIZE, then
  1109. // this there is no "sparseness" in the front.
  1110. //
  1111. EmptyBackupStream();
  1112. }
  1113. hdr.SetCbToSkip(_iBack,0);
  1114. CRcovStrmTrans::SetStrmSize( _iBack, cbNew );
  1115. CopyToBack( 0, 0, cbNew );
  1116. hdr.SetUserDataSize( _iBack, cbNew );
  1117. CommitPh2();
  1118. Win4Assert( hdr.IsBackupClean() );
  1119. }
  1120. CATCH( CException, e )
  1121. {
  1122. GetRcovObj().Close( _iPrim );
  1123. GetRcovObj().Close( _iBack );
  1124. ciDebugOut(( DEB_ERROR, "Phase2 of ShrinkFromFront() failed 0x%X\n",
  1125. e.GetErrorCode() ));
  1126. }
  1127. END_CATCH
  1128. }
  1129. void CRcovStrmMDTrans::ShrinkFromFront( ULONG cbDelta )
  1130. {
  1131. CRcovStorageHdr & hdr = GetStorageHdr();
  1132. Win4Assert( cbDelta <= hdr.GetUserDataSize( _iCurr ) );
  1133. Win4Assert( _iCurr == _iBack );
  1134. cbDelta = min (cbDelta, hdr.GetUserDataSize( _iCurr ));
  1135. Win4Assert( hdr.GetCbToSkip(_iCurr) >= hdr.GetHoleLength(_iCurr) );
  1136. const ULONG cbCommittedSkip = lltoul( hdr.GetCbToSkip(_iCurr) - hdr.GetHoleLength(_iCurr) );
  1137. //
  1138. // If the total number of bytes "present but invisible" to user is
  1139. // < the threshold, don't do any copying or shrinking. Just increment
  1140. // the bytest to skip and return.
  1141. //
  1142. if ( cbCommittedSkip + cbDelta < SHRINK_FROM_FRONT_PAGE_SIZE )
  1143. {
  1144. IncreaseBytesToSkip( cbDelta );
  1145. return;
  1146. }
  1147. const ULONG cbNew = hdr.GetUserDataSize(_iCurr) - cbDelta;
  1148. CopyShrinkFromFront( cbNew, cbDelta );
  1149. }
  1150. //+---------------------------------------------------------------------------
  1151. //
  1152. // Member: CCopyRcovObject::_SetDstSize
  1153. //
  1154. // Synopsis: Sets the size of the destination object to be same as
  1155. // the source object.
  1156. //
  1157. // History: 3-17-97 srikants Created
  1158. //
  1159. //----------------------------------------------------------------------------
  1160. void CCopyRcovObject::_SetDstSize()
  1161. {
  1162. CRcovStrmMDTrans trans( _dst, CRcovStrmMDTrans::mdopSetSize, _cbSrc );
  1163. trans.Commit();
  1164. }
  1165. //+---------------------------------------------------------------------------
  1166. //
  1167. // Member: CCopyRcovObject::_CopyData
  1168. //
  1169. // Synopsis: Copies the data from the source object to the destination
  1170. // object.
  1171. //
  1172. // History: 3-17-97 srikants Created
  1173. //
  1174. //----------------------------------------------------------------------------
  1175. void CCopyRcovObject::_CopyData()
  1176. {
  1177. const cbPageSize = 4096; // Read and write 4k at a time.
  1178. XArray<BYTE> xByte( cbPageSize );
  1179. //
  1180. // Start a read transaction on the source object
  1181. //
  1182. CRcovStrmReadTrans srcTrans( _src );
  1183. //
  1184. // Start a write transaction on the destination.
  1185. //
  1186. CRcovStrmWriteTrans dstTrans( _dst );
  1187. dstTrans.Empty();
  1188. dstTrans.Seek(0);
  1189. ULONG cbRemaining = _cbSrc;
  1190. while ( cbRemaining > 0 )
  1191. {
  1192. ULONG cbToCopy = min( cbRemaining, cbPageSize );
  1193. srcTrans.Read( xByte.GetPointer(), cbToCopy );
  1194. dstTrans.Write( xByte.GetPointer(), cbToCopy );
  1195. cbRemaining -= cbToCopy;
  1196. }
  1197. //
  1198. // Set the user header.
  1199. //
  1200. CRcovUserHdr usrHdr;
  1201. _srcHdr.GetUserHdr( _srcHdr.GetPrimary(), usrHdr );
  1202. _dstHdr.SetUserHdr( _dstHdr.GetBackup(), usrHdr );
  1203. //
  1204. // Set the number of records.
  1205. //
  1206. ULONG nRec = _srcHdr.GetCount( _srcHdr.GetPrimary() );
  1207. _dstHdr.SetCount( _dstHdr.GetBackup(), nRec );
  1208. //
  1209. // Commit the transaction.
  1210. //
  1211. dstTrans.Commit();
  1212. }
  1213. //+---------------------------------------------------------------------------
  1214. //
  1215. // Member: CCopyRcovObject::DoIt
  1216. //
  1217. // Synopsis: Copies the contents of one object to another object.
  1218. //
  1219. // Returns: STATUS_SUCCESS if successful;
  1220. // Other error code if there is an error.
  1221. //
  1222. // History: 3-17-97 srikants Created
  1223. //
  1224. //----------------------------------------------------------------------------
  1225. NTSTATUS CCopyRcovObject::DoIt()
  1226. {
  1227. NTSTATUS status = STATUS_SUCCESS;
  1228. TRY
  1229. {
  1230. _SetDstSize();
  1231. _CopyData();
  1232. }
  1233. CATCH( CException, e )
  1234. {
  1235. status = e.GetErrorCode();
  1236. ciDebugOut(( DEB_ERROR, "CCopyRcovObject::DoIt. Error 0x%X\n", status ));
  1237. }
  1238. END_CATCH
  1239. return status;
  1240. }