2 Using hash table for counting events
4 Copyright (C) Amitay Isaacs 2017
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, see <http://www.gnu.org/licenses/>.
21 #include "system/filesys.h"
22 #include "system/time.h"
26 #include "lib/util/time.h"
28 #include "common/db_hash.h"
29 #include "common/hash_count.h"
31 struct hash_count_value
{
32 struct timeval update_time
;
36 struct hash_count_context
{
37 struct db_hash_context
*dh
;
38 struct timeval update_interval
;
39 hash_count_update_handler_fn handler
;
44 * Initialise hash count map
46 int hash_count_init(TALLOC_CTX
*mem_ctx
, struct timeval update_interval
,
47 hash_count_update_handler_fn handler
, void *private_data
,
48 struct hash_count_context
**result
)
50 struct hash_count_context
*hcount
;
53 if (handler
== NULL
) {
57 hcount
= talloc_zero(mem_ctx
, struct hash_count_context
);
62 ret
= db_hash_init(hcount
, "hash_count_db", 8192, DB_HASH_COMPLEX
,
69 hcount
->update_interval
= update_interval
;
70 hcount
->handler
= handler
;
71 hcount
->private_data
= private_data
;
77 static int hash_count_fetch_parser(uint8_t *keybuf
, size_t keylen
,
78 uint8_t *databuf
, size_t datalen
,
81 struct hash_count_value
*value
=
82 (struct hash_count_value
*)private_data
;
84 if (datalen
!= sizeof(struct hash_count_value
)) {
88 *value
= *(struct hash_count_value
*)databuf
;
92 static int hash_count_fetch(struct hash_count_context
*hcount
, TDB_DATA key
,
93 struct hash_count_value
*value
)
95 return db_hash_fetch(hcount
->dh
, key
.dptr
, key
.dsize
,
96 hash_count_fetch_parser
, value
);
99 static int hash_count_insert(struct hash_count_context
*hcount
, TDB_DATA key
,
100 struct hash_count_value
*value
)
102 return db_hash_insert(hcount
->dh
, key
.dptr
, key
.dsize
,
104 sizeof(struct hash_count_value
));
107 static int hash_count_update(struct hash_count_context
*hcount
, TDB_DATA key
,
108 struct hash_count_value
*value
)
110 return db_hash_add(hcount
->dh
, key
.dptr
, key
.dsize
,
111 (uint8_t *)value
, sizeof(struct hash_count_value
));
114 int hash_count_increment(struct hash_count_context
*hcount
, TDB_DATA key
)
116 struct hash_count_value value
;
117 struct timeval current_time
= timeval_current();
120 if (hcount
== NULL
) {
124 ret
= hash_count_fetch(hcount
, key
, &value
);
126 struct timeval tmp_t
;
128 tmp_t
= timeval_sum(&value
.update_time
,
129 &hcount
->update_interval
);
130 if (timeval_compare(¤t_time
, &tmp_t
) < 0) {
133 value
.update_time
= current_time
;
137 hcount
->handler(key
, value
.counter
, hcount
->private_data
);
138 ret
= hash_count_update(hcount
, key
, &value
);
140 } else if (ret
== ENOENT
) {
141 value
.update_time
= current_time
;
144 hcount
->handler(key
, value
.counter
, hcount
->private_data
);
145 ret
= hash_count_insert(hcount
, key
, &value
);
151 static struct timeval
timeval_subtract(const struct timeval
*tv1
,
152 const struct timeval
*tv2
)
154 struct timeval tv
= *tv1
;
155 const unsigned int million
= 1000000;
159 tv
.tv_usec
+= million
;
164 tv
.tv_sec
-= tv2
->tv_sec
;
165 tv
.tv_usec
-= tv2
->tv_usec
;
167 tv
.tv_sec
+= tv
.tv_usec
/ million
;
168 tv
.tv_usec
= tv
.tv_usec
% million
;
173 struct hash_count_expire_state
{
174 struct db_hash_context
*dh
;
175 struct timeval last_time
;
179 static int hash_count_expire_parser(uint8_t *keybuf
, size_t keylen
,
180 uint8_t *databuf
, size_t datalen
,
183 struct hash_count_expire_state
*state
=
184 (struct hash_count_expire_state
*)private_data
;
185 struct hash_count_value
*value
;
188 if (datalen
!= sizeof(struct hash_count_value
)) {
192 value
= (struct hash_count_value
*)databuf
;
193 if (timeval_compare(&value
->update_time
, &state
->last_time
) < 0) {
194 ret
= db_hash_delete(state
->dh
, keybuf
, keylen
);
203 void hash_count_expire(struct hash_count_context
*hcount
, int *delete_count
)
205 struct timeval current_time
= timeval_current();
206 struct hash_count_expire_state state
;
208 state
.dh
= hcount
->dh
;
209 state
.last_time
= timeval_subtract(¤t_time
,
210 &hcount
->update_interval
);
213 (void) db_hash_traverse_update(hcount
->dh
, hash_count_expire_parser
,
216 if (delete_count
!= NULL
) {
217 *delete_count
= state
.count
;