2 Unix SMB/CIFS implementation.
4 Generic, persistent and shared between processes cache mechanism for use
5 by various parts of the Samba code
7 Copyright (C) Rafal Szczesniak 2002
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 #define DBGC_CLASS DBGC_TDB
29 #define TIMEOUT_LEN 12
30 #define CACHE_DATA_FMT "%12u/%s"
32 static TDB_CONTEXT *cache;
36 * @brief Generic, persistent and shared between processes cache mechanism
37 * for use by various parts of the Samba code
43 * Cache initialisation function. Opens cache tdb file or creates
44 * it if does not exist.
46 * @return true on successful initialisation of the cache or
50 BOOL gencache_init(void)
52 char* cache_fname = NULL;
54 /* skip file open if it's already opened */
55 if (cache) return True;
57 asprintf(&cache_fname, "%s/%s", lp_lockdir(), "gencache.tdb");
59 DEBUG(5, ("Opening cache file at %s\n", cache_fname));
61 DEBUG(0, ("Filename allocation failed.\n"));
65 cache = tdb_open_log(cache_fname, 0, TDB_DEFAULT,
66 O_RDWR|O_CREAT, 0644);
68 SAFE_FREE(cache_fname);
70 DEBUG(0, ("Attempt to open the cache file has failed.\n"));
78 * Cache shutdown function. Closes opened cache tdb file.
80 * @return true on successful closing the cache or
81 * false on failure during cache shutdown
84 BOOL gencache_shutdown(void)
86 /* tdb_close routine returns 0 on successful close */
87 if (!cache) return False;
88 DEBUG(5, ("Closing cache file\n"));
89 return tdb_close(cache) ? False : True;
94 * Add one entry to the cache file.
95 * (it part of tridge's proposed API)
97 * @param key string that represents a key of this entry
98 * @param value text representation value being cached
99 * @param timeout time when the value is expired
101 * @return true when entry is successfuly stored or
102 * false on the attempt's failure
105 BOOL gencache_add(const char *keystr, const char *value, time_t timeout)
108 TDB_DATA keybuf, databuf;
111 /* fail completely if get null pointers passed */
112 SMB_ASSERT(keystr && value);
114 if (!gencache_init()) return False;
116 asprintf(&valstr, CACHE_DATA_FMT, (int)timeout, value);
117 keybuf.dptr = strdup(keystr);
118 keybuf.dsize = strlen(keystr);
119 databuf.dptr = strdup(valstr);
120 databuf.dsize = strlen(valstr);
121 DEBUG(10, ("Adding cache entry with key = %s; value = %s and timeout \
122 = %s (%d seconds %s)\n", keybuf.dptr, value, ctime(&timeout),
123 (int)(timeout - time(NULL)), timeout > time(NULL) ? "ahead" : "in the past"));
125 ret = tdb_store(cache, keybuf, databuf, TDB_INSERT);
127 SAFE_FREE(keybuf.dptr);
128 SAFE_FREE(databuf.dptr);
130 return ret == 0 ? True : False;
135 * Set existing entry to the cache file.
136 * (it part of tridge's proposed API)
138 * @param key string that represents a key of this entry
139 * @param value text representation value being cached
140 * @param timeout time when the value is expired
142 * @return true when entry is successfuly set or
143 * false on the attempt's failure
146 BOOL gencache_set(const char *keystr, const char *valstr, time_t timeout)
149 TDB_DATA keybuf, databuf;
150 char *old_valstr, *datastr;
153 /* fail completely if get null pointers passed */
154 SMB_ASSERT(keystr && valstr);
156 if (!gencache_init()) return False;
159 * Check whether entry exists in the cache
160 * Don't verify gencache_get exit code, since the entry may be expired
162 gencache_get(keystr, &old_valstr, &old_timeout);
164 if (!(old_valstr && old_timeout)) return False;
166 DEBUG(10, ("Setting cache entry with key = %s; old value = %s and old timeout \
167 = %s\n", keystr, old_valstr, ctime(&old_timeout)));
169 asprintf(&datastr, CACHE_DATA_FMT, (int)timeout, valstr);
170 keybuf.dptr = strdup(keystr);
171 keybuf.dsize = strlen(keystr);
172 databuf.dptr = strdup(datastr);
173 databuf.dsize = strlen(datastr);
174 DEBUGADD(10, ("New value = %s, new timeout = %s (%d seconds %s)", valstr,
175 ctime(&timeout), (int)(timeout - time(NULL)),
176 timeout > time(NULL) ? "ahead" : "in the past"));
179 ret = tdb_store(cache, keybuf, databuf, TDB_REPLACE);
182 SAFE_FREE(old_valstr);
183 SAFE_FREE(keybuf.dptr);
184 SAFE_FREE(databuf.dptr);
186 return ret == 0 ? True : False;
191 * Delete one entry from the cache file.
192 * (it part of tridge's proposed API)
194 * @param key string that represents a key of this entry
196 * @return true upon successful deletion or
197 * false in case of failure
200 BOOL gencache_del(const char *keystr)
205 /* fail completely if get null pointers passed */
208 if (!gencache_init()) return False;
210 keybuf.dptr = strdup(keystr);
211 keybuf.dsize = strlen(keystr);
212 DEBUG(10, ("Deleting cache entry (key = %s)\n", keystr));
213 ret = tdb_delete(cache, keybuf);
215 SAFE_FREE(keybuf.dptr);
216 return ret == 0 ? True : False;
221 * Get existing entry from the cache file.
222 * (it part of tridge's proposed API)
224 * @param key string that represents a key of this entry
225 * @param value buffer that is allocated and filled with the entry value
226 * buffer's disposing is done outside
227 * @param timeout pointer to a time_t that is filled with entry's
230 * @return true when entry is successfuly fetched or
231 * false on the failure
234 BOOL gencache_get(const char *keystr, char **valstr, time_t *timeout)
236 TDB_DATA keybuf, databuf;
238 /* fail completely if get null pointers passed */
239 SMB_ASSERT(keystr && valstr && timeout);
241 if (!gencache_init())
244 keybuf.dptr = strdup(keystr);
245 keybuf.dsize = strlen(keystr);
246 databuf = tdb_fetch(cache, keybuf);
248 if (databuf.dptr && databuf.dsize > TIMEOUT_LEN) {
249 char* entry_buf = strndup(databuf.dptr, databuf.dsize);
250 *valstr = (char*)malloc(sizeof(char) * (databuf.dsize - TIMEOUT_LEN));
252 SAFE_FREE(databuf.dptr);
253 sscanf(entry_buf, CACHE_DATA_FMT, (int*)timeout, *valstr);
254 SAFE_FREE(entry_buf);
256 DEBUG(10, ("Returning %s cache entry: key = %s, value = %s, timeout = %s\n",
257 *timeout > time(NULL) ? "valid" : "expired", keystr, *valstr,
259 return *timeout > time(NULL);
261 SAFE_FREE(databuf.dptr);
264 DEBUG(10, ("Cache entry with key = %s couldn't be found\n", keystr));
271 * Iterate through all entries which key matches to specified pattern
273 * @param fn pointer to the function that will be supplied with each single
274 * matching cache entry (key, value and timeout) as an arguments
275 * @param keystr_pattern pattern the existing entries' keys are matched to
279 void gencache_iterate(void (*fn)(const char* key, const char *value, time_t timeout),
280 const char* keystr_pattern)
282 TDB_LIST_NODE *node, *first_node;
284 char *keystr = NULL, *valstr = NULL, *entry = NULL;
287 /* fail completely if get null pointers passed */
288 SMB_ASSERT(fn && keystr_pattern);
290 if (!gencache_init()) return;
292 DEBUG(5, ("Searching cache keys with pattern %s", keystr_pattern));
293 node = tdb_search_keys(cache, keystr_pattern);
297 /* ensure null termination of the key string */
298 node->node_key.dptr[node->node_key.dsize] = '\0';
299 keystr = node->node_key.dptr;
302 * We don't use gencache_get function, because we need to iterate through
303 * all of the entries. Validity verification is up to fn routine.
305 databuf = tdb_fetch(cache, node->node_key);
306 if (!databuf.dptr || databuf.dsize <= TIMEOUT_LEN) {
307 SAFE_FREE(databuf.dptr);
310 entry = strndup(databuf.dptr, databuf.dsize);
311 SAFE_FREE(databuf.dptr);
312 valstr = (char*)malloc(sizeof(char) * (databuf.dsize - TIMEOUT_LEN));
313 sscanf(entry, CACHE_DATA_FMT, (int*)(&timeout), valstr);
315 DEBUG(10, ("Calling function with arguments (key = %s, value = %s, timeout = %s)\n",
316 keystr, valstr, ctime(&timeout)));
317 fn(keystr, valstr, timeout);
324 tdb_search_list_free(first_node);