comparison src/http/ngx_http_file_cache.c @ 6445:c9d680b00744

Cache: added watermark to reduce IO load when keys_zone is full. When a keys_zone is full then each next request to the cache is penalized. That is, the cache has to evict older files to get a slot from the keys_zone synchronously. The patch introduces new behavior in this scenario. Manager will try to maintain available free slots in the keys_zone by cleaning old files in the background.
author Dmitry Volyntsev <xeioex@nginx.com>
date Fri, 18 Mar 2016 15:08:21 +0300
parents 043914d19be8
children 22c32937a41f
comparison
equal deleted inserted replaced
6444:043914d19be8 6445:c9d680b00744
60 ngx_str_t *path); 60 ngx_str_t *path);
61 static ngx_int_t ngx_http_file_cache_add(ngx_http_file_cache_t *cache, 61 static ngx_int_t ngx_http_file_cache_add(ngx_http_file_cache_t *cache,
62 ngx_http_cache_t *c); 62 ngx_http_cache_t *c);
63 static ngx_int_t ngx_http_file_cache_delete_file(ngx_tree_ctx_t *ctx, 63 static ngx_int_t ngx_http_file_cache_delete_file(ngx_tree_ctx_t *ctx,
64 ngx_str_t *path); 64 ngx_str_t *path);
65 static void ngx_http_file_cache_set_watermark(ngx_http_file_cache_t *cache);
65 66
66 67
67 ngx_str_t ngx_http_cache_status[] = { 68 ngx_str_t ngx_http_cache_status[] = {
68 ngx_string("MISS"), 69 ngx_string("MISS"),
69 ngx_string("BYPASS"), 70 ngx_string("BYPASS"),
145 ngx_queue_init(&cache->sh->queue); 146 ngx_queue_init(&cache->sh->queue);
146 147
147 cache->sh->cold = 1; 148 cache->sh->cold = 1;
148 cache->sh->loading = 0; 149 cache->sh->loading = 0;
149 cache->sh->size = 0; 150 cache->sh->size = 0;
151 cache->sh->count = 0;
152 cache->sh->watermark = (ngx_uint_t) -1;
150 153
151 cache->bsize = ngx_fs_bsize(cache->path->name.data); 154 cache->bsize = ngx_fs_bsize(cache->path->name.data);
152 155
153 cache->max_size /= cache->bsize; 156 cache->max_size /= cache->bsize;
154 157
859 } 862 }
860 863
861 fcn = ngx_slab_calloc_locked(cache->shpool, 864 fcn = ngx_slab_calloc_locked(cache->shpool,
862 sizeof(ngx_http_file_cache_node_t)); 865 sizeof(ngx_http_file_cache_node_t));
863 if (fcn == NULL) { 866 if (fcn == NULL) {
867 ngx_http_file_cache_set_watermark(cache);
868
864 ngx_shmtx_unlock(&cache->shpool->mutex); 869 ngx_shmtx_unlock(&cache->shpool->mutex);
865 870
866 (void) ngx_http_file_cache_forced_expire(cache); 871 (void) ngx_http_file_cache_forced_expire(cache);
867 872
868 ngx_shmtx_lock(&cache->shpool->mutex); 873 ngx_shmtx_lock(&cache->shpool->mutex);
874 "could not allocate node%s", cache->shpool->log_ctx); 879 "could not allocate node%s", cache->shpool->log_ctx);
875 rc = NGX_ERROR; 880 rc = NGX_ERROR;
876 goto failed; 881 goto failed;
877 } 882 }
878 } 883 }
884
885 cache->sh->count++;
879 886
880 ngx_memcpy((u_char *) &fcn->node.key, c->key, sizeof(ngx_rbtree_key_t)); 887 ngx_memcpy((u_char *) &fcn->node.key, c->key, sizeof(ngx_rbtree_key_t));
881 888
882 ngx_memcpy(fcn->key, &c->key[sizeof(ngx_rbtree_key_t)], 889 ngx_memcpy(fcn->key, &c->key[sizeof(ngx_rbtree_key_t)],
883 NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t)); 890 NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t));
1629 1636
1630 } else if (!fcn->exists && fcn->count == 0 && c->min_uses == 1) { 1637 } else if (!fcn->exists && fcn->count == 0 && c->min_uses == 1) {
1631 ngx_queue_remove(&fcn->queue); 1638 ngx_queue_remove(&fcn->queue);
1632 ngx_rbtree_delete(&cache->sh->rbtree, &fcn->node); 1639 ngx_rbtree_delete(&cache->sh->rbtree, &fcn->node);
1633 ngx_slab_free_locked(cache->shpool, fcn); 1640 ngx_slab_free_locked(cache->shpool, fcn);
1641 cache->sh->count--;
1634 c->node = NULL; 1642 c->node = NULL;
1635 } 1643 }
1636 1644
1637 ngx_shmtx_unlock(&cache->shpool->mutex); 1645 ngx_shmtx_unlock(&cache->shpool->mutex);
1638 1646
1881 1889
1882 if (fcn->count == 0) { 1890 if (fcn->count == 0) {
1883 ngx_queue_remove(q); 1891 ngx_queue_remove(q);
1884 ngx_rbtree_delete(&cache->sh->rbtree, &fcn->node); 1892 ngx_rbtree_delete(&cache->sh->rbtree, &fcn->node);
1885 ngx_slab_free_locked(cache->shpool, fcn); 1893 ngx_slab_free_locked(cache->shpool, fcn);
1894 cache->sh->count--;
1886 } 1895 }
1887 } 1896 }
1888 1897
1889 1898
1890 static time_t 1899 static time_t
1891 ngx_http_file_cache_manager(void *data) 1900 ngx_http_file_cache_manager(void *data)
1892 { 1901 {
1893 ngx_http_file_cache_t *cache = data; 1902 ngx_http_file_cache_t *cache = data;
1894 1903
1895 off_t size; 1904 off_t size;
1896 time_t next, wait; 1905 time_t next, wait;
1906 ngx_uint_t count, watermark;
1897 1907
1898 next = ngx_http_file_cache_expire(cache); 1908 next = ngx_http_file_cache_expire(cache);
1899 1909
1900 cache->last = ngx_current_msec; 1910 cache->last = ngx_current_msec;
1901 cache->files = 0; 1911 cache->files = 0;
1902 1912
1903 for ( ;; ) { 1913 for ( ;; ) {
1904 ngx_shmtx_lock(&cache->shpool->mutex); 1914 ngx_shmtx_lock(&cache->shpool->mutex);
1905 1915
1906 size = cache->sh->size; 1916 size = cache->sh->size;
1917 count = cache->sh->count;
1918 watermark = cache->sh->watermark;
1907 1919
1908 ngx_shmtx_unlock(&cache->shpool->mutex); 1920 ngx_shmtx_unlock(&cache->shpool->mutex);
1909 1921
1910 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, 1922 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
1911 "http file cache size: %O", size); 1923 "http file cache size: %O c:%ui w:%i",
1912 1924 size, count, (ngx_int_t) watermark);
1913 if (size < cache->max_size) { 1925
1926 if (size < cache->max_size && count < watermark) {
1914 return next; 1927 return next;
1915 } 1928 }
1916 1929
1917 wait = ngx_http_file_cache_forced_expire(cache); 1930 wait = ngx_http_file_cache_forced_expire(cache);
1918 1931
2092 if (fcn == NULL) { 2105 if (fcn == NULL) {
2093 2106
2094 fcn = ngx_slab_calloc_locked(cache->shpool, 2107 fcn = ngx_slab_calloc_locked(cache->shpool,
2095 sizeof(ngx_http_file_cache_node_t)); 2108 sizeof(ngx_http_file_cache_node_t));
2096 if (fcn == NULL) { 2109 if (fcn == NULL) {
2110 ngx_http_file_cache_set_watermark(cache);
2111
2097 if (cache->fail_time != ngx_time()) { 2112 if (cache->fail_time != ngx_time()) {
2098 cache->fail_time = ngx_time(); 2113 cache->fail_time = ngx_time();
2099 ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, 2114 ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
2100 "could not allocate node%s", cache->shpool->log_ctx); 2115 "could not allocate node%s", cache->shpool->log_ctx);
2101 } 2116 }
2102 2117
2118 cache->sh->count++;
2119
2103 ngx_shmtx_unlock(&cache->shpool->mutex); 2120 ngx_shmtx_unlock(&cache->shpool->mutex);
2104 return NGX_ERROR; 2121 return NGX_ERROR;
2105 } 2122 }
2106 2123
2107 ngx_memcpy((u_char *) &fcn->node.key, c->key, sizeof(ngx_rbtree_key_t)); 2124 ngx_memcpy((u_char *) &fcn->node.key, c->key, sizeof(ngx_rbtree_key_t));
2141 ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno, 2158 ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
2142 ngx_delete_file_n " \"%s\" failed", path->data); 2159 ngx_delete_file_n " \"%s\" failed", path->data);
2143 } 2160 }
2144 2161
2145 return NGX_OK; 2162 return NGX_OK;
2163 }
2164
2165
2166 static void
2167 ngx_http_file_cache_set_watermark(ngx_http_file_cache_t *cache)
2168 {
2169 cache->sh->watermark = cache->sh->count - cache->sh->count / 8;
2170
2171 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
2172 "http file cache watermark: %ui", cache->sh->watermark);
2146 } 2173 }
2147 2174
2148 2175
2149 time_t 2176 time_t
2150 ngx_http_file_cache_valid(ngx_array_t *cache_valid, ngx_uint_t status) 2177 ngx_http_file_cache_valid(ngx_array_t *cache_valid, ngx_uint_t status)