The branch, master has been updated
       via  76705d10c626a66cc77f3ec294f4f98bef95aeb5 (commit)
       via  3d7dfc1197017c34bdb8dbc6e62460f19bd7d141 (commit)
       via  8a17cd810fa6cbe7b11139ff0f6f24e7bacd318b (commit)
       via  ed87594e5fd3251f9cb3beaca06c8eee1dcd4ed2 (commit)
       via  3edcd55bf140d09833284ba5a0f04f86b04ef7dc (commit)
       via  d936d1bd84e130aaff1de64cb1ecbd1f936dd9c4 (commit)
       via  e5a34b2533720ebb9181c0edebad6774ceeff189 (commit)
       via  3e965d017d243f0a99e7838e6c92c37df270486c (commit)
       via  565046891f9f7725b5d93eefbc3be5b9c62176fd (commit)
      from  8cb44830e0356804e21d9973382e0070f20b15be (commit)

http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit 76705d10c626a66cc77f3ec294f4f98bef95aeb5
Author: Volker Lendecke <v...@samba.org>
Date:   Tue Jul 14 18:31:28 2009 +0200

    Consolidate gencache also every 100 writes in a single process

commit 3d7dfc1197017c34bdb8dbc6e62460f19bd7d141
Author: Volker Lendecke <v...@samba.org>
Date:   Tue Jul 14 11:33:04 2009 +0200

    Consolidate string and data_blob routines in gencache

commit 8a17cd810fa6cbe7b11139ff0f6f24e7bacd318b
Author: Volker Lendecke <v...@samba.org>
Date:   Mon Jul 13 17:04:29 2009 +0200

    Make gencache more stable
    
    This provides a compromise between stability and performance: gencache is a
    persistent database these days that for performance reasons can not use tdb
    transactions for all writes. This patch splits up gencache into gencache.tdb
    and gencache_notrans.tdb. gencache_notrans is used with CLEAR_IF_FIRST, 
writes
    to it don't use transactions. By default every 5 minutes and when a program
    exits, all entries from _notrans.tdb are transferred to gencache.tdb in one
    transaction.

commit ed87594e5fd3251f9cb3beaca06c8eee1dcd4ed2
Author: Volker Lendecke <v...@samba.org>
Date:   Mon Jul 13 17:03:52 2009 +0200

    Add tdb_data_cmp

commit 3edcd55bf140d09833284ba5a0f04f86b04ef7dc
Author: Volker Lendecke <v...@samba.org>
Date:   Fri Jul 10 12:24:56 2009 +0200

    Remove gencache_init/shutdown
    
    gencache_get/set/del/iterate call gencache_init() internally anyway. And 
we've
    been very lazy calling gencache_shutdown, so this seems not really required.

commit d936d1bd84e130aaff1de64cb1ecbd1f936dd9c4
Author: Volker Lendecke <v...@samba.org>
Date:   Fri Jul 10 12:12:30 2009 +0200

    Fix some nonempty blank lines

commit e5a34b2533720ebb9181c0edebad6774ceeff189
Author: Volker Lendecke <v...@samba.org>
Date:   Fri Jul 10 12:03:35 2009 +0200

    Remove gencache_[un]lock_key

commit 3e965d017d243f0a99e7838e6c92c37df270486c
Author: Volker Lendecke <v...@samba.org>
Date:   Fri Jul 10 11:00:24 2009 +0200

    TDB_CONTEXT -> "struct tdb_context"

commit 565046891f9f7725b5d93eefbc3be5b9c62176fd
Author: Volker Lendecke <v...@samba.org>
Date:   Fri Jul 10 10:54:33 2009 +0200

    Replace ASSERTs in gencache with "return false"
    
    It's a bit strong to panic here I think.

-----------------------------------------------------------------------

Summary of changes:
 source3/include/proto.h         |    8 +-
 source3/include/util_tdb.h      |    2 +
 source3/lib/gencache.c          |  529 +++++++++++++++++++++++++--------------
 source3/lib/netapi/netapi.c     |    1 -
 source3/lib/util_tdb.c          |   19 ++
 source3/libads/dns.c            |    8 -
 source3/libsmb/dsgetdcname.c    |   33 +--
 source3/libsmb/libsmb_context.c |    1 -
 source3/libsmb/namecache.c      |   34 ---
 source3/libsmb/namequery.c      |   12 -
 source3/libsmb/trustdom_cache.c |   67 ++----
 source3/nmbd/nmbd.c             |    2 +
 source3/smbd/server.c           |    1 +
 source3/torture/torture.c       |   16 --
 source3/utils/net.c             |    2 +
 source3/utils/net_cache.c       |   27 ++-
 source3/winbindd/winbindd.c     |    2 +
 17 files changed, 415 insertions(+), 349 deletions(-)


