diff --git a/core/cache.c b/core/cache.c index 4481391c..9c1cf48b 100644 --- a/core/cache.c +++ b/core/cache.c @@ -156,14 +156,14 @@ static void cache_send_udp_command(struct uwsgi_cache *, char *, uint16_t, char static void cache_sync_hook(char *k, uint16_t kl, char *v, uint16_t vl, void *data) { struct uwsgi_cache *uc = (struct uwsgi_cache *) data; if (!uwsgi_strncmp(k, kl, "items", 5)) { - size_t num = uwsgi_str_num(v, vl); + size_t num = uwsgi_str_num(v, vl); if (num != uc->max_items) { uwsgi_log("[cache-sync] invalid cache size, expected %llu received %llu\n", (unsigned long long) uc->max_items, (unsigned long long) num); exit(1); } } if (!uwsgi_strncmp(k, kl, "blocksize", 9)) { - size_t num = uwsgi_str_num(v, vl); + size_t num = uwsgi_str_num(v, vl); if (num != uc->blocksize) { uwsgi_log("[cache-sync] invalid cache block size, expected %llu received %llu\n", (unsigned long long) uc->blocksize, (unsigned long long) num); exit(1); @@ -427,6 +427,10 @@ int uwsgi_cache_del2(struct uwsgi_cache *uc, char *key, uint16_t keylen, uint64_ uci->expires = 0; uc->n_items--; + + if (uc->use_last_modified) { + uc->last_modified_at = uwsgi_now(); + } } if (uc->nodes && ret == 0 && !(flags & UWSGI_CACHE_FLAG_LOCAL)) { @@ -473,6 +477,7 @@ int uwsgi_cache_set2(struct uwsgi_cache *uc, char *key, uint16_t keylen, char *v uint8_t rollback_mode = 0; int ret = -1; + time_t now = 0; if (!keylen || !vallen) return -1; @@ -518,13 +523,13 @@ int uwsgi_cache_set2(struct uwsgi_cache *uc, char *key, uint16_t keylen, char *v uc->unused_blocks_stack_ptr++; } else if (rollback_mode == 2) { - uc->first_available_block--; + uc->first_available_block--; } goto end; } // mark used blocks; - uint64_t needed_blocks = cache_mark_blocks(uc, uci->first_block, vallen); - // optimize teh scan + uint64_t needed_blocks = cache_mark_blocks(uc, uci->first_block, vallen); + // optimize the scan if (uc->blocks_bitmap_pos + (needed_blocks+1) > uc->blocks) { uc->blocks_bitmap_pos = 0; } @@ -532,8 +537,10 @@ int uwsgi_cache_set2(struct uwsgi_cache *uc, char *key, uint16_t keylen, char *v uc->blocks_bitmap_pos = uci->first_block + needed_blocks + 1; } } - if (expires && !(flags & UWSGI_CACHE_FLAG_ABSEXPIRE)) - expires += uwsgi_now(); + if (expires && !(flags & UWSGI_CACHE_FLAG_ABSEXPIRE)) { + now = uwsgi_now(); + expires += now; + } uci->expires = expires; uci->hash = uc->hash->func(key, keylen); uci->hits = 0; @@ -572,7 +579,8 @@ int uwsgi_cache_set2(struct uwsgi_cache *uc, char *key, uint16_t keylen, char *v else if (flags & UWSGI_CACHE_FLAG_UPDATE) { uci = cache_item(index); if (expires && !(flags & UWSGI_CACHE_FLAG_ABSEXPIRE)) { - expires += uwsgi_now(); + now = uwsgi_now(); + expires += now; uci->expires = expires; } if (uc->blocks_bitmap) { @@ -601,7 +609,11 @@ int uwsgi_cache_set2(struct uwsgi_cache *uc, char *key, uint16_t keylen, char *v uci->valsize = vallen; ret = 0; } - + + if (uc->use_last_modified) { + uc->last_modified_at = (now ? now : uwsgi_now()); + } + if (uc->nodes && ret == 0 && !(flags & UWSGI_CACHE_FLAG_LOCAL)) { cache_send_udp_command(uc, key, keylen, val, vallen, expires, 10); } @@ -879,6 +891,7 @@ struct uwsgi_cache *uwsgi_cache_create(char *arg) { uc->nodes = uwsgi.cache_udp_node; uc->udp_servers = uwsgi.cache_udp_server; uc->store_sync = uwsgi.cache_store_sync; + uc->use_last_modified = (uint8_t) uwsgi.cache_use_last_modified; if (uwsgi.cache_sync) { uwsgi_string_new_list(&uc->sync_nodes, uwsgi.cache_sync); @@ -898,6 +911,7 @@ struct uwsgi_cache *uwsgi_cache_create(char *arg) { char *c_sync = NULL; char *c_udp_servers = NULL; char *c_bitmap = NULL; + char *c_use_last_modified = NULL; if (uwsgi_kvlist_parse(arg, strlen(arg), ',', '=', "name", &c_name, @@ -923,6 +937,7 @@ struct uwsgi_cache *uwsgi_cache_create(char *arg) { "udpservers", &c_udp_servers, "udpserver", &c_udp_servers, "bitmap", &c_bitmap, + "lastmod", &c_use_last_modified, NULL)) { uwsgi_log("unable to parse cache definition\n"); exit(1); @@ -967,6 +982,7 @@ struct uwsgi_cache *uwsgi_cache_create(char *arg) { uc->use_blocks_bitmap = 1; uc->max_item_size = uc->blocksize * uc->blocks; } + if (c_use_last_modified) uc->use_last_modified = 1; uc->store_sync = uwsgi.cache_store_sync; if (c_store_sync) { uc->store_sync = uwsgi_n64(c_store_sync); } diff --git a/core/master_utils.c b/core/master_utils.c index 28909312..302f9c58 100644 --- a/core/master_utils.c +++ b/core/master_utils.c @@ -858,7 +858,10 @@ struct uwsgi_stats *uwsgi_master_generate_stats() { if (uwsgi_stats_keylong_comma(us, "miss", (unsigned long long) uc->miss)) goto end; - if (uwsgi_stats_keylong(us, "full", (unsigned long long) uc->full)) + if (uwsgi_stats_keylong_comma(us, "full", (unsigned long long) uc->full)) + goto end; + + if (uwsgi_stats_keylong(us, "last_modified_at", (unsigned long long) uc->last_modified_at)) goto end; if (uwsgi_stats_object_close(us)) diff --git a/core/uwsgi.c b/core/uwsgi.c index cfe10058..4a6a0c6e 100644 --- a/core/uwsgi.c +++ b/core/uwsgi.c @@ -226,6 +226,7 @@ static struct uwsgi_option uwsgi_base_options[] = { {"cache-udp-server", required_argument, 0, "bind the cache udp server (used only for set/update/delete) to the specified socket", uwsgi_opt_add_string_list, &uwsgi.cache_udp_server, UWSGI_OPT_MASTER}, {"cache-udp-node", required_argument, 0, "send cache update/deletion to the specified cache udp server", uwsgi_opt_add_string_list, &uwsgi.cache_udp_node, UWSGI_OPT_MASTER}, {"cache-sync", required_argument, 0, "copy the whole content of another uWSGI cache server on server startup", uwsgi_opt_set_str, &uwsgi.cache_sync, 0}, + {"cache-use-last-modified", no_argument, 0, "update last_modified_at timestamp on every cache item modification (default is disabled)", uwsgi_opt_true, &uwsgi.cache_use_last_modified, 0}, {"load-file-in-cache", required_argument, 0, "load a static file in the cache", uwsgi_opt_add_string_list, &uwsgi.load_file_in_cache, 0}, diff --git a/uwsgi.h b/uwsgi.h index 2d1d006c..1f6531a7 100644 --- a/uwsgi.h +++ b/uwsgi.h @@ -713,6 +713,9 @@ struct uwsgi_cache { uint64_t n_items; struct uwsgi_cache_item *items; + uint8_t use_last_modified; + time_t last_modified_at; + void *data; uint8_t no_expire; @@ -1863,6 +1866,7 @@ struct uwsgi_server { struct uwsgi_string_list *cache2; int cache_setup; int locking_setup; + int cache_use_last_modified; struct uwsgi_dyn_dict *static_expires_type; struct uwsgi_dyn_dict *static_expires_type_mtime;