zend_accelerator_hash.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. /*
  2. +----------------------------------------------------------------------+
  3. | Zend OPcache |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) The PHP Group |
  6. +----------------------------------------------------------------------+
  7. | This source file is subject to version 3.01 of the PHP license, |
  8. | that is bundled with this package in the file LICENSE, and is |
  9. | available through the world-wide-web at the following url: |
  10. | https://www.php.net/license/3_01.txt |
  11. | If you did not receive a copy of the PHP license and are unable to |
  12. | obtain it through the world-wide-web, please send a note to |
  13. | license@php.net so we can mail you a copy immediately. |
  14. +----------------------------------------------------------------------+
  15. | Authors: Andi Gutmans <andi@php.net> |
  16. | Zeev Suraski <zeev@php.net> |
  17. | Stanislav Malyshev <stas@zend.com> |
  18. | Dmitry Stogov <dmitry@php.net> |
  19. +----------------------------------------------------------------------+
  20. */
  21. #include "ZendAccelerator.h"
  22. #include "zend_accelerator_hash.h"
  23. #include "zend_hash.h"
  24. #include "zend_shared_alloc.h"
  25. /* Generated on an Octa-ALPHA 300MHz CPU & 2.5GB RAM monster */
  26. static uint32_t prime_numbers[] =
  27. {5, 11, 19, 53, 107, 223, 463, 983, 1979, 3907, 7963, 16229, 32531, 65407, 130987, 262237, 524521, 1048793 };
  28. static uint32_t num_prime_numbers = sizeof(prime_numbers) / sizeof(uint32_t);
  29. void zend_accel_hash_clean(zend_accel_hash *accel_hash)
  30. {
  31. accel_hash->num_entries = 0;
  32. accel_hash->num_direct_entries = 0;
  33. memset(accel_hash->hash_table, 0, sizeof(zend_accel_hash_entry *)*accel_hash->max_num_entries);
  34. }
  35. void zend_accel_hash_init(zend_accel_hash *accel_hash, uint32_t hash_size)
  36. {
  37. uint32_t i;
  38. for (i=0; i<num_prime_numbers; i++) {
  39. if (hash_size <= prime_numbers[i]) {
  40. hash_size = prime_numbers[i];
  41. break;
  42. }
  43. }
  44. accel_hash->num_entries = 0;
  45. accel_hash->num_direct_entries = 0;
  46. accel_hash->max_num_entries = hash_size;
  47. /* set up hash pointers table */
  48. accel_hash->hash_table = zend_shared_alloc(sizeof(zend_accel_hash_entry *)*accel_hash->max_num_entries);
  49. if (!accel_hash->hash_table) {
  50. zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Insufficient shared memory!");
  51. return;
  52. }
  53. /* set up hash values table */
  54. accel_hash->hash_entries = zend_shared_alloc(sizeof(zend_accel_hash_entry)*accel_hash->max_num_entries);
  55. if (!accel_hash->hash_entries) {
  56. zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Insufficient shared memory!");
  57. return;
  58. }
  59. memset(accel_hash->hash_table, 0, sizeof(zend_accel_hash_entry *)*accel_hash->max_num_entries);
  60. }
  61. /* Returns NULL if hash is full
  62. * Returns pointer the actual hash entry on success
  63. * key needs to be already allocated as it is not copied
  64. */
  65. zend_accel_hash_entry* zend_accel_hash_update(zend_accel_hash *accel_hash, zend_string *key, bool indirect, void *data)
  66. {
  67. zend_ulong hash_value;
  68. zend_ulong index;
  69. zend_accel_hash_entry *entry;
  70. zend_accel_hash_entry *indirect_bucket = NULL;
  71. if (indirect) {
  72. indirect_bucket = (zend_accel_hash_entry*)data;
  73. while (indirect_bucket->indirect) {
  74. indirect_bucket = (zend_accel_hash_entry*)indirect_bucket->data;
  75. }
  76. }
  77. hash_value = zend_string_hash_val(key);
  78. #ifndef ZEND_WIN32
  79. hash_value ^= ZCG(root_hash);
  80. #endif
  81. index = hash_value % accel_hash->max_num_entries;
  82. /* try to see if the element already exists in the hash */
  83. entry = accel_hash->hash_table[index];
  84. while (entry) {
  85. if (entry->hash_value == hash_value
  86. && zend_string_equals(entry->key, key)) {
  87. if (entry->indirect) {
  88. if (indirect_bucket) {
  89. entry->data = indirect_bucket;
  90. } else {
  91. ((zend_accel_hash_entry*)entry->data)->data = data;
  92. }
  93. } else {
  94. if (indirect_bucket) {
  95. accel_hash->num_direct_entries--;
  96. entry->data = indirect_bucket;
  97. entry->indirect = 1;
  98. } else {
  99. entry->data = data;
  100. }
  101. }
  102. return entry;
  103. }
  104. entry = entry->next;
  105. }
  106. /* Does not exist, add a new entry */
  107. if (accel_hash->num_entries == accel_hash->max_num_entries) {
  108. return NULL;
  109. }
  110. entry = &accel_hash->hash_entries[accel_hash->num_entries++];
  111. if (indirect) {
  112. entry->data = indirect_bucket;
  113. entry->indirect = 1;
  114. } else {
  115. accel_hash->num_direct_entries++;
  116. entry->data = data;
  117. entry->indirect = 0;
  118. }
  119. entry->hash_value = hash_value;
  120. entry->key = key;
  121. entry->next = accel_hash->hash_table[index];
  122. accel_hash->hash_table[index] = entry;
  123. return entry;
  124. }
  125. static zend_always_inline void* zend_accel_hash_find_ex(zend_accel_hash *accel_hash, zend_string *key, int data)
  126. {
  127. zend_ulong index;
  128. zend_accel_hash_entry *entry;
  129. zend_ulong hash_value;
  130. hash_value = zend_string_hash_val(key);
  131. #ifndef ZEND_WIN32
  132. hash_value ^= ZCG(root_hash);
  133. #endif
  134. index = hash_value % accel_hash->max_num_entries;
  135. entry = accel_hash->hash_table[index];
  136. while (entry) {
  137. if (entry->hash_value == hash_value
  138. && zend_string_equals(entry->key, key)) {
  139. if (entry->indirect) {
  140. if (data) {
  141. return ((zend_accel_hash_entry*)entry->data)->data;
  142. } else {
  143. return entry->data;
  144. }
  145. } else {
  146. if (data) {
  147. return entry->data;
  148. } else {
  149. return entry;
  150. }
  151. }
  152. }
  153. entry = entry->next;
  154. }
  155. return NULL;
  156. }
  157. /* Returns the data associated with key on success
  158. * Returns NULL if data doesn't exist
  159. */
  160. void* zend_accel_hash_find(zend_accel_hash *accel_hash, zend_string *key)
  161. {
  162. return zend_accel_hash_find_ex(accel_hash, key, 1);
  163. }
  164. /* Returns the hash entry associated with key on success
  165. * Returns NULL if it doesn't exist
  166. */
  167. zend_accel_hash_entry* zend_accel_hash_find_entry(zend_accel_hash *accel_hash, zend_string *key)
  168. {
  169. return (zend_accel_hash_entry *)zend_accel_hash_find_ex(accel_hash, key, 0);
  170. }
  171. int zend_accel_hash_unlink(zend_accel_hash *accel_hash, zend_string *key)
  172. {
  173. zend_ulong hash_value;
  174. zend_ulong index;
  175. zend_accel_hash_entry *entry, *last_entry=NULL;
  176. hash_value = zend_string_hash_val(key);
  177. #ifndef ZEND_WIN32
  178. hash_value ^= ZCG(root_hash);
  179. #endif
  180. index = hash_value % accel_hash->max_num_entries;
  181. entry = accel_hash->hash_table[index];
  182. while (entry) {
  183. if (entry->hash_value == hash_value
  184. && zend_string_equals(entry->key, key)) {
  185. if (!entry->indirect) {
  186. accel_hash->num_direct_entries--;
  187. }
  188. if (last_entry) {
  189. last_entry->next = entry->next;
  190. } else {
  191. accel_hash->hash_table[index] = entry->next;
  192. }
  193. return SUCCESS;
  194. }
  195. last_entry = entry;
  196. entry = entry->next;
  197. }
  198. return FAILURE;
  199. }