6
6
#define _XQC_STR_HASH_INCLUDED_
7
7
8
8
#include <stdint.h>
9
+ #include <time.h>
9
10
10
11
#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
11
24
12
25
typedef struct xqc_str_hash_element_s {
13
26
uint64_t hash ;
@@ -24,20 +37,79 @@ typedef struct xqc_str_hash_table_s {
24
37
xqc_str_hash_node_t * * list ;
25
38
size_t count ;
26
39
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*/
27
45
} xqc_str_hash_table_t ;
28
46
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
+ }
29
61
30
62
static 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 )
32
67
{
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 ));
33
78
hash_tab -> allocator = allocator ;
34
79
hash_tab -> list = allocator .malloc (allocator .opaque , sizeof (xqc_str_hash_node_t * ) * bucket_num );
35
80
if (hash_tab -> list == NULL ) {
36
81
return XQC_ERROR ;
37
82
}
38
83
xqc_memzero (hash_tab -> list , sizeof (xqc_str_hash_node_t * ) * bucket_num );
39
84
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
+ }
40
103
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 ;
41
113
}
42
114
43
115
static inline void
@@ -53,6 +125,7 @@ xqc_str_hash_release(xqc_str_hash_table_t *hash_tab)
53
125
}
54
126
}
55
127
a -> free (a -> opaque , hash_tab -> list );
128
+ a -> free (a -> opaque , hash_tab -> conflict_stat );
56
129
}
57
130
58
131
static inline void *
@@ -90,6 +163,16 @@ xqc_str_hash_add(xqc_str_hash_table_t *hash_tab, xqc_str_hash_element_t e)
90
163
91
164
node -> next = hash_tab -> list [index ];
92
165
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
+ }
93
176
94
177
return XQC_OK ;
95
178
}
@@ -104,6 +187,9 @@ xqc_str_hash_delete(xqc_str_hash_table_t *hash_tab, uint64_t hash, xqc_str_t str
104
187
while (node ) {
105
188
if (node -> element .hash == hash && xqc_str_equal (str , node -> element .str )) {
106
189
* pp = node -> next ;
190
+ if (hash_tab -> conflict_stat [index ] > 0 ) {
191
+ hash_tab -> conflict_stat [index ] -= 1 ;
192
+ }
107
193
a -> free (a -> opaque , node -> element .str .data );
108
194
a -> free (a -> opaque , node );
109
195
return XQC_OK ;
0 commit comments