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.

877 lines
25 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1992.
  5. //
  6. // File: cache.cxx
  7. //
  8. // Contents: Stream cache code
  9. //
  10. // Classes:
  11. //
  12. // Functions:
  13. //
  14. // History: 26-May-93 PhilipLa Created
  15. //
  16. //----------------------------------------------------------------------------
  17. #include "msfhead.cxx"
  18. #pragma hdrstop
  19. #include <sstream.hxx>
  20. #include <cache.hxx>
  21. #include <mread.hxx>
  22. #if DBG == 1
  23. static ULONG csTotalWalked = 0;
  24. static ULONG csSeqWalked = 0;
  25. static ULONG csRealWalked = 0;
  26. static ULONG cTotalCalls = 0;
  27. #endif
  28. inline SECT CacheStart(SCacheEntry cache)
  29. {
  30. return cache.sect;
  31. }
  32. inline SECT CacheEnd(SCacheEntry cache)
  33. {
  34. return cache.sect + cache.ulRunLength - 1;
  35. }
  36. inline ULONG CacheLength(SCacheEntry cache)
  37. {
  38. return cache.ulRunLength;
  39. }
  40. inline ULONG CacheStartOffset(SCacheEntry cache)
  41. {
  42. return cache.ulOffset;
  43. }
  44. inline ULONG CacheEndOffset(SCacheEntry cache)
  45. {
  46. return cache.ulOffset + cache.ulRunLength - 1;
  47. }
  48. //+---------------------------------------------------------------------------
  49. //
  50. // Member: CStreamCache::CheckSegment, private
  51. //
  52. // Synopsis: Given a bunch of information, determine if there is
  53. // a cache hit on a given segment and set return variables
  54. // to represent best hit.
  55. //
  56. // Arguments: [ulOffset] -- Offset being sought.
  57. // [sce] -- Stream cache entry being checked
  58. // [pulCount] -- Pointer to count of best hit so far
  59. // [psectCache] -- Pointer to sect of best hit so far
  60. // [pulCacheOffset] -- Pointer to offset of best hit so far
  61. //
  62. // Returns: TRUE if this is the best hit, FALSE otherwise.
  63. //
  64. // History: 11-Jul-94 PhilipLa Created
  65. //
  66. // Notes: This function has mega side effects. Think of it as
  67. // a typesafe #define.
  68. //
  69. //----------------------------------------------------------------------------
  70. inline BOOL CStreamCache::CheckSegment(ULONG ulOffset,
  71. SCacheEntry sce,
  72. ULONG *pulCount,
  73. SECT *psectCache,
  74. ULONG *pulCacheOffset)
  75. {
  76. if (CacheStartOffset(sce) <= ulOffset)
  77. {
  78. //We have a potential cache hit. Check the runlength to
  79. // get the best fit.
  80. if (ulOffset <= CacheEndOffset(sce))
  81. {
  82. //Direct hit.
  83. *pulCount = 0;
  84. *pulCacheOffset = ulOffset;
  85. *psectCache = CacheStart(sce) + (ulOffset - CacheStartOffset(sce));
  86. }
  87. else
  88. {
  89. if (*pulCount > ulOffset - CacheEndOffset(sce))
  90. {
  91. //The requested sector is past the end of the cached
  92. // segment. Use the endpoint as the closest hit.
  93. *pulCount = ulOffset - CacheEndOffset(sce);
  94. *psectCache = CacheEnd(sce);
  95. *pulCacheOffset = CacheEndOffset(sce);
  96. }
  97. else
  98. {
  99. return FALSE;
  100. }
  101. }
  102. msfAssert(*pulCacheOffset <= ulOffset);
  103. return TRUE;
  104. }
  105. return FALSE;
  106. }
  107. inline CDirectory * CStreamCache::GetDir(void)
  108. {
  109. return _pmsParent->GetDir();
  110. }
  111. inline CFat * CStreamCache::GetFat(void)
  112. {
  113. return _pmsParent->GetFat();
  114. }
  115. inline CFat * CStreamCache::GetMiniFat(void)
  116. {
  117. return _pmsParent->GetMiniFat();
  118. }
  119. #ifdef LARGE_STREAMS
  120. inline ULONGLONG CStreamCache::GetSize(void)
  121. #else
  122. inline ULONG CStreamCache::GetSize(void)
  123. #endif
  124. {
  125. #ifdef LARGE_STREAMS
  126. ULONGLONG ulSize = 0;
  127. #else
  128. ULONG ulSize = 0;
  129. #endif
  130. if (_pds != NULL)
  131. {
  132. _pds->CDirectStream::GetSize(&ulSize);
  133. }
  134. else
  135. {
  136. _pmsParent->GetSize(_sid, &ulSize);
  137. }
  138. return ulSize;
  139. }
  140. inline SID CStreamCache::GetSid(void)
  141. {
  142. return _sid;
  143. }
  144. //+---------------------------------------------------------------------------
  145. //
  146. // Member: CStreamCache::SelectFat, private
  147. //
  148. // Synopsis: Returns the appropriate CFat object for the cache.
  149. // If we are a control structure, then the real fat is
  150. // always the right one. Otherwise (we are a real stream)
  151. // key off of size to determine whether the minifat or
  152. // the real fat is appropriate.
  153. //
  154. // Arguments: None.
  155. //
  156. // Returns: Appropriate CFat pointer
  157. //
  158. // History: 16-Jun-94 PhilipLa Created
  159. //----------------------------------------------------------------------------
  160. inline CFat * CStreamCache::SelectFat(void)
  161. {
  162. return ((_pds == NULL) || (GetSize() >= MINISTREAMSIZE) ||
  163. (GetSid() == SIDMINISTREAM)) ? GetFat() : GetMiniFat();
  164. }
  165. //+---------------------------------------------------------------------------
  166. //
  167. // Member: CStreamCache::CacheSegment, private
  168. //
  169. // Synopsis: Store a segment in the cache.
  170. //
  171. // Arguments: [pseg] -- Pointer to segment to store
  172. //
  173. // Returns: void
  174. //
  175. // History: 19-Oct-94 PhilipLa Created
  176. //
  177. //----------------------------------------------------------------------------
  178. void CStreamCache::CacheSegment(SSegment *pseg)
  179. {
  180. USHORT iCache;
  181. if (_uNextCacheIndex >= CACHESIZE)
  182. {
  183. _uNextCacheIndex = 0;
  184. }
  185. iCache = _uNextCacheIndex;
  186. _ase[iCache].ulOffset = SegStartOffset(*pseg);
  187. _ase[iCache].ulRunLength = SegLength(*pseg);
  188. _ase[iCache].sect = SegStart(*pseg);
  189. _uNextCacheIndex++;
  190. _uHighCacheIndex = (USHORT) max(_uHighCacheIndex, iCache + 1);
  191. //_uCacheState can be used to determine if the cache has changed.
  192. _uCacheState++;
  193. }
  194. //+---------------------------------------------------------------------------
  195. //
  196. // Member: CStreamCache::GetStart, private
  197. //
  198. // Synopsis: Get start sector for this chain
  199. //
  200. // Arguments: [psectStart] -- Return location
  201. //
  202. // Returns: Appropriate status code
  203. //
  204. // History: 01-Jun-94 PhilipLa Created
  205. //
  206. //----------------------------------------------------------------------------
  207. SCODE CStreamCache::GetStart(SECT *psectStart)
  208. {
  209. SCODE sc = S_OK;
  210. if (_pds != NULL)
  211. {
  212. //We're a normal stream, so get the start sect from the
  213. // directory.
  214. sc = GetDir()->GetStart(_sid, psectStart);
  215. }
  216. else
  217. {
  218. //We're a control stream, so get the start sect from the
  219. // multistream.
  220. *psectStart = _pmsParent->GetStart(_sid);
  221. }
  222. return sc;
  223. }
  224. //+---------------------------------------------------------------------------
  225. //
  226. // Member: CStreamCache::CStreamCache, public
  227. //
  228. // Synopsis: CStreamCache constructor
  229. //
  230. // History: 14-Dec-92 PhilipLa Created
  231. //
  232. //----------------------------------------------------------------------------
  233. CStreamCache::CStreamCache()
  234. {
  235. _sid = NOSTREAM;
  236. _pmsParent = NULL;
  237. _pds = NULL;
  238. _uHighCacheIndex = 0;
  239. _uNextCacheIndex = 0;
  240. _uCacheState = 0;
  241. }
  242. CStreamCache::~CStreamCache()
  243. {
  244. #if DBG == 1
  245. msfDebugOut((DEB_ITRACE,
  246. "Cache stats: Total = %lu Seq = %lu Real = %lu Calls = %lu\n",
  247. csTotalWalked, csSeqWalked, csRealWalked, cTotalCalls));
  248. #endif
  249. }
  250. void CStreamCache::Init(CMStream *pmsParent, SID sid, CDirectStream *pds)
  251. {
  252. _pmsParent = P_TO_BP(CBasedMStreamPtr, pmsParent);
  253. _sid = sid;
  254. _pds = P_TO_BP(CBasedDirectStreamPtr, pds);
  255. Empty();
  256. }
  257. void CStreamCache::Empty(void)
  258. {
  259. for (USHORT uIndex = 0; uIndex < CACHESIZE; uIndex++)
  260. {
  261. _ase[uIndex].ulOffset = MAX_ULONG;
  262. _ase[uIndex].sect = ENDOFCHAIN;
  263. _ase[uIndex].ulRunLength = 0;
  264. }
  265. _uHighCacheIndex = 0;
  266. _uNextCacheIndex = 0;
  267. _uCacheState++;
  268. }
  269. //+---------------------------------------------------------------------------
  270. //
  271. // Member: CStreamCache::GetSect, public
  272. //
  273. // Synopsis: Retrieve a SECT from the cache given an offset
  274. //
  275. // Arguments: [ulOffset] -- Offset to look up.
  276. // [psect] -- Location for return value
  277. //
  278. // Returns: Appropriate status code
  279. //
  280. // History: 26-May-93 PhilipLa Created
  281. //
  282. //----------------------------------------------------------------------------
  283. SCODE CStreamCache::GetSect(ULONG ulOffset, SECT *psect)
  284. {
  285. SCODE sc = S_OK;
  286. CFat *pfat;
  287. USHORT iCache = 0;
  288. ULONG ulCount = MAX_ULONG;
  289. SECT sectCache = ENDOFCHAIN;
  290. ULONG ulCacheOffset = MAX_ULONG;
  291. *psect = ENDOFCHAIN;
  292. pfat = SelectFat();
  293. for (USHORT iCacheLoop = 0; iCacheLoop < _uHighCacheIndex; iCacheLoop++)
  294. {
  295. if (CheckSegment(ulOffset,
  296. _ase[iCacheLoop],
  297. &ulCount,
  298. &sectCache,
  299. &ulCacheOffset))
  300. {
  301. //Cache hit.
  302. }
  303. }
  304. //We now have the best hit from the cache. If it is exact, return
  305. // now.
  306. if (ulCount == 0)
  307. {
  308. *psect = sectCache;
  309. return S_OK;
  310. }
  311. if (ulCacheOffset == MAX_ULONG)
  312. {
  313. //No cache hit.
  314. msfChk(GetStart(&sectCache));
  315. ulCacheOffset = 0;
  316. }
  317. //Otherwise, go to the fat and get the real thing.
  318. #if DBG == 1 && defined(CHECKLENGTH)
  319. SECT sectStart;
  320. ULONG ulLengthOld, ulLengthNew;
  321. GetStart(&sectStart);
  322. pfat->GetLength(sectStart, &ulLengthOld);
  323. #endif
  324. SSegment segtab[CSEG + 1];
  325. ULONG ulSegCount;
  326. while (TRUE)
  327. {
  328. msfChk(pfat->Contig(
  329. segtab,
  330. FALSE,
  331. sectCache,
  332. ulOffset - ulCacheOffset + 1,
  333. &ulSegCount));
  334. if (ulSegCount <= CSEG)
  335. {
  336. //We're done.
  337. break;
  338. }
  339. //We need to call Contig again. Update ulCacheOffset and
  340. //sectCache to be the last sector in the current table.
  341. ulCacheOffset = ulCacheOffset + SegEndOffset(segtab[CSEG - 1]);
  342. sectCache = SegEnd(segtab[CSEG - 1]);
  343. }
  344. //Last segment is in segtab[ulSegCount - 1].
  345. //ulSegOffset is the absolute offset within the stream of the first
  346. //sector in the last segment.
  347. ULONG ulSegOffset;
  348. ulSegOffset = ulCacheOffset + SegStartOffset(segtab[ulSegCount - 1]);
  349. msfAssert(ulSegOffset <= ulOffset);
  350. msfAssert(ulOffset < ulSegOffset + SegLength(segtab[ulSegCount - 1]));
  351. *psect = SegStart(segtab[ulSegCount - 1]) + (ulOffset - ulSegOffset);
  352. //Now, stick the last segment into our cache. We need to update
  353. // the ulOffset field to be the absolute offset (i.e. ulSegOffset)
  354. // before calling CacheSegment().
  355. segtab[ulSegCount - 1].ulOffset = ulSegOffset;
  356. CacheSegment(&(segtab[ulSegCount - 1]));
  357. #if DBG == 1 && defined(CHECKLENGTH)
  358. //Confirm that the chain hasn't grown.
  359. pfat->GetLength(sectStart, &ulLengthNew);
  360. msfAssert(ulLengthOld == ulLengthNew);
  361. //Confirm that we're getting the right sector.
  362. SECT sectCheck;
  363. pfat->GetSect(sectStart, ulOffset, &sectCheck);
  364. msfAssert(*psect == sectCheck);
  365. #endif
  366. Err:
  367. return sc;
  368. }
  369. //+---------------------------------------------------------------------------
  370. //
  371. // Member: CStreamCache::GetESect, public
  372. //
  373. // Synopsis: Retrieve a SECT from the cache given an offset, extending
  374. // the stream if necessary.
  375. //
  376. // Arguments: [ulOffset] -- Offset to look up.
  377. // [psect] -- Location for return value
  378. //
  379. // Returns: Appropriate status code
  380. //
  381. // History: 26-May-93 PhilipLa Created
  382. //
  383. //----------------------------------------------------------------------------
  384. SCODE CStreamCache::GetESect(ULONG ulOffset, SECT *psect)
  385. {
  386. SCODE sc = S_OK;
  387. CFat *pfat;
  388. USHORT iCache = 0;
  389. ULONG ulCount = MAX_ULONG;
  390. SECT sectCache = ENDOFCHAIN;
  391. ULONG ulCacheOffset = MAX_ULONG;
  392. USHORT uCacheHit = CACHESIZE + 1;
  393. *psect = ENDOFCHAIN;
  394. pfat = SelectFat();
  395. for (USHORT iCacheLoop = 0; iCacheLoop < _uHighCacheIndex; iCacheLoop++)
  396. {
  397. if (CheckSegment(ulOffset,
  398. _ase[iCacheLoop],
  399. &ulCount,
  400. &sectCache,
  401. &ulCacheOffset))
  402. {
  403. uCacheHit = iCacheLoop;
  404. //Cache hit.
  405. }
  406. }
  407. //We now have the best hit from the cache. If it is exact, return
  408. // now.
  409. if (ulCount == 0)
  410. {
  411. *psect = sectCache;
  412. return S_OK;
  413. }
  414. if (ulCacheOffset == MAX_ULONG)
  415. {
  416. //No cache hit.
  417. msfChk(GetStart(&sectCache));
  418. ulCacheOffset = 0;
  419. }
  420. //Otherwise, go to the fat and get the real thing.
  421. SSegment segtab[CSEG + 1];
  422. ULONG ulSegCount;
  423. while (TRUE)
  424. {
  425. msfChk(pfat->Contig(
  426. segtab,
  427. TRUE,
  428. sectCache,
  429. ulOffset - ulCacheOffset + 1,
  430. &ulSegCount));
  431. if (ulSegCount <= CSEG)
  432. {
  433. //We're done.
  434. break;
  435. }
  436. //We need to call Contig again. Update ulCacheOffset and
  437. //sectCache to be the last sector in the current table.
  438. ulCacheOffset = ulCacheOffset + SegEndOffset(segtab[CSEG - 1]);
  439. sectCache = SegEnd(segtab[CSEG - 1]);
  440. }
  441. //Last segment is in segtab[ulSegCount - 1].
  442. //ulSegOffset is the absolute offset within the stream of the first
  443. //sector in the last segment.
  444. ULONG ulSegOffset;
  445. ulSegOffset = ulCacheOffset + SegStartOffset(segtab[ulSegCount - 1]);
  446. msfAssert(ulSegOffset <= ulOffset);
  447. msfAssert(ulOffset < ulSegOffset + SegLength(segtab[ulSegCount - 1]));
  448. *psect = SegStart(segtab[ulSegCount - 1]) + (ulOffset - ulSegOffset);
  449. segtab[ulSegCount - 1].ulOffset = ulSegOffset;
  450. //If we grew the chain with this call, we may need to merge the
  451. // new segment with the previous best-hit in our cache.
  452. // Otherwise, we end up with excessive fragmentation.
  453. if ((uCacheHit != CACHESIZE + 1) &&
  454. (SegStart(segtab[ulSegCount - 1]) <= CacheEnd(_ase[uCacheHit]) + 1) &&
  455. (SegStart(segtab[ulSegCount - 1]) > CacheStart(_ase[uCacheHit])) &&
  456. (SegStartOffset(segtab[ulSegCount - 1]) <=
  457. CacheEndOffset(_ase[uCacheHit]) + 1))
  458. {
  459. //We can merge the two.
  460. _ase[uCacheHit].ulRunLength += (SegLength(segtab[ulSegCount - 1]) -
  461. (CacheEnd(_ase[uCacheHit]) + 1 -
  462. SegStart(segtab[ulSegCount - 1])));
  463. _uCacheState++;
  464. }
  465. else
  466. {
  467. //Now, stick the last segment into our cache. We need to update
  468. // the ulOffset field to be the absolute offset (i.e. ulSegOffset)
  469. // before calling CacheSegment().
  470. CacheSegment(&(segtab[ulSegCount - 1]));
  471. }
  472. #if DBG == 1
  473. //Confirm that we're getting the right sector.
  474. SECT sectCheck;
  475. SECT sectStart;
  476. msfChk(GetStart(&sectStart));
  477. pfat->GetESect(sectStart, ulOffset, &sectCheck);
  478. msfAssert(*psect == sectCheck);
  479. #endif
  480. Err:
  481. return sc;
  482. }
  483. //+---------------------------------------------------------------------------
  484. //
  485. // Member: CStreamCache::EmptyRegion, public
  486. //
  487. // Synopsis: Invalidate cached values for a segment that has been
  488. // remapped
  489. //
  490. // Arguments: [oStart] -- Offset marking first remapped sector
  491. // [oEnd] -- Offset marking last remapped sector
  492. //
  493. // Returns: Appropriate status code
  494. //
  495. // History: 26-May-93 PhilipLa Created
  496. //
  497. //----------------------------------------------------------------------------
  498. SCODE CStreamCache::EmptyRegion(ULONG oStart, ULONG oEnd)
  499. {
  500. for (USHORT i = 0; i < CACHESIZE; i ++)
  501. {
  502. ULONG ulStart = CacheStartOffset(_ase[i]);
  503. ULONG ulEnd = CacheEndOffset(_ase[i]);
  504. if ((ulStart <= oEnd) && (ulEnd >= oStart))
  505. {
  506. //There are 3 possible cases:
  507. // 1) The cache entry is completely contained in the
  508. // region being invalidated.
  509. // 2) The front part of the cache entry is contained in
  510. // the region being invalidated.
  511. // 3) The tail part of the cache entry is contained in
  512. // the region being validated.
  513. if ((oStart <= ulStart) && (oEnd >= ulEnd))
  514. {
  515. //Invalidate the entire thing.
  516. _ase[i].ulOffset = MAX_ULONG;
  517. _ase[i].sect = ENDOFCHAIN;
  518. _ase[i].ulRunLength = 0;
  519. }
  520. else if (oStart <= ulStart)
  521. {
  522. #if DBG == 1
  523. ULONG ulCacheStart = _ase[i].ulOffset;
  524. SECT sectCache = _ase[i].sect;
  525. ULONG ulCacheLength = _ase[i].ulRunLength;
  526. #endif
  527. //Invalidate the front of the cache entry
  528. ULONG ulInvalid;
  529. ulInvalid = oEnd - ulStart + 1;
  530. _ase[i].ulOffset += ulInvalid;
  531. msfAssert(_ase[i].ulRunLength > ulInvalid);
  532. _ase[i].sect += ulInvalid;
  533. _ase[i].ulRunLength -= ulInvalid;
  534. #if DBG == 1
  535. //Make sure our cache is still within the old valid range.
  536. msfAssert((_ase[i].ulOffset >= ulCacheStart) &&
  537. (_ase[i].ulOffset <=
  538. ulCacheStart + ulCacheLength - 1));
  539. msfAssert(_ase[i].ulRunLength <= ulCacheLength);
  540. msfAssert(_ase[i].ulRunLength > 0);
  541. msfAssert((_ase[i].sect >= sectCache) &&
  542. (_ase[i].sect <= sectCache + ulCacheLength - 1));
  543. #endif
  544. }
  545. else
  546. {
  547. #if DBG == 1
  548. ULONG ulCacheStart = _ase[i].ulOffset;
  549. SECT sectCache = _ase[i].sect;
  550. ULONG ulCacheLength = _ase[i].ulRunLength;
  551. #endif
  552. //Invalidate the tail of the cache entry
  553. ULONG ulInvalid;
  554. ulInvalid = ulEnd - oStart + 1;
  555. msfAssert(_ase[i].ulRunLength > ulInvalid);
  556. _ase[i].ulRunLength -= ulInvalid;
  557. #if DBG == 1
  558. //Make sure our cache is still within the old valid range.
  559. msfAssert((_ase[i].ulOffset >= ulCacheStart) &&
  560. (_ase[i].ulOffset <=
  561. ulCacheStart + ulCacheLength - 1));
  562. msfAssert(_ase[i].ulRunLength <= ulCacheLength);
  563. msfAssert(_ase[i].ulRunLength > 0);
  564. msfAssert((_ase[i].sect >= sectCache) &&
  565. (_ase[i].sect <= sectCache + ulCacheLength - 1));
  566. #endif
  567. }
  568. _uCacheState++;
  569. }
  570. }
  571. return S_OK;
  572. }
  573. //+---------------------------------------------------------------------------
  574. //
  575. // Member: CStreamCache::Contig, public
  576. //
  577. // Synopsis: Return a contig table from a given offset and runlength
  578. //
  579. // Arguments: [ulOffset] -- Offset to begin contiguity check at
  580. // [fWrite] -- TRUE if segment is to be written to.
  581. // [aseg] -- Pointer to SSegment array
  582. // [ulLength] -- Run length of sectors to return table for
  583. //
  584. // Returns: Appropriate status code
  585. //
  586. // History: 21-Apr-94 PhilipLa Created
  587. //
  588. //----------------------------------------------------------------------------
  589. SCODE CStreamCache::Contig(
  590. ULONG ulOffset,
  591. BOOL fWrite,
  592. SSegment STACKBASED *aseg,
  593. ULONG ulLength,
  594. ULONG *pcSeg)
  595. {
  596. SCODE sc;
  597. msfDebugOut((DEB_ITRACE, "In CStreamCache::Contig:%p()\n", this));
  598. SECT sect;
  599. USHORT uCacheState;
  600. CFat *pfat;
  601. for (USHORT iCache = 0; iCache < _uHighCacheIndex; iCache++)
  602. {
  603. //Look for direct hit.
  604. if ((ulOffset >= _ase[iCache].ulOffset) &&
  605. (ulOffset < _ase[iCache].ulOffset + _ase[iCache].ulRunLength))
  606. {
  607. //Direct hit. Return this segment.
  608. ULONG ulCacheOffset = ulOffset - _ase[iCache].ulOffset;
  609. aseg[0].ulOffset = ulOffset;
  610. aseg[0].sectStart = _ase[iCache].sect + ulCacheOffset;
  611. aseg[0].cSect = _ase[iCache].ulRunLength - ulCacheOffset;
  612. *pcSeg = 1;
  613. return S_OK;
  614. }
  615. }
  616. uCacheState = _uCacheState;
  617. if (fWrite)
  618. {
  619. //This can grow the chain, so get the whole thing at once
  620. // instead of one sector at a time. Chances are good that
  621. // the second GetESect call will be fed from the cache, so
  622. // this won't be too expensive in the common case.
  623. //Ideally, we'd like to make this first call only when we
  624. // know the stream is growing. There isn't a convenient
  625. // way to detect that here, though.
  626. msfChk(GetESect(ulOffset + ulLength - 1, &sect));
  627. msfChk(GetESect(ulOffset, &sect));
  628. }
  629. else
  630. {
  631. msfChk(GetSect(ulOffset, &sect));
  632. }
  633. //The GetSect() or GetESect() call may have actually snagged the
  634. // segment we need, so check the cache again. If _uCacheState
  635. // changed in the duration of the call, we know that something
  636. // new is in the cache, so we go look again.
  637. if (uCacheState != _uCacheState)
  638. {
  639. for (USHORT iCache = 0; iCache < _uHighCacheIndex; iCache++)
  640. {
  641. //Look for direct hit.
  642. if ((ulOffset >= _ase[iCache].ulOffset) &&
  643. (ulOffset < _ase[iCache].ulOffset + _ase[iCache].ulRunLength))
  644. {
  645. //Direct hit. Return this segment.
  646. ULONG ulCacheOffset = ulOffset - _ase[iCache].ulOffset;
  647. aseg[0].ulOffset = ulOffset;
  648. aseg[0].sectStart = _ase[iCache].sect + ulCacheOffset;
  649. aseg[0].cSect = _ase[iCache].ulRunLength - ulCacheOffset;
  650. *pcSeg = 1;
  651. return S_OK;
  652. }
  653. }
  654. }
  655. pfat = SelectFat();
  656. msfChk(pfat->Contig(aseg, fWrite, sect, ulLength, pcSeg));
  657. //At this point, we can peek at the contig table and pick out
  658. // the choice entries to put in the cache.
  659. //For the first pass, we just grab the last thing in the Contig
  660. //table and cache it.
  661. aseg[*pcSeg - 1].ulOffset += ulOffset;
  662. CacheSegment(&(aseg[*pcSeg - 1]));
  663. Err:
  664. return sc;
  665. }
  666. //+---------------------------------------------------------------------------
  667. //
  668. // Member: CStreamCache::Allocate, public
  669. //
  670. // Synopsis: Allocate a new chain for a stream, returning the start
  671. // sector and caching the appropriate amount of contig
  672. // information.
  673. //
  674. // Arguments: [pfat] -- Pointer to fat to allocate in
  675. // [cSect] -- Number of sectors to allocate
  676. // [psectStart] -- Returns starts sector for chain
  677. //
  678. // Returns: Appropriate status code
  679. //
  680. // History: 19-Oct-94 PhilipLa Created
  681. //
  682. //----------------------------------------------------------------------------
  683. SCODE CStreamCache::Allocate(CFat *pfat, ULONG cSect, SECT *psectStart)
  684. {
  685. SCODE sc;
  686. msfAssert((_uHighCacheIndex == 0) &&
  687. aMsg("Called Allocate with non-empty buffer"));
  688. #ifndef CACHE_ALLOCATE_OPTIMIZATION
  689. //This will allocate the complete requested chain. We'll then
  690. // walk over that chain again in the Contig() call, which isn't
  691. // optimal. Ideally, we'd like GetFree() to return us the
  692. // contiguity information, but that's a fairly major change.
  693. // Consider it for future optimization work.
  694. msfChk(pfat->GetFree(cSect, psectStart, GF_WRITE));
  695. #else
  696. //Get the first sector (to simplify Contig code)
  697. //First reserve enough free sectors for the whole thing.
  698. msfChk(pfat->ReserveSects(cSect));
  699. msfChk(pfat->GetFree(1, psectStart, GF_WRITE));
  700. #endif
  701. SSegment segtab[CSEG + 1];
  702. ULONG ulSegCount;
  703. ULONG ulSegStart;
  704. SECT sectSegStart;
  705. sectSegStart = *psectStart;
  706. ulSegStart = 0;
  707. while (TRUE)
  708. {
  709. msfChk(pfat->Contig(
  710. segtab,
  711. TRUE,
  712. sectSegStart,
  713. cSect - ulSegStart,
  714. &ulSegCount));
  715. if (ulSegCount <= CSEG)
  716. {
  717. //We're done.
  718. break;
  719. }
  720. //We need to call Contig again. Update ulSegStart and
  721. //sectSegStart to be the last sector in the current table.
  722. ulSegStart = ulSegStart + SegEndOffset(segtab[CSEG - 1]);
  723. sectSegStart = SegEnd(segtab[CSEG - 1]);
  724. }
  725. //Last segment is in segtab[ulSegCount - 1].
  726. //ulSegOffset is the absolute offset within the stream of the first
  727. //sector in the last segment.
  728. ULONG ulSegOffset;
  729. ulSegOffset = ulSegStart + SegStartOffset(segtab[ulSegCount - 1]);
  730. //Now, stick the last segment into our cache. We need to update
  731. // the ulOffset field to be the absolute offset (i.e. ulSegOffset)
  732. // before calling CacheSegment().
  733. segtab[ulSegCount - 1].ulOffset = ulSegOffset;
  734. CacheSegment(&(segtab[ulSegCount - 1]));
  735. #if DBG == 1 && defined(CHECKLENGTH)
  736. ULONG ulLength;
  737. pfat->GetLength(*psectStart, &ulLength);
  738. msfAssert(ulLength == cSect);
  739. #endif
  740. Err:
  741. return sc;
  742. }