Welcome! Log In Create A New Profile

Advanced

[ PATCH ] Add preadv2 support with RWF_NOWAIT flag

Vadim Fedorenko
January 09, 2018 10:08AM
Introduction of thread pools is really good thing, but it adds
overhead to reading files which are already in page cache in linux.
With preadv2 (introduced in Linux 4.6) and RWF_NOWAIT flag (introduced
in Linux 4.14) we can eliminate this overhead. Needs glibc >= 2.26

# HG changeset patch
# User Vadim Fedorenko <vfedorenko@yandex-team.ru>
# Date 1515498853 -10800
# Tue Jan 09 14:54:13 2018 +0300
# Node ID f955f9cddd38ce35e19c50b871558ca8739a1d4b
# Parent 6d2e92acb013224e6ef2c71c9e61ab07f0b03271
Add preadv2() with RWF_NOWAIT flag

Eliminate overhead with threads synchronization when cache file or
chain is in page cache already

diff -r 6d2e92acb013 -r f955f9cddd38 auto/unix
--- a/auto/unix Thu Dec 28 12:01:05 2017 +0200
+++ b/auto/unix Tue Jan 09 14:54:13 2018 +0300
@@ -726,6 +726,21 @@
if (n == -1) return 1"
. auto/feature

+# preadv2() was introduced in Linux 4.6, glibc 2.26
+# RWF_NOWAIT flag was introduced in Linux 4.14
+
+ngx_feature="preadv2()"
+ngx_feature_name="NGX_HAVE_PREADV2_NONBLOCK"
+ngx_feature_run=no
+ngx_feature_incs='#include <sys/uio.h>'
+ngx_feature_path=
+ngx_feature_libs=
+ngx_feature_test="char buf[1]; struct iovec vec[1]; ssize_t n;
+ vec[0].iov_base = buf;
+ vec[0].iov_len = 1;
+ n = preadv2(0, vec, 1, 0, RWF_NOWAIT);
+ if (n == -1) return 1"
+. auto/feature

