Groonga 3.0.9 Source Code Document
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
ngx_file_aio_read.c
Go to the documentation of this file.
1 
2 /*
3  * Copyright (C) Igor Sysoev
4  * Copyright (C) Nginx, Inc.
5  */
6 
7 
8 #include <ngx_config.h>
9 #include <ngx_core.h>
10 #include <ngx_event.h>
11 
12 
13 /*
14  * FreeBSD file AIO features and quirks:
15  *
16  * if an asked data are already in VM cache, then aio_error() returns 0,
17  * and the data are already copied in buffer;
18  *
19  * aio_read() preread in VM cache as minimum 16K (probably BKVASIZE);
20  * the first AIO preload may be up to 128K;
21  *
22  * aio_read/aio_error() may return EINPROGRESS for just written data;
23  *
24  * kqueue EVFILT_AIO filter is level triggered only: an event repeats
25  * until aio_return() will be called;
26  *
27  * aio_cancel() cannot cancel file AIO: it returns AIO_NOTCANCELED always.
28  */
29 
30 
31 extern int ngx_kqueue;
32 
33 
34 static ssize_t ngx_file_aio_result(ngx_file_t *file, ngx_event_aio_t *aio,
35  ngx_event_t *ev);
36 static void ngx_file_aio_event_handler(ngx_event_t *ev);
37 
38 
39 ssize_t
40 ngx_file_aio_read(ngx_file_t *file, u_char *buf, size_t size, off_t offset,
41  ngx_pool_t *pool)
42 {
43  int n;
44  ngx_event_t *ev;
45  ngx_event_aio_t *aio;
46 
47  if (!ngx_file_aio) {
48  return ngx_read_file(file, buf, size, offset);
49  }
50 
51  aio = file->aio;
52 
53  if (aio == NULL) {
54  aio = ngx_pcalloc(pool, sizeof(ngx_event_aio_t));
55  if (aio == NULL) {
56  return NGX_ERROR;
57  }
58 
59  aio->file = file;
60  aio->fd = file->fd;
61  aio->event.data = aio;
62  aio->event.ready = 1;
63  aio->event.log = file->log;
64 #if (NGX_HAVE_AIO_SENDFILE)
65  aio->last_offset = -1;
66 #endif
67  file->aio = aio;
68  }
69 
70  ev = &aio->event;
71 
72  if (!ev->ready) {
74  "second aio post for \"%V\"", &file->name);
75  return NGX_AGAIN;
76  }
77 
79  "aio complete:%d @%O:%z %V",
80  ev->complete, offset, size, &file->name);
81 
82  if (ev->complete) {
83  ev->complete = 0;
84  ngx_set_errno(aio->err);
85 
86  if (aio->err == 0) {
87  return aio->nbytes;
88  }
89 
91  "aio read \"%s\" failed", file->name.data);
92 
93  return NGX_ERROR;
94  }
95 
96  ngx_memzero(&aio->aiocb, sizeof(struct aiocb));
97 
98  aio->aiocb.aio_fildes = file->fd;
99  aio->aiocb.aio_offset = offset;
100  aio->aiocb.aio_buf = buf;
101  aio->aiocb.aio_nbytes = size;
102 #if (NGX_HAVE_KQUEUE)
103  aio->aiocb.aio_sigevent.sigev_notify_kqueue = ngx_kqueue;
104  aio->aiocb.aio_sigevent.sigev_notify = SIGEV_KEVENT;
105  aio->aiocb.aio_sigevent.sigev_value.sigval_ptr = ev;
106 #endif
107  ev->handler = ngx_file_aio_event_handler;
108 
109  n = aio_read(&aio->aiocb);
110 
111  if (n == -1) {
112  n = ngx_errno;
113 
114  if (n == NGX_EAGAIN) {
115  return ngx_read_file(file, buf, size, offset);
116  }
117 
118  ngx_log_error(NGX_LOG_CRIT, file->log, n,
119  "aio_read(\"%V\") failed", &file->name);
120 
121  if (n == NGX_ENOSYS) {
122  ngx_file_aio = 0;
123  return ngx_read_file(file, buf, size, offset);
124  }
125 
126  return NGX_ERROR;
127  }
128 
130  "aio_read: fd:%d %d", file->fd, n);
131 
132  ev->active = 1;
133  ev->ready = 0;
134  ev->complete = 0;
135 
136  return ngx_file_aio_result(aio->file, aio, ev);
137 }
138 
139 
140 static ssize_t
141 ngx_file_aio_result(ngx_file_t *file, ngx_event_aio_t *aio, ngx_event_t *ev)
142 {
143  int n;
144  ngx_err_t err;
145 
146  n = aio_error(&aio->aiocb);
147 
149  "aio_error: fd:%d %d", file->fd, n);
150 
151  if (n == -1) {
152  err = ngx_errno;
153  aio->err = err;
154 
155  ngx_log_error(NGX_LOG_ALERT, file->log, err,
156  "aio_error(\"%V\") failed", &file->name);
157  return NGX_ERROR;
158  }
159 
160  if (n == NGX_EINPROGRESS) {
161  if (ev->ready) {
162  ev->ready = 0;
163  ngx_log_error(NGX_LOG_ALERT, file->log, n,
164  "aio_read(\"%V\") still in progress",
165  &file->name);
166  }
167 
168  return NGX_AGAIN;
169  }
170 
171  n = aio_return(&aio->aiocb);
172 
173  if (n == -1) {
174  err = ngx_errno;
175  aio->err = err;
176  ev->ready = 1;
177 
178  ngx_log_error(NGX_LOG_CRIT, file->log, err,
179  "aio_return(\"%V\") failed", &file->name);
180  return NGX_ERROR;
181  }
182 
183  aio->err = 0;
184  aio->nbytes = n;
185  ev->ready = 1;
186  ev->active = 0;
187 
189  "aio_return: fd:%d %d", file->fd, n);
190 
191  return n;
192 }
193 
194 
195 static void
196 ngx_file_aio_event_handler(ngx_event_t *ev)
197 {
198  ngx_event_aio_t *aio;
199 
200  aio = ev->data;
201 
203  "aio event handler fd:%d %V", aio->fd, &aio->file->name);
204 
205  if (ngx_file_aio_result(aio->file, aio, ev) != NGX_AGAIN) {
206  aio->handler(ev);
207  }
208 }