<div dir="ltr"># HG changeset patch<br># User Vadim Fedorenko <<a href="mailto:vfedorenko@yandex-team.ru">vfedorenko@yandex-team.ru</a>><br># Date 1515713238 -10800<br>#      Fri Jan 12 02:27:18 2018 +0300<br># Node ID fbf6a421212b291cbacfcfc503173c0168449165<br># Parent  93abb5a855d6534f0356882f45be49f8c6a95a8b<br>Add preadv2 support with RWF_NOWAIT flag<br><br>Introduction of thread pools is really good thing, but it adds<br>overhead to reading files which are already in page cache in linux.<br>With preadv2 (introduced in Linux 4.6) and RWF_NOWAIT flag (introduced<br>in Linux 4.14) we can eliminate this overhead. Needs glibc >= 2.26<br><br>This is v2 patch with code style fixes. Feature renamed to<br>NGX_HAVE_PREADV2_NOWAIT, call to preadv2() moved to ngx_thread_read(),<br>that's why it became simpler.<br><br>diff -r 93abb5a855d6 -r fbf6a421212b auto/unix<br>--- a/auto/unix Thu Jan 11 21:43:49 2018 +0300<br>+++ b/auto/unix Fri Jan 12 02:27:18 2018 +0300<br>@@ -727,6 +727,23 @@<br> . auto/feature<br> <br> <br>+# preadv2() was introduced in Linux 4.6, glibc 2.26<br>+# RWF_NOWAIT flag was introduced in Linux 4.14<br>+<br>+ngx_feature="preadv2()"<br>+ngx_feature_name="NGX_HAVE_PREADV2_NOWAIT"<br>+ngx_feature_run=no<br>+ngx_feature_incs='#include <sys/uio.h>'<br>+ngx_feature_path=<br>+ngx_feature_libs=<br>+ngx_feature_test="char buf[1]; struct iovec vec[1]; ssize_t n;<br>+                  vec[0].iov_base = buf;<br>+                  vec[0].iov_len = 1;<br>+                  n = preadv2(0, vec, 1, 0, RWF_NOWAIT);<br>+                  if (n == -1) return 1"<br>+. auto/feature<br>+<br>+<br> ngx_feature="sys_nerr"<br> ngx_feature_name="NGX_SYS_NERR"<br> ngx_feature_run=value<br>diff -r 93abb5a855d6 -r fbf6a421212b src/os/unix/ngx_files.c<br>--- a/src/os/unix/ngx_files.c   Thu Jan 11 21:43:49 2018 +0300<br>+++ b/src/os/unix/ngx_files.c   Fri Jan 12 02:27:18 2018 +0300<br>@@ -26,6 +26,61 @@<br> <br> #endif<br> <br>+#if (NGX_THREADS) && (NGX_HAVE_PREADV2_NOWAIT)<br>+<br>+ngx_uint_t  ngx_preadv2_nowait = 1;<br>+<br>+<br>+ssize_t<br>+ngx_preadv2_file(ngx_file_t *file, u_char *buf, size_t size, off_t offset)<br>+{<br>+    ssize_t  n;<br>+    struct iovec   iovs[1];<br>+<br>+    if (!ngx_preadv2_nowait) {<br>+        return NGX_AGAIN;<br>+    }<br>+<br>+    iovs[0].iov_base = buf;<br>+    iovs[0].iov_len = size;<br>+<br>+    n = preadv2(file->fd, iovs, 1, offset, RWF_NOWAIT);<br>+<br>+    if (n == -1) { /* let's analyze the return code */<br>+        switch (ngx_errno) {<br>+            case EAGAIN:<br>+                ngx_log_debug(NGX_LOG_DEBUG_CORE, file->log, 0,<br>+                              "preadv2() will block on \"%s\"",<br>+                              file->name.data);<br>+                return NGX_AGAIN;<br>+            case EINVAL:<br>+                /* Most possible case - not supported RWF_NOWAIT */<br>+                ngx_log_error(NGX_LOG_ERR, file->log, ngx_errno,<br>+                              "preadv2() \"%s\" failed RWF_NOWAIT",<br>+                              file->name.data);<br>+                ngx_preadv2_nowait = 0;<br>+                return NGX_AGAIN;<br>+            default:<br>+                return NGX_AGAIN;<br>+<br>+        }<br>+    }<br>+<br>+    /* Check if we read partial file */<br>+    if (((size_t)n < size) && (n < file->info.st_size)) {<br>+        /* blocked on partial read */<br>+        ngx_log_debug2(NGX_LOG_DEBUG_CORE, file->log, 0,<br>+                       "preadv2() blocked partial on \"%s\" "<br>+                       "with read size %uz", file->name.data, n);<br>+        return NGX_AGAIN;<br>+    }<br>+<br>+    file->offset += n;<br>+<br>+    return n;<br>+}<br>+#endif<br>+<br> <br> ssize_t<br> ngx_read_file(ngx_file_t *file, u_char *buf, size_t size, off_t offset)<br>@@ -97,6 +152,9 @@<br> {<br>     ngx_thread_task_t      *task;<br>     ngx_thread_file_ctx_t  *ctx;<br>+#if (NGX_HAVE_PREADV2_NOWAIT)<br>+    ssize_t  n;<br>+#endif<br> <br>     ngx_log_debug4(NGX_LOG_DEBUG_CORE, file->log, 0,<br>                    "thread read: %d, %p, %uz, %O",<br>@@ -105,6 +163,15 @@<br>     task = file->thread_task;<br> <br>     if (task == NULL) {<br>+#if (NGX_HAVE_PREADV2_NOWAIT)<br>+        n = ngx_preadv2_file(file, buf, size, offset);<br>+        if (n != NGX_AGAIN) {<br>+            ngx_log_debug2(NGX_LOG_DEBUG_CORE, file->log, 0,<br>+                           "preadv2 non blocking: \"%s\" - %uz",<br>+                           file->name.data, n);<br>+            return n;<br>+        }<br>+#endif<br>         task = ngx_thread_task_alloc(pool, sizeof(ngx_thread_file_ctx_t));<br>         if (task == NULL) {<br>             return NGX_ERROR;</div>