ngx_feature="sys_nerr"
ngx_feature_name="NGX_SYS_NERR"
diff -r 6d2e92acb013 -r f955f9cddd38 src/core/ngx_output_chain.c
--- a/src/core/ngx_output_chain.c Thu Dec 28 12:01:05 2017 +0200
+++ b/src/core/ngx_output_chain.c Tue Jan 09 14:54:13 2018 +0300
@@ -577,7 +577,15 @@
} else
#endif
#if (NGX_THREADS)
- if (ctx->thread_handler) {
+#if (NGX_HAVE_PREADV2_NONBLOCK)
+
+ n = ngx_preadv2_file(src->file, dst->pos, (size_t) size,
+ src->file_pos);
+#else
+ n = NGX_AGAIN;
+#endif
+ if (n == NGX_AGAIN && ctx->thread_handler) {
+
src->file->thread_task = ctx->thread_task;
src->file->thread_handler = ctx->thread_handler;
src->file->thread_ctx = ctx->filter_ctx;
@@ -589,7 +597,7 @@
return NGX_AGAIN;
}

- } else
+ } else if (!ctx->thread_handler && n == NGX_AGAIN)
#endif
{
n = ngx_read_file(src->file, dst->pos, (size_t) size,
diff -r 6d2e92acb013 -r f955f9cddd38 src/http/ngx_http_file_cache.c
--- a/src/http/ngx_http_file_cache.c Thu Dec 28 12:01:05 2017 +0200
+++ b/src/http/ngx_http_file_cache.c Tue Jan 09 14:54:13 2018 +0300
@@ -699,6 +699,19 @@
#if (NGX_THREADS)

if (clcf->aio == NGX_HTTP_AIO_THREADS) {
+
+#if (NGX_HAVE_PREADV2_NONBLOCK)
+
+ n = ngx_preadv2_file(&c->file, c->buf->pos, c->body_start, 0);
+
+ if (n != NGX_AGAIN) {
+ ngx_log_debug2(NGX_LOG_DEBUG_CORE, c->file.log, 0,
+ "preadv2 non blocking: \"%s\" - %uz",
c->file.name.data, c->body_start);
+ return n;
+ }
+
+#endif
+
c->file.thread_task = c->thread_task;
c->file.thread_handler = ngx_http_cache_thread_handler;
c->file.thread_ctx = r;
diff -r 6d2e92acb013 -r f955f9cddd38 src/os/unix/ngx_files.c
--- a/src/os/unix/ngx_files.c Thu Dec 28 12:01:05 2017 +0200
+++ b/src/os/unix/ngx_files.c Tue Jan 09 14:54:13 2018 +0300
@@ -26,6 +26,68 @@

#endif

+#if (NGX_THREADS)
+#if (NGX_HAVE_PREADV2_NONBLOCK)
+
+ngx_uint_t ngx_preadv2_nonblock = 1;
+
+#endif
+
+ssize_t
+ngx_preadv2_file(ngx_file_t *file, u_char *buf, size_t size, off_t offset)
+{
+#if (NGX_HAVE_PREADV2_NONBLOCK)
+ ssize_t n;
+ struct iovec iovs[1];
+
+ if (!ngx_preadv2_nonblock) {
+ return NGX_AGAIN;
+ }
+
+ iovs[0].iov_base = buf;
+ iovs[0].iov_len = size;
+
+ n = preadv2(file->fd, iovs, 1, offset, RWF_NOWAIT);
+
+ if (n == -1) { // let's analyze the return code
+ switch (ngx_errno) {
+ case EAGAIN:
+ ngx_log_debug(NGX_LOG_DEBUG_CORE, file->log, 0,
+ "preadv2() will block on \"%s\"", file->name.data);
+ return NGX_AGAIN;
+ case EINVAL:
+ // Most possible case - not supported RWF_NOWAIT
+ ngx_log_error(NGX_LOG_ERR, file->log, ngx_errno,
+ "preadv2() \"%s\" failed RWF_NOWAIT", file->name.data);
+ ngx_preadv2_nonblock = 0;
+ return NGX_AGAIN;
+ default:
+ return NGX_AGAIN;
+
+ }
+ }
+
+ // Check if we read partial file
+ if (((size_t)n < size) && (n < file->info.st_size)) {
+ // blocked on partial read
+ ngx_log_debug2(NGX_LOG_DEBUG_CORE, file->log, 0,
+ "preadv2() blocked partial on \"%s\" "
+ "with read size %uz", file->name.data, n);
+ return NGX_AGAIN;
+ }
+
+ file->offset += n;
+
+ return n;
+
+#else
+
+ return NGX_AGAIN;
+
+#endif
+}
+
+#endif

ssize_t
ngx_read_file(ngx_file_t *file, u_char *buf, size_t size, off_t offset)
diff -r 6d2e92acb013 -r f955f9cddd38 src/os/unix/ngx_files.h
--- a/src/os/unix/ngx_files.h Thu Dec 28 12:01:05 2017 +0200
+++ b/src/os/unix/ngx_files.h Tue Jan 09 14:54:13 2018 +0300
@@ -389,7 +389,12 @@
off_t offset, ngx_pool_t *pool);
ssize_t ngx_thread_write_chain_to_file(ngx_file_t *file, ngx_chain_t *cl,
off_t offset, ngx_pool_t *pool);
+
+#if (NGX_HAVE_PREADV2_NONBLOCK)
+ssize_t ngx_preadv2_file(ngx_file_t *file, u_char *buf, size_t size,
+ off_t offset);
#endif

+#endif

#endif /* _NGX_FILES_H_INCLUDED_ */
_______________________________________________
nginx-devel mailing list
nginx-devel@nginx.org
http://mailman.nginx.org/mailman/listinfo/nginx-devel
Subject Author Views Posted

[ PATCH ] Add preadv2 support with RWF_NOWAIT flag

Vadim Fedorenko 637 January 09, 2018 10:08AM

Re: [ PATCH ] Add preadv2 support with RWF_NOWAIT flag

Maxim Dounin 239 January 11, 2018 01:00PM



Sorry, you do not have permission to post/reply in this forum.

Online Users

Guests: 169
Record Number of Users: 8 on April 13, 2023
Record Number of Guests: 421 on December 02, 2018
Powered by nginx      Powered by FreeBSD      PHP Powered      Powered by MariaDB      ipv6 ready