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.

834 lines
29 KiB

  1. /*
  2. * pathash.c
  3. *
  4. * author: John R. Douceur
  5. * date: 5 May 1997
  6. *
  7. * This source file provides functions that implement insertion, removal,
  8. * search, scan, and flush operations on the pat-hash table database. The
  9. * code is object-oriented C, transliterated from a C++ implementation.
  10. *
  11. * The pat-hash database is a combination of a dynamically sized, separately
  12. * chained hash table and a Patricia tree. The hash table dynamically grows
  13. * and shrinks as needed, and the workload of modifying the table size is
  14. * distributed evenly among the insertion or removal operations that cause
  15. * the growth or shrinkage.
  16. *
  17. * The insertion and removal operations manage both a hash table and a Patricia
  18. * tree, but the search routine uses only the hash table for performing the
  19. * search. The Patrica tree is present to support a scan operation, which
  20. * searches the database for all entries that match a given pattern, where the
  21. * pattern that is scanned may contain wildcards.
  22. *
  23. * None of the code or comments in this file needs to be understood by writers
  24. * of client code; all explanatory information for clients is found in the
  25. * associated header file, rhizome.h.
  26. *
  27. */
  28. #include "gpcpre.h"
  29. #define MAGIC_NUMBER 0x9e4155b9 // Fibonacci hash multiplier (see Knuth 6.4)
  30. // This macro allocates a new pat-hash table entry structure. The size of
  31. // the structure is a function of the value of keybytes, since the entry stores
  32. // a copy of the pattern. The value array, which is the last field in the
  33. // structure, is declared as having a single element, but this array will
  34. // actually extend beyond the defined end of the structure into additional
  35. // space that is allocated for it by the following macro.
  36. //
  37. //#define NEW_PHTableEntry \
  38. // ((PHTableEntry *)malloc(sizeof(PHTableEntry) + phtable->keybytes - 1))
  39. #define NEW_PHTableEntry(_pe) \
  40. GpcAllocMem(&_pe,\
  41. sizeof(PHTableEntry) + phtable->keybytes - 1,\
  42. PathHashTag)
  43. // This macro allocates a new pat-hash table group structure. The size of
  44. // the structure is a function of the size of the group. The entry_list array,
  45. // which is the last field in the structure, is declared as having a single
  46. // element, but this array will actually extend beyond the defined end of the
  47. // structure into additional space that is allocated for it by the following
  48. // macro.
  49. //
  50. //#define NEW_PHTableGroup(group_size) \
  51. // ((PHTableGroup *)malloc(sizeof(PHTableGroup) + \
  52. // ((group_size) - 1) * sizeof(PHTableEntry *)))
  53. #define NEW_PHTableGroup(group_size, _pg) \
  54. GpcAllocMem(&_pg,\
  55. sizeof(PHTableGroup) + \
  56. ((group_size) - 1) * sizeof(PHTableEntry *),\
  57. PathHashTag)
  58. // This macro gets the indexed bit of the value, where the most-significant bit
  59. // is defined as bit 0.
  60. //
  61. #define BIT_OF(value, index) \
  62. (((value)[(index) >> 3] >> (7 - ((index) & 0x7))) & 0x1)
  63. // Following is a prototype for a static function that is used internally by
  64. // the implementation of the pat-hash routines.
  65. void
  66. node_scan(
  67. PatHashTable *phtable,
  68. PHTableEntry *node,
  69. int prev_bit,
  70. char *value,
  71. char *mask,
  72. void *context,
  73. ScanCallback func);
  74. // Since this is not C++, the PatHashTable structure is not self-constructing;
  75. // therefore, the following constructor code must be called on the PatHashTable
  76. // structure after it is allocated. The argument keybits specifies the size
  77. // (in bits) of each pattern that will be stored in the database. The usage
  78. // ratio is the target ratio of database entries to discrete hash chains, which
  79. // is also the mean length of a hash chain. The usage histeresis is the
  80. // histeresis between resizing operations due to insertions and removals.
  81. // Allocation histeresis is the histeresis between allocation and deallocation
  82. // of groups, specified as a binary exponent. The maximum free list size
  83. // determines the maximum number of elements that will be placed on a free
  84. // list, rather than deallocated, when they are removed.
  85. //
  86. int
  87. constructPatHashTable(
  88. PatHashTable *phtable,
  89. int keybits,
  90. int usage_ratio,
  91. int usage_histeresis,
  92. int allocation_histeresis,
  93. int max_free_list_size)
  94. {
  95. PHTableGroup *group;
  96. phtable->keybits = keybits;
  97. phtable->keybytes = (keybits - 1) / 8 + 1;
  98. phtable->usage_ratio = usage_ratio;
  99. phtable->usage_histeresis = usage_histeresis;
  100. phtable->allocation_histeresis = allocation_histeresis;
  101. phtable->max_free_list_size = max_free_list_size;
  102. NEW_PHTableGroup(1, phtable->initial_group);
  103. phtable->top_group = phtable->initial_group;
  104. phtable->allocation_exponent = 0;
  105. phtable->size_exponent = 0;
  106. phtable->extension_size = 0;
  107. phtable->population = 0;
  108. phtable->root = 0;
  109. phtable->free_list = 0;
  110. phtable->free_list_size = 0;
  111. NEW_PHTableGroup(1, group);
  112. if (phtable->initial_group == 0 || group == 0)
  113. {
  114. // Memory could not be allocated for one of the two groups created by
  115. // the constructor. Therefore, we return an indication of failure to
  116. // the client.
  117. // 286334 : Not so fast! Please free memory before leaving...
  118. if (phtable->initial_group != 0) {
  119. GpcFreeMem(phtable->initial_group, PatHashTag);
  120. }
  121. if (group != 0) {
  122. GpcFreeMem(group, PatHashTag);
  123. }
  124. return 1;
  125. }
  126. group->previous = 0;
  127. group->entry_list[0] = 0;
  128. phtable->initial_group->previous = group;
  129. return 0;
  130. }
  131. // Since this is not C++, the PatHashTable structure is not self-destructing;
  132. // therefore, the following destructor code must be called on the PatHashTable
  133. // structure before it is deallocated.
  134. //
  135. void
  136. destructPatHashTable(
  137. PatHashTable *phtable)
  138. {
  139. PHTableGroup *group, *previous;
  140. PHTableEntry *entry, *next;
  141. int index, size;
  142. // First, free all groups that are allocated but not currently used.
  143. group = phtable->top_group;
  144. while (group != phtable->initial_group)
  145. {
  146. previous = group->previous;
  147. GpcFreeMem(group, PatHashTag);
  148. group = previous;
  149. }
  150. // Then, free the entries in the initial group. Since not all fields
  151. // in the initial group's table may be valid, only check those whose
  152. // indices are less than the extension size.
  153. for (index = phtable->extension_size - 1; index >= 0; index--)
  154. {
  155. entry = group->entry_list[index];
  156. while (entry != 0)
  157. {
  158. next = entry->next;
  159. GpcFreeMem(entry, PatHashTag);
  160. entry = next;
  161. }
  162. }
  163. // Then free the initial group.
  164. previous = group->previous;
  165. GpcFreeMem(group, PatHashTag);
  166. group = previous;
  167. // Scan through all remaining groups except the last one, freeing all
  168. // entries in each group, and thereafter freeing the group.
  169. size = 1 << (phtable->size_exponent - 1);
  170. while (group->previous != 0)
  171. {
  172. for (index = size - 1; index >= 0; index--)
  173. {
  174. entry = group->entry_list[index];
  175. while (entry != 0)
  176. {
  177. next = entry->next;
  178. GpcFreeMem(entry, PatHashTag);
  179. entry = next;
  180. }
  181. }
  182. previous = group->previous;
  183. GpcFreeMem(group, PatHashTag);
  184. group = previous;
  185. size >>= 1;
  186. }
  187. // The last group is special, since it has a size of one, but the logic
  188. // used in the preceding loop would have calculated its size as zero.
  189. // Rather than complicating the previous loop with a check for a single
  190. // special case, we simply free the last group and its entries in the
  191. // following code.
  192. entry = group->entry_list[0];
  193. while (entry != 0)
  194. {
  195. next = entry->next;
  196. GpcFreeMem(entry, PatHashTag);
  197. entry = next;
  198. }
  199. GpcFreeMem(group, PatHashTag);
  200. // Finally, free all of the entries in the free list.
  201. while (phtable->free_list != 0)
  202. {
  203. next = phtable->free_list->next;
  204. GpcFreeMem(phtable->free_list, PatHashTag);
  205. phtable->free_list = next;
  206. }
  207. }
  208. // This function inserts a new specific pattern into the database, passed as
  209. // an array of bytes. The client supplies a digested form of the pattern as
  210. // the chyme argument.
  211. //
  212. // The client specifies a void pointer reference value to associate with the
  213. // specific pattern. When the specific pattern is installed, the insert
  214. // routine returns a pointer to a SpecificPatternHandle.
  215. //
  216. // If the submitted pattern has already been installed in the database, then
  217. // the insertion does not occur, and the SpecificPatternHandle of the
  218. // previously installed pattern is returned.
  219. //
  220. // The insertion routine inserts the new pattern into both the hash table and
  221. // the Patricia tree, and the two insertions are almost completely independent
  222. // except for the shared entry structure.
  223. //
  224. SpecificPatternHandle
  225. insertPatHashTable(
  226. PatHashTable *phtable,
  227. char *pattern,
  228. unsigned int chyme,
  229. void *reference)
  230. {
  231. unsigned int hash, address, small_address, split_point;
  232. PHTableGroup *group;
  233. PHTableEntry **entry, *new_entry;
  234. char *value;
  235. int index, group_size, pivot_bit, bit_value;
  236. // The first portion of this routine inserts the new pattern into the hash
  237. // table. To begin, we determine whether the number of hash chains needs
  238. // to be increased in order to maintain the desired usage ratio.
  239. group_size = 1 << phtable->size_exponent;
  240. if (phtable->population >=
  241. (group_size + phtable->extension_size) * phtable->usage_ratio)
  242. {
  243. // The number of hash chains needs to be increased. So, determine
  244. // whether the initial group is completely full.
  245. if (phtable->extension_size == group_size)
  246. {
  247. // The initial group is completely full. So, determine whether
  248. // all allocated groups are currently in use.
  249. if (phtable->allocation_exponent == phtable->size_exponent)
  250. {
  251. // All allocated groups are currently in use. So, allocate
  252. // a new group and set its previous pointer to point to the
  253. // initial group. Update the allocation values of the structure
  254. // to reflect the new allocation.
  255. NEW_PHTableGroup(group_size << 1, group);
  256. if (group == 0)
  257. {
  258. // Memory could not be allocated for the new group.
  259. // Therefore, we return an indication of falure to the
  260. // client.
  261. return 0;
  262. }
  263. group->previous = phtable->initial_group;
  264. phtable->top_group = group;
  265. phtable->allocation_exponent++;
  266. }
  267. else
  268. {
  269. // Not all allocated groups are in use. So, scanning backward
  270. // from the top group, find the group that immediately follows
  271. // the initial group.
  272. group = phtable->top_group;
  273. while (group->previous != phtable->initial_group)
  274. {
  275. group = group->previous;
  276. }
  277. }
  278. // We now have either a newly allocated group or a previously
  279. // allocated group that immediately follows the initial group.
  280. // Set this group to be the new initial group, and set the extension
  281. // size to zero.
  282. phtable->initial_group = group;
  283. phtable->size_exponent++;
  284. phtable->extension_size = 0;
  285. }
  286. else
  287. {
  288. // The initial group is not completely full. So, select the initial
  289. // group.
  290. group = phtable->initial_group;
  291. }
  292. // We now have a group that is not completely full, either because it
  293. // wasn't completely full when the insert routine was entered, or
  294. // because it has just been allocated. In either case, we now split
  295. // a hash chain from a smaller group into two hash chains, one of which
  296. // will be placed into an unused entry in the new group. The address
  297. // of the hash chain to be split is determined by the extension size.
  298. // First we find the group that contains this address.
  299. group = group->previous;
  300. address = phtable->extension_size;
  301. while ((address & 0x1) == 0 && group->previous != 0)
  302. {
  303. address >>= 1;
  304. group = group->previous;
  305. }
  306. // Then, we scan through the entry list at the given address for the
  307. // appropriate split point. The entries are stored in sorted order,
  308. // and we are essentially shifting one more bit into the address for
  309. // this value, so the split point can be found by searching for the
  310. // first entry with the bit set.
  311. address >>= 1;
  312. entry = &group->entry_list[address];
  313. split_point = ((phtable->extension_size << 1) | 0x1)
  314. << (31 - phtable->size_exponent);
  315. while (*entry != 0 && (*entry)->hash < split_point)
  316. {
  317. entry = &(*entry)->next;
  318. }
  319. // Now that we have found the split point, we move the split-off
  320. // piece of the list to the new address, and increment the extension
  321. // size.
  322. phtable->initial_group->entry_list[phtable->extension_size] = *entry;
  323. *entry = 0;
  324. phtable->extension_size++;
  325. }
  326. // Now that the memory management aspects of the hash table insertion have
  327. // been taken care of, we can perform the actual insertion. First, we find
  328. // the address by hashing the chyme value.
  329. group = phtable->initial_group;
  330. hash = MAGIC_NUMBER * chyme;
  331. address = hash >> (31 - phtable->size_exponent);
  332. // There are two possible values for the address depending upon whether
  333. // the hash chain pointer is below the extension size. If it is, then the
  334. // larger (by one bit) address is used; otherwise, the smaller address is
  335. // used.
  336. small_address = address >> 1;
  337. if ((int)small_address >= phtable->extension_size)
  338. {
  339. address = small_address;
  340. group = group->previous;
  341. }
  342. // Next we find the group that contains this address.
  343. while ((address & 0x1) == 0 && group->previous != 0)
  344. {
  345. address >>= 1;
  346. group = group->previous;
  347. }
  348. // Then, we scan through the entry list at the given address for the first
  349. // entry whose hash value is equal to or greater than the hash of the search
  350. // key. The entries are stored in sorted order to improve the search speed.
  351. address >>= 1;
  352. entry = &group->entry_list[address];
  353. while (*entry != 0 && (*entry)->hash < hash)
  354. {
  355. entry = &(*entry)->next;
  356. }
  357. // Now, we check all entries whose hash value matches that of the search
  358. // key.
  359. while (*entry != 0 && (*entry)->hash == hash)
  360. {
  361. // For each value whose hash matches, check the actual value to see
  362. // if it matches the search key.
  363. value = (*entry)->value;
  364. for (index = phtable->keybytes-1; index >= 0; index--)
  365. {
  366. if (value[index] != pattern[index])
  367. {
  368. break;
  369. }
  370. }
  371. if (index < 0)
  372. {
  373. // A match is found, so we return the SpecificPatternHandle of the
  374. // matching entry to the client.
  375. return *entry;
  376. }
  377. entry = &(*entry)->next;
  378. }
  379. // A match was not found, so we insert the new entry into the hash chain.
  380. // First we check to see if there is an entry avalable on the free list.
  381. if (phtable->free_list != 0)
  382. {
  383. // There is an entry available on the free list, so grab it and
  384. // decrement the size of the free list.
  385. new_entry = phtable->free_list;
  386. phtable->free_list = phtable->free_list->next;
  387. phtable->free_list_size--;
  388. }
  389. else
  390. {
  391. // There is no entry available on the free list, so allocate a new one.
  392. NEW_PHTableEntry(new_entry);
  393. if (new_entry == 0)
  394. {
  395. // Memory could not be allocated for the new entry. Therefore,
  396. // we return an indication of falure to the client.
  397. return 0;
  398. }
  399. }
  400. // Set the fields of the new entry to the appropriate information and add
  401. // the entry to the hash chain.
  402. new_entry->hash = hash;
  403. new_entry->reference = reference;
  404. new_entry->next = *entry;
  405. for (index = phtable->keybytes - 1; index >= 0; index--)
  406. {
  407. new_entry->value[index] = pattern[index];
  408. }
  409. *entry = new_entry;
  410. // The hash table insertion is now complete. Here we begin the insertion
  411. // of the new entry into the Patricia tree. We have to treat an empty
  412. // tree as a special case.
  413. if (phtable->root == 0)
  414. {
  415. // The Patricia tree is empty, so we set the root to point to the new
  416. // entry. This entry is special, since it serves only as a leaf of
  417. // the Patricia search and not also as a branch node. A Patricia tree
  418. // always contains one fewer branch node than the number of leaves.
  419. // Since a leaf is determined by a pivot bit that is less than or equal
  420. // to the pivot bit of the parent branch node, a pivot bit of -1 flags
  421. // this node as always a leaf.
  422. new_entry->pivot_bit = -1;
  423. new_entry->children[0] = 0;
  424. new_entry->children[1] = 0;
  425. phtable->root = new_entry;
  426. }
  427. else
  428. {
  429. // The Patricia tree is not empty, so we proceed with the normal
  430. // insertion process. Beginning at the root, scan through the tree
  431. // according to the bits of the new pattern, until we reach a leaf.
  432. entry = &phtable->root;
  433. index = -1;
  434. while ((*entry)->pivot_bit > index)
  435. {
  436. index = (*entry)->pivot_bit;
  437. entry = &(*entry)->children[BIT_OF(pattern, index)];
  438. }
  439. // Now, compare the new pattern, bit by bit, to the pattern stored at
  440. // the leaf, until a non-matching bit is found. There is no need to
  441. // check for an exact match, since the hash insert above would have
  442. // aborted if an exact match had been found.
  443. value = (*entry)->value;
  444. pivot_bit = 0;
  445. while (BIT_OF(value, pivot_bit) == BIT_OF(pattern, pivot_bit))
  446. {
  447. pivot_bit++;
  448. }
  449. // Now, scan a second time through the tree, until finding either a leaf
  450. // or a branch with a pivot bit greater than the bit of the non-match.
  451. entry = &phtable->root;
  452. index = -1;
  453. while ((*entry)->pivot_bit > index && (*entry)->pivot_bit < pivot_bit)
  454. {
  455. index = (*entry)->pivot_bit;
  456. entry = &(*entry)->children[BIT_OF(pattern, index)];
  457. }
  458. // This is the point at which the new branch must be inserted. Since
  459. // each node is both a branch and a leaf, the new entry serves as the
  460. // new branch, and one of its children points to itself as a leaf. The
  461. // other child points to the remaining subtree below the insertion
  462. // point.
  463. bit_value = BIT_OF(value, pivot_bit);
  464. new_entry->pivot_bit = pivot_bit;
  465. new_entry->children[1 - bit_value] = new_entry;
  466. new_entry->children[bit_value] = *entry;
  467. *entry = new_entry;
  468. }
  469. // Having inserted the new entry in both the hash table and the Patricia
  470. // tree, we increment the population and return the SpecificPatternHandle
  471. // of the new entry.
  472. phtable->population++;
  473. return new_entry;
  474. }
  475. // This function removes a pattern from the pat-hash table. The pattern is
  476. // specified by the SpecificPatternHandle that was returned by the insert
  477. // routine. No checks are performed to insure that this is a valid handle.
  478. //
  479. // The removal routine removes the pattern from both the hash table and the
  480. // Patricia tree, and the two removals are almost completely independent
  481. // except for the shared entry structure.
  482. //
  483. void
  484. removePatHashTable(
  485. PatHashTable *phtable,
  486. SpecificPatternHandle sphandle)
  487. {
  488. unsigned int hash, address, small_address;
  489. PHTableGroup *group;
  490. PHTableEntry **entry, **branch, **parent, *epoint, *bpoint;
  491. char *value;
  492. int index, group_size;
  493. // The first portion of this routine removess the new pattern from the hash
  494. // table. First, we find the address by hashing the chyme value.
  495. group = phtable->initial_group;
  496. hash = sphandle->hash;
  497. address = hash >> (31 - phtable->size_exponent);
  498. // There are two possible values for the address depending upon whether
  499. // the hash chain pointer is below the extension size. If it is, then the
  500. // larger (by one bit) address is used; otherwise, the smaller address is
  501. // used.
  502. small_address = address >> 1;
  503. if ((int)small_address >= phtable->extension_size)
  504. {
  505. address = small_address;
  506. group = group->previous;
  507. }
  508. // Next we find the group that contains this address.
  509. while ((address & 0x1) == 0 && group->previous != 0)
  510. {
  511. address >>= 1;
  512. group = group->previous;
  513. }
  514. // Then, we scan through the entry list at the given address for the entry
  515. // that matches the given SpecificPatternHandle.
  516. address >>= 1;
  517. entry = &group->entry_list[address];
  518. while (*entry != sphandle)
  519. {
  520. entry = &(*entry)->next;
  521. }
  522. // We then remove the entry from the hash chain and decrement the
  523. // population.
  524. *entry = sphandle->next;
  525. phtable->population--;
  526. // This completes the actual removal of the entry from the hash table, but
  527. // we now have to determine whether to reduce the number of hash chains in
  528. // order to maintain the desired usage ratio. Note that the usage
  529. // histeresis is factored into the calculation.
  530. group_size = 1 << phtable->size_exponent;
  531. if (phtable->population + phtable->usage_histeresis <
  532. (group_size + phtable->extension_size - 1) * phtable->usage_ratio)
  533. {
  534. // The number of hash chains needs to be reduced. So, we coalesce two
  535. // hash chains into a single hash chain. The address of the hash chains
  536. // is determined by the extension size. First we decrement the
  537. // extension size and find the group that contains the address of the
  538. // hash chain that is being retained.
  539. phtable->extension_size--;
  540. group = phtable->initial_group->previous;
  541. address = phtable->extension_size;
  542. while ((address & 0x1) == 0 && group->previous != 0)
  543. {
  544. address >>= 1;
  545. group = group->previous;
  546. }
  547. // Then, we find the end of the entry list at the given address.
  548. address >>= 1;
  549. entry = &group->entry_list[address];
  550. while (*entry != 0)
  551. {
  552. entry = &(*entry)->next;
  553. }
  554. // We then make the last entry in the hash chain point to the first
  555. // entry in the other hash chain that is being coalesced. We do not
  556. // need to update the group's pointer to the other hash chain, since
  557. // it is now beyond the extension size, and it will thus never be seen.
  558. *entry = phtable->initial_group->entry_list[phtable->extension_size];
  559. // Now, we check to see whether a group has been completely emptied.
  560. // We also check the size exponent, since even if we have just emptied
  561. // the first non-special group, we do not remove it.
  562. if (phtable->extension_size == 0 && phtable->size_exponent > 0)
  563. {
  564. // The initial group has just been completely emptied, so we set
  565. // the previous group as the new initial group. Update all
  566. // housekeeping information accordingly.
  567. phtable->size_exponent--;
  568. phtable->extension_size = group_size >> 1;
  569. phtable->initial_group = phtable->initial_group->previous;
  570. // We now determine whether we should deallocate a group. Note
  571. // that the allocation histeresis is factored into the calculation.
  572. if (phtable->size_exponent + phtable->allocation_histeresis <
  573. phtable->allocation_exponent)
  574. {
  575. // We should deallocate a group, so we deallocate the top group.
  576. phtable->allocation_exponent--;
  577. group = phtable->top_group->previous;
  578. GpcFreeMem(phtable->top_group, PatHashTag);
  579. phtable->top_group = group;
  580. }
  581. }
  582. }
  583. // Now, the hash table removal operation is complete, including the memory
  584. // management functions. Here we begin the removal of the entry from the
  585. // Patricia tree. First, we scan through the tree according to the bits of
  586. // the pattern being removed, until we reach a leaf. We keep track of the
  587. // branch that immediately precedes the leaf, and we also note the parent
  588. // of the pattern, in the latter's capacity as a branch node.
  589. value = sphandle->value;
  590. entry = &phtable->root;
  591. branch = entry;
  592. parent = 0;
  593. index = -1;
  594. while ((*entry)->pivot_bit > index)
  595. {
  596. if ((*entry) == sphandle)
  597. {
  598. parent = entry;
  599. }
  600. branch = entry;
  601. index = (*entry)->pivot_bit;
  602. entry = &(*entry)->children[BIT_OF(value, index)];
  603. }
  604. // We set the branch that points to the leaf to instead point to the child
  605. // of the leaf that is not selected by the bit of the removed pattern, thus
  606. // removing the branch from the tree.
  607. epoint = *entry;
  608. bpoint = *branch;
  609. *branch = bpoint->children[1 - BIT_OF(value, index)];
  610. // If the branch that was removed is also the leaf that contains the
  611. // pattern, then the removal from the Patricia tree is complete. Otherwise,
  612. // we replace the leaf that is being removed with the branch that is not
  613. // being removed.
  614. if (epoint != bpoint)
  615. {
  616. bpoint->pivot_bit = epoint->pivot_bit;
  617. bpoint->children[0] = epoint->children[0];
  618. bpoint->children[1] = epoint->children[1];
  619. // In the case of the special node that is not a branch node, we do
  620. // not update its parent to point to the replacing branch, since this
  621. // node has no parent.
  622. if (parent != 0)
  623. {
  624. *parent = bpoint;
  625. }
  626. }
  627. // The removal from the Patricia tree is now complete. If appropriate, we
  628. // place the removed entry onto the free list. If not, we simply free it.
  629. if (phtable->free_list_size < phtable->max_free_list_size)
  630. {
  631. sphandle->next = phtable->free_list;
  632. phtable->free_list = sphandle;
  633. phtable->free_list_size++;
  634. }
  635. else
  636. {
  637. GpcFreeMem(sphandle, PatHashTag);
  638. }
  639. }
  640. // This function searches the database for the specific pattern that matches
  641. // the given key, which is passed as an array of bytes. The client supplies
  642. // a digested form of the pattern as the chyme argument. If a match is found,
  643. // the SpecificPatternHandle of that matching specific pattern is returned.
  644. // If no match is found, then a value of 0 is returned.
  645. //
  646. // This search uses only the hash table; the Patricia tree is not used at all.
  647. //
  648. SpecificPatternHandle
  649. searchPatHashTable(
  650. PatHashTable *phtable,
  651. char *key,
  652. unsigned int chyme)
  653. {
  654. unsigned int hash, address, small_address;
  655. PHTableGroup *group;
  656. PHTableEntry *entry;
  657. char *value;
  658. int index;
  659. // First, we find the address by hashing the chyme value.
  660. group = phtable->initial_group;
  661. hash = MAGIC_NUMBER * chyme;
  662. address = hash >> (31 - phtable->size_exponent);
  663. // There are two possible values for the address depending upon whether
  664. // the hash chain pointer is below the extension size. If it is, then the
  665. // larger (by one bit) address is used; otherwise, the smaller address is
  666. // used.
  667. small_address = address >> 1;
  668. if ((int)small_address >= phtable->extension_size)
  669. {
  670. address = small_address;
  671. group = group->previous;
  672. }
  673. // Next we find the group that contains this address.
  674. while ((address & 0x1) == 0 && group->previous != 0)
  675. {
  676. address >>= 1;
  677. group = group->previous;
  678. }
  679. // Then, we scan through the entry list at the given address for the first
  680. // entry whose hash value is equal to or greater than the hash of the search
  681. // key. The entries are stored in sorted order to improve the search speed.
  682. address >>= 1;
  683. entry = group->entry_list[address];
  684. while (entry != 0 && entry->hash < hash)
  685. {
  686. entry = entry->next;
  687. }
  688. // Now, we check all entries whose hash value matches that of the search
  689. // key.
  690. while (entry != 0 && entry->hash == hash)
  691. {
  692. // For each value whose hash matches, check the actual value to see
  693. // if it matches the search key.
  694. value = entry->value;
  695. for (index = phtable->keybytes-1; index >= 0; index--)
  696. {
  697. if (value[index] != key[index])
  698. {
  699. break;
  700. }
  701. }
  702. if (index < 0)
  703. {
  704. // A match is found, so we return the SpecificPatternHandle of the
  705. // matching entry to the client.
  706. return entry;
  707. }
  708. entry = entry->next;
  709. }
  710. // A match was not found, so we return a null pointer to the client.
  711. return 0;
  712. }
  713. // This function searches the database for all specific patterns that match a
  714. // given general pattern. The general pattern is specified by a value and a
  715. // mask. For each specific pattern in the database that matches the supplied
  716. // general pattern, a client-supplied callback function is called with the
  717. // SpecificPatternHandle of the matching specific pattern. This callback
  718. // function is also passed a context (as a void pointer) that is supplied by
  719. // the client in the call to the scan routine.
  720. //
  721. // This scan uses only the Patricia tree; the hash table is not used at all.
  722. //
  723. void
  724. scanPatHashTable(
  725. PatHashTable *phtable,
  726. char *value,
  727. char *mask,
  728. void *context,
  729. ScanCallback func)
  730. {
  731. // Call the recursive node_scan routine, starting at the root of the
  732. // Patricia tree.
  733. if (phtable->root != 0)
  734. {
  735. node_scan(phtable, phtable->root, -1, value, mask, context, func);
  736. }
  737. }
  738. // This function recursively scans the Patricia tree for all specific patterns
  739. // that match a given general pattern.
  740. void
  741. node_scan(
  742. PatHashTable *phtable,
  743. PHTableEntry *node,
  744. int prev_bit,
  745. char *value,
  746. char *mask,
  747. void *context,
  748. ScanCallback func)
  749. {
  750. int mask_bit, index;
  751. // Partial recursion removal. The while loop takes the place of one of the
  752. // recursive calls to node_scan(). We remain in the while loop while we
  753. // are still examining branch nodes.
  754. while (node->pivot_bit > prev_bit)
  755. {
  756. // For each branch node, determine which way(s) to branch based upon
  757. // the bit of the general pattern. If the mask bit is a zero, then
  758. // branch both ways, requiring a recursive call. If the mask bit is
  759. // a one, then branch in the direction indicated by the value bit.
  760. mask_bit = BIT_OF(mask, node->pivot_bit);
  761. if (mask_bit == 0)
  762. {
  763. // The general pattern has a wildcard for this node's pivot bit,
  764. // so we must branch both ways. We branch on child one through
  765. // an actual recursive call.
  766. node_scan(phtable, node->children[1], node->pivot_bit,
  767. value, mask, context, func);
  768. }
  769. // We then branch either to the child selected by the value bit (if
  770. // the mask bit is one) or to child zero (if the mask bit is zero).
  771. prev_bit = node->pivot_bit;
  772. node = node->children[BIT_OF(value, node->pivot_bit) & mask_bit];
  773. }
  774. // We have reached a leaf node. Examine its specific pattern to see if
  775. // it matches the given general pattern. If it doesn't match, then just
  776. // return; otherwise, call the client's callback function.
  777. for (index = phtable->keybytes-1; index >= 0; index--)
  778. {
  779. if ((mask[index] & value[index]) !=
  780. (mask[index] & node->value[index]))
  781. {
  782. return;
  783. }
  784. }
  785. func(context, node);
  786. }
  787. // This function forces the pat-hash table to release all of the memory that
  788. // it currently can, by deallocating all unneeded groups and entries.
  789. //
  790. void
  791. flushPatHashTable(
  792. PatHashTable *phtable)
  793. {
  794. PHTableGroup *group, *previous;
  795. PHTableEntry *entry, *next;
  796. // First, free all groups that are allocated but not currently used.
  797. group = phtable->top_group;
  798. while (group != phtable->initial_group)
  799. {
  800. previous = group->previous;
  801. GpcFreeMem(group, PatHashTag);
  802. group = previous;
  803. }
  804. phtable->top_group = phtable->initial_group;
  805. phtable->allocation_exponent = phtable->size_exponent;
  806. // Then, free all of the entries in the free list.
  807. entry = phtable->free_list;
  808. while (entry != 0)
  809. {
  810. next = entry->next;
  811. GpcFreeMem(entry, PatHashTag);
  812. entry = next;
  813. }
  814. phtable->free_list = 0;
  815. phtable->free_list_size = 0;
  816. }