[PATCH] introduce new variable fs_watermark for proxy_cache_path

Maxim Dounin mdounin at mdounin.ru
Fri Jun 5 13:22:05 UTC 2020


Hello!

On Thu, May 07, 2020 at 01:40:54AM +0200, Adam Bambuch wrote:

> # HG changeset patch
> # User Adam Bambuch <adam.bambuch2 at gmail.com>
> # Date 1588808163 -7200
> #      Thu May 07 01:36:03 2020 +0200
> # Node ID 8d054b64f07457cad2b74376d5f88162c887ba35
> # Parent  716eddd74bc2831537f5b3f7ecd16ad3e516d043
> introduce new variable fs_watermark for proxy_cache_path
> 
> This configuration parameter should help with better disk usage,
> especially in environments, where nginx doesn't have a separate
> partition for caching and disk space is shared between multiple apps.
> It could also help in environments, where cache contains many small
> files, and cache loader can't load all the files in a reasonable time
> and therefore max_size is exceeded for many hours after nginx restart.

[...]

Thanks for the patch.

This is something I was thinking about for a while, since such 
approach indeed can be better than existing cache clearing in many 
cases, even if the cache partition is dedicated to nginx: in 
particular, it can be used to keep disk usage under control 
regardless of the amount of temporary files kept on the same 
partition.

The patch below simplifies the approach, and also fixes some 
issues with the patch.  Notable changes include:

- The parameter is renamed to "min_free", which is in line with 
  "max_size" and seems to be much more readable.

- Error reporting is removed and statfs() / statvfs() / 
  GetDiskFreeSpaceEx() errors, if any, instead result in maximum 
  amount of free space being reported (and min_free cache clearing 
  effectively disabled), similarly to how it happens with 
  ngx_fs_bsize().

- Fixed overflow on 32-bit platforms and incorrect cast in "return 
  (ssize_t) (fs.f_bavail * fs.f_bsize);" in statfs() and statvfs() 
  cases.

- Fixed incorrect usage of fs.f_bsize instead of fs.f_frsize in 
  statvfs() case.

- Fixed configuration parsing to report "not available on this 
  platform" if statfs() / statvfs() is not present for some 
  reason.

- Slightly improved ngx_http_file_cache_manager() logic to avoid 
  reporting very large free space values in debug logs if min_free 
  is not configured.

- Unused output arguments of GetDiskFreeSpaceEx() replaced with 
  NULL pointers, since GetDiskFreeSpaceEx() allows this.

- Various style issues fixed.

# HG changeset patch
# User Maxim Dounin <mdounin at mdounin.ru>
# Date 1591326790 -10800
#      Fri Jun 05 06:13:10 2020 +0300
# Node ID 850c0efeaddaf3274f791c90d321d295702bd55c
# Parent  14665e4b377c9eae1f07de003b6248923ca087ee
Cache: introduced min_free cache clearing.

Clearing cache based on free space left on a filesystem is
expected to allow better disk utilization in some cases, notably
when disk space might be also used for something other than nginx
cache (including nginx own temporary files) and while loading
cache (when cache size might be inaccurate for a while, effectively
disabling max_size cache clearing).

Based on a patch by Adam Bambuch.

diff --git a/src/http/ngx_http_cache.h b/src/http/ngx_http_cache.h
--- a/src/http/ngx_http_cache.h
+++ b/src/http/ngx_http_cache.h
@@ -160,6 +160,7 @@ struct ngx_http_file_cache_s {
 
     ngx_path_t                      *path;
 
+    off_t                            min_free;
     off_t                            max_size;
     size_t                           bsize;
 
diff --git a/src/http/ngx_http_file_cache.c b/src/http/ngx_http_file_cache.c
--- a/src/http/ngx_http_file_cache.c
+++ b/src/http/ngx_http_file_cache.c
@@ -1959,7 +1959,7 @@ ngx_http_file_cache_manager(void *data)
 {
     ngx_http_file_cache_t  *cache = data;
 
-    off_t       size;
+    off_t       size, free;
     time_t      wait;
     ngx_msec_t  elapsed, next;
     ngx_uint_t  count, watermark;
@@ -1988,7 +1988,19 @@ ngx_http_file_cache_manager(void *data)
                        size, count, (ngx_int_t) watermark);
 
         if (size < cache->max_size && count < watermark) {
-            break;
+
+            if (!cache->min_free) {
+                break;
+            }
+
+            free = ngx_fs_available(cache->path->name.data);
+
+            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
+                           "http file cache free: %O", free);
+
+            if (free > cache->min_free) {
+                break;
+            }
         }
 
         wait = ngx_http_file_cache_forced_expire(cache);
