]> git.meshlink.io Git - catta/blob - cache.c
9180570b9b63eac0d3fb2c9bdd60b3733d65b951
[catta] / cache.c
1 #include <string.h>
2
3 #include "cache.h"
4
5 static void remove_entry(flxCache *c, flxCacheEntry *e, gboolean remove_from_hash_table) {
6     g_assert(c);
7     g_assert(e);
8
9     if (remove_from_hash_table) {
10         flxCacheEntry *t;
11         t = g_hash_table_lookup(c->hash_table, &e->record->key);
12         FLX_LLIST_REMOVE(flxCacheEntry, by_name, t, e);
13         if (t)
14             g_hash_table_replace(c->hash_table, &t->record->key, t);
15         else
16             g_hash_table_remove(c->hash_table, &e->record->key);
17     }
18         
19     flx_record_unref(e->record);
20     g_free(e);
21 }
22
23 flxCache *flx_cache_new(flxServer *server, flxInterface *iface) {
24     flxCache *c;
25     g_assert(server);
26
27     c = g_new(flxCache, 1);
28     c->server = server;
29     c->interface = iface;
30     c->hash_table = g_hash_table_new((GHashFunc) flx_key_hash, (GEqualFunc) flx_key_equal);
31
32     return c;
33 }
34
35 gboolean remove_func(gpointer key, gpointer value, gpointer user_data) {
36     flxCacheEntry *e, *next;
37
38     for (e = value; e; e = next) {
39         next = e->by_name_next;
40         remove_entry(user_data, e, FALSE);
41     }
42     
43     return TRUE;
44 }
45
46 void flx_cache_free(flxCache *c) {
47     g_assert(c);
48
49     g_hash_table_foreach_remove(c->hash_table, remove_func, c);
50     g_hash_table_destroy(c->hash_table);
51     
52     g_free(c);
53 }
54
55 flxCacheEntry *flx_cache_lookup_key(flxCache *c, flxKey *k) {
56     g_assert(c);
57     g_assert(k);
58
59     return g_hash_table_lookup(c->hash_table, k);
60 }
61
62 flxCacheEntry *flx_cache_lookup_record(flxCache *c, flxRecord *r) {
63     flxCacheEntry *e;
64     g_assert(c);
65     g_assert(r);
66
67     for (e = flx_cache_lookup_key(c, r->key); e; e = e->by_name_next)
68         if (e->record->size == r->size && !memcmp(e->record->data, r->data, r->size))
69             return e;
70
71     return NULL;
72 }
73
74 flxCacheEntry *flx_cache_update(flxCache *c, flxRecord *r, gboolean unique, const flxAddress *a) {
75     flxCacheEntry *e, *t;
76     
77     g_assert(c);
78     g_assert(r);
79
80     if ((t = e = flx_cache_lookup_key(c, r->key))) {
81
82         if (unique) {
83             flxCacheEntry *n;
84             /* Drop all entries but the first which we replace */
85
86             while (e->by_name_next)
87                 remove_entry(c, e->by_name_next, TRUE);
88
89             g_free(e->record->data);
90             e->record->data = g_memdup(r->data, r->size);
91             e->record->size = r->size;
92             e->record->ttl = r->ttl;
93
94         } else {
95             /* Look for exactly the same entry */
96
97             for (; e; e = e->by_name_next) {
98                 if (e->record->size == r->size &&
99                     !memcmp(e->record->data, r->data, r->size)) {
100
101                     /* We found it, so let's update the TTL */
102                     e->record->ttl = r->ttl;
103                     break;
104                 }
105             }
106         }
107     }
108
109     if (!e) {
110         /* No entry found, therefore we create a new one */
111         
112         e = g_new(flxCacheEntry, 1);
113         e->node = NULL;
114
115         e->record = flx_record_ref(r);
116         FLX_LLIST_PREPEND(flxCacheEntry, by_name, t, e);
117         g_hash_table_replace(c->hash_table, e->record->key, e);
118     } 
119
120     e->origin = *a;
121     
122     g_get_current_time(&e->timestamp);
123     e->expiry = e->timestamp;
124     g_time_val_add(&e->expiry, e->record->ttl * 1000000);
125
126     e->state = FLX_CACHE_VALID;
127
128     return e;
129 }
130
131 void flx_cache_drop_key(flxCache *c, flxKey *k) {
132     flxCacheEntry *e;
133     
134     g_assert(c);
135     g_assert(k);
136
137     while ((e = flx_cache_lookup_key(c, k)))
138         remove_entry(c, e, TRUE);
139 }
140
141 void flx_cache_drop_record(flxCache *c, flxRecord *r) {
142     flxCacheEntry *e;
143     
144     g_assert(c);
145     g_assert(r);
146
147     if ((e = flx_cache_lookup_record(c, r))) 
148         remove_entry(c, e, TRUE);
149 }
150
151 static void func(gpointer key, gpointer data, gpointer userdata) {
152     flxCacheEntry *e = data;
153     flxKey *k = key;
154
155     gchar *s, *t;
156
157     s = flx_key_to_string(k);
158     t = flx_record_to_string(e->record);
159
160     fprintf((FILE*) userdata, "%s %s\n", s, t);
161     
162     g_free(s);
163     g_free(t);
164 }
165
166 void flx_cache_dump(flxCache *c, FILE *f) {
167     g_assert(c);
168     g_assert(f);
169
170     fprintf(f, ";;; CACHE DUMP FOLLOWS ;;;\n");
171     g_hash_table_foreach(c->hash_table, func, f);
172 }