Changeset truncated at 500 lines:

diff --git a/source3/include/proto.h b/source3/include/proto.h
index 0dd1e98..df78155 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -515,17 +515,15 @@ void pull_file_id_24(char *buf, struct file_id *id);
 
 /* The following definitions come from lib/gencache.c  */
 
-bool gencache_init(void);
-bool gencache_shutdown(void);
 bool gencache_set(const char *keystr, const char *value, time_t timeout);
 bool gencache_del(const char *keystr);
 bool gencache_get(const char *keystr, char **valstr, time_t *timeout);
-bool gencache_get_data_blob(const char *keystr, DATA_BLOB *blob, bool 
*expired);
+bool gencache_get_data_blob(const char *keystr, DATA_BLOB *blob,
+                           time_t *timeout);
+bool gencache_stabilize(void);
 bool gencache_set_data_blob(const char *keystr, const DATA_BLOB *blob, time_t 
timeout);
 void gencache_iterate(void (*fn)(const char* key, const char *value, time_t 
timeout, void* dptr),
                       void* data, const char* keystr_pattern);
-int gencache_lock_entry( const char *key );
-void gencache_unlock_entry( const char *key );
 
 /* The following definitions come from lib/interface.c  */
 
diff --git a/source3/include/util_tdb.h b/source3/include/util_tdb.h
index c794364..80b9592 100644
--- a/source3/include/util_tdb.h
+++ b/source3/include/util_tdb.h
@@ -59,4 +59,6 @@ struct tdb_wrap *tdb_wrap_open(TALLOC_CTX *mem_ctx,
 
 NTSTATUS map_nt_error_from_tdb(enum TDB_ERROR err);
 
+int tdb_data_cmp(TDB_DATA t1, TDB_DATA t2);
+
 #endif /* __TDBUTIL_H__ */
diff --git a/source3/lib/gencache.c b/source3/lib/gencache.c
index 7f133f2..ee1f4b7 100644
--- a/source3/lib/gencache.c
+++ b/source3/lib/gencache.c
@@ -26,12 +26,13 @@
 #define DBGC_CLASS DBGC_TDB
 
 #define TIMEOUT_LEN 12
-#define CACHE_DATA_FMT "%12u/%s"
+#define CACHE_DATA_FMT "%12u/"
 #define READ_CACHE_DATA_FMT_TEMPLATE "%%12u/%%%us"
 #define BLOB_TYPE "DATA_BLOB"
 #define BLOB_TYPE_LEN 9
 
-static TDB_CONTEXT *cache;
+static struct tdb_context *cache;
+static struct tdb_context *cache_notrans;
 
 /**
  * @file gencache.c
@@ -49,9 +50,10 @@ static TDB_CONTEXT *cache;
  *         false on failure
  **/
 
-bool gencache_init(void)
+static bool gencache_init(void)
 {
        char* cache_fname = NULL;
+       int open_flags = O_RDWR|O_CREAT;
 
        /* skip file open if it's already opened */
        if (cache) return True;
@@ -60,11 +62,12 @@ bool gencache_init(void)
 
        DEBUG(5, ("Opening cache file at %s\n", cache_fname));
 
-       cache = tdb_open_log(cache_fname, 0, TDB_DEFAULT,
-                            O_RDWR|O_CREAT, 0644);
+       cache = tdb_open_log(cache_fname, 0, TDB_DEFAULT, open_flags, 0644);
 
        if (!cache && (errno == EACCES)) {
-               cache = tdb_open_log(cache_fname, 0, TDB_DEFAULT, O_RDONLY, 
0644);
+               open_flags = O_RDONLY;
+               cache = tdb_open_log(cache_fname, 0, TDB_DEFAULT, open_flags,
+                                    0644);
                if (cache) {
                        DEBUG(5, ("gencache_init: Opening cache file %s 
read-only.\n", cache_fname));
                }
@@ -74,65 +77,123 @@ bool gencache_init(void)
                DEBUG(5, ("Attempt to open gencache.tdb has failed.\n"));
                return False;
        }
-       return True;
-}
 
+       cache_fname = lock_path("gencache_notrans.tdb");
 
-/**
- * Cache shutdown function. Closes opened cache tdb file.
- *
- * @return true on successful closing the cache or
- *         false on failure during cache shutdown
- **/
+       DEBUG(5, ("Opening cache file at %s\n", cache_fname));
 
-bool gencache_shutdown(void)
-{
-       int ret;
-       /* tdb_close routine returns -1 on error */
-       if (!cache) return False;
-       DEBUG(5, ("Closing cache file\n"));
-       ret = tdb_close(cache);
-       cache = NULL;
-       return ret != -1;
+       cache_notrans = tdb_open_log(cache_fname, 0, TDB_CLEAR_IF_FIRST,
+                                    open_flags, 0644);
+       if (cache_notrans == NULL) {
+               DEBUG(5, ("Opening %s failed: %s\n", cache_fname,
+                         strerror(errno)));
+               tdb_close(cache);
+               return false;
+       }
+
+       return True;
 }
 
+static TDB_DATA last_stabilize_key(void)
+{
+       TDB_DATA result;
+       result.dptr = (uint8_t *)"@LAST_STABILIZED";
+       result.dsize = 17;
+       return result;
+}
 
 /**
  * Set an entry in the cache file. If there's no such
  * one, then add it.
  *
  * @param keystr string that represents a key of this entry
- * @param value text representation value being cached
+ * @param blob DATA_BLOB value being cached
  * @param timeout time when the value is expired
  *
  * @retval true when entry is successfuly stored
  * @retval false on failure
  **/
 
-bool gencache_set(const char *keystr, const char *value, time_t timeout)
+bool gencache_set_data_blob(const char *keystr, const DATA_BLOB *blob,
+                           time_t timeout)
 {
        int ret;
        TDB_DATA databuf;
-       char* valstr = NULL;
+       char* val;
+       time_t last_stabilize;
+       static int writecount;
+
+       if (tdb_data_cmp(string_term_tdb_data(keystr),
+                        last_stabilize_key()) == 0) {
+               DEBUG(10, ("Can't store %s as a key\n", keystr));
+               return false;
+       }
 
-       /* fail completely if get null pointers passed */
-       SMB_ASSERT(keystr && value);
+       if ((keystr == NULL) || (blob == NULL)) {
+               return false;
+       }
 
        if (!gencache_init()) return False;
 
-       if (asprintf(&valstr, CACHE_DATA_FMT, (int)timeout, value) == -1) {
+       val = talloc_asprintf(talloc_tos(), CACHE_DATA_FMT, (int)timeout);
+       if (val == NULL) {
                return False;
        }
+       val = talloc_realloc(NULL, val, char, talloc_array_length(val)-1);
+       if (val == NULL) {
+               return false;
+       }
+       val = (char *)talloc_append_blob(NULL, val, *blob);
+       if (val == NULL) {
+               return false;
+       }
 
-       databuf = string_term_tdb_data(valstr);
-       DEBUG(10, ("Adding cache entry with key = %s; value = %s and timeout ="
-                  " %s (%d seconds %s)\n", keystr, value,ctime(&timeout),
+       DEBUG(10, ("Adding cache entry with key = %s and timeout ="
+                  " %s (%d seconds %s)\n", keystr, ctime(&timeout),
                   (int)(timeout - time(NULL)), 
                   timeout > time(NULL) ? "ahead" : "in the past"));
 
-       ret = tdb_store_bystring(cache, keystr, databuf, 0);
-       SAFE_FREE(valstr);
+       ret = tdb_store_bystring(
+               cache_notrans, keystr,
+               make_tdb_data((uint8_t *)val, talloc_array_length(val)),
+               0);
+       TALLOC_FREE(val);
 
+       if (ret != 0) {
+               return false;
+       }
+
+       /*
+        * Every 100 writes within a single process, stabilize the cache with
+        * a transaction. This is done to prevent a single transaction to
+        * become huge and chew lots of memory.
+        */
+       writecount += 1;
+       if (writecount > lp_parm_int(-1, "gencache", "stabilize_count", 100)) {
+               gencache_stabilize();
+               writecount = 0;
+               goto done;
+       }
+
+       /*
+        * Every 5 minutes, call gencache_stabilize() to not let grow
+        * gencache_notrans.tdb too large.
+        */
+
+       last_stabilize = 0;
+       databuf = tdb_fetch(cache_notrans, last_stabilize_key());
+       if ((databuf.dptr != NULL)
+           && (databuf.dptr[databuf.dsize-1] == '\0')) {
+               last_stabilize = atoi((char *)databuf.dptr);
+               SAFE_FREE(databuf.dptr);
+       }
+       if ((last_stabilize
+            + lp_parm_int(-1, "gencache", "stabilize_interval", 300))
+           < time(NULL)) {
+               gencache_stabilize();
+       }
+
+done:
        return ret == 0;
 }
 
@@ -147,26 +208,63 @@ bool gencache_set(const char *keystr, const char *value, 
time_t timeout)
 
 bool gencache_del(const char *keystr)
 {
-       int ret;
+       bool exists;
+       bool ret = false;
+       char *value;
 
-       /* fail completely if get null pointers passed */
-       SMB_ASSERT(keystr);
+       if (keystr == NULL) {
+               return false;
+       }
 
        if (!gencache_init()) return False;     
 
        DEBUG(10, ("Deleting cache entry (key = %s)\n", keystr));
-       ret = tdb_delete_bystring(cache, keystr);
 
-       return ret == 0;
+       if (tdb_lock_bystring(cache_notrans, keystr) == -1) {
+               DEBUG(5, ("Could not lock key for %s\n", keystr));
+               return false;
+       }
+
+       /*
+        * We delete an element by setting its timeout to 0. This way we don't
+        * have to do a transaction on gencache.tdb every time we delete an
+        * element.
+        */
+
+       exists = gencache_get(keystr, &value, NULL);
+       if (exists) {
+               SAFE_FREE(value);
+               ret = gencache_set(keystr, "", 0);
+       }
+       tdb_unlock_bystring(cache_notrans, keystr);
+       return ret;
 }
 
+static bool gencache_pull_timeout(char *val, time_t *pres, char **pendptr)
+{
+       time_t res;
+       char *endptr;
+
+       res = strtol(val, &endptr, 10);
+
+       if ((endptr == NULL) || (*endptr != '/')) {
+               DEBUG(2, ("Invalid gencache data format: %s\n", val));
+               return false;
+       }
+       if (pres != NULL) {
+               *pres = res;
+       }
+       if (pendptr != NULL) {
+               *pendptr = endptr;
+       }
+       return true;
+}
 
 /**
  * Get existing entry from the cache file.
  *
  * @param keystr string that represents a key of this entry
- * @param valstr buffer that is allocated and filled with the entry value
- *        buffer's disposing must be done outside
+ * @param blob DATA_BLOB that is filled with entry's blob
  * @param timeout pointer to a time_t that is filled with entry's
  *        timeout
  *
@@ -174,31 +272,40 @@ bool gencache_del(const char *keystr)
  * @retval False for failure
  **/
 
-bool gencache_get(const char *keystr, char **valstr, time_t *timeout)
+bool gencache_get_data_blob(const char *keystr, DATA_BLOB *blob,
+                           time_t *timeout)
 {
        TDB_DATA databuf;
        time_t t;
        char *endptr;
 
-       /* fail completely if get null pointers passed */
-       SMB_ASSERT(keystr);
+       if (keystr == NULL) {
+               return false;
+       }
+
+       if (tdb_data_cmp(string_term_tdb_data(keystr),
+                        last_stabilize_key()) == 0) {
+               DEBUG(10, ("Can't get %s as a key\n", keystr));
+               return false;
+       }
 
        if (!gencache_init()) {
                return False;
        }
 
-       databuf = tdb_fetch_bystring(cache, keystr);
+       databuf = tdb_fetch_bystring(cache_notrans, keystr);
 
        if (databuf.dptr == NULL) {
-               DEBUG(10, ("Cache entry with key = %s couldn't be found\n",
+               databuf = tdb_fetch_bystring(cache, keystr);
+       }
+
+       if (databuf.dptr == NULL) {
+               DEBUG(10, ("Cache entry with key = %s couldn't be found \n",
                           keystr));
                return False;
        }
 
-       t = strtol((const char *)databuf.dptr, &endptr, 10);
-
-       if ((endptr == NULL) || (*endptr != '/')) {
-               DEBUG(2, ("Invalid gencache data format: %s\n", databuf.dptr));
+       if (!gencache_pull_timeout((char *)databuf.dptr, &t, &endptr)) {
                SAFE_FREE(databuf.dptr);
                return False;
        }
@@ -207,20 +314,33 @@ bool gencache_get(const char *keystr, char **valstr, 
time_t *timeout)
                   "timeout = %s", t > time(NULL) ? "valid" :
                   "expired", keystr, endptr+1, ctime(&t)));
 
+       if (t == 0) {
+               /* Deleted */
+               SAFE_FREE(databuf.dptr);
+               return False;
+       }
+
        if (t <= time(NULL)) {
 
-               /* We're expired, delete the entry */
-               tdb_delete_bystring(cache, keystr);
+               /*
+                * We're expired, delete the entry. We can't use gencache_del
+                * here, because that uses gencache_get_data_blob for checking
+                * the existence of a record. We know the thing exists and
+                * directly store an empty value with 0 timeout.
+                */
+               gencache_set(keystr, "", 0);
 
                SAFE_FREE(databuf.dptr);
                return False;
        }
 
-       if (valstr) {
-               *valstr = SMB_STRDUP(endptr+1);
-               if (*valstr == NULL) {
+       if (blob != NULL) {
+               *blob = data_blob(
+                       endptr+1,
+                       databuf.dsize - PTR_DIFF(endptr+1, databuf.dptr));
+               if (blob->data == NULL) {
                        SAFE_FREE(databuf.dptr);
-                       DEBUG(0, ("strdup failed\n"));
+                       DEBUG(0, ("memdup failed\n"));
                        return False;
                }
        }
@@ -234,155 +354,192 @@ bool gencache_get(const char *keystr, char **valstr, 
time_t *timeout)
        return True;
 } 
 
+struct stabilize_state {
+       bool written;
+       bool error;
+};
+static int stabilize_fn(struct tdb_context *tdb, TDB_DATA key, TDB_DATA val,
+                       void *priv);
+
 /**
- * Get existing entry from the cache file.
- *
- * @param keystr string that represents a key of this entry
- * @param blob DATA_BLOB that is filled with entry's blob
- * @param expired pointer to a bool that indicates whether the entry is expired
+ * Stabilize gencache
  *
- * @retval true when entry is successfuly fetched
- * @retval False for failure
- **/
+ * Migrate the clear-if-first gencache data to the stable,
+ * transaction-based gencache.tdb
+ */
 
-bool gencache_get_data_blob(const char *keystr, DATA_BLOB *blob, bool *expired)
+bool gencache_stabilize(void)
 {
-       TDB_DATA databuf;
-       time_t t;
-       char *blob_type;
-       unsigned char *buf = NULL;
-       bool ret = False;
-       fstring valstr;
-       int buflen = 0, len = 0, blob_len = 0;
-       unsigned char *blob_buf = NULL;
-
-       /* fail completely if get null pointers passed */
-       SMB_ASSERT(keystr);
+       struct stabilize_state state;
+       int res;
+       char *now;
 
        if (!gencache_init()) {
-               return False;
+               return false;
        }
 
-       databuf = tdb_fetch_bystring(cache, keystr);
-       if (!databuf.dptr) {
-               DEBUG(10,("Cache entry with key = %s couldn't be found\n",
-                         keystr));
-               return False;
+       res = tdb_transaction_start(cache);
+       if (res == -1) {
+               DEBUG(10, ("Could not start transaction on gencache.tdb: "
+                          "%s\n", tdb_errorstr(cache)));
+               return false;
+       }
+       res = tdb_transaction_start(cache_notrans);
+       if (res == -1) {
+               tdb_transaction_cancel(cache);
+               DEBUG(10, ("Could not start transaction on "
+                          "gencache_notrans.tdb: %s\n",
+                          tdb_errorstr(cache_notrans)));
+               return false;
        }
 
-       buf = (unsigned char *)databuf.dptr;
-       buflen = databuf.dsize;
+       state.error = false;
+       state.written = false;
 
-       len += tdb_unpack(buf+len, buflen-len, "fB",
-                         &valstr,
-                         &blob_len, &blob_buf);
-       if (len == -1) {
-               goto out;
+       res = tdb_traverse(cache_notrans, stabilize_fn, &state);
+       if ((res == -1) || state.error) {
+               if ((tdb_transaction_cancel(cache_notrans) == -1)
+                   || (tdb_transaction_cancel(cache) == -1)) {
+                       smb_panic("tdb_transaction_cancel failed\n");
+               }
+               return false;
        }
 
-       t = strtol(valstr, &blob_type, 10);
+       if (!state.written) {
+               if ((tdb_transaction_cancel(cache_notrans) == -1)
+                   || (tdb_transaction_cancel(cache) == -1)) {
+                       smb_panic("tdb_transaction_cancel failed\n");
+               }
+               return true;
+       }
 
-       if (strcmp(blob_type+1, BLOB_TYPE) != 0) {
-               goto out;
+       res = tdb_transaction_commit(cache);
+       if (res == -1) {
+               DEBUG(10, ("tdb_transaction_commit on gencache.tdb failed: "
+                          "%s\n", tdb_errorstr(cache)));


-- 
Samba Shared Repository

Reply via email to