blob: 3b673300fc5c42e7870352a2686a4e839a03c24b [file] [log] [blame]
Igor Sysoev297c0482003-11-14 16:52:04 +00001
2#include <ngx_config.h>
3#include <ngx_core.h>
Igor Sysoev1b138ed2003-11-18 21:34:08 +00004#include <ngx_garbage_collector.h>
Igor Sysoev297c0482003-11-14 16:52:04 +00005
6
Igor Sysoev1b138ed2003-11-18 21:34:08 +00007int ngx_garbage_collector_temp_handler(ngx_gc_t *ctx, ngx_str_t *name,
8 ngx_dir_t *dir);
Igor Sysoev297c0482003-11-14 16:52:04 +00009
10
11static int ngx_collect_garbage(ngx_gc_t *ctx, ngx_str_t *dname, int level);
12
13
14
15#if 0
16
17{
18 ngx_test_null(cycle->timer_events,
19 ngx_alloc(sizeof(ngx_event_t) * TIMERS, cycle->log),
20 NGX_ERROR);
21
22 ngx_event_timer_init(cycle);
23}
24
25
26void garbage_collector()
27{
28 ngx_msec_t timer;
29 struct timeval tv;
30 ngx_epoch_msec_t delta;
31
32 for ( ;; ) {
33 timer = ngx_event_find_timer();
34
35 ngx_gettimeofday(&tv);
36 delta = tv.tv_sec * 1000 + tv.tv_usec / 1000;
37
38 msleep(timer);
39
40 ngx_gettimeofday(&tv);
41
42 ngx_cached_time = tv.tv_sec;
43 ngx_time_update();
44
45 delta = tv.tv_sec * 1000 + tv.tv_usec / 1000 - delta;
46
47 ngx_event_expire_timers((ngx_msec_t) delta);
48 }
49}
50
51#endif
52
53
Igor Sysoev1b138ed2003-11-18 21:34:08 +000054void stub_init(ngx_cycle_t *cycle)
Igor Sysoev297c0482003-11-14 16:52:04 +000055{
Igor Sysoev10a543a2004-03-16 07:10:12 +000056 ngx_uint_t i;
Igor Sysoev1b138ed2003-11-18 21:34:08 +000057 ngx_gc_t ctx;
58 ngx_path_t **path;
Igor Sysoev297c0482003-11-14 16:52:04 +000059
Igor Sysoev1b138ed2003-11-18 21:34:08 +000060 path = cycle->pathes.elts;
61 for (i = 0; i < cycle->pathes.nelts; i++) {
62 ctx.path = path[i];
63 ctx.log = cycle->log;
64 ctx.handler = path[i]->gc_handler;
65
66 ngx_collect_garbage(&ctx, &path[i]->name, 0);
Igor Sysoev297c0482003-11-14 16:52:04 +000067 }
Igor Sysoev297c0482003-11-14 16:52:04 +000068}
69
70
71static int ngx_collect_garbage(ngx_gc_t *ctx, ngx_str_t *dname, int level)
72{
Igor Sysoevd9d0ca12003-11-21 06:30:49 +000073 int rc;
Igor Sysoev10a543a2004-03-16 07:10:12 +000074 u_char *last;
Igor Sysoevd9d0ca12003-11-21 06:30:49 +000075 size_t len;
Igor Sysoevf2e676a2003-11-16 21:49:42 +000076 ngx_err_t err;
77 ngx_str_t fname, buf;
78 ngx_dir_t dir;
Igor Sysoev297c0482003-11-14 16:52:04 +000079
Igor Sysoevf2e676a2003-11-16 21:49:42 +000080 buf.len = 0;
Igor Sysoev10a543a2004-03-16 07:10:12 +000081#if (NGX_SUPPRESS_WARN)
82 buf.data = NULL;
83 fname.data = NULL;
84#endif
Igor Sysoev297c0482003-11-14 16:52:04 +000085
Igor Sysoev54498db2004-02-11 17:08:49 +000086 ngx_log_debug2(NGX_LOG_DEBUG_CORE, ctx->log, 0,
87 "gc dir \"%s\":%d", dname->data, dname->len);
Igor Sysoev297c0482003-11-14 16:52:04 +000088
Igor Sysoevf2e676a2003-11-16 21:49:42 +000089 if (ngx_open_dir(dname, &dir) == NGX_ERROR) {
90 ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
91 ngx_open_dir_n " \"%s\" failed", dname->data);
Igor Sysoev297c0482003-11-14 16:52:04 +000092 return NGX_ERROR;
93 }
94
95 for ( ;; ) {
Igor Sysoevf2e676a2003-11-16 21:49:42 +000096 ngx_set_errno(0);
97 if (ngx_read_dir(&dir) == NGX_ERROR) {
98 err = ngx_errno;
Igor Sysoev297c0482003-11-14 16:52:04 +000099
Igor Sysoevf2e676a2003-11-16 21:49:42 +0000100 if (err != NGX_ENOMOREFILES) {
101 ngx_log_error(NGX_LOG_CRIT, ctx->log, err,
102 ngx_read_dir_n " \"%s\" failed", dname->data);
103 rc = NGX_ERROR;
104
105 } else {
106 rc = NGX_OK;
Igor Sysoev297c0482003-11-14 16:52:04 +0000107 }
Igor Sysoevf2e676a2003-11-16 21:49:42 +0000108
Igor Sysoev297c0482003-11-14 16:52:04 +0000109 break;
110 }
111
Igor Sysoevf2e676a2003-11-16 21:49:42 +0000112 len = ngx_de_namelen(&dir);
Igor Sysoev297c0482003-11-14 16:52:04 +0000113
Igor Sysoev54498db2004-02-11 17:08:49 +0000114 ngx_log_debug2(NGX_LOG_DEBUG_CORE, ctx->log, 0,
115 "gc name \"%s\":%d", ngx_de_name(&dir), len);
Igor Sysoev297c0482003-11-14 16:52:04 +0000116
Igor Sysoevf2e676a2003-11-16 21:49:42 +0000117 if (len == 1 && ngx_de_name(&dir)[0] == '.') {
Igor Sysoev297c0482003-11-14 16:52:04 +0000118 continue;
119 }
120
Igor Sysoevf2e676a2003-11-16 21:49:42 +0000121 if (len == 2
122 && ngx_de_name(&dir)[0] == '.'
123 && ngx_de_name(&dir)[1] == '.')
124 {
Igor Sysoev297c0482003-11-14 16:52:04 +0000125 continue;
126 }
127
Igor Sysoevf2e676a2003-11-16 21:49:42 +0000128 fname.len = dname->len + 1+ len;
129
130 if (fname.len + NGX_DIR_MASK_LEN > buf.len) {
131
132 if (buf.len) {
133 ngx_free(buf.data);
Igor Sysoev297c0482003-11-14 16:52:04 +0000134 }
135
Igor Sysoevf2e676a2003-11-16 21:49:42 +0000136 buf.len = dname->len + 1 + len + NGX_DIR_MASK_LEN;
Igor Sysoev297c0482003-11-14 16:52:04 +0000137
Igor Sysoevf2e676a2003-11-16 21:49:42 +0000138 if (!(buf.data = ngx_alloc(buf.len + 1, ctx->log))) {
Igor Sysoev297c0482003-11-14 16:52:04 +0000139 return NGX_ABORT;
140 }
141 }
142
Igor Sysoevf2e676a2003-11-16 21:49:42 +0000143 last = ngx_cpymem(buf.data, dname->data, dname->len);
Igor Sysoev297c0482003-11-14 16:52:04 +0000144 *last++ = '/';
Igor Sysoevf2e676a2003-11-16 21:49:42 +0000145 ngx_memcpy(last, ngx_de_name(&dir), len + 1);
146 fname.data = buf.data;
Igor Sysoev297c0482003-11-14 16:52:04 +0000147
Igor Sysoev54498db2004-02-11 17:08:49 +0000148 ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0,
149 "gc path: \"%s\"", fname.data);
Igor Sysoev297c0482003-11-14 16:52:04 +0000150
Igor Sysoevf2e676a2003-11-16 21:49:42 +0000151 if (!dir.info_valid) {
152 if (ngx_de_info(fname.data, &dir) == NGX_FILE_ERROR) {
153 ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
154 ngx_de_info_n " \"%s\" failed", fname.data);
155 continue;
156 }
Igor Sysoev297c0482003-11-14 16:52:04 +0000157 }
158
Igor Sysoevf2e676a2003-11-16 21:49:42 +0000159 if (ngx_de_is_dir(&dir)) {
Igor Sysoev297c0482003-11-14 16:52:04 +0000160
Igor Sysoev54498db2004-02-11 17:08:49 +0000161 ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0,
162 "gc enter dir \"%s\"", fname.data);
Igor Sysoev297c0482003-11-14 16:52:04 +0000163
164 if (level == -1
165 /* there can not be directory on the last level */
166 || level == NGX_MAX_PATH_LEVEL
167 /* an directory from the old path hierarchy */
Igor Sysoevf2e676a2003-11-16 21:49:42 +0000168 || len != ctx->path->level[level])
Igor Sysoev297c0482003-11-14 16:52:04 +0000169 {
170 if (ngx_collect_garbage(ctx, &fname, -1) == NGX_ABORT) {
171 return NGX_ABORT;
172 }
173
Igor Sysoevf2e676a2003-11-16 21:49:42 +0000174 fname.data[fname.len] = '\0';
175
Igor Sysoev297c0482003-11-14 16:52:04 +0000176 ngx_log_error(NGX_LOG_NOTICE, ctx->log, 0,
177 "delete old hierachy directory \"%s\"",
178 fname.data);
179
180 if (ngx_delete_dir(fname.data) == NGX_FILE_ERROR) {
181 ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
182 ngx_delete_dir_n " \"%s\" failed",
183 fname.data);
184 } else {
185 ctx->deleted++;
Igor Sysoevf2e676a2003-11-16 21:49:42 +0000186 ctx->freed += ngx_de_size(&dir);
Igor Sysoev297c0482003-11-14 16:52:04 +0000187 }
188
189 continue;
190 }
191
192 if (ngx_collect_garbage(ctx, &fname, level + 1) == NGX_ABORT) {
193 return NGX_ABORT;
194 }
195
Igor Sysoevf2e676a2003-11-16 21:49:42 +0000196 } else if (ngx_de_is_file(&dir)) {
197
Igor Sysoev54498db2004-02-11 17:08:49 +0000198 ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0,
199 "gc file \"%s\"", fname.data);
Igor Sysoev297c0482003-11-14 16:52:04 +0000200
201 if (level == -1
202 || (level < NGX_MAX_PATH_LEVEL && ctx->path->level[level] != 0))
203 {
204 if (ngx_delete_file(fname.data) == NGX_FILE_ERROR) {
205 ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
206 ngx_delete_file_n " \"%s\" failed",
207 fname.data);
208 } else {
209 ctx->deleted++;
Igor Sysoevf2e676a2003-11-16 21:49:42 +0000210 ctx->freed += ngx_de_size(&dir);
Igor Sysoev297c0482003-11-14 16:52:04 +0000211 }
212
213 continue;
214 }
215
Igor Sysoevf2e676a2003-11-16 21:49:42 +0000216 if (ctx->handler(ctx, &fname, &dir) == NGX_ABORT) {
Igor Sysoev297c0482003-11-14 16:52:04 +0000217 return NGX_ABORT;
218 }
219
220 } else {
221 ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
222 "\"%s\" has unknown file type, deleting", fname.data);
223
224 if (ngx_delete_file(fname.data) == NGX_FILE_ERROR) {
225 ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
226 ngx_delete_file_n " \"%s\" failed", fname.data);
227 } else {
228 ctx->deleted++;
Igor Sysoevf2e676a2003-11-16 21:49:42 +0000229 ctx->freed += ngx_de_size(&dir);
Igor Sysoev297c0482003-11-14 16:52:04 +0000230 }
231 }
232 }
233
Igor Sysoevf2e676a2003-11-16 21:49:42 +0000234 if (buf.len) {
235 ngx_free(buf.data);
236 }
237
238 if (ngx_close_dir(&dir) == NGX_ERROR) {
239 ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
240 ngx_close_dir_n " \"%s\" failed", fname.data);
241 }
242
243 return rc;
Igor Sysoev297c0482003-11-14 16:52:04 +0000244}
245
246
Igor Sysoev1b138ed2003-11-18 21:34:08 +0000247int ngx_garbage_collector_temp_handler(ngx_gc_t *ctx, ngx_str_t *name,
248 ngx_dir_t *dir)
Igor Sysoev297c0482003-11-14 16:52:04 +0000249{
250 /*
Igor Sysoev54498db2004-02-11 17:08:49 +0000251 * We use mtime only and do not use atime because:
Igor Sysoev297c0482003-11-14 16:52:04 +0000252 * on NTFS access time has a resolution of 1 hour,
253 * on NT FAT access time has a resolution of 1 day,
Igor Sysoev54498db2004-02-11 17:08:49 +0000254 * Unices have the mount option "noatime".
Igor Sysoev297c0482003-11-14 16:52:04 +0000255 */
256
Igor Sysoevf2e676a2003-11-16 21:49:42 +0000257 if (ngx_cached_time - ngx_de_mtime(dir) < 3600) {
Igor Sysoev297c0482003-11-14 16:52:04 +0000258 return NGX_OK;
259 }
260
261 ngx_log_error(NGX_LOG_NOTICE, ctx->log, 0,
262 "delete stale temporary \"%s\"", name->data);
263
264 if (ngx_delete_file(name->data) == NGX_FILE_ERROR) {
265 ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
266 ngx_delete_file_n " \"%s\" failed", name->data);
267 return NGX_ERROR;
268 }
269
270 ctx->deleted++;
Igor Sysoevf2e676a2003-11-16 21:49:42 +0000271 ctx->freed += ngx_de_size(dir);
Igor Sysoev1b138ed2003-11-18 21:34:08 +0000272
Igor Sysoev297c0482003-11-14 16:52:04 +0000273 return NGX_OK;
274}