diff options
-rw-r--r-- | source3/lib/gencache.c | 89 |
1 files changed, 75 insertions, 14 deletions
diff --git a/source3/lib/gencache.c b/source3/lib/gencache.c index 9a4cbc2cd7..577ff12a19 100644 --- a/source3/lib/gencache.c +++ b/source3/lib/gencache.c @@ -40,6 +40,13 @@ static struct tdb_context *cache_notrans; * @brief Generic, persistent and shared between processes cache mechanism * for use by various parts of the Samba code * + * We have two cache files, one with transactions (gencache.tdb) and + * one without (gencache_notrans.tdb) that is CLEAR_IF_FIRST. Normal + * writes go to the gencache_notrans.tdb to be fast. Every 100 writes + * to the gencache (settable with gencache:stabilize_count) or every 5 + * minutes (settable with gencache:stabilize_interval) we stabilize + * gencache_notrans.tdb with one transaction to gencache.tdb. + * **/ @@ -107,7 +114,8 @@ again: DEBUG(5, ("Opening cache file at %s\n", cache_fname)); - cache_notrans = tdb_open_log(cache_fname, 0, TDB_CLEAR_IF_FIRST, + cache_notrans = tdb_open_log(cache_fname, 0, + TDB_CLEAR_IF_FIRST | TDB_SEQNUM, open_flags, 0644); if (cache_notrans == NULL) { DEBUG(5, ("Opening %s failed: %s\n", cache_fname, @@ -128,6 +136,51 @@ static TDB_DATA last_stabilize_key(void) return result; } +struct gencache_parse_last_stabilize_state { + bool found; + int last_time; + int last_seqnum; +}; + +static int gencache_parse_last_stabilize_fn(TDB_DATA key, TDB_DATA data, + void *private_data) +{ + struct gencache_parse_last_stabilize_state *state = + (struct gencache_parse_last_stabilize_state *)private_data; + + if ((data.dptr == NULL) || (data.dsize == 0) || + (data.dptr[data.dsize-1] != '\0')) { + return -1; + } + + if (sscanf((char *)data.dptr, "%d/%d", &state->last_time, + &state->last_seqnum) != 2) { + return -1; + } + + state->found = true; + return 0; +} + +static bool gencache_parse_last_stabilize(time_t *last_time, int *last_seqnum) +{ + struct gencache_parse_last_stabilize_state state; + + state.found = false; + + if (tdb_parse_record(cache_notrans, last_stabilize_key(), + gencache_parse_last_stabilize_fn, + &state) == -1) { + return false; + } + if (!state.found) { + return false; + } + *last_time = state.last_time; + *last_seqnum = state.last_seqnum; + return true; +} + /** * Set an entry in the cache file. If there's no such * one, then add it. @@ -144,9 +197,9 @@ bool gencache_set_data_blob(const char *keystr, const DATA_BLOB *blob, time_t timeout) { int ret; - TDB_DATA databuf; char* val; time_t last_stabilize; + int last_seqnum; static int writecount; if (tdb_data_cmp(string_term_tdb_data(keystr), @@ -206,17 +259,15 @@ bool gencache_set_data_blob(const char *keystr, const DATA_BLOB *blob, * 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(); + if (gencache_parse_last_stabilize(&last_stabilize, &last_seqnum)) { + time_t next; + + next = last_stabilize + lp_parm_int( + -1, "gencache", "stabilize_interval", 300); + + if (next < time(NULL)) { + gencache_stabilize(); + } } done: @@ -411,11 +462,19 @@ bool gencache_stabilize(void) struct stabilize_state state; int res; char *now; + time_t last_time; + int last_seqnum; if (!gencache_init()) { return false; } + if (gencache_parse_last_stabilize(&last_time, &last_seqnum) + && (last_seqnum == tdb_get_seqnum(cache_notrans))) { + /* Nothing changed */ + return true; + } + res = tdb_transaction_start(cache); if (res == -1) { DEBUG(10, ("Could not start transaction on gencache.tdb: " @@ -468,7 +527,9 @@ bool gencache_stabilize(void) return false; } - now = talloc_asprintf(talloc_tos(), "%d", (int)time(NULL)); + now = talloc_asprintf(talloc_tos(), "%d/%d", + (int)time(NULL), + tdb_get_seqnum(cache_notrans)+1); if (now != NULL) { tdb_store(cache_notrans, last_stabilize_key(), string_term_tdb_data(now), 0); |