@@ -2304,7 +2316,7 @@ ngx_http_file_cache_set_slot(ngx_conf_t 
 {
     char  *confp = conf;
 
-    off_t                   max_size;
+    off_t                   max_size, min_free;
     u_char                 *last, *p;
     time_t                  inactive;
     ssize_t                 size;
@@ -2341,6 +2353,7 @@ ngx_http_file_cache_set_slot(ngx_conf_t 
     name.len = 0;
     size = 0;
     max_size = NGX_MAX_OFF_T_VALUE;
+    min_free = 0;
 
     value = cf->args->elts;
 
@@ -2476,6 +2489,29 @@ ngx_http_file_cache_set_slot(ngx_conf_t 
             continue;
         }
 
+        if (ngx_strncmp(value[i].data, "min_free=", 9) == 0) {
+
+#if (NGX_WIN32 || NGX_HAVE_STATFS || NGX_HAVE_STATVFS)
+
+            s.len = value[i].len - 9;
+            s.data = value[i].data + 9;
+
+            min_free = ngx_parse_offset(&s);
+            if (min_free < 0) {
+                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                                   "invalid min_free value \"%V\"", &value[i]);
+                return NGX_CONF_ERROR;
+            }
+
+#else
+            ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
+                               "min_free is not supported "
+                               "on this platform, ignored");
+#endif
+
+            continue;
+        }
+
         if (ngx_strncmp(value[i].data, "loader_files=", 13) == 0) {
 
             loader_files = ngx_atoi(value[i].data + 13, value[i].len - 13);
@@ -2607,6 +2643,7 @@ ngx_http_file_cache_set_slot(ngx_conf_t 
 
     cache->inactive = inactive;
     cache->max_size = max_size;
+    cache->min_free = min_free;
 
     caches = (ngx_array_t *) (confp + cmd->offset);
 
diff --git a/src/os/unix/ngx_files.c b/src/os/unix/ngx_files.c
--- a/src/os/unix/ngx_files.c
+++ b/src/os/unix/ngx_files.c
@@ -884,6 +884,19 @@ ngx_fs_bsize(u_char *name)
     return (size_t) fs.f_bsize;
 }
 
+
+off_t
+ngx_fs_available(u_char *name)
+{
+    struct statfs  fs;
+
+    if (statfs((char *) name, &fs) == -1) {
+        return NGX_MAX_OFF_T_VALUE;
+    }
+
+    return (off_t) fs.f_bavail * fs.f_bsize;
+}
+
 #elif (NGX_HAVE_STATVFS)
 
 size_t
@@ -908,6 +921,19 @@ ngx_fs_bsize(u_char *name)
     return (size_t) fs.f_frsize;
 }
 
+
+off_t
+ngx_fs_available(u_char *name)
+{
+    struct statvfs  fs;
+
+    if (statvfs((char *) name, &fs) == -1) {
+        return NGX_MAX_OFF_T_VALUE;
+    }
+
+    return (off_t) fs.f_bavail * fs.f_frsize;
+}
+
 #else
 
 size_t
@@ -916,4 +942,11 @@ ngx_fs_bsize(u_char *name)
     return 512;
 }
 
+
+off_t
+ngx_fs_available(u_char *name)
+{
+    return NGX_MAX_OFF_T_VALUE;
+}
+
 #endif
diff --git a/src/os/unix/ngx_files.h b/src/os/unix/ngx_files.h
--- a/src/os/unix/ngx_files.h
+++ b/src/os/unix/ngx_files.h
@@ -349,6 +349,7 @@ ngx_int_t ngx_directio_off(ngx_fd_t fd);
 #endif
 
 size_t ngx_fs_bsize(u_char *name);
+off_t ngx_fs_available(u_char *name);
 
 
 #if (NGX_HAVE_OPENAT)
diff --git a/src/os/win32/ngx_files.c b/src/os/win32/ngx_files.c
--- a/src/os/win32/ngx_files.c
+++ b/src/os/win32/ngx_files.c
@@ -658,6 +658,19 @@ ngx_fs_bsize(u_char *name)
 }
 
 
+off_t
+ngx_fs_available(u_char *name)
+{
+    ULARGE_INTEGER  navail;
+
+    if (GetDiskFreeSpaceEx((const char *) name, &navail, NULL, NULL) == 0) {
+        return NGX_MAX_OFF_T_VALUE;
+    }
+
+    return (off_t) navail.QuadPart;
+}
+
+
 static ngx_int_t
 ngx_win32_check_filename(u_char *name, u_short *u, size_t len)
 {
diff --git a/src/os/win32/ngx_files.h b/src/os/win32/ngx_files.h
--- a/src/os/win32/ngx_files.h
+++ b/src/os/win32/ngx_files.h
@@ -259,6 +259,7 @@ ngx_int_t ngx_directio_off(ngx_fd_t fd);
 #define ngx_directio_off_n          "ngx_directio_off_n"
 
 size_t ngx_fs_bsize(u_char *name);
+off_t ngx_fs_available(u_char *name);
 
 
 #define ngx_stdout               GetStdHandle(STD_OUTPUT_HANDLE)


-- 
Maxim Dounin
http://mdounin.ru/


More information about the nginx-devel mailing list