zend_accelerator_hash.c 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. /*
  2. +----------------------------------------------------------------------+
  3. | Zend OPcache |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 1998-2016 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. | http://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@zend.com> |
  16. | Zeev Suraski <zeev@zend.com> |
  17. | Stanislav Malyshev <stas@zend.com> |
  18. | Dmitry Stogov <dmitry@zend.com> |
  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 uint prime_numbers[] =
  27. {5, 11, 19, 53, 107, 223, 463, 983, 1979, 3907, 7963, 16229, 32531, 65407, 130987, 262237, 524521, 1048793 };
  28. static uint num_prime_numbers = sizeof(prime_numbers) / sizeof(uint);
  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, zend_uint hash_size)
  36. {
  37. uint 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(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(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, char *key, zend_uint key_length, zend_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. #ifndef ZEND_WIN32
  72. TSRMLS_FETCH();
  73. #endif
  74. if (indirect) {
  75. indirect_bucket = (zend_accel_hash_entry*)data;
  76. while (indirect_bucket->indirect) {
  77. indirect_bucket = (zend_accel_hash_entry*)indirect_bucket->data;
  78. }
  79. }
  80. hash_value = zend_inline_hash_func(key, key_length);
  81. #ifndef ZEND_WIN32
  82. hash_value ^= ZCG(root_hash);
  83. #endif
  84. index = hash_value % accel_hash->max_num_entries;
  85. /* try to see if the element already exists in the hash */
  86. entry = accel_hash->hash_table[index];
  87. while (entry) {
  88. if (entry->hash_value == hash_value
  89. && entry->key_length == key_length
  90. && !memcmp(entry->key, key, key_length)) {
  91. if (entry->indirect) {
  92. if (indirect_bucket) {
  93. entry->data = indirect_bucket;
  94. } else {
  95. ((zend_accel_hash_entry*)entry->data)->data = data;
  96. }
  97. } else {
  98. if (indirect_bucket) {
  99. accel_hash->num_direct_entries--;
  100. entry->data = indirect_bucket;
  101. entry->indirect = 1;
  102. } else {
  103. entry->data = data;
  104. }
  105. }
  106. return entry;
  107. }
  108. entry = entry->next;
  109. }
  110. /* Does not exist, add a new entry */
  111. if (accel_hash->num_entries == accel_hash->max_num_entries) {
  112. return NULL;
  113. }
  114. entry = &accel_hash->hash_entries[accel_hash->num_entries++];
  115. if (indirect) {
  116. entry->data = indirect_bucket;
  117. entry->indirect = 1;
  118. } else {
  119. accel_hash->num_direct_entries++;
  120. entry->data = data;
  121. entry->indirect = 0;
  122. }
  123. entry->hash_value = hash_value;
  124. entry->key = key;
  125. entry->key_length = key_length;
  126. entry->next = accel_hash->hash_table[index];
  127. accel_hash->hash_table[index] = entry;
  128. return entry;
  129. }
  130. /* Returns the data associated with key on success
  131. * Returns NULL if data doesn't exist
  132. */
  133. void* zend_accel_hash_find(zend_accel_hash *accel_hash, char *key, zend_uint key_length)
  134. {
  135. zend_ulong hash_value;
  136. zend_ulong index;
  137. zend_accel_hash_entry *entry;
  138. #ifndef ZEND_WIN32
  139. TSRMLS_FETCH();
  140. #endif
  141. hash_value = zend_inline_hash_func(key, key_length);
  142. #ifndef ZEND_WIN32
  143. hash_value ^= ZCG(root_hash);
  144. #endif
  145. index = hash_value % accel_hash->max_num_entries;
  146. entry = accel_hash->hash_table[index];
  147. while (entry) {
  148. if (entry->hash_value == hash_value
  149. && entry->key_length == key_length
  150. && !memcmp(entry->key, key, key_length)) {
  151. if (entry->indirect) {
  152. return ((zend_accel_hash_entry *) entry->data)->data;
  153. } else {
  154. return entry->data;
  155. }
  156. }
  157. entry = entry->next;
  158. }
  159. return NULL;
  160. }
  161. /* Returns the hash entry associated with key on success
  162. * Returns NULL if it doesn't exist
  163. */
  164. zend_accel_hash_entry* zend_accel_hash_find_entry(zend_accel_hash *accel_hash, char *key, zend_uint key_length)
  165. {
  166. zend_ulong hash_value;
  167. zend_ulong index;
  168. zend_accel_hash_entry *entry;
  169. #ifndef ZEND_WIN32
  170. TSRMLS_FETCH();
  171. #endif
  172. hash_value = zend_inline_hash_func(key, key_length);
  173. #ifndef ZEND_WIN32
  174. hash_value ^= ZCG(root_hash);
  175. #endif
  176. index = hash_value % accel_hash->max_num_entries;
  177. entry = accel_hash->hash_table[index];
  178. while (entry) {
  179. if (entry->hash_value == hash_value
  180. && entry->key_length == key_length
  181. && !memcmp(entry->key, key, key_length)) {
  182. if (entry->indirect) {
  183. return (zend_accel_hash_entry *) entry->data;
  184. } else {
  185. return entry;
  186. }
  187. }
  188. entry = entry->next;
  189. }
  190. return NULL;
  191. }
  192. int zend_accel_hash_unlink(zend_accel_hash *accel_hash, char *key, zend_uint key_length)
  193. {
  194. zend_ulong hash_value;
  195. zend_ulong index;
  196. zend_accel_hash_entry *entry, *last_entry=NULL;
  197. #ifndef ZEND_WIN32
  198. TSRMLS_FETCH();
  199. #endif
  200. hash_value = zend_inline_hash_func(key, key_length);
  201. #ifndef ZEND_WIN32
  202. hash_value ^= ZCG(root_hash);
  203. #endif
  204. index = hash_value % accel_hash->max_num_entries;
  205. entry = accel_hash->hash_table[index];
  206. while (entry) {
  207. if (entry->hash_value == hash_value
  208. && entry->key_length == key_length
  209. && !memcmp(entry->key, key, key_length)) {
  210. if (!entry->indirect) {
  211. accel_hash->num_direct_entries--;
  212. }
  213. if (last_entry) {
  214. last_entry->next = entry->next;
  215. } else {
  216. accel_hash->hash_table[index] = entry->next;
  217. }
  218. return SUCCESS;
  219. }
  220. last_entry = entry;
  221. entry = entry->next;
  222. }
  223. return FAILURE;
  224. }