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;