lib/gencache.c

説明を見る。
00001 /* 
00002    Unix SMB/CIFS implementation.
00003 
00004    Generic, persistent and shared between processes cache mechanism for use
00005    by various parts of the Samba code
00006 
00007    Copyright (C) Rafal Szczesniak    2002
00008    
00009    This program is free software; you can redistribute it and/or modify
00010    it under the terms of the GNU General Public License as published by
00011    the Free Software Foundation; either version 2 of the License, or
00012    (at your option) any later version.
00013    
00014    This program is distributed in the hope that it will be useful,
00015    but WITHOUT ANY WARRANTY; without even the implied warranty of
00016    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017    GNU General Public License for more details.
00018    
00019    You should have received a copy of the GNU General Public License
00020    along with this program; if not, write to the Free Software
00021    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00022 */
00023 
00024 #include "includes.h"
00025 
00026 #undef  DBGC_CLASS
00027 #define DBGC_CLASS DBGC_TDB
00028 
00029 #define TIMEOUT_LEN 12
00030 #define CACHE_DATA_FMT  "%12u/%s"
00031 #define READ_CACHE_DATA_FMT_TEMPLATE "%%12u/%%%us"
00032 
00033 static TDB_CONTEXT *cache;
00034 static BOOL cache_readonly;
00035 
00036 /**
00037  * @file gencache.c
00038  * @brief Generic, persistent and shared between processes cache mechanism
00039  *        for use by various parts of the Samba code
00040  *
00041  **/
00042 
00043 
00044 /**
00045  * Cache initialisation function. Opens cache tdb file or creates
00046  * it if does not exist.
00047  *
00048  * @return true on successful initialisation of the cache or
00049  *         false on failure
00050  **/
00051 
00052 BOOL gencache_init(void)
00053 {
00054         char* cache_fname = NULL;
00055         
00056         /* skip file open if it's already opened */
00057         if (cache) return True;
00058 
00059         cache_fname = lock_path("gencache.tdb");
00060 
00061         DEBUG(5, ("Opening cache file at %s\n", cache_fname));
00062 
00063         cache = tdb_open_log(cache_fname, 0, TDB_DEFAULT,
00064                              O_RDWR|O_CREAT, 0644);
00065 
00066         if (!cache && (errno == EACCES)) {
00067                 cache = tdb_open_log(cache_fname, 0, TDB_DEFAULT, O_RDONLY, 0644);
00068                 if (cache) {
00069                         cache_readonly = True;
00070                         DEBUG(5, ("gencache_init: Opening cache file %s read-only.\n", cache_fname));
00071                 }
00072         }
00073 
00074         if (!cache) {
00075                 DEBUG(5, ("Attempt to open gencache.tdb has failed.\n"));
00076                 return False;
00077         }
00078         return True;
00079 }
00080 
00081 
00082 /**
00083  * Cache shutdown function. Closes opened cache tdb file.
00084  *
00085  * @return true on successful closing the cache or
00086  *         false on failure during cache shutdown
00087  **/
00088  
00089 BOOL gencache_shutdown(void)
00090 {
00091         int ret;
00092         /* tdb_close routine returns -1 on error */
00093         if (!cache) return False;
00094         DEBUG(5, ("Closing cache file\n"));
00095         ret = tdb_close(cache);
00096         cache = NULL;
00097         cache_readonly = False;
00098         return ret != -1;
00099 }
00100 
00101 
00102 /**
00103  * Set an entry in the cache file. If there's no such
00104  * one, then add it.
00105  *
00106  * @param keystr string that represents a key of this entry
00107  * @param value text representation value being cached
00108  * @param timeout time when the value is expired
00109  *
00110  * @retval true when entry is successfuly stored
00111  * @retval false on failure
00112  **/
00113  
00114 BOOL gencache_set(const char *keystr, const char *value, time_t timeout)
00115 {
00116         int ret;
00117         TDB_DATA keybuf, databuf;
00118         char* valstr = NULL;
00119         
00120         /* fail completely if get null pointers passed */
00121         SMB_ASSERT(keystr && value);
00122 
00123         if (!gencache_init()) return False;
00124         
00125         if (cache_readonly) {
00126                 return False;
00127         }
00128 
00129         asprintf(&valstr, CACHE_DATA_FMT, (int)timeout, value);
00130         if (!valstr)
00131                 return False;
00132 
00133         keybuf.dptr = CONST_DISCARD(char *, keystr);
00134         keybuf.dsize = strlen(keystr)+1;
00135         databuf.dptr = valstr;
00136         databuf.dsize = strlen(valstr)+1;
00137         DEBUG(10, ("Adding cache entry with key = %s; value = %s and timeout ="
00138                    " %s (%d seconds %s)\n", keybuf.dptr, value,ctime(&timeout),
00139                    (int)(timeout - time(NULL)), 
00140                    timeout > time(NULL) ? "ahead" : "in the past"));
00141 
00142         ret = tdb_store(cache, keybuf, databuf, 0);
00143         SAFE_FREE(valstr);
00144         
00145         return ret == 0;
00146 }
00147 
00148 /**
00149  * Delete one entry from the cache file.
00150  *
00151  * @param keystr string that represents a key of this entry
00152  *
00153  * @retval true upon successful deletion
00154  * @retval false in case of failure
00155  **/
00156 
00157 BOOL gencache_del(const char *keystr)
00158 {
00159         int ret;
00160         TDB_DATA keybuf;
00161         
00162         /* fail completely if get null pointers passed */
00163         SMB_ASSERT(keystr);
00164 
00165         if (!gencache_init()) return False;     
00166         
00167         if (cache_readonly) {
00168                 return False;
00169         }
00170 
00171         keybuf.dptr = CONST_DISCARD(char *, keystr);
00172         keybuf.dsize = strlen(keystr)+1;
00173         DEBUG(10, ("Deleting cache entry (key = %s)\n", keystr));
00174         ret = tdb_delete(cache, keybuf);
00175         
00176         return ret == 0;
00177 }
00178 
00179 
00180 /**
00181  * Get existing entry from the cache file.
00182  *
00183  * @param keystr string that represents a key of this entry
00184  * @param valstr buffer that is allocated and filled with the entry value
00185  *        buffer's disposing must be done outside
00186  * @param timeout pointer to a time_t that is filled with entry's
00187  *        timeout
00188  *
00189  * @retval true when entry is successfuly fetched
00190  * @retval False for failure
00191  **/
00192 
00193 BOOL gencache_get(const char *keystr, char **valstr, time_t *timeout)
00194 {
00195         TDB_DATA keybuf, databuf;
00196         time_t t;
00197         char *endptr;
00198 
00199         /* fail completely if get null pointers passed */
00200         SMB_ASSERT(keystr);
00201 
00202         if (!gencache_init()) {
00203                 return False;
00204         }
00205         
00206         keybuf.dptr = CONST_DISCARD(char *, keystr);
00207         keybuf.dsize = strlen(keystr)+1;
00208         databuf = tdb_fetch(cache, keybuf);
00209 
00210         if (databuf.dptr == NULL) {
00211                 DEBUG(10, ("Cache entry with key = %s couldn't be found\n",
00212                            keystr));
00213                 return False;
00214         }
00215 
00216         t = strtol(databuf.dptr, &endptr, 10);
00217 
00218         if ((endptr == NULL) || (*endptr != '/')) {
00219                 DEBUG(2, ("Invalid gencache data format: %s\n", databuf.dptr));
00220                 SAFE_FREE(databuf.dptr);
00221                 return False;
00222         }
00223 
00224         DEBUG(10, ("Returning %s cache entry: key = %s, value = %s, "
00225                    "timeout = %s", t > time(NULL) ? "valid" :
00226                    "expired", keystr, endptr+1, ctime(&t)));
00227 
00228         if (t <= time(NULL)) {
00229 
00230                 /* We're expired, delete the entry */
00231                 tdb_delete(cache, keybuf);
00232 
00233                 SAFE_FREE(databuf.dptr);
00234                 return False;
00235         }
00236 
00237         if (valstr) {
00238                 *valstr = SMB_STRDUP(endptr+1);
00239                 if (*valstr == NULL) {
00240                         SAFE_FREE(databuf.dptr);
00241                         DEBUG(0, ("strdup failed\n"));
00242                         return False;
00243                 }
00244         }
00245         
00246         SAFE_FREE(databuf.dptr);
00247 
00248         if (timeout) {
00249                 *timeout = t;
00250         }
00251 
00252         return True;
00253 } 
00254 
00255 
00256 /**
00257  * Iterate through all entries which key matches to specified pattern
00258  *
00259  * @param fn pointer to the function that will be supplied with each single
00260  *        matching cache entry (key, value and timeout) as an arguments
00261  * @param data void pointer to an arbitrary data that is passed directly to the fn
00262  *        function on each call
00263  * @param keystr_pattern pattern the existing entries' keys are matched to
00264  *
00265  **/
00266 
00267 void gencache_iterate(void (*fn)(const char* key, const char *value, time_t timeout, void* dptr),
00268                       void* data, const char* keystr_pattern)
00269 {
00270         TDB_LIST_NODE *node, *first_node;
00271         TDB_DATA databuf;
00272         char *keystr = NULL, *valstr = NULL, *entry = NULL;
00273         time_t timeout = 0;
00274         int status;
00275         unsigned u;
00276 
00277         /* fail completely if get null pointers passed */
00278         SMB_ASSERT(fn && keystr_pattern);
00279 
00280         if (!gencache_init()) return;
00281 
00282         DEBUG(5, ("Searching cache keys with pattern %s\n", keystr_pattern));
00283         node = tdb_search_keys(cache, keystr_pattern);
00284         first_node = node;
00285         
00286         while (node) {
00287                 char *fmt;
00288 
00289                 /* ensure null termination of the key string */
00290                 keystr = SMB_STRNDUP(node->node_key.dptr, node->node_key.dsize);
00291                 if (!keystr) {
00292                         break;
00293                 }
00294                 
00295                 /* 
00296                  * We don't use gencache_get function, because we need to iterate through
00297                  * all of the entries. Validity verification is up to fn routine.
00298                  */
00299                 databuf = tdb_fetch(cache, node->node_key);
00300                 if (!databuf.dptr || databuf.dsize <= TIMEOUT_LEN) {
00301                         SAFE_FREE(databuf.dptr);
00302                         SAFE_FREE(keystr);
00303                         node = node->next;
00304                         continue;
00305                 }
00306                 entry = SMB_STRNDUP(databuf.dptr, databuf.dsize);
00307                 if (!entry) {
00308                         SAFE_FREE(databuf.dptr);
00309                         SAFE_FREE(keystr);
00310                         break;
00311                 }
00312 
00313                 SAFE_FREE(databuf.dptr);
00314 
00315                 valstr = (char *)SMB_MALLOC(databuf.dsize + 1 - TIMEOUT_LEN);
00316                 if (!valstr) {
00317                         SAFE_FREE(entry);
00318                         SAFE_FREE(keystr);
00319                         break;
00320                 }
00321 
00322                 asprintf(&fmt, READ_CACHE_DATA_FMT_TEMPLATE, (unsigned int)databuf.dsize - TIMEOUT_LEN);
00323                 if (!fmt) {
00324                         SAFE_FREE(valstr);
00325                         SAFE_FREE(entry);
00326                         SAFE_FREE(keystr);
00327                         break;
00328                 }
00329                 status = sscanf(entry, fmt, &u, valstr);
00330                 SAFE_FREE(fmt);
00331 
00332                 if ( status != 2 ) {
00333                         DEBUG(0,("gencache_iterate: invalid return from sscanf %d\n",status));
00334                 }
00335                 timeout = u;
00336                 
00337                 DEBUG(10, ("Calling function with arguments (key = %s, value = %s, timeout = %s)\n",
00338                            keystr, valstr, ctime(&timeout)));
00339                 fn(keystr, valstr, timeout, data);
00340                 
00341                 SAFE_FREE(valstr);
00342                 SAFE_FREE(entry);
00343                 SAFE_FREE(keystr);
00344                 node = node->next;
00345         }
00346         
00347         tdb_search_list_free(first_node);
00348 }
00349 
00350 /********************************************************************
00351  lock a key
00352 ********************************************************************/
00353 
00354 int gencache_lock_entry( const char *key )
00355 {
00356         if (!gencache_init())
00357                 return -1;
00358         
00359         return tdb_lock_bystring(cache, key);
00360 }
00361 
00362 /********************************************************************
00363  unlock a key
00364 ********************************************************************/
00365 
00366 void gencache_unlock_entry( const char *key )
00367 {
00368         if (!gencache_init())
00369                 return;
00370         
00371         tdb_unlock_bystring(cache, key);
00372         return;
00373 }

Sambaに対してSat Aug 29 21:22:58 2009に生成されました。  doxygen 1.4.7