0
|
1
|
|
2 /*
|
|
3 * Copyright (C) Igor Sysoev
|
|
4 */
|
|
5
|
|
6
|
|
7 #include <ngx_config.h>
|
|
8 #include <ngx_core.h>
|
|
9 #include <ngx_garbage_collector.h>
|
|
10
|
|
11
|
|
12 int ngx_garbage_collector_temp_handler(ngx_gc_t *ctx, ngx_str_t *name,
|
|
13 ngx_dir_t *dir);
|
|
14
|
|
15
|
|
16 static int ngx_collect_garbage(ngx_gc_t *ctx, ngx_str_t *dname, int level);
|
|
17
|
|
18
|
|
19
|
|
20 #if 0
|
|
21
|
|
22 {
|
|
23 ngx_test_null(cycle->timer_events,
|
|
24 ngx_alloc(sizeof(ngx_event_t) * TIMERS, cycle->log),
|
|
25 NGX_ERROR);
|
|
26
|
|
27 ngx_event_timer_init(cycle);
|
|
28 }
|
|
29
|
|
30
|
|
31 void garbage_collector()
|
|
32 {
|
|
33 ngx_msec_t timer;
|
|
34 struct timeval tv;
|
|
35 ngx_epoch_msec_t delta;
|
|
36
|
|
37 for ( ;; ) {
|
|
38 timer = ngx_event_find_timer();
|
|
39
|
|
40 ngx_gettimeofday(&tv);
|
|
41 delta = tv.tv_sec * 1000 + tv.tv_usec / 1000;
|
|
42
|
|
43 msleep(timer);
|
|
44
|
|
45 ngx_gettimeofday(&tv);
|
|
46
|
|
47 ngx_cached_time = tv.tv_sec;
|
|
48 ngx_time_update();
|
|
49
|
|
50 delta = tv.tv_sec * 1000 + tv.tv_usec / 1000 - delta;
|
|
51
|
|
52 ngx_event_expire_timers((ngx_msec_t) delta);
|
|
53 }
|
|
54 }
|
|
55
|
|
56 #endif
|
|
57
|
|
58
|
|
59 void stub_init(ngx_cycle_t *cycle)
|
|
60 {
|
|
61 ngx_uint_t i;
|
|
62 ngx_gc_t ctx;
|
|
63 ngx_path_t **path;
|
|
64
|
|
65 path = cycle->pathes.elts;
|
|
66 for (i = 0; i < cycle->pathes.nelts; i++) {
|
|
67 ctx.path = path[i];
|
|
68 ctx.log = cycle->log;
|
|
69 ctx.handler = path[i]->gc_handler;
|
|
70
|
|
71 ngx_collect_garbage(&ctx, &path[i]->name, 0);
|
|
72 }
|
|
73 }
|
|
74
|
|
75
|
|
76 static int ngx_collect_garbage(ngx_gc_t *ctx, ngx_str_t *dname, int level)
|
|
77 {
|
|
78 int rc;
|
|
79 u_char *last;
|
|
80 size_t len;
|
|
81 ngx_err_t err;
|
|
82 ngx_str_t fname, buf;
|
|
83 ngx_dir_t dir;
|
|
84
|
|
85 buf.len = 0;
|
|
86 #if (NGX_SUPPRESS_WARN)
|
|
87 buf.data = NULL;
|
|
88 fname.data = NULL;
|
|
89 #endif
|
|
90
|
|
91 ngx_log_debug2(NGX_LOG_DEBUG_CORE, ctx->log, 0,
|
|
92 "gc dir \"%s\":%d", dname->data, dname->len);
|
|
93
|
|
94 if (ngx_open_dir(dname, &dir) == NGX_ERROR) {
|
|
95 ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
|
|
96 ngx_open_dir_n " \"%s\" failed", dname->data);
|
|
97 return NGX_ERROR;
|
|
98 }
|
|
99
|
|
100 for ( ;; ) {
|
|
101 ngx_set_errno(0);
|
|
102 if (ngx_read_dir(&dir) == NGX_ERROR) {
|
|
103 err = ngx_errno;
|
|
104
|
|
105 if (err != NGX_ENOMOREFILES) {
|
|
106 ngx_log_error(NGX_LOG_CRIT, ctx->log, err,
|
|
107 ngx_read_dir_n " \"%s\" failed", dname->data);
|
|
108 rc = NGX_ERROR;
|
|
109
|
|
110 } else {
|
|
111 rc = NGX_OK;
|
|
112 }
|
|
113
|
|
114 break;
|
|
115 }
|
|
116
|
|
117 len = ngx_de_namelen(&dir);
|
|
118
|
|
119 ngx_log_debug2(NGX_LOG_DEBUG_CORE, ctx->log, 0,
|
|
120 "gc name \"%s\":%d", ngx_de_name(&dir), len);
|
|
121
|
|
122 if (len == 1 && ngx_de_name(&dir)[0] == '.') {
|
|
123 continue;
|
|
124 }
|
|
125
|
|
126 if (len == 2
|
|
127 && ngx_de_name(&dir)[0] == '.'
|
|
128 && ngx_de_name(&dir)[1] == '.')
|
|
129 {
|
|
130 continue;
|
|
131 }
|
|
132
|
|
133 fname.len = dname->len + 1+ len;
|
|
134
|
|
135 if (fname.len + NGX_DIR_MASK_LEN > buf.len) {
|
|
136
|
|
137 if (buf.len) {
|
|
138 ngx_free(buf.data);
|
|
139 }
|
|
140
|
|
141 buf.len = dname->len + 1 + len + NGX_DIR_MASK_LEN;
|
|
142
|
|
143 if (!(buf.data = ngx_alloc(buf.len + 1, ctx->log))) {
|
|
144 return NGX_ABORT;
|
|
145 }
|
|
146 }
|
|
147
|
|
148 last = ngx_cpymem(buf.data, dname->data, dname->len);
|
|
149 *last++ = '/';
|
|
150 ngx_memcpy(last, ngx_de_name(&dir), len + 1);
|
|
151 fname.data = buf.data;
|
|
152
|
|
153 ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0,
|
|
154 "gc path: \"%s\"", fname.data);
|
|
155
|
6
|
156 if (!dir.valid_info) {
|
0
|
157 if (ngx_de_info(fname.data, &dir) == NGX_FILE_ERROR) {
|
|
158 ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
|
|
159 ngx_de_info_n " \"%s\" failed", fname.data);
|
|
160 continue;
|
|
161 }
|
|
162 }
|
|
163
|
|
164 if (ngx_de_is_dir(&dir)) {
|
|
165
|
|
166 ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0,
|
|
167 "gc enter dir \"%s\"", fname.data);
|
|
168
|
|
169 if (level == -1
|
|
170 /* there can not be directory on the last level */
|
|
171 || level == NGX_MAX_PATH_LEVEL
|
|
172 /* an directory from the old path hierarchy */
|
|
173 || len != ctx->path->level[level])
|
|
174 {
|
|
175 if (ngx_collect_garbage(ctx, &fname, -1) == NGX_ABORT) {
|
|
176 return NGX_ABORT;
|
|
177 }
|
|
178
|
|
179 fname.data[fname.len] = '\0';
|
|
180
|
|
181 ngx_log_error(NGX_LOG_NOTICE, ctx->log, 0,
|
|
182 "delete old hierachy directory \"%s\"",
|
|
183 fname.data);
|
|
184
|
|
185 if (ngx_delete_dir(fname.data) == NGX_FILE_ERROR) {
|
|
186 ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
|
|
187 ngx_delete_dir_n " \"%s\" failed",
|
|
188 fname.data);
|
|
189 } else {
|
|
190 ctx->deleted++;
|
|
191 ctx->freed += ngx_de_size(&dir);
|
|
192 }
|
|
193
|
|
194 continue;
|
|
195 }
|
|
196
|
|
197 if (ngx_collect_garbage(ctx, &fname, level + 1) == NGX_ABORT) {
|
|
198 return NGX_ABORT;
|
|
199 }
|
|
200
|
|
201 } else if (ngx_de_is_file(&dir)) {
|
|
202
|
|
203 ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0,
|
|
204 "gc file \"%s\"", fname.data);
|
|
205
|
|
206 if (level == -1
|
|
207 || (level < NGX_MAX_PATH_LEVEL && ctx->path->level[level] != 0))
|
|
208 {
|
|
209 if (ngx_delete_file(fname.data) == NGX_FILE_ERROR) {
|
|
210 ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
|
|
211 ngx_delete_file_n " \"%s\" failed",
|
|
212 fname.data);
|
|
213 } else {
|
|
214 ctx->deleted++;
|
|
215 ctx->freed += ngx_de_size(&dir);
|
|
216 }
|
|
217
|
|
218 continue;
|
|
219 }
|
|
220
|
|
221 if (ctx->handler(ctx, &fname, &dir) == NGX_ABORT) {
|
|
222 return NGX_ABORT;
|
|
223 }
|
|
224
|
|
225 } else {
|
|
226 ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
|
|
227 "\"%s\" has unknown file type, deleting", fname.data);
|
|
228
|
|
229 if (ngx_delete_file(fname.data) == NGX_FILE_ERROR) {
|
|
230 ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
|
|
231 ngx_delete_file_n " \"%s\" failed", fname.data);
|
|
232 } else {
|
|
233 ctx->deleted++;
|
|
234 ctx->freed += ngx_de_size(&dir);
|
|
235 }
|
|
236 }
|
|
237 }
|
|
238
|
|
239 if (buf.len) {
|
|
240 ngx_free(buf.data);
|
|
241 }
|
|
242
|
|
243 if (ngx_close_dir(&dir) == NGX_ERROR) {
|
|
244 ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
|
|
245 ngx_close_dir_n " \"%s\" failed", fname.data);
|
|
246 }
|
|
247
|
|
248 return rc;
|
|
249 }
|
|
250
|
|
251
|
|
252 int ngx_garbage_collector_temp_handler(ngx_gc_t *ctx, ngx_str_t *name,
|
|
253 ngx_dir_t *dir)
|
|
254 {
|
|
255 /*
|
|
256 * We use mtime only and do not use atime because:
|
|
257 * on NTFS access time has a resolution of 1 hour,
|
|
258 * on NT FAT access time has a resolution of 1 day,
|
|
259 * Unices have the mount option "noatime".
|
|
260 */
|
|
261
|
|
262 if (ngx_time() - ngx_de_mtime(dir) < 3600) {
|
|
263 return NGX_OK;
|
|
264 }
|
|
265
|
|
266 ngx_log_error(NGX_LOG_NOTICE, ctx->log, 0,
|
|
267 "delete stale temporary \"%s\"", name->data);
|
|
268
|
|
269 if (ngx_delete_file(name->data) == NGX_FILE_ERROR) {
|
|
270 ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
|
|
271 ngx_delete_file_n " \"%s\" failed", name->data);
|
|
272 return NGX_ERROR;
|
|
273 }
|
|
274
|
|
275 ctx->deleted++;
|
|
276 ctx->freed += ngx_de_size(dir);
|
|
277
|
|
278 return NGX_OK;
|
|
279 }
|