xref: /unit/src/nxt_job_file.c (revision 0)
1*0Sigor@sysoev.ru 
2*0Sigor@sysoev.ru /*
3*0Sigor@sysoev.ru  * Copyright (C) Igor Sysoev
4*0Sigor@sysoev.ru  * Copyright (C) NGINX, Inc.
5*0Sigor@sysoev.ru  */
6*0Sigor@sysoev.ru 
7*0Sigor@sysoev.ru 
8*0Sigor@sysoev.ru #include <nxt_main.h>
9*0Sigor@sysoev.ru 
10*0Sigor@sysoev.ru 
11*0Sigor@sysoev.ru static void nxt_job_file_open_and_read(nxt_thread_t *thr, void *obj,
12*0Sigor@sysoev.ru     void *data);
13*0Sigor@sysoev.ru static nxt_int_t nxt_job_file_open(nxt_job_file_t *jbf);
14*0Sigor@sysoev.ru static nxt_int_t nxt_job_file_info(nxt_job_file_t *jbf);
15*0Sigor@sysoev.ru static nxt_int_t nxt_job_file_mmap(nxt_job_file_t *jbf, size_t size);
16*0Sigor@sysoev.ru static nxt_int_t nxt_job_file_read_data(nxt_job_file_t *jbf, size_t size);
17*0Sigor@sysoev.ru static nxt_int_t nxt_job_file_read_required(nxt_job_file_t *jbf);
18*0Sigor@sysoev.ru 
19*0Sigor@sysoev.ru 
20*0Sigor@sysoev.ru nxt_job_file_t *
21*0Sigor@sysoev.ru nxt_job_file_create(nxt_mem_pool_t *mp)
22*0Sigor@sysoev.ru {
23*0Sigor@sysoev.ru     nxt_job_file_t  *jbf;
24*0Sigor@sysoev.ru 
25*0Sigor@sysoev.ru     jbf = nxt_job_create(mp, sizeof(nxt_job_file_t));
26*0Sigor@sysoev.ru 
27*0Sigor@sysoev.ru     if (nxt_fast_path(jbf != NULL)) {
28*0Sigor@sysoev.ru         jbf->file.fd = NXT_FILE_INVALID;
29*0Sigor@sysoev.ru         jbf->file.accessed = NXT_FILE_ACCESSED_LONG_AGO;
30*0Sigor@sysoev.ru         jbf->read_required = nxt_job_file_read_required;
31*0Sigor@sysoev.ru     }
32*0Sigor@sysoev.ru 
33*0Sigor@sysoev.ru     return jbf;
34*0Sigor@sysoev.ru }
35*0Sigor@sysoev.ru 
36*0Sigor@sysoev.ru 
37*0Sigor@sysoev.ru void
38*0Sigor@sysoev.ru nxt_job_file_init(nxt_job_file_t *jbf)
39*0Sigor@sysoev.ru {
40*0Sigor@sysoev.ru     nxt_job_init(&jbf->job, sizeof(nxt_job_file_t));
41*0Sigor@sysoev.ru 
42*0Sigor@sysoev.ru     jbf->file.fd = NXT_FILE_INVALID;
43*0Sigor@sysoev.ru     jbf->file.accessed = NXT_FILE_ACCESSED_LONG_AGO;
44*0Sigor@sysoev.ru     jbf->read_required = nxt_job_file_read_required;
45*0Sigor@sysoev.ru }
46*0Sigor@sysoev.ru 
47*0Sigor@sysoev.ru 
48*0Sigor@sysoev.ru /*
49*0Sigor@sysoev.ru  * Must be a function but not a macro, because
50*0Sigor@sysoev.ru  * it can be used as function pointer.
51*0Sigor@sysoev.ru  */
52*0Sigor@sysoev.ru 
53*0Sigor@sysoev.ru void
54*0Sigor@sysoev.ru nxt_job_file_read(nxt_thread_t *thr, nxt_job_t *job)
55*0Sigor@sysoev.ru {
56*0Sigor@sysoev.ru     nxt_job_start(thr, job, nxt_job_file_open_and_read);
57*0Sigor@sysoev.ru }
58*0Sigor@sysoev.ru 
59*0Sigor@sysoev.ru 
60*0Sigor@sysoev.ru static void
61*0Sigor@sysoev.ru nxt_job_file_open_and_read(nxt_thread_t *thr, void *obj, void *data)
62*0Sigor@sysoev.ru {
63*0Sigor@sysoev.ru     size_t              size;
64*0Sigor@sysoev.ru     nxt_int_t           n;
65*0Sigor@sysoev.ru     nxt_bool_t          read_ahead;
66*0Sigor@sysoev.ru     nxt_file_t          *file;
67*0Sigor@sysoev.ru     nxt_job_file_t      *jbf;
68*0Sigor@sysoev.ru     nxt_work_handler_t  handler;
69*0Sigor@sysoev.ru 
70*0Sigor@sysoev.ru     jbf = obj;
71*0Sigor@sysoev.ru     file = &jbf->file;
72*0Sigor@sysoev.ru 
73*0Sigor@sysoev.ru     nxt_log_debug(thr->log, "file job read: \"%FN\"", file->name);
74*0Sigor@sysoev.ru 
75*0Sigor@sysoev.ru     if (file->fd != NXT_FILE_INVALID && jbf->close_before_open) {
76*0Sigor@sysoev.ru         nxt_file_close(file);
77*0Sigor@sysoev.ru         file->fd = NXT_FILE_INVALID;
78*0Sigor@sysoev.ru     }
79*0Sigor@sysoev.ru 
80*0Sigor@sysoev.ru     if (file->fd == NXT_FILE_INVALID) {
81*0Sigor@sysoev.ru 
82*0Sigor@sysoev.ru         switch (nxt_job_file_open(jbf)) {
83*0Sigor@sysoev.ru 
84*0Sigor@sysoev.ru         case NXT_OK:
85*0Sigor@sysoev.ru             break;
86*0Sigor@sysoev.ru 
87*0Sigor@sysoev.ru         case NXT_DECLINED:
88*0Sigor@sysoev.ru             handler = jbf->ready_handler;
89*0Sigor@sysoev.ru             goto done;
90*0Sigor@sysoev.ru 
91*0Sigor@sysoev.ru         default: /* NXT_ERROR */
92*0Sigor@sysoev.ru             handler = jbf->error_handler;
93*0Sigor@sysoev.ru             goto done;
94*0Sigor@sysoev.ru         }
95*0Sigor@sysoev.ru     }
96*0Sigor@sysoev.ru 
97*0Sigor@sysoev.ru     if (file->size > 0) {
98*0Sigor@sysoev.ru 
99*0Sigor@sysoev.ru         if (jbf->buffer != NULL) {
100*0Sigor@sysoev.ru             size = nxt_buf_mem_size(&jbf->buffer->mem);
101*0Sigor@sysoev.ru             size = nxt_min(file->size, (nxt_off_t) size);
102*0Sigor@sysoev.ru             read_ahead = nxt_buf_is_mmap(jbf->buffer);
103*0Sigor@sysoev.ru 
104*0Sigor@sysoev.ru         } else {
105*0Sigor@sysoev.ru             size = nxt_min(file->size, 1024 * 1024);
106*0Sigor@sysoev.ru             read_ahead = jbf->read_ahead;
107*0Sigor@sysoev.ru         }
108*0Sigor@sysoev.ru 
109*0Sigor@sysoev.ru         if (read_ahead) {
110*0Sigor@sysoev.ru             nxt_file_read_ahead(&jbf->file, jbf->offset, size);
111*0Sigor@sysoev.ru         }
112*0Sigor@sysoev.ru 
113*0Sigor@sysoev.ru         if (jbf->buffer != NULL) {
114*0Sigor@sysoev.ru 
115*0Sigor@sysoev.ru             if (nxt_buf_is_mmap(jbf->buffer)) {
116*0Sigor@sysoev.ru                 n = nxt_job_file_mmap(jbf, size);
117*0Sigor@sysoev.ru 
118*0Sigor@sysoev.ru             } else {
119*0Sigor@sysoev.ru                 n = nxt_job_file_read_data(jbf, size);
120*0Sigor@sysoev.ru             }
121*0Sigor@sysoev.ru 
122*0Sigor@sysoev.ru             if (nxt_slow_path(n != NXT_OK)) {
123*0Sigor@sysoev.ru                 handler = jbf->error_handler;
124*0Sigor@sysoev.ru                 goto done;
125*0Sigor@sysoev.ru             }
126*0Sigor@sysoev.ru         }
127*0Sigor@sysoev.ru     }
128*0Sigor@sysoev.ru 
129*0Sigor@sysoev.ru     if (jbf->offset == file->size) {
130*0Sigor@sysoev.ru         jbf->complete = 1;
131*0Sigor@sysoev.ru 
132*0Sigor@sysoev.ru         if (jbf->close) {
133*0Sigor@sysoev.ru             nxt_file_close(file);
134*0Sigor@sysoev.ru             file->fd = NXT_FILE_INVALID;
135*0Sigor@sysoev.ru         }
136*0Sigor@sysoev.ru     }
137*0Sigor@sysoev.ru 
138*0Sigor@sysoev.ru     nxt_job_return(thr, &jbf->job, jbf->ready_handler);
139*0Sigor@sysoev.ru     return;
140*0Sigor@sysoev.ru 
141*0Sigor@sysoev.ru done:
142*0Sigor@sysoev.ru 
143*0Sigor@sysoev.ru     if (file->fd != NXT_FILE_INVALID) {
144*0Sigor@sysoev.ru         nxt_file_close(file);
145*0Sigor@sysoev.ru         file->fd = NXT_FILE_INVALID;
146*0Sigor@sysoev.ru     }
147*0Sigor@sysoev.ru 
148*0Sigor@sysoev.ru     nxt_job_return(thr, &jbf->job, handler);
149*0Sigor@sysoev.ru }
150*0Sigor@sysoev.ru 
151*0Sigor@sysoev.ru 
152*0Sigor@sysoev.ru static nxt_int_t
153*0Sigor@sysoev.ru nxt_job_file_open(nxt_job_file_t *jbf)
154*0Sigor@sysoev.ru {
155*0Sigor@sysoev.ru     nxt_int_t  n;
156*0Sigor@sysoev.ru 
157*0Sigor@sysoev.ru     if (jbf->test_before_open) {
158*0Sigor@sysoev.ru         n = nxt_job_file_info(jbf);
159*0Sigor@sysoev.ru 
160*0Sigor@sysoev.ru         if (n != NXT_OK) {
161*0Sigor@sysoev.ru             goto test_directory;
162*0Sigor@sysoev.ru         }
163*0Sigor@sysoev.ru 
164*0Sigor@sysoev.ru         if (jbf->file.type == NXT_FILE_DIRECTORY) {
165*0Sigor@sysoev.ru             return NXT_DECLINED;
166*0Sigor@sysoev.ru         }
167*0Sigor@sysoev.ru 
168*0Sigor@sysoev.ru         if (jbf->read_required(jbf) != NXT_OK) {
169*0Sigor@sysoev.ru             return NXT_DECLINED;
170*0Sigor@sysoev.ru         }
171*0Sigor@sysoev.ru     }
172*0Sigor@sysoev.ru 
173*0Sigor@sysoev.ru     n = nxt_file_open(&jbf->file, NXT_FILE_RDONLY, NXT_FILE_OPEN, 0);
174*0Sigor@sysoev.ru 
175*0Sigor@sysoev.ru     if (n == NXT_OK) {
176*0Sigor@sysoev.ru         n = nxt_job_file_info(jbf);
177*0Sigor@sysoev.ru 
178*0Sigor@sysoev.ru         if (nxt_fast_path(n == NXT_OK)) {
179*0Sigor@sysoev.ru 
180*0Sigor@sysoev.ru             if (jbf->file.type == NXT_FILE_DIRECTORY) {
181*0Sigor@sysoev.ru                 return NXT_DECLINED;
182*0Sigor@sysoev.ru             }
183*0Sigor@sysoev.ru 
184*0Sigor@sysoev.ru             return jbf->read_required(jbf);
185*0Sigor@sysoev.ru         }
186*0Sigor@sysoev.ru 
187*0Sigor@sysoev.ru         return n;
188*0Sigor@sysoev.ru     }
189*0Sigor@sysoev.ru 
190*0Sigor@sysoev.ru test_directory:
191*0Sigor@sysoev.ru 
192*0Sigor@sysoev.ru     if (jbf->directory_end != 0
193*0Sigor@sysoev.ru         && jbf->file.error != NXT_ENOTDIR
194*0Sigor@sysoev.ru         && jbf->file.error != NXT_ENAMETOOLONG
195*0Sigor@sysoev.ru         && jbf->file.error != NXT_EACCES)
196*0Sigor@sysoev.ru     {
197*0Sigor@sysoev.ru         jbf->file.name[jbf->directory_end] = '\0';
198*0Sigor@sysoev.ru 
199*0Sigor@sysoev.ru         return nxt_job_file_info(jbf);
200*0Sigor@sysoev.ru     }
201*0Sigor@sysoev.ru 
202*0Sigor@sysoev.ru     return n;
203*0Sigor@sysoev.ru }
204*0Sigor@sysoev.ru 
205*0Sigor@sysoev.ru 
206*0Sigor@sysoev.ru static nxt_int_t
207*0Sigor@sysoev.ru nxt_job_file_info(nxt_job_file_t *jbf)
208*0Sigor@sysoev.ru {
209*0Sigor@sysoev.ru     nxt_int_t        n;
210*0Sigor@sysoev.ru     nxt_file_t       *file;
211*0Sigor@sysoev.ru     nxt_file_info_t  fi;
212*0Sigor@sysoev.ru 
213*0Sigor@sysoev.ru     file = &jbf->file;
214*0Sigor@sysoev.ru 
215*0Sigor@sysoev.ru     n = nxt_file_info(file, &fi);
216*0Sigor@sysoev.ru 
217*0Sigor@sysoev.ru     if (n != NXT_OK) {
218*0Sigor@sysoev.ru         return NXT_ERROR;
219*0Sigor@sysoev.ru     }
220*0Sigor@sysoev.ru 
221*0Sigor@sysoev.ru     if (nxt_is_file(&fi)) {
222*0Sigor@sysoev.ru         file->type = NXT_FILE_REGULAR;
223*0Sigor@sysoev.ru         file->size = nxt_file_size(&fi);
224*0Sigor@sysoev.ru         file->mtime = nxt_file_mtime(&fi);
225*0Sigor@sysoev.ru 
226*0Sigor@sysoev.ru     } else if (nxt_is_dir(&fi)) {
227*0Sigor@sysoev.ru         file->type = NXT_FILE_DIRECTORY;
228*0Sigor@sysoev.ru         file->size = nxt_file_size(&fi);
229*0Sigor@sysoev.ru         file->mtime = nxt_file_mtime(&fi);
230*0Sigor@sysoev.ru     }
231*0Sigor@sysoev.ru 
232*0Sigor@sysoev.ru     return NXT_OK;
233*0Sigor@sysoev.ru }
234*0Sigor@sysoev.ru 
235*0Sigor@sysoev.ru 
236*0Sigor@sysoev.ru static nxt_int_t
237*0Sigor@sysoev.ru nxt_job_file_mmap(nxt_job_file_t *jbf, size_t size)
238*0Sigor@sysoev.ru {
239*0Sigor@sysoev.ru     u_char             *p, *end;
240*0Sigor@sysoev.ru     static nxt_uint_t  n;
241*0Sigor@sysoev.ru 
242*0Sigor@sysoev.ru     p = nxt_mem_map(NULL, &jbf->buffer->mmap, size, NXT_MEM_MAP_READ,
243*0Sigor@sysoev.ru                     (NXT_MEM_MAP_FILE | NXT_MEM_MAP_PREFAULT),
244*0Sigor@sysoev.ru                     jbf->file.fd, jbf->offset);
245*0Sigor@sysoev.ru 
246*0Sigor@sysoev.ru     if (nxt_fast_path(p != NXT_MEM_MAP_FAILED)) {
247*0Sigor@sysoev.ru 
248*0Sigor@sysoev.ru         end = p + size;
249*0Sigor@sysoev.ru 
250*0Sigor@sysoev.ru         jbf->buffer->mem.pos = p;
251*0Sigor@sysoev.ru         jbf->buffer->mem.free = end;
252*0Sigor@sysoev.ru         jbf->buffer->mem.start = p;
253*0Sigor@sysoev.ru         jbf->buffer->mem.end = end;
254*0Sigor@sysoev.ru         jbf->buffer->file_end += size;
255*0Sigor@sysoev.ru         jbf->offset += size;
256*0Sigor@sysoev.ru 
257*0Sigor@sysoev.ru         /*
258*0Sigor@sysoev.ru          * The mapped pages should be already preloaded in the kernel page
259*0Sigor@sysoev.ru          * cache by nxt_file_read_ahead().  Touching them should wire the pages
260*0Sigor@sysoev.ru          * in user land memory if mmap() did not do this.  Adding to the static
261*0Sigor@sysoev.ru          * variable "n" disables the loop elimination during optimization.
262*0Sigor@sysoev.ru          */
263*0Sigor@sysoev.ru         n += *p;
264*0Sigor@sysoev.ru 
265*0Sigor@sysoev.ru         for (p = nxt_align_ptr(p, nxt_pagesize); p < end; p += nxt_pagesize) {
266*0Sigor@sysoev.ru             n += *p;
267*0Sigor@sysoev.ru         }
268*0Sigor@sysoev.ru 
269*0Sigor@sysoev.ru         return NXT_OK;
270*0Sigor@sysoev.ru     }
271*0Sigor@sysoev.ru 
272*0Sigor@sysoev.ru     return NXT_ERROR;
273*0Sigor@sysoev.ru }
274*0Sigor@sysoev.ru 
275*0Sigor@sysoev.ru 
276*0Sigor@sysoev.ru static nxt_int_t
277*0Sigor@sysoev.ru nxt_job_file_read_data(nxt_job_file_t *jbf, size_t size)
278*0Sigor@sysoev.ru {
279*0Sigor@sysoev.ru     ssize_t  n;
280*0Sigor@sysoev.ru 
281*0Sigor@sysoev.ru     n = nxt_file_read(&jbf->file, jbf->buffer->mem.pos, size, jbf->offset);
282*0Sigor@sysoev.ru 
283*0Sigor@sysoev.ru     if (nxt_fast_path(n > 0)) {
284*0Sigor@sysoev.ru 
285*0Sigor@sysoev.ru         jbf->buffer->mem.free += n;
286*0Sigor@sysoev.ru         jbf->offset += n;
287*0Sigor@sysoev.ru 
288*0Sigor@sysoev.ru         if (nxt_buf_is_file(jbf->buffer)) {
289*0Sigor@sysoev.ru             jbf->buffer->file_end += n;
290*0Sigor@sysoev.ru         }
291*0Sigor@sysoev.ru 
292*0Sigor@sysoev.ru         return NXT_OK;
293*0Sigor@sysoev.ru     }
294*0Sigor@sysoev.ru 
295*0Sigor@sysoev.ru     return NXT_ERROR;
296*0Sigor@sysoev.ru }
297*0Sigor@sysoev.ru 
298*0Sigor@sysoev.ru 
299*0Sigor@sysoev.ru static nxt_int_t
300*0Sigor@sysoev.ru nxt_job_file_read_required(nxt_job_file_t *jbf)
301*0Sigor@sysoev.ru {
302*0Sigor@sysoev.ru     return NXT_OK;
303*0Sigor@sysoev.ru }
304