Mercurial > hg > nginx
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) |