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.

1134 lines
29 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. blrange.c
  5. Abstract:
  6. This module implements ranges and rangelists. These can be used
  7. to keep track of cached ranges of a disk for instance.
  8. Author:
  9. Cenk Ergan (cenke) 11-Jan-2000
  10. Revision History:
  11. --*/
  12. #include "blrange.h"
  13. //
  14. // Range function definitions.
  15. //
  16. VOID
  17. BlRangeListInitialize (
  18. PBLCRANGE_LIST pRangeList,
  19. OPTIONAL PBLCRANGE_MERGE_ROUTINE pMergeRoutine,
  20. OPTIONAL PBLCRANGE_FREE_ROUTINE pFreeRoutine
  21. )
  22. /*++
  23. Routine Description:
  24. This routine initializes the range list whose address is passed in
  25. so it can be used by the other range functions.
  26. Arguments:
  27. pRangeList - Address of the range list to initialize.
  28. pMergeRoutine - Optional routine to merge Data fields of merged
  29. range entries. See PBLCRANGE_MERGE_ROUTINE description.
  30. pFreeRoutine - Optional routine to free the memory for an entry
  31. that was merged into another. See PBLCRANGE_FREE_ROUTINE desc.
  32. Return Value:
  33. None. [Always successful]
  34. --*/
  35. {
  36. InitializeListHead(&pRangeList->Head);
  37. pRangeList->NumEntries = 0;
  38. pRangeList->MergeRoutine = pMergeRoutine;
  39. pRangeList->FreeRoutine = pFreeRoutine;
  40. }
  41. BOOLEAN
  42. BlRangeListAddRange (
  43. PBLCRANGE_LIST pRangeList,
  44. PBLCRANGE_ENTRY pRangeEntry
  45. )
  46. /*++
  47. Routine Description:
  48. This routine adds pRangeEntry to pRangeList only if it does not
  49. have any overlap with other ranges in the list and its size > 0;
  50. If merging becomes possible it is attempted. It does not have to
  51. be successful.
  52. Arguments:
  53. pRangeList - Address of the range list to add range to.
  54. pRangeEntry - Range to add to pRangeList.
  55. Return Value:
  56. TRUE if addition is successful [even if merging was possible but failed]
  57. FALSE if not [e.g. overlap/collusion]
  58. --*/
  59. {
  60. PBLCRANGE_ENTRY pCurEntry = NULL;
  61. PBLCRANGE_ENTRY pLastEntry = NULL;
  62. LIST_ENTRY *pHead, *pNext;
  63. //
  64. // Handle special empty range case.
  65. //
  66. if (pRangeEntry->Range.Start == pRangeEntry->Range.End)
  67. return TRUE;
  68. //
  69. // Walk through the ranges in the sorted list checking for
  70. // overlaps and looking for the right place for us.
  71. //
  72. pHead = &pRangeList->Head;
  73. pNext = pHead->Flink;
  74. while (pNext != pHead)
  75. {
  76. pCurEntry = CONTAINING_RECORD(pNext, BLCRANGE_ENTRY, Link);
  77. //
  78. // Check if we are completely before this entry.
  79. //
  80. if (pRangeEntry->Range.End <= pCurEntry->Range.Start)
  81. {
  82. //
  83. // Insert the new entry at its place.
  84. //
  85. InsertTailList(pNext, &pRangeEntry->Link);
  86. pRangeList->NumEntries++;
  87. //
  88. // Check if merging is possible.
  89. //
  90. if (pLastEntry && (pRangeEntry->Range.Start == pLastEntry->Range.End))
  91. {
  92. BlRangeListMergeRangeEntries(
  93. pRangeList,
  94. pRangeEntry,
  95. pLastEntry
  96. );
  97. }
  98. if (pRangeEntry->Range.End == pCurEntry->Range.Start)
  99. {
  100. BlRangeListMergeRangeEntries(
  101. pRangeList,
  102. pRangeEntry,
  103. pCurEntry
  104. );
  105. }
  106. return TRUE;
  107. }
  108. //
  109. // Check if we are not completely after this entry.
  110. //
  111. if (pRangeEntry->Range.Start < pCurEntry->Range.End)
  112. {
  113. //
  114. // We have an overlapping range.
  115. //
  116. return FALSE;
  117. }
  118. //
  119. // We come after this entry.
  120. //
  121. pLastEntry = pCurEntry;
  122. pNext = pNext->Flink;
  123. }
  124. //
  125. // We come after the last entry [if there is one], i.e. before the head.
  126. // Insert the new entry and check if merging is possible.
  127. //
  128. InsertTailList(pHead, &pRangeEntry->Link);
  129. pRangeList->NumEntries++;
  130. if (pLastEntry && (pRangeEntry->Range.Start == pLastEntry->Range.End))
  131. {
  132. BlRangeListMergeRangeEntries(
  133. pRangeList,
  134. pRangeEntry,
  135. pLastEntry
  136. );
  137. }
  138. return TRUE;
  139. }
  140. BOOLEAN
  141. BlRangeListFindOverlaps (
  142. PBLCRANGE_LIST pRangeList,
  143. PBLCRANGE pRange,
  144. PBLCRANGE_ENTRY *pOverlapsBuffer,
  145. ULONG OverlapsBufferSize,
  146. OUT ULONG *pNumOverlaps
  147. )
  148. /*++
  149. Routine Description:
  150. This routine will find ranges in pRangeList that overlap with
  151. pRange and put pointers to them into pOverlapsBuffer one after the
  152. other. If all overlapping ranges cannot be copied because
  153. pOverlapsBuffer is NULL or OverlapsBufferSize is 0 or not enough,
  154. the function will return FALSE and but still put the number of
  155. overlapping ranges in pNumOverlaps. You can calculate the required
  156. buffer size from this.
  157. Arguments:
  158. pRangeList - Address of the range list to search for overlaps.
  159. pRange - We will look for range entries that overlap with pRange.
  160. pOverlapsBuffer - Pointer to buffer we can fill with pointers to
  161. overlapping ranges.
  162. OverlapsBufferSize - Size up to which we can fill pOverlapsBuffer.
  163. pNumOverlaps - Number of overlapping ranges will always be put
  164. here.
  165. Return Value:
  166. TRUE if successful, FALSE if not.
  167. --*/
  168. {
  169. PBLCRANGE_ENTRY pCurEntry;
  170. LIST_ENTRY *pHead, *pNext;
  171. ULONG NumOverlaps = 0;
  172. ULONG RequiredOverlapsBufferSize = 0;
  173. //
  174. // Handle special empty range case.
  175. //
  176. if (pRange->Start == pRange->End)
  177. {
  178. *pNumOverlaps = NumOverlaps;
  179. return (BOOLEAN)(pOverlapsBuffer != NULL);
  180. }
  181. //
  182. // Walk through the ranges in the sorted list and copy over ones
  183. // that overlap into callers buffer if there is enough space.
  184. //
  185. pHead = &pRangeList->Head;
  186. pNext = pHead->Flink;
  187. while (pNext != pHead)
  188. {
  189. pCurEntry = CONTAINING_RECORD(pNext, BLCRANGE_ENTRY, Link);
  190. if ((pRange->End > pCurEntry->Range.Start) &&
  191. (pRange->Start < pCurEntry->Range.End))
  192. {
  193. //
  194. // This entry overlaps.
  195. //
  196. RequiredOverlapsBufferSize += sizeof(PBLCRANGE_ENTRY);
  197. if (pOverlapsBuffer &&
  198. (OverlapsBufferSize >= RequiredOverlapsBufferSize))
  199. {
  200. pOverlapsBuffer[NumOverlaps] = pCurEntry;
  201. }
  202. NumOverlaps++;
  203. }
  204. pNext = pNext->Flink;
  205. }
  206. *pNumOverlaps = NumOverlaps;
  207. return ((BOOLEAN)(pOverlapsBuffer &&
  208. (OverlapsBufferSize >= RequiredOverlapsBufferSize)));
  209. }
  210. BOOLEAN
  211. BlRangeListFindDistinctRanges (
  212. PBLCRANGE_LIST pRangeList,
  213. PBLCRANGE pRange,
  214. PBLCRANGE pDistinctRanges,
  215. ULONG BufferSize,
  216. OUT ULONG *pNumRanges
  217. )
  218. /*++
  219. Routine Description:
  220. This routine will look at ranges in pRangeList that overlap with
  221. pRange and extract the overlaps from pRange, thus keeping track of
  222. those ranges that are distinct. If all distinct ranges cannot be
  223. put into pDistinctRanges buffer because pDistinctRanges is NULL or
  224. BufferSize is 0 or not enough, the function will return FALSE and
  225. but still put the number of resulting distinct ranges in
  226. pNumRanges. You can calculate the required buffer size from
  227. this.
  228. Arguments:
  229. pRangeList - Address of the range list.
  230. pRange - We will extract distinct ranges in pRange that do not
  231. overlap with other ranges in pRangeList.
  232. pDistinctRanges - Pointer to buffer we can fill with distinct
  233. ranges.
  234. BufferSize - Size up to which we can fill pDistinctRanges buffer.
  235. pNumRanges - Number of resulting distinct ranges will always be
  236. put here.
  237. Return Value:
  238. TRUE if successful, FALSE if not.
  239. --*/
  240. {
  241. PBLCRANGE_ENTRY pCurEntry;
  242. BLCRANGE RemainingRange = *pRange;
  243. ULONGLONG OverlapStart;
  244. ULONGLONG OverlapEnd;
  245. LIST_ENTRY *pHead, *pNext;
  246. ULONG NumRanges = 0;
  247. ULONG RequiredBufferSize = 0;
  248. if (pRange->Start == pRange->End)
  249. {
  250. *pNumRanges = NumRanges;
  251. return (BOOLEAN)(pDistinctRanges != NULL);
  252. }
  253. //
  254. // Looking at each range in the sorted list, we carve out overlap
  255. // and distinct zones from the start of our range.
  256. //
  257. pHead = &pRangeList->Head;
  258. pNext = pHead->Flink;
  259. while (pNext != pHead)
  260. {
  261. pCurEntry = CONTAINING_RECORD(pNext, BLCRANGE_ENTRY, Link);
  262. //
  263. // Is there still anything remaining from the range that we
  264. // have not carved out as overlap or distinct?
  265. //
  266. if (RemainingRange.Start >= RemainingRange.End)
  267. break;
  268. //
  269. // There are three possibilities:
  270. //
  271. //
  272. // 1. Is the range completely before the current range?
  273. //
  274. if (RemainingRange.End <= pCurEntry->Range.Start)
  275. {
  276. //
  277. // The whole range is distinct.
  278. //
  279. RequiredBufferSize += sizeof(BLCRANGE);
  280. if (pDistinctRanges && (RequiredBufferSize <= BufferSize))
  281. {
  282. pDistinctRanges[NumRanges].Start = RemainingRange.Start;
  283. pDistinctRanges[NumRanges].End = RemainingRange.End;
  284. }
  285. NumRanges++;
  286. RemainingRange.Start = RemainingRange.End;
  287. }
  288. //
  289. // 2. Are we completely beyond the current range?
  290. //
  291. if (RemainingRange.Start >= pCurEntry->Range.End)
  292. {
  293. //
  294. // We cannot carve out anything from the remaining range.
  295. // Fall through to processing the next entry.
  296. //
  297. }
  298. //
  299. // 3. Is the remaining range overlaps with the current range.
  300. //
  301. if ((RemainingRange.End > pCurEntry->Range.Start) &&
  302. (RemainingRange.Start < pCurEntry->Range.End))
  303. {
  304. OverlapStart = BLRGMAX(RemainingRange.Start,
  305. pCurEntry->Range.Start);
  306. OverlapEnd = BLRGMIN(RemainingRange.End,
  307. pCurEntry->Range.End);
  308. if (OverlapStart > pRange->Start)
  309. {
  310. //
  311. // There is a distinct region before the overlap
  312. //
  313. RequiredBufferSize += sizeof(BLCRANGE);
  314. if (pDistinctRanges && (RequiredBufferSize <= BufferSize))
  315. {
  316. pDistinctRanges[NumRanges].Start = RemainingRange.Start;
  317. pDistinctRanges[NumRanges].End = OverlapStart;
  318. }
  319. NumRanges++;
  320. }
  321. RemainingRange.Start = OverlapEnd;
  322. }
  323. pNext = pNext->Flink;
  324. }
  325. //
  326. // The remaining range (if there is any) is also distinct.
  327. //
  328. if (RemainingRange.Start < RemainingRange.End)
  329. {
  330. RequiredBufferSize += sizeof(BLCRANGE);
  331. if (pDistinctRanges && (RequiredBufferSize <= BufferSize))
  332. {
  333. pDistinctRanges[NumRanges].Start = RemainingRange.Start;
  334. pDistinctRanges[NumRanges].End = RemainingRange.End;
  335. }
  336. NumRanges++;
  337. }
  338. *pNumRanges = NumRanges;
  339. return ((BOOLEAN)(pDistinctRanges &&
  340. RequiredBufferSize <= BufferSize));
  341. }
  342. BOOLEAN
  343. BlRangeListMergeRangeEntries (
  344. PBLCRANGE_LIST pRangeList,
  345. PBLCRANGE_ENTRY pDestEntry,
  346. PBLCRANGE_ENTRY pSrcEntry
  347. )
  348. /*++
  349. Routine Description:
  350. Merges SrcEntry and DestEntry range entries into DestEntry by
  351. calling BlRangeEntryMerge. If successful it tries to remove
  352. pSrcEntry from the range list it is in and free its memory by
  353. calling the FreeRoutine specified on the list.
  354. Arguments:
  355. pRangeList - Range list pDestEntry and pSrcEntry belong to.
  356. pDestEntry - Range entry that we will merge into.
  357. pSrcEntry - Range entry that will be merged into pDestEntry,
  358. removed from its list and free'ed.
  359. Return Value:
  360. TRUE if successful, FALSE if not. The success is mainly determined
  361. by calls to a MergeRoutine if specified on the list.
  362. --*/
  363. {
  364. if(BlRangeEntryMerge(pDestEntry,
  365. pSrcEntry,
  366. pRangeList->MergeRoutine))
  367. {
  368. //
  369. // Remove pSrcEntry from the list since it is merged into
  370. // pDestEntry now.
  371. //
  372. pRangeList->NumEntries--;
  373. RemoveEntryList(&pSrcEntry->Link);
  374. //
  375. // Free the removed entry.
  376. //
  377. if (pRangeList->FreeRoutine) pRangeList->FreeRoutine(pSrcEntry);
  378. return TRUE;
  379. }
  380. else
  381. {
  382. return FALSE;
  383. }
  384. }
  385. BOOLEAN
  386. BlRangeEntryMerge (
  387. PBLCRANGE_ENTRY pDestEntry,
  388. PBLCRANGE_ENTRY pSrcEntry,
  389. OPTIONAL PBLCRANGE_MERGE_ROUTINE pMergeRoutine
  390. )
  391. /*++
  392. Routine Description:
  393. Merges SrcEntry and DestEntry range entries into DestEntry. It
  394. uses pMergeRoutine if specified to merge the user's Data field of
  395. the range entries.
  396. Arguments:
  397. pDestEntry - Range entry that we will merge into
  398. pSrcEntry - Range entry that will be merged into pDestEntry
  399. pMergeRoutine - Optional routine to merge Data fields of
  400. merged range entries. See PBLCRANGE_MERGE_ROUTINE description.
  401. Return Value:
  402. TRUE if successful, FALSE if not. The success is mainly
  403. determined by calls to the pMergeRoutine if specified.
  404. --*/
  405. {
  406. BLCRANGE_ENTRY TempDest = *pDestEntry;
  407. BOOLEAN RetVal = TRUE;
  408. if (pMergeRoutine)
  409. {
  410. RetVal = pMergeRoutine(&TempDest, pSrcEntry);
  411. }
  412. if (RetVal)
  413. {
  414. TempDest.Range.Start = BLRGMIN(TempDest.Range.Start,
  415. pSrcEntry->Range.Start);
  416. TempDest.Range.End = BLRGMAX(TempDest.Range.End,
  417. pSrcEntry->Range.End);
  418. *pDestEntry = TempDest;
  419. }
  420. return RetVal;
  421. }
  422. VOID
  423. BlRangeListRemoveRange (
  424. PBLCRANGE_LIST pRangeList,
  425. PBLCRANGE pRange
  426. )
  427. /*++
  428. Routine Description:
  429. Find the ranges that overlap with pRange, remove them from the
  430. list and free them. It may be possible to reclaim non-overlapping
  431. parts of range entries by allowing the caller to specify a
  432. DivideRoutine in an _Ex version of this function. This function
  433. would be called for invalidating part of the cache, if the range
  434. list is being used for a disk cache.
  435. Arguments:
  436. pRangeList - Range entry list we are removing range entries that
  437. overlap with pRange from.
  438. pRange - Range to remove from the range entry list.
  439. Return Value:
  440. None.
  441. --*/
  442. {
  443. PBLCRANGE_ENTRY pCurEntry;
  444. LIST_ENTRY *pHead, *pNext;
  445. //
  446. // Handle special empty range case.
  447. //
  448. if (pRange->Start == pRange->End)
  449. {
  450. return;
  451. }
  452. //
  453. // Looking at each range in the list, remove the ones that overlap with
  454. // pRange even slightly.
  455. //
  456. pHead = &pRangeList->Head;
  457. pNext = pHead->Flink;
  458. while (pNext != pHead)
  459. {
  460. pCurEntry = CONTAINING_RECORD(pNext, BLCRANGE_ENTRY, Link);
  461. pNext = pNext->Flink;
  462. if ((pRange->End > pCurEntry->Range.Start) &&
  463. (pRange->Start < pCurEntry->Range.End))
  464. {
  465. pRangeList->NumEntries--;
  466. RemoveEntryList(&pCurEntry->Link);
  467. if (pRangeList->FreeRoutine) pRangeList->FreeRoutine(pCurEntry);
  468. }
  469. }
  470. return;
  471. }
  472. VOID
  473. BlRangeListRemoveAllRanges (
  474. PBLCRANGE_LIST pRangeList
  475. )
  476. /*++
  477. Routine Description:
  478. Remove all ranges from the list and free them.
  479. Arguments:
  480. pRangeList - Range entry list we are removing range entries that
  481. overlap with pRange from.
  482. Return Value:
  483. None.
  484. --*/
  485. {
  486. PBLCRANGE_ENTRY pCurEntry;
  487. LIST_ENTRY *pHead, *pNext;
  488. pHead = &pRangeList->Head;
  489. pNext = pHead->Flink;
  490. while (pNext != pHead)
  491. {
  492. pCurEntry = CONTAINING_RECORD(pNext, BLCRANGE_ENTRY, Link);
  493. pRangeList->NumEntries--;
  494. RemoveEntryList(&pCurEntry->Link);
  495. if (pRangeList->FreeRoutine) pRangeList->FreeRoutine(pCurEntry);
  496. pNext = pNext->Flink;
  497. }
  498. return;
  499. }
  500. #ifdef BLRANGE_SELF_TEST
  501. //
  502. // In order to to test blrange implementation, define
  503. // BLRANGE_SELF_TEST and call BlRangeSelfTest from you program passing
  504. // in a function to output debug results.
  505. //
  506. #include <stdlib.h>
  507. #include <stdio.h>
  508. #include <time.h>
  509. //
  510. // Keep MAX_RANDOM above 1000 or you may hit difficulties creating new
  511. // entries.
  512. //
  513. #define MAX_RANDOM 10000
  514. VOID
  515. GetRandom_GetNewSeed(
  516. VOID
  517. )
  518. {
  519. srand((unsigned)time(NULL));
  520. }
  521. ULONG
  522. GetRandom(
  523. VOID
  524. )
  525. {
  526. return (rand() * 10000 / RAND_MAX);
  527. }
  528. typedef
  529. int
  530. (*PBLCRANGE_SELFTEST_FPRINTF_ROUTINE) (
  531. void *stream,
  532. const char *format,
  533. ...
  534. );
  535. PBLCRANGE_SELFTEST_FPRINTF_ROUTINE g_fpTestPrintf = NULL;
  536. VOID *g_pTestStream = NULL;
  537. BOOLEAN
  538. BlRangeSelfTest_MergeRoutine (
  539. PBLCRANGE_ENTRY pDestEntry,
  540. PBLCRANGE_ENTRY pSrcEntry
  541. )
  542. {
  543. g_fpTestPrintf(g_pTestStream,
  544. " Merging RangeDest %I64u-%I64u RangeSrc %I64u-%I64u : ",
  545. pDestEntry->Range.Start,
  546. pDestEntry->Range.End,
  547. pSrcEntry->Range.Start,
  548. pSrcEntry->Range.End);
  549. if (GetRandom() < (MAX_RANDOM / 5))
  550. {
  551. g_fpTestPrintf(g_pTestStream,"FAIL\n");
  552. return FALSE;
  553. }
  554. else
  555. {
  556. g_fpTestPrintf(g_pTestStream,"SUCCESS\n");
  557. return TRUE;
  558. }
  559. }
  560. VOID
  561. BlRangeSelfTest_FreeRoutine (
  562. PBLCRANGE_ENTRY pRangeEntry
  563. )
  564. {
  565. g_fpTestPrintf(g_pTestStream,
  566. " Freeing range %I64u-%I64u \n",
  567. pRangeEntry->Range.Start,
  568. pRangeEntry->Range.End);
  569. free(pRangeEntry);
  570. }
  571. BLCRANGE
  572. BlRangeSelfTest_RandomRange(
  573. VOID
  574. )
  575. {
  576. BLCRANGE RetRange;
  577. ULONG Rand1;
  578. ULONG Rand2;
  579. ULONGLONG Size;
  580. ULONG i;
  581. Rand1 = GetRandom();
  582. Rand2 = GetRandom();
  583. RetRange.Start = BLRGMIN(Rand1, Rand2);
  584. RetRange.End = BLRGMAX(Rand1, Rand2);
  585. //
  586. // Make sure that ranges are small and there are not just a couple
  587. // of big ones.
  588. //
  589. for (i = 0; i < 3; i++)
  590. {
  591. if ((Size = (RetRange.End - RetRange.Start)) > MAX_RANDOM / 20)
  592. {
  593. RetRange.Start += (Size / 2);
  594. }
  595. else
  596. {
  597. break;
  598. }
  599. }
  600. return RetRange;
  601. }
  602. PBLCRANGE_ENTRY
  603. BlRangeSelfTest_CreateNewEntry(
  604. VOID
  605. )
  606. {
  607. PBLCRANGE_ENTRY pNewEntry;
  608. pNewEntry = malloc(sizeof(BLCRANGE_ENTRY));
  609. if (pNewEntry)
  610. {
  611. pNewEntry->Range = BlRangeSelfTest_RandomRange();
  612. }
  613. return pNewEntry;
  614. }
  615. VOID
  616. BlRangeSelfTest_FreeEntry(
  617. PBLCRANGE_ENTRY pEntry
  618. )
  619. {
  620. free(pEntry);
  621. }
  622. typedef enum _BLRANGE_OP_TYPE
  623. {
  624. BLRANGE_OP_ADD_RANGE,
  625. BLRANGE_OP_ADD_MERGE_RANGE,
  626. BLRANGE_OP_REMOVE_RANGE,
  627. BLRANGE_OP_FIND_OVERLAP,
  628. BLRANGE_OP_FIND_DISTINCT,
  629. BLRANGE_OP_MAX_OP_NO, // Leave this at the end of the enumeration.
  630. } BLRANGE_OP_TYPE;
  631. VOID
  632. BlRangeSelfTest(
  633. PBLCRANGE_SELFTEST_FPRINTF_ROUTINE TestOutFPrintf,
  634. PVOID TestOutStream,
  635. ULONG NumIterations
  636. )
  637. /*++
  638. Routine Description:
  639. Range routines self test routine.
  640. Arguments:
  641. TestOutFPrintf - Pointer to a routine like fprintf that will be used to
  642. print the output.
  643. TestOutStream - Argument to be passed to fpPrintf as its first argument.
  644. NumIterations - Number of random operations to perform in this self test.
  645. Return Value:
  646. None.
  647. --*/
  648. {
  649. BLCRANGE_LIST RangeList;
  650. ULONG Rand1;
  651. ULONG Rand2;
  652. BLCRANGE Range1;
  653. PBLCRANGE_ENTRY pEntry1;
  654. PBLCRANGE_ENTRY pEntry2;
  655. BLRANGE_OP_TYPE OpType;
  656. PLIST_ENTRY pHead;
  657. PLIST_ENTRY pNext;
  658. PBLCRANGE_ENTRY *pOverlaps;
  659. PBLCRANGE pDistinctRanges;
  660. ULONG BufSize;
  661. ULONG NumDistincts;
  662. ULONG NumOverlaps;
  663. ULONG RandEntryNo;
  664. //
  665. // Simulation Parameters.
  666. //
  667. ULONG StartNumRanges = 10;
  668. ULONG CurIterIdx;
  669. ULONG CurRangeIdx;
  670. ULONG CurEntryIdx;
  671. //
  672. // Set global output function and stream variable so merge/free etc.
  673. // routines can also output.
  674. //
  675. g_fpTestPrintf = TestOutFPrintf;
  676. g_pTestStream = TestOutStream;
  677. //
  678. // Set semi-random starting point for pseudorandom number generation.
  679. //
  680. GetRandom_GetNewSeed();
  681. //
  682. // Initialize the range list.
  683. //
  684. BlRangeListInitialize(&RangeList,
  685. BlRangeSelfTest_MergeRoutine,
  686. BlRangeSelfTest_FreeRoutine);
  687. //
  688. // Try to add StartNumRanges random entries.
  689. //
  690. for(CurRangeIdx = 0; CurRangeIdx < StartNumRanges; CurRangeIdx++)
  691. {
  692. pEntry1 = BlRangeSelfTest_CreateNewEntry();
  693. if (!pEntry1) continue;
  694. g_fpTestPrintf(g_pTestStream,
  695. "AddStartRange %I64u-%I64u : ",
  696. pEntry1->Range.Start,
  697. pEntry1->Range.End);
  698. if (BlRangeListAddRange(&RangeList, pEntry1))
  699. {
  700. g_fpTestPrintf(g_pTestStream, "SUCCESS\n");
  701. }
  702. else
  703. {
  704. g_fpTestPrintf(g_pTestStream, "FAILED\n");
  705. BlRangeSelfTest_FreeEntry(pEntry1);
  706. }
  707. }
  708. for(CurIterIdx = 0; CurIterIdx < NumIterations; CurIterIdx++)
  709. {
  710. //
  711. // Print out the current list.
  712. //
  713. g_fpTestPrintf(g_pTestStream, "List: ");
  714. pHead = &RangeList.Head;
  715. pNext = pHead->Flink;
  716. while (pNext != pHead)
  717. {
  718. pEntry1 = CONTAINING_RECORD(pNext, BLCRANGE_ENTRY, Link);
  719. g_fpTestPrintf(g_pTestStream,
  720. "%I64u-%I64u ",
  721. pEntry1->Range.Start,
  722. pEntry1->Range.End);
  723. pNext = pNext->Flink;
  724. }
  725. g_fpTestPrintf(g_pTestStream, "\n");
  726. get_new_optype:
  727. OpType = GetRandom() % BLRANGE_OP_MAX_OP_NO;
  728. switch (OpType)
  729. {
  730. case BLRANGE_OP_ADD_RANGE:
  731. pEntry1 = BlRangeSelfTest_CreateNewEntry();
  732. g_fpTestPrintf(g_pTestStream,
  733. "AddRange %I64u-%I64u : ",
  734. pEntry1->Range.Start,
  735. pEntry1->Range.End);
  736. if (BlRangeListAddRange(&RangeList, pEntry1))
  737. {
  738. g_fpTestPrintf(g_pTestStream, "SUCCESS\n");
  739. }
  740. else
  741. {
  742. g_fpTestPrintf(g_pTestStream, "FAILED\n");
  743. BlRangeSelfTest_FreeEntry(pEntry1);
  744. }
  745. break;
  746. case BLRANGE_OP_ADD_MERGE_RANGE:
  747. RandEntryNo = GetRandom() * RangeList.NumEntries / MAX_RANDOM;
  748. pHead = &RangeList.Head;
  749. pNext = pHead->Flink;
  750. for (CurEntryIdx = 0; CurEntryIdx < RandEntryNo; CurEntryIdx++)
  751. {
  752. pNext = pNext->Flink;
  753. }
  754. if (pNext == pHead) goto get_new_optype;
  755. pEntry1 = CONTAINING_RECORD(pNext, BLCRANGE_ENTRY, Link);
  756. pEntry2 = BlRangeSelfTest_CreateNewEntry();
  757. if (GetRandom() > (MAX_RANDOM / 2))
  758. {
  759. pEntry2->Range.Start = pEntry1->Range.End;
  760. pEntry2->Range.End = pEntry2->Range.Start +
  761. (GetRandom() * (MAX_RANDOM - pEntry2->Range.Start)) / MAX_RANDOM;
  762. }
  763. else
  764. {
  765. pEntry2->Range.End = pEntry1->Range.Start;
  766. pEntry2->Range.Start = pEntry2->Range.End -
  767. (GetRandom() * pEntry2->Range.End) / MAX_RANDOM;
  768. }
  769. g_fpTestPrintf(g_pTestStream,
  770. "MergeAddRange %I64u-%I64u : ",
  771. pEntry2->Range.Start,
  772. pEntry2->Range.End);
  773. if (BlRangeListAddRange(&RangeList, pEntry2))
  774. {
  775. g_fpTestPrintf(g_pTestStream, "SUCCESS\n");
  776. }
  777. else
  778. {
  779. g_fpTestPrintf(g_pTestStream, "FAILED\n");
  780. BlRangeSelfTest_FreeEntry(pEntry2);
  781. }
  782. break;
  783. case BLRANGE_OP_REMOVE_RANGE:
  784. Range1 = BlRangeSelfTest_RandomRange();
  785. g_fpTestPrintf(g_pTestStream,
  786. "RemoveRange %I64u-%I64u\n",
  787. Range1.Start,
  788. Range1.End);
  789. BlRangeListRemoveRange(&RangeList, &Range1);
  790. break;
  791. case BLRANGE_OP_FIND_OVERLAP:
  792. Range1 = BlRangeSelfTest_RandomRange();
  793. g_fpTestPrintf(g_pTestStream,
  794. "FindOverlaps %I64u-%I64u : ",
  795. Range1.Start,
  796. Range1.End);
  797. BlRangeListFindOverlaps(&RangeList,
  798. &Range1,
  799. NULL,
  800. 0,
  801. &NumOverlaps);
  802. g_fpTestPrintf(g_pTestStream, "%u Overlaps... ", NumOverlaps);
  803. BufSize = NumOverlaps * sizeof(PBLCRANGE_ENTRY);
  804. pOverlaps = malloc(BufSize);
  805. if (!pOverlaps) goto get_new_optype;
  806. if (BlRangeListFindOverlaps(&RangeList,
  807. &Range1,
  808. pOverlaps,
  809. BufSize,
  810. &NumOverlaps) &&
  811. (BufSize == NumOverlaps * sizeof(PBLCRANGE_ENTRY)))
  812. {
  813. g_fpTestPrintf(g_pTestStream, "SUCCESS\n");
  814. }
  815. else
  816. {
  817. g_fpTestPrintf(g_pTestStream, "FAIL\n");
  818. free(pOverlaps);
  819. break;
  820. }
  821. for (CurEntryIdx = 0; CurEntryIdx < NumOverlaps; CurEntryIdx++)
  822. {
  823. g_fpTestPrintf(g_pTestStream,
  824. " %I64u-%I64u\n",
  825. pOverlaps[CurEntryIdx]->Range.Start,
  826. pOverlaps[CurEntryIdx]->Range.End);
  827. }
  828. free(pOverlaps);
  829. break;
  830. case BLRANGE_OP_FIND_DISTINCT:
  831. Range1 = BlRangeSelfTest_RandomRange();
  832. g_fpTestPrintf(g_pTestStream,
  833. "FindDistincts %I64u-%I64u : ",
  834. Range1.Start,
  835. Range1.End);
  836. BlRangeListFindDistinctRanges(&RangeList,
  837. &Range1,
  838. NULL,
  839. 0,
  840. &NumDistincts);
  841. g_fpTestPrintf(g_pTestStream, "%u Distincts... ", NumDistincts);
  842. BufSize = NumDistincts * sizeof(BLCRANGE);
  843. pDistinctRanges = malloc(BufSize);
  844. if (!pDistinctRanges) goto get_new_optype;
  845. if (BlRangeListFindDistinctRanges(&RangeList,
  846. &Range1,
  847. pDistinctRanges,
  848. BufSize,
  849. &NumDistincts) &&
  850. (BufSize == NumDistincts * sizeof(BLCRANGE)))
  851. {
  852. g_fpTestPrintf(g_pTestStream, "SUCCESS\n");
  853. }
  854. else
  855. {
  856. g_fpTestPrintf(g_pTestStream, "FAIL\n");
  857. free(pDistinctRanges);
  858. break;
  859. }
  860. for (CurRangeIdx = 0; CurRangeIdx < NumDistincts; CurRangeIdx++)
  861. {
  862. g_fpTestPrintf(g_pTestStream,
  863. " %I64u-%I64u\n",
  864. pDistinctRanges[CurRangeIdx].Start,
  865. pDistinctRanges[CurRangeIdx].End);
  866. }
  867. free(pDistinctRanges);
  868. break;
  869. default:
  870. g_fpTestPrintf(g_pTestStream, "ERR: INVALID OP CODE!");
  871. goto get_new_optype;
  872. }
  873. }
  874. return;
  875. }
  876. #endif // BLRANGE_SELF_TEST