xref: /unit/src/nxt_job_file.c (revision 237:491330b10958)
10Sigor@sysoev.ru 
20Sigor@sysoev.ru /*
30Sigor@sysoev.ru  * Copyright (C) Igor Sysoev
40Sigor@sysoev.ru  * Copyright (C) NGINX, Inc.
50Sigor@sysoev.ru  */
60Sigor@sysoev.ru 
70Sigor@sysoev.ru 
80Sigor@sysoev.ru #include <nxt_main.h>
90Sigor@sysoev.ru 
100Sigor@sysoev.ru 
111Sigor@sysoev.ru static void nxt_job_file_open_and_read(nxt_task_t *task, void *obj, void *data);
120Sigor@sysoev.ru static nxt_int_t nxt_job_file_open(nxt_job_file_t *jbf);
130Sigor@sysoev.ru static nxt_int_t nxt_job_file_info(nxt_job_file_t *jbf);
140Sigor@sysoev.ru static nxt_int_t nxt_job_file_mmap(nxt_job_file_t *jbf, size_t size);
150Sigor@sysoev.ru static nxt_int_t nxt_job_file_read_data(nxt_job_file_t *jbf, size_t size);
160Sigor@sysoev.ru static nxt_int_t nxt_job_file_read_required(nxt_job_file_t *jbf);
170Sigor@sysoev.ru 
180Sigor@sysoev.ru 
190Sigor@sysoev.ru nxt_job_file_t *
nxt_job_file_create(nxt_mp_t * mp)2065Sigor@sysoev.ru nxt_job_file_create(nxt_mp_t *mp)
210Sigor@sysoev.ru {
220Sigor@sysoev.ru     nxt_job_file_t  *jbf;
230Sigor@sysoev.ru 
240Sigor@sysoev.ru     jbf = nxt_job_create(mp, sizeof(nxt_job_file_t));
250Sigor@sysoev.ru 
260Sigor@sysoev.ru     if (nxt_fast_path(jbf != NULL)) {
270Sigor@sysoev.ru         jbf->file.fd = NXT_FILE_INVALID;
280Sigor@sysoev.ru         jbf->file.accessed = NXT_FILE_ACCESSED_LONG_AGO;
290Sigor@sysoev.ru         jbf->read_required = nxt_job_file_read_required;
300Sigor@sysoev.ru     }
310Sigor@sysoev.ru 
320Sigor@sysoev.ru     return jbf;
330Sigor@sysoev.ru }
340Sigor@sysoev.ru 
350Sigor@sysoev.ru 
360Sigor@sysoev.ru void
nxt_job_file_init(nxt_job_file_t * jbf)370Sigor@sysoev.ru nxt_job_file_init(nxt_job_file_t *jbf)
380Sigor@sysoev.ru {
390Sigor@sysoev.ru     nxt_job_init(&jbf->job, sizeof(nxt_job_file_t));
400Sigor@sysoev.ru 
410Sigor@sysoev.ru     jbf->file.fd = NXT_FILE_INVALID;
420Sigor@sysoev.ru     jbf->file.accessed = NXT_FILE_ACCESSED_LONG_AGO;
430Sigor@sysoev.ru     jbf->read_required = nxt_job_file_read_required;
440Sigor@sysoev.ru }
450Sigor@sysoev.ru 
460Sigor@sysoev.ru 
470Sigor@sysoev.ru /*
480Sigor@sysoev.ru  * Must be a function but not a macro, because
490Sigor@sysoev.ru  * it can be used as function pointer.
500Sigor@sysoev.ru  */
510Sigor@sysoev.ru 
520Sigor@sysoev.ru void
nxt_job_file_read(nxt_task_t * task,nxt_job_t * job)531Sigor@sysoev.ru nxt_job_file_read(nxt_task_t *task, nxt_job_t *job)
540Sigor@sysoev.ru {
551Sigor@sysoev.ru     nxt_job_start(task, job, nxt_job_file_open_and_read);
560Sigor@sysoev.ru }
570Sigor@sysoev.ru 
580Sigor@sysoev.ru 
590Sigor@sysoev.ru static void
nxt_job_file_open_and_read(nxt_task_t * task,void * obj,void * data)601Sigor@sysoev.ru nxt_job_file_open_and_read(nxt_task_t *task, void *obj, void *data)
610Sigor@sysoev.ru {
620Sigor@sysoev.ru     size_t              size;
630Sigor@sysoev.ru     nxt_int_t           n;
640Sigor@sysoev.ru     nxt_bool_t          read_ahead;
650Sigor@sysoev.ru     nxt_file_t          *file;
660Sigor@sysoev.ru     nxt_job_file_t      *jbf;
670Sigor@sysoev.ru     nxt_work_handler_t  handler;
680Sigor@sysoev.ru 
690Sigor@sysoev.ru     jbf = obj;
700Sigor@sysoev.ru     file = &jbf->file;
710Sigor@sysoev.ru 
721Sigor@sysoev.ru     nxt_debug(task, "file job read: \"%FN\"", file->name);
730Sigor@sysoev.ru 
740Sigor@sysoev.ru     if (file->fd != NXT_FILE_INVALID && jbf->close_before_open) {
750Sigor@sysoev.ru         nxt_file_close(file);
760Sigor@sysoev.ru         file->fd = NXT_FILE_INVALID;
770Sigor@sysoev.ru     }
780Sigor@sysoev.ru 
790Sigor@sysoev.ru     if (file->fd == NXT_FILE_INVALID) {
800Sigor@sysoev.ru 
810Sigor@sysoev.ru         switch (nxt_job_file_open(jbf)) {
820Sigor@sysoev.ru 
830Sigor@sysoev.ru         case NXT_OK:
840Sigor@sysoev.ru             break;
850Sigor@sysoev.ru 
860Sigor@sysoev.ru         case NXT_DECLINED:
870Sigor@sysoev.ru             handler = jbf->ready_handler;
880Sigor@sysoev.ru             goto done;
890Sigor@sysoev.ru 
900Sigor@sysoev.ru         default: /* NXT_ERROR */
910Sigor@sysoev.ru             handler = jbf->error_handler;
920Sigor@sysoev.ru             goto done;
930Sigor@sysoev.ru         }
940Sigor@sysoev.ru     }
950Sigor@sysoev.ru 
960Sigor@sysoev.ru     if (file->size > 0) {
970Sigor@sysoev.ru 
980Sigor@sysoev.ru         if (jbf->buffer != NULL) {
990Sigor@sysoev.ru             size = nxt_buf_mem_size(&jbf->buffer->mem);
1000Sigor@sysoev.ru             size = nxt_min(file->size, (nxt_off_t) size);
1010Sigor@sysoev.ru             read_ahead = nxt_buf_is_mmap(jbf->buffer);
1020Sigor@sysoev.ru 
1030Sigor@sysoev.ru         } else {
1040Sigor@sysoev.ru             size = nxt_min(file->size, 1024 * 1024);
1050Sigor@sysoev.ru             read_ahead = jbf->read_ahead;
1060Sigor@sysoev.ru         }
1070Sigor@sysoev.ru 
1080Sigor@sysoev.ru         if (read_ahead) {
1090Sigor@sysoev.ru             nxt_file_read_ahead(&jbf->file, jbf->offset, size);
1100Sigor@sysoev.ru         }
1110Sigor@sysoev.ru 
1120Sigor@sysoev.ru         if (jbf->buffer != NULL) {
1130Sigor@sysoev.ru 
1140Sigor@sysoev.ru             if (nxt_buf_is_mmap(jbf->buffer)) {
1150Sigor@sysoev.ru                 n = nxt_job_file_mmap(jbf, size);
1160Sigor@sysoev.ru 
1170Sigor@sysoev.ru             } else {
1180Sigor@sysoev.ru                 n = nxt_job_file_read_data(jbf, size);
1190Sigor@sysoev.ru             }
1200Sigor@sysoev.ru 
1210Sigor@sysoev.ru             if (nxt_slow_path(n != NXT_OK)) {
1220Sigor@sysoev.ru                 handler = jbf->error_handler;
1230Sigor@sysoev.ru                 goto done;
1240Sigor@sysoev.ru             }
1250Sigor@sysoev.ru         }
1260Sigor@sysoev.ru     }
1270Sigor@sysoev.ru 
1280Sigor@sysoev.ru     if (jbf->offset == file->size) {
1290Sigor@sysoev.ru         jbf->complete = 1;
1300Sigor@sysoev.ru 
1310Sigor@sysoev.ru         if (jbf->close) {
1320Sigor@sysoev.ru             nxt_file_close(file);
1330Sigor@sysoev.ru             file->fd = NXT_FILE_INVALID;
1340Sigor@sysoev.ru         }
1350Sigor@sysoev.ru     }
1360Sigor@sysoev.ru 
1371Sigor@sysoev.ru     nxt_job_return(task, &jbf->job, jbf->ready_handler);
1380Sigor@sysoev.ru     return;
1390Sigor@sysoev.ru 
1400Sigor@sysoev.ru done:
1410Sigor@sysoev.ru 
1420Sigor@sysoev.ru     if (file->fd != NXT_FILE_INVALID) {
1430Sigor@sysoev.ru         nxt_file_close(file);
1440Sigor@sysoev.ru         file->fd = NXT_FILE_INVALID;
1450Sigor@sysoev.ru     }
1460Sigor@sysoev.ru 
1471Sigor@sysoev.ru     nxt_job_return(task, &jbf->job, handler);
1480Sigor@sysoev.ru }
1490Sigor@sysoev.ru 
1500Sigor@sysoev.ru 
1510Sigor@sysoev.ru static nxt_int_t
nxt_job_file_open(nxt_job_file_t * jbf)1520Sigor@sysoev.ru nxt_job_file_open(nxt_job_file_t *jbf)
1530Sigor@sysoev.ru {
1540Sigor@sysoev.ru     nxt_int_t  n;
1550Sigor@sysoev.ru 
1560Sigor@sysoev.ru     if (jbf->test_before_open) {
1570Sigor@sysoev.ru         n = nxt_job_file_info(jbf);
1580Sigor@sysoev.ru 
1590Sigor@sysoev.ru         if (n != NXT_OK) {
1600Sigor@sysoev.ru             goto test_directory;
1610Sigor@sysoev.ru         }
1620Sigor@sysoev.ru 
1630Sigor@sysoev.ru         if (jbf->file.type == NXT_FILE_DIRECTORY) {
1640Sigor@sysoev.ru             return NXT_DECLINED;
1650Sigor@sysoev.ru         }
1660Sigor@sysoev.ru 
1670Sigor@sysoev.ru         if (jbf->read_required(jbf) != NXT_OK) {
1680Sigor@sysoev.ru             return NXT_DECLINED;
1690Sigor@sysoev.ru         }
1700Sigor@sysoev.ru     }
1710Sigor@sysoev.ru 
1720Sigor@sysoev.ru     n = nxt_file_open(&jbf->file, NXT_FILE_RDONLY, NXT_FILE_OPEN, 0);
1730Sigor@sysoev.ru 
1740Sigor@sysoev.ru     if (n == NXT_OK) {
1750Sigor@sysoev.ru         n = nxt_job_file_info(jbf);
1760Sigor@sysoev.ru 
1770Sigor@sysoev.ru         if (nxt_fast_path(n == NXT_OK)) {
1780Sigor@sysoev.ru 
1790Sigor@sysoev.ru             if (jbf->file.type == NXT_FILE_DIRECTORY) {
1800Sigor@sysoev.ru                 return NXT_DECLINED;
1810Sigor@sysoev.ru             }
1820Sigor@sysoev.ru 
1830Sigor@sysoev.ru             return jbf->read_required(jbf);
1840Sigor@sysoev.ru         }
1850Sigor@sysoev.ru 
1860Sigor@sysoev.ru         return n;
1870Sigor@sysoev.ru     }
1880Sigor@sysoev.ru 
1890Sigor@sysoev.ru test_directory:
1900Sigor@sysoev.ru 
1910Sigor@sysoev.ru     if (jbf->directory_end != 0
1920Sigor@sysoev.ru         && jbf->file.error != NXT_ENOTDIR
1930Sigor@sysoev.ru         && jbf->file.error != NXT_ENAMETOOLONG
1940Sigor@sysoev.ru         && jbf->file.error != NXT_EACCES)
1950Sigor@sysoev.ru     {
1960Sigor@sysoev.ru         jbf->file.name[jbf->directory_end] = '\0';
1970Sigor@sysoev.ru 
1980Sigor@sysoev.ru         return nxt_job_file_info(jbf);
1990Sigor@sysoev.ru     }
2000Sigor@sysoev.ru 
2010Sigor@sysoev.ru     return n;
2020Sigor@sysoev.ru }
2030Sigor@sysoev.ru 
2040Sigor@sysoev.ru 
2050Sigor@sysoev.ru static nxt_int_t
nxt_job_file_info(nxt_job_file_t * jbf)2060Sigor@sysoev.ru nxt_job_file_info(nxt_job_file_t *jbf)
2070Sigor@sysoev.ru {
2080Sigor@sysoev.ru     nxt_int_t        n;
2090Sigor@sysoev.ru     nxt_file_t       *file;
2100Sigor@sysoev.ru     nxt_file_info_t  fi;
2110Sigor@sysoev.ru 
2120Sigor@sysoev.ru     file = &jbf->file;
2130Sigor@sysoev.ru 
2140Sigor@sysoev.ru     n = nxt_file_info(file, &fi);
2150Sigor@sysoev.ru 
2160Sigor@sysoev.ru     if (n != NXT_OK) {
2170Sigor@sysoev.ru         return NXT_ERROR;
2180Sigor@sysoev.ru     }
2190Sigor@sysoev.ru 
2200Sigor@sysoev.ru     if (nxt_is_file(&fi)) {
2210Sigor@sysoev.ru         file->type = NXT_FILE_REGULAR;
2220Sigor@sysoev.ru         file->size = nxt_file_size(&fi);
2230Sigor@sysoev.ru         file->mtime = nxt_file_mtime(&fi);
2240Sigor@sysoev.ru 
2250Sigor@sysoev.ru     } else if (nxt_is_dir(&fi)) {
2260Sigor@sysoev.ru         file->type = NXT_FILE_DIRECTORY;
2270Sigor@sysoev.ru         file->size = nxt_file_size(&fi);
2280Sigor@sysoev.ru         file->mtime = nxt_file_mtime(&fi);
2290Sigor@sysoev.ru     }
2300Sigor@sysoev.ru 
2310Sigor@sysoev.ru     return NXT_OK;
2320Sigor@sysoev.ru }
2330Sigor@sysoev.ru 
2340Sigor@sysoev.ru 
2350Sigor@sysoev.ru static nxt_int_t
nxt_job_file_mmap(nxt_job_file_t * jbf,size_t size)2360Sigor@sysoev.ru nxt_job_file_mmap(nxt_job_file_t *jbf, size_t size)
2370Sigor@sysoev.ru {
2380Sigor@sysoev.ru     u_char             *p, *end;
2390Sigor@sysoev.ru     static nxt_uint_t  n;
2400Sigor@sysoev.ru 
2410Sigor@sysoev.ru     p = nxt_mem_map(NULL, &jbf->buffer->mmap, size, NXT_MEM_MAP_READ,
2420Sigor@sysoev.ru                     (NXT_MEM_MAP_FILE | NXT_MEM_MAP_PREFAULT),
2430Sigor@sysoev.ru                     jbf->file.fd, jbf->offset);
2440Sigor@sysoev.ru 
2450Sigor@sysoev.ru     if (nxt_fast_path(p != NXT_MEM_MAP_FAILED)) {
2460Sigor@sysoev.ru 
2470Sigor@sysoev.ru         end = p + size;
2480Sigor@sysoev.ru 
2490Sigor@sysoev.ru         jbf->buffer->mem.pos = p;
2500Sigor@sysoev.ru         jbf->buffer->mem.free = end;
2510Sigor@sysoev.ru         jbf->buffer->mem.start = p;
2520Sigor@sysoev.ru         jbf->buffer->mem.end = end;
2530Sigor@sysoev.ru         jbf->buffer->file_end += size;
2540Sigor@sysoev.ru         jbf->offset += size;
2550Sigor@sysoev.ru 
2560Sigor@sysoev.ru         /*
2570Sigor@sysoev.ru          * The mapped pages should be already preloaded in the kernel page
2580Sigor@sysoev.ru          * cache by nxt_file_read_ahead().  Touching them should wire the pages
2590Sigor@sysoev.ru          * in user land memory if mmap() did not do this.  Adding to the static
2600Sigor@sysoev.ru          * variable "n" disables the loop elimination during optimization.
2610Sigor@sysoev.ru          */
2620Sigor@sysoev.ru         n += *p;
2630Sigor@sysoev.ru 
2640Sigor@sysoev.ru         for (p = nxt_align_ptr(p, nxt_pagesize); p < end; p += nxt_pagesize) {
2650Sigor@sysoev.ru             n += *p;
2660Sigor@sysoev.ru         }
2670Sigor@sysoev.ru 
2680Sigor@sysoev.ru         return NXT_OK;
2690Sigor@sysoev.ru     }
2700Sigor@sysoev.ru 
2710Sigor@sysoev.ru     return NXT_ERROR;
2720Sigor@sysoev.ru }
2730Sigor@sysoev.ru 
2740Sigor@sysoev.ru 
2750Sigor@sysoev.ru static nxt_int_t
nxt_job_file_read_data(nxt_job_file_t * jbf,size_t size)2760Sigor@sysoev.ru nxt_job_file_read_data(nxt_job_file_t *jbf, size_t size)
2770Sigor@sysoev.ru {
2780Sigor@sysoev.ru     ssize_t  n;
2790Sigor@sysoev.ru 
280*237Svbart@nginx.com     n = nxt_file_read(&jbf->file, jbf->buffer->mem.free, size, jbf->offset);
2810Sigor@sysoev.ru 
2820Sigor@sysoev.ru     if (nxt_fast_path(n > 0)) {
2830Sigor@sysoev.ru 
2840Sigor@sysoev.ru         jbf->buffer->mem.free += n;
2850Sigor@sysoev.ru         jbf->offset += n;
2860Sigor@sysoev.ru 
2870Sigor@sysoev.ru         if (nxt_buf_is_file(jbf->buffer)) {
2880Sigor@sysoev.ru             jbf->buffer->file_end += n;
2890Sigor@sysoev.ru         }
2900Sigor@sysoev.ru 
2910Sigor@sysoev.ru         return NXT_OK;
2920Sigor@sysoev.ru     }
2930Sigor@sysoev.ru 
2940Sigor@sysoev.ru     return NXT_ERROR;
2950Sigor@sysoev.ru }
2960Sigor@sysoev.ru 
2970Sigor@sysoev.ru 
2980Sigor@sysoev.ru static nxt_int_t
nxt_job_file_read_required(nxt_job_file_t * jbf)2990Sigor@sysoev.ru nxt_job_file_read_required(nxt_job_file_t *jbf)
3000Sigor@sysoev.ru {
3010Sigor@sysoev.ru     return NXT_OK;
3020Sigor@sysoev.ru }
303