66#define _XQC_STR_HASH_INCLUDED_
77
88#include <stdint.h>
9+ #include <time.h>
910
1011#include "src/common/xqc_str.h"
12+ #include "src/common/xqc_siphash.h"
13+ #include "src/common/xqc_log.h"
14+
15+ /*
16+ * default log threshold of number of element in on bucket
17+ * test result of max conflict (default 1024*1024 hash buckets) in one bucket:
18+ * 100000 connections, the max conflict is 5
19+ * 1000000 connections, the max conflict is 24
20+ */
21+ #define XQC_HASH_DEFAULT_CONFLICT_THRESHOLD 50
22+ /*10 second, log interval must not less then 10 second*/
23+ #define XQC_HASH_CONFLICT_LOG_INTERVAL 10
1124
1225typedef struct xqc_str_hash_element_s {
1326 uint64_t hash ;
@@ -24,20 +37,79 @@ typedef struct xqc_str_hash_table_s {
2437 xqc_str_hash_node_t * * list ;
2538 size_t count ;
2639 xqc_allocator_t allocator ; /* memory allocator */
40+ uint8_t * conflict_stat ; /* statistic the number of elements in every bucket */
41+ xqc_siphash_ctx_t siphash_ctx ; /* siphash context */
42+ uint32_t conflict_thres ; /* conflict threshold in one bucket, warning if exceeded */
43+ time_t last_log_time ; /* last timestamp(second) for logging the max conflict value*/
44+ xqc_log_t * log ; /* pointer to engine's log*/
2745} xqc_str_hash_table_t ;
2846
47+ /* calculate the hash value using the siphash algorithm */
48+ static inline uint64_t
49+ xqc_siphash_get_hash (xqc_siphash_ctx_t * ctx , const uint8_t * data , size_t len )
50+ {
51+ uint64_t hash_value ;
52+ if (xqc_siphash (ctx , data , len , (uint8_t * )(& hash_value ), sizeof (hash_value )) == XQC_OK ) {
53+ return hash_value ;
54+ }
55+ /*
56+ * impossible, we set hash_size value 8 when we call xqc_siphash_init, sizeof(hash_value) is always 8
57+ * xqc_siphash return XQC_ERROR only when hash_size not equal sizeof(hash_value), it is impossible here
58+ */
59+ return 0 ;
60+ }
2961
3062static inline int
31- xqc_str_hash_init (xqc_str_hash_table_t * hash_tab , xqc_allocator_t allocator , size_t bucket_num )
63+ xqc_str_hash_init (xqc_str_hash_table_t * hash_tab ,
64+ xqc_allocator_t allocator , size_t bucket_num ,
65+ uint32_t conflict_thres , uint8_t * key ,
66+ size_t key_len , xqc_log_t * log )
3267{
68+ if (bucket_num == 0 ) { /* impossible */
69+ return XQC_ERROR ;
70+ }
71+ if (key_len != XQC_SIPHASH_KEY_SIZE ) { /* siphash key length must be 16 */
72+ return XQC_ERROR ;
73+ }
74+ if (log == NULL ) {
75+ return XQC_ERROR ;
76+ }
77+ xqc_memzero (hash_tab , sizeof (xqc_str_hash_table_t ));
3378 hash_tab -> allocator = allocator ;
3479 hash_tab -> list = allocator .malloc (allocator .opaque , sizeof (xqc_str_hash_node_t * ) * bucket_num );
3580 if (hash_tab -> list == NULL ) {
3681 return XQC_ERROR ;
3782 }
3883 xqc_memzero (hash_tab -> list , sizeof (xqc_str_hash_node_t * ) * bucket_num );
3984 hash_tab -> count = bucket_num ;
85+ hash_tab -> conflict_stat = allocator .malloc (allocator .opaque , sizeof (uint8_t ) * bucket_num );
86+ if (hash_tab -> conflict_stat == NULL ) {
87+ goto fail ;
88+ }
89+ xqc_memzero (hash_tab -> conflict_stat , sizeof (uint8_t ) * bucket_num );
90+ if (conflict_thres > 0 ) {
91+ hash_tab -> conflict_thres = conflict_thres ;
92+ } else {
93+ hash_tab -> conflict_thres = XQC_HASH_DEFAULT_CONFLICT_THRESHOLD ;
94+ }
95+ hash_tab -> last_log_time = 0 ;
96+ hash_tab -> log = log ;
97+ if (xqc_siphash_init (& hash_tab -> siphash_ctx , key , key_len ,
98+ XQC_DEFAULT_HASH_SIZE , XQC_SIPHASH_C_ROUNDS ,
99+ XQC_SIPHASH_D_ROUNDS ) != XQC_OK )
100+ {
101+ goto fail ;
102+ }
40103 return XQC_OK ;
104+
105+ fail :
106+ if (hash_tab -> list ) {
107+ allocator .free (allocator .opaque , hash_tab -> list );
108+ }
109+ if (hash_tab -> conflict_stat ) {
110+ allocator .free (allocator .opaque , hash_tab -> conflict_stat );
111+ }
112+ return XQC_ERROR ;
41113}
42114
43115static inline void
@@ -53,6 +125,7 @@ xqc_str_hash_release(xqc_str_hash_table_t *hash_tab)
53125 }
54126 }
55127 a -> free (a -> opaque , hash_tab -> list );
128+ a -> free (a -> opaque , hash_tab -> conflict_stat );
56129}
57130
58131static inline void *
@@ -90,6 +163,16 @@ xqc_str_hash_add(xqc_str_hash_table_t *hash_tab, xqc_str_hash_element_t e)
90163
91164 node -> next = hash_tab -> list [index ];
92165 hash_tab -> list [index ] = node ;
166+ hash_tab -> conflict_stat [index ] += 1 ;
167+ if (hash_tab -> conflict_stat [index ] > hash_tab -> conflict_thres ) {
168+ time_t now_sec = time (NULL );
169+ if (now_sec >= hash_tab -> last_log_time + XQC_HASH_CONFLICT_LOG_INTERVAL ) {
170+ xqc_log (hash_tab -> log , XQC_LOG_WARN ,
171+ "|xqc conn hash conflict exceed|index:%ui, number of elements:%d|" ,
172+ index , hash_tab -> conflict_stat [index ]);
173+ hash_tab -> last_log_time = now_sec ;
174+ }
175+ }
93176
94177 return XQC_OK ;
95178}
@@ -104,6 +187,9 @@ xqc_str_hash_delete(xqc_str_hash_table_t *hash_tab, uint64_t hash, xqc_str_t str
104187 while (node ) {
105188 if (node -> element .hash == hash && xqc_str_equal (str , node -> element .str )) {
106189 * pp = node -> next ;
190+ if (hash_tab -> conflict_stat [index ] > 0 ) {
191+ hash_tab -> conflict_stat [index ] -= 1 ;
192+ }
107193 a -> free (a -> opaque , node -> element .str .data );
108194 a -> free (a -> opaque , node );
109195 return XQC_OK ;
0 commit comments