Mercurial > hg > nginx
comparison src/http/ngx_http_copy_filter_module.c @ 7985:ec2e6893caaa
Simplified sendfile(SF_NODISKIO) usage.
Starting with FreeBSD 11, there is no need to use AIO operations to preload
data into cache for sendfile(SF_NODISKIO) to work. Instead, sendfile()
handles non-blocking loading data from disk by itself. It still can, however,
return EBUSY if a page is already being loaded (for example, by a different
process). If this happens, we now post an event for the next event loop
iteration, so sendfile() is retried "after a short period", as manpage
recommends.
The limit of the number of EBUSY tolerated without any progress is preserved,
but now it does not result in an alert, since on an idle system event loop
iteration might be very short and EBUSY can happen many times in a row.
Instead, SF_NODISKIO is simply disabled for one call once the limit is
reached.
With this change, sendfile(SF_NODISKIO) is now used automatically as long as
sendfile() is enabled, and no longer requires "aio on;".
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Mon, 27 Dec 2021 19:48:33 +0300 |
parents | a7a77549265e |
children | e88cdaa0f1ff |
comparison
equal
deleted
inserted
replaced
7984:ae992b5a27b2 | 7985:ec2e6893caaa |
---|---|
17 | 17 |
18 #if (NGX_HAVE_FILE_AIO) | 18 #if (NGX_HAVE_FILE_AIO) |
19 static void ngx_http_copy_aio_handler(ngx_output_chain_ctx_t *ctx, | 19 static void ngx_http_copy_aio_handler(ngx_output_chain_ctx_t *ctx, |
20 ngx_file_t *file); | 20 ngx_file_t *file); |
21 static void ngx_http_copy_aio_event_handler(ngx_event_t *ev); | 21 static void ngx_http_copy_aio_event_handler(ngx_event_t *ev); |
22 #if (NGX_HAVE_AIO_SENDFILE) | |
23 static ssize_t ngx_http_copy_aio_sendfile_preload(ngx_buf_t *file); | |
24 static void ngx_http_copy_aio_sendfile_event_handler(ngx_event_t *ev); | |
25 #endif | |
26 #endif | 22 #endif |
27 #if (NGX_THREADS) | 23 #if (NGX_THREADS) |
28 static ngx_int_t ngx_http_copy_thread_handler(ngx_thread_task_t *task, | 24 static ngx_int_t ngx_http_copy_thread_handler(ngx_thread_task_t *task, |
29 ngx_file_t *file); | 25 ngx_file_t *file); |
30 static void ngx_http_copy_thread_event_handler(ngx_event_t *ev); | 26 static void ngx_http_copy_thread_event_handler(ngx_event_t *ev); |
126 ctx->filter_ctx = r; | 122 ctx->filter_ctx = r; |
127 | 123 |
128 #if (NGX_HAVE_FILE_AIO) | 124 #if (NGX_HAVE_FILE_AIO) |
129 if (ngx_file_aio && clcf->aio == NGX_HTTP_AIO_ON) { | 125 if (ngx_file_aio && clcf->aio == NGX_HTTP_AIO_ON) { |
130 ctx->aio_handler = ngx_http_copy_aio_handler; | 126 ctx->aio_handler = ngx_http_copy_aio_handler; |
131 #if (NGX_HAVE_AIO_SENDFILE) | |
132 ctx->aio_preload = ngx_http_copy_aio_sendfile_preload; | |
133 #endif | |
134 } | 127 } |
135 #endif | 128 #endif |
136 | 129 |
137 #if (NGX_THREADS) | 130 #if (NGX_THREADS) |
138 if (clcf->aio == NGX_HTTP_AIO_THREADS) { | 131 if (clcf->aio == NGX_HTTP_AIO_THREADS) { |
205 r->write_event_handler(r); | 198 r->write_event_handler(r); |
206 | 199 |
207 ngx_http_run_posted_requests(c); | 200 ngx_http_run_posted_requests(c); |
208 } | 201 } |
209 | 202 |
210 | 203 #endif |
211 #if (NGX_HAVE_AIO_SENDFILE) | 204 |
212 | 205 |
213 static ssize_t | 206 #if (NGX_THREADS) |
214 ngx_http_copy_aio_sendfile_preload(ngx_buf_t *file) | 207 |
215 { | 208 static ngx_int_t |
216 ssize_t n; | 209 ngx_http_copy_thread_handler(ngx_thread_task_t *task, ngx_file_t *file) |
217 static u_char buf[1]; | 210 { |
218 ngx_event_aio_t *aio; | 211 ngx_str_t name; |
219 ngx_http_request_t *r; | 212 ngx_connection_t *c; |
220 ngx_output_chain_ctx_t *ctx; | 213 ngx_thread_pool_t *tp; |
221 | 214 ngx_http_request_t *r; |
222 aio = file->file->aio; | 215 ngx_output_chain_ctx_t *ctx; |
223 r = aio->data; | 216 ngx_http_core_loc_conf_t *clcf; |
217 | |
218 r = file->thread_ctx; | |
224 | 219 |
225 if (r->aio) { | 220 if (r->aio) { |
226 /* | 221 /* |
227 * tolerate sendfile() calls if another operation is already | 222 * tolerate sendfile() calls if another operation is already |
228 * running; this can happen due to subrequests, multiple calls | 223 * running; this can happen due to subrequests, multiple calls |
229 * of the next body filter from a filter, or in HTTP/2 due to | 224 * of the next body filter from a filter, or in HTTP/2 due to |
230 * a write event on the main connection | 225 * a write event on the main connection |
231 */ | 226 */ |
232 | 227 |
233 return NGX_AGAIN; | |
234 } | |
235 | |
236 n = ngx_file_aio_read(file->file, buf, 1, file->file_pos, NULL); | |
237 | |
238 if (n == NGX_AGAIN) { | |
239 aio->handler = ngx_http_copy_aio_sendfile_event_handler; | |
240 | |
241 r->main->blocked++; | |
242 r->aio = 1; | |
243 | |
244 ctx = ngx_http_get_module_ctx(r, ngx_http_copy_filter_module); | |
245 ctx->aio = 1; | |
246 } | |
247 | |
248 return n; | |
249 } | |
250 | |
251 | |
252 static void | |
253 ngx_http_copy_aio_sendfile_event_handler(ngx_event_t *ev) | |
254 { | |
255 ngx_event_aio_t *aio; | |
256 ngx_connection_t *c; | |
257 ngx_http_request_t *r; | |
258 | |
259 aio = ev->data; | |
260 r = aio->data; | |
261 c = r->connection; | |
262 | |
263 r->main->blocked--; | |
264 r->aio = 0; | |
265 ev->complete = 0; | |
266 | |
267 #if (NGX_HTTP_V2) | |
268 | |
269 if (r->stream) { | |
270 /* | |
271 * for HTTP/2, update write event to make sure processing will | |
272 * reach the main connection to handle sendfile() preload | |
273 */ | |
274 | |
275 c->write->ready = 1; | |
276 c->write->active = 0; | |
277 } | |
278 | |
279 #endif | |
280 | |
281 c->write->handler(c->write); | |
282 } | |
283 | |
284 #endif | |
285 #endif | |
286 | |
287 | |
288 #if (NGX_THREADS) | |
289 | |
290 static ngx_int_t | |
291 ngx_http_copy_thread_handler(ngx_thread_task_t *task, ngx_file_t *file) | |
292 { | |
293 ngx_str_t name; | |
294 ngx_connection_t *c; | |
295 ngx_thread_pool_t *tp; | |
296 ngx_http_request_t *r; | |
297 ngx_output_chain_ctx_t *ctx; | |
298 ngx_http_core_loc_conf_t *clcf; | |
299 | |
300 r = file->thread_ctx; | |
301 | |
302 if (r->aio) { | |
303 /* | |
304 * tolerate sendfile() calls if another operation is already | |
305 * running; this can happen due to subrequests, multiple calls | |
306 * of the next body filter from a filter, or in HTTP/2 due to | |
307 * a write event on the main connection | |
308 */ | |
309 | |
310 c = r->connection; | 228 c = r->connection; |
311 | 229 |
312 #if (NGX_HTTP_V2) | 230 #if (NGX_HTTP_V2) |
313 if (r->stream) { | 231 if (r->stream) { |
314 c = r->stream->connection->connection; | 232 c = r->stream->connection->connection; |