Mercurial > hg > nginx-quic
annotate src/mysql/ngx_http_mysql_test.c @ 6422:768e287a6f36
Fixed sendfile in threads (or with aio preload) and subrequests.
If sendfile in threads is used, it is possible that multiple
subrequests will trigger multiple ngx_linux_sendfile_thread() calls,
as operations are only serialized in output chain based on r->aio,
that is, on subrequest level.
This resulted in "task #N already active" alerts, in particular, when
running proxy_store.t with "aio threads; sendfile on;".
Fix is to tolerate duplicate calls, with an additional safety check
that the file is the same as previously used.
The same problem also affects "aio on; sendfile on;" on FreeBSD
(previously known as "aio sendfile;"), where aio->preload_handler()
could be called multiple times due to similar reasons, resulting in
"second aio post" alerts. Fix is the same as well.
It is also believed that similar problems can arise if a filter
calls the next body filter multiple times for some reason. These are
mostly theoretical though.
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Thu, 03 Mar 2016 21:14:12 +0300 |
parents | d620f497c50f |
children |
rev | line source |
---|---|
653 | 1 |
2 /* | |
3 * Copyright (C) Igor Sysoev | |
4412 | 4 * Copyright (C) Nginx, Inc. |
653 | 5 */ |
6 | |
7 #include <ngx_config.h> | |
8 #include <ngx_core.h> | |
9 #include <ngx_mysql.h> | |
10 #include <ngx_http.h> | |
11 | |
12 | |
13 typedef struct { | |
3269
f0d596e84634
rename ngx_peer_addr_t to ngx_addr_t
Igor Sysoev <igor@sysoev.ru>
parents:
2049
diff
changeset
|
14 ngx_addr_t *peers; |
f0d596e84634
rename ngx_peer_addr_t to ngx_addr_t
Igor Sysoev <igor@sysoev.ru>
parents:
2049
diff
changeset
|
15 ngx_uint_t npeers; |
653 | 16 } ngx_http_mysql_test_conf_t; |
17 | |
18 | |
19 static void ngx_http_mysql_auth(ngx_mysql_t *m); | |
20 static void ngx_http_mysql_done(ngx_mysql_t *m); | |
21 static void *ngx_http_mysql_test_create_loc_conf(ngx_conf_t *cf); | |
22 static char *ngx_http_mysql_test(ngx_conf_t *cf, ngx_command_t *cmd, | |
23 void *conf); | |
24 | |
25 static ngx_command_t ngx_http_mysql_test_commands[] = { | |
26 | |
27 { ngx_string("mysql_test"), | |
28 NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, | |
29 ngx_http_mysql_test, | |
30 NGX_HTTP_LOC_CONF_OFFSET, | |
31 0, | |
32 NULL }, | |
33 | |
34 ngx_null_command | |
35 }; | |
36 | |
37 | |
667 | 38 static ngx_http_module_t ngx_http_mysql_test_module_ctx = { |
653 | 39 NULL, /* preconfiguration */ |
40 NULL, /* postconfiguration */ | |
41 | |
42 NULL, /* create main configuration */ | |
43 NULL, /* init main configuration */ | |
44 | |
45 NULL, /* create server configuration */ | |
46 NULL, /* merge server configuration */ | |
47 | |
48 ngx_http_mysql_test_create_loc_conf, /* create location configuration */ | |
49 NULL /* merge location configuration */ | |
50 }; | |
51 | |
52 | |
53 ngx_module_t ngx_http_mysql_test_module = { | |
54 NGX_MODULE_V1, | |
55 &ngx_http_mysql_test_module_ctx, /* module context */ | |
56 ngx_http_mysql_test_commands, /* module directives */ | |
57 NGX_HTTP_MODULE, /* module type */ | |
58 NULL, /* init master */ | |
59 NULL, /* init module */ | |
60 NULL, /* init process */ | |
61 NULL, /* init thread */ | |
62 NULL, /* exit thread */ | |
63 NULL, /* exit process */ | |
64 NULL, /* exit master */ | |
65 NGX_MODULE_V1_PADDING | |
66 }; | |
67 | |
68 | |
69 static ngx_str_t ngx_mysql_login = ngx_string("root"); | |
70 static ngx_str_t ngx_mysql_passwd = ngx_string("tp"); | |
71 static ngx_str_t ngx_mysql_database = ngx_string("mysql"); | |
72 static ngx_str_t ngx_mysql_command_query = | |
73 ngx_string("select * from user"); | |
74 | |
75 | |
76 static ngx_int_t | |
77 ngx_http_mysql_test_handler(ngx_http_request_t *r) | |
78 { | |
79 ngx_int_t rc; | |
80 ngx_mysql_t *m; | |
81 ngx_http_mysql_test_conf_t *mtcf; | |
82 | |
83 mtcf = ngx_http_get_module_loc_conf(r, ngx_http_mysql_test_module); | |
84 | |
85 m = ngx_pcalloc(r->pool, sizeof(ngx_mysql_t)); | |
86 | |
87 if (m == NULL) { | |
88 return NGX_HTTP_INTERNAL_SERVER_ERROR; | |
89 } | |
90 | |
91 m->pool = r->pool; | |
92 m->handler = ngx_http_mysql_auth; | |
93 m->data = r; | |
94 | |
95 m->login = &ngx_mysql_login; | |
96 m->passwd = &ngx_mysql_passwd; | |
97 m->database = &ngx_mysql_database; | |
98 | |
884 | 99 /* STUB */ |
100 m->peer.sockaddr = mtcf->peers[0].sockaddr; | |
101 m->peer.socklen = mtcf->peers[0].socklen; | |
102 m->peer.name = &mtcf->peers[0].name; | |
103 m->peer.tries = mtcf->npeers; | |
104 m->peer.get = ngx_event_get_peer; | |
105 /**/ | |
653 | 106 m->peer.log = r->connection->log; |
107 m->peer.log_error = NGX_ERROR_ERR; | |
108 | |
109 rc = ngx_mysql_connect(m); | |
110 | |
111 if (rc == NGX_OK || rc == NGX_AGAIN) { | |
112 return NGX_DONE; | |
113 } | |
114 | |
115 return NGX_HTTP_INTERNAL_SERVER_ERROR; | |
116 } | |
117 | |
118 | |
119 static void | |
120 ngx_http_mysql_auth(ngx_mysql_t *m) | |
121 { | |
122 ngx_http_request_t *r; | |
123 | |
124 r = m->data; | |
125 | |
126 if (m->state != NGX_OK) { | |
127 ngx_http_finalize_request(r, NGX_HTTP_NO_CONTENT); | |
128 return; | |
129 } | |
130 | |
131 m->query.len = NGX_MYSQL_CMDPKT_LEN + ngx_mysql_command_query.len; | |
132 | |
2049 | 133 m->query.data = ngx_pnalloc(r->pool, m->query.len); |
653 | 134 if (m->query.data == NULL) { |
135 ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); | |
136 return; | |
137 } | |
138 | |
139 ngx_memcpy(m->query.data + NGX_MYSQL_CMDPKT_LEN, | |
140 ngx_mysql_command_query.data, ngx_mysql_command_query.len); | |
141 | |
142 m->handler = ngx_http_mysql_done; | |
143 | |
144 ngx_mysql_query(m); | |
145 } | |
146 | |
147 | |
148 static void | |
149 ngx_http_mysql_done(ngx_mysql_t *m) | |
150 { | |
151 ngx_http_request_t *r; | |
152 | |
153 r = m->data; | |
154 | |
155 ngx_http_finalize_request(r, NGX_HTTP_NO_CONTENT); | |
156 } | |
157 | |
158 | |
159 static void * | |
160 ngx_http_mysql_test_create_loc_conf(ngx_conf_t *cf) | |
161 { | |
162 ngx_http_mysql_test_conf_t *conf; | |
163 | |
164 conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_mysql_test_conf_t)); | |
165 if (conf == NULL) { | |
166 return NGX_CONF_ERROR; | |
167 } | |
168 | |
169 return conf; | |
170 } | |
171 | |
172 static char * | |
173 ngx_http_mysql_test(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) | |
174 { | |
175 ngx_http_mysql_test_conf_t *mtcf = conf; | |
176 | |
177 ngx_str_t *value; | |
178 ngx_url_t u; | |
179 ngx_http_core_loc_conf_t *clcf; | |
180 | |
181 clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); | |
182 clcf->handler = ngx_http_mysql_test_handler; | |
183 | |
184 value = cf->args->elts; | |
185 | |
186 ngx_memzero(&u, sizeof(ngx_url_t)); | |
187 | |
188 u.url = value[1]; | |
906 | 189 u.default_port = 3306; |
653 | 190 |
1559
fe11e2a3946d
use pool instead of ngx_conf_t
Igor Sysoev <igor@sysoev.ru>
parents:
906
diff
changeset
|
191 if (ngx_parse_url(cf->pool, &u) != NGX_OK) { |
653 | 192 if (u.err) { |
193 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
194 "%s in upstream \"%V\"", u.err, &u.url); | |
195 } | |
196 | |
197 return NGX_CONF_ERROR; | |
198 } | |
199 | |
884 | 200 mtcf->peers = u.addrs; |
201 mtcf->npeers = u.naddrs; | |
653 | 202 |
203 return NGX_CONF_OK; | |
204 } |