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;