Igor Sysoev | 297c048 | 2003-11-14 16:52:04 +0000 | [diff] [blame] | 1 | |
| 2 | #include <ngx_config.h> |
| 3 | #include <ngx_core.h> |
Igor Sysoev | 1b138ed | 2003-11-18 21:34:08 +0000 | [diff] [blame] | 4 | #include <ngx_garbage_collector.h> |
Igor Sysoev | 297c048 | 2003-11-14 16:52:04 +0000 | [diff] [blame] | 5 | |
| 6 | |
Igor Sysoev | 1b138ed | 2003-11-18 21:34:08 +0000 | [diff] [blame] | 7 | int ngx_garbage_collector_temp_handler(ngx_gc_t *ctx, ngx_str_t *name, |
| 8 | ngx_dir_t *dir); |
Igor Sysoev | 297c048 | 2003-11-14 16:52:04 +0000 | [diff] [blame] | 9 | |
| 10 | |
| 11 | static 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 | |
| 26 | void 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 Sysoev | 1b138ed | 2003-11-18 21:34:08 +0000 | [diff] [blame] | 54 | void stub_init(ngx_cycle_t *cycle) |
Igor Sysoev | 297c048 | 2003-11-14 16:52:04 +0000 | [diff] [blame] | 55 | { |
Igor Sysoev | 10a543a | 2004-03-16 07:10:12 +0000 | [diff] [blame] | 56 | ngx_uint_t i; |
Igor Sysoev | 1b138ed | 2003-11-18 21:34:08 +0000 | [diff] [blame] | 57 | ngx_gc_t ctx; |
| 58 | ngx_path_t **path; |
Igor Sysoev | 297c048 | 2003-11-14 16:52:04 +0000 | [diff] [blame] | 59 | |
Igor Sysoev | 1b138ed | 2003-11-18 21:34:08 +0000 | [diff] [blame] | 60 | 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 Sysoev | 297c048 | 2003-11-14 16:52:04 +0000 | [diff] [blame] | 67 | } |
Igor Sysoev | 297c048 | 2003-11-14 16:52:04 +0000 | [diff] [blame] | 68 | } |
| 69 | |
| 70 | |
| 71 | static int ngx_collect_garbage(ngx_gc_t *ctx, ngx_str_t *dname, int level) |
| 72 | { |
Igor Sysoev | d9d0ca1 | 2003-11-21 06:30:49 +0000 | [diff] [blame] | 73 | int rc; |
Igor Sysoev | 10a543a | 2004-03-16 07:10:12 +0000 | [diff] [blame] | 74 | u_char *last; |
Igor Sysoev | d9d0ca1 | 2003-11-21 06:30:49 +0000 | [diff] [blame] | 75 | size_t len; |
Igor Sysoev | f2e676a | 2003-11-16 21:49:42 +0000 | [diff] [blame] | 76 | ngx_err_t err; |
| 77 | ngx_str_t fname, buf; |
| 78 | ngx_dir_t dir; |
Igor Sysoev | 297c048 | 2003-11-14 16:52:04 +0000 | [diff] [blame] | 79 | |
Igor Sysoev | f2e676a | 2003-11-16 21:49:42 +0000 | [diff] [blame] | 80 | buf.len = 0; |
Igor Sysoev | 10a543a | 2004-03-16 07:10:12 +0000 | [diff] [blame] | 81 | #if (NGX_SUPPRESS_WARN) |
| 82 | buf.data = NULL; |
| 83 | fname.data = NULL; |
| 84 | #endif |
Igor Sysoev | 297c048 | 2003-11-14 16:52:04 +0000 | [diff] [blame] | 85 | |
Igor Sysoev | 54498db | 2004-02-11 17:08:49 +0000 | [diff] [blame] | 86 | ngx_log_debug2(NGX_LOG_DEBUG_CORE, ctx->log, 0, |
| 87 | "gc dir \"%s\":%d", dname->data, dname->len); |
Igor Sysoev | 297c048 | 2003-11-14 16:52:04 +0000 | [diff] [blame] | 88 | |
Igor Sysoev | f2e676a | 2003-11-16 21:49:42 +0000 | [diff] [blame] | 89 | 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 Sysoev | 297c048 | 2003-11-14 16:52:04 +0000 | [diff] [blame] | 92 | return NGX_ERROR; |
| 93 | } |
| 94 | |
| 95 | for ( ;; ) { |
Igor Sysoev | f2e676a | 2003-11-16 21:49:42 +0000 | [diff] [blame] | 96 | ngx_set_errno(0); |
| 97 | if (ngx_read_dir(&dir) == NGX_ERROR) { |
| 98 | err = ngx_errno; |
Igor Sysoev | 297c048 | 2003-11-14 16:52:04 +0000 | [diff] [blame] | 99 | |
Igor Sysoev | f2e676a | 2003-11-16 21:49:42 +0000 | [diff] [blame] | 100 | 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 Sysoev | 297c048 | 2003-11-14 16:52:04 +0000 | [diff] [blame] | 107 | } |
Igor Sysoev | f2e676a | 2003-11-16 21:49:42 +0000 | [diff] [blame] | 108 | |
Igor Sysoev | 297c048 | 2003-11-14 16:52:04 +0000 | [diff] [blame] | 109 | break; |
| 110 | } |
| 111 | |
Igor Sysoev | f2e676a | 2003-11-16 21:49:42 +0000 | [diff] [blame] | 112 | len = ngx_de_namelen(&dir); |
Igor Sysoev | 297c048 | 2003-11-14 16:52:04 +0000 | [diff] [blame] | 113 | |
Igor Sysoev | 54498db | 2004-02-11 17:08:49 +0000 | [diff] [blame] | 114 | ngx_log_debug2(NGX_LOG_DEBUG_CORE, ctx->log, 0, |
| 115 | "gc name \"%s\":%d", ngx_de_name(&dir), len); |
Igor Sysoev | 297c048 | 2003-11-14 16:52:04 +0000 | [diff] [blame] | 116 | |
Igor Sysoev | f2e676a | 2003-11-16 21:49:42 +0000 | [diff] [blame] | 117 | if (len == 1 && ngx_de_name(&dir)[0] == '.') { |
Igor Sysoev | 297c048 | 2003-11-14 16:52:04 +0000 | [diff] [blame] | 118 | continue; |
| 119 | } |
| 120 | |
Igor Sysoev | f2e676a | 2003-11-16 21:49:42 +0000 | [diff] [blame] | 121 | if (len == 2 |
| 122 | && ngx_de_name(&dir)[0] == '.' |
| 123 | && ngx_de_name(&dir)[1] == '.') |
| 124 | { |
Igor Sysoev | 297c048 | 2003-11-14 16:52:04 +0000 | [diff] [blame] | 125 | continue; |
| 126 | } |
| 127 | |
Igor Sysoev | f2e676a | 2003-11-16 21:49:42 +0000 | [diff] [blame] | 128 | 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 Sysoev | 297c048 | 2003-11-14 16:52:04 +0000 | [diff] [blame] | 134 | } |
| 135 | |
Igor Sysoev | f2e676a | 2003-11-16 21:49:42 +0000 | [diff] [blame] | 136 | buf.len = dname->len + 1 + len + NGX_DIR_MASK_LEN; |
Igor Sysoev | 297c048 | 2003-11-14 16:52:04 +0000 | [diff] [blame] | 137 | |
Igor Sysoev | f2e676a | 2003-11-16 21:49:42 +0000 | [diff] [blame] | 138 | if (!(buf.data = ngx_alloc(buf.len + 1, ctx->log))) { |
Igor Sysoev | 297c048 | 2003-11-14 16:52:04 +0000 | [diff] [blame] | 139 | return NGX_ABORT; |
| 140 | } |
| 141 | } |
| 142 | |
Igor Sysoev | f2e676a | 2003-11-16 21:49:42 +0000 | [diff] [blame] | 143 | last = ngx_cpymem(buf.data, dname->data, dname->len); |
Igor Sysoev | 297c048 | 2003-11-14 16:52:04 +0000 | [diff] [blame] | 144 | *last++ = '/'; |
Igor Sysoev | f2e676a | 2003-11-16 21:49:42 +0000 | [diff] [blame] | 145 | ngx_memcpy(last, ngx_de_name(&dir), len + 1); |
| 146 | fname.data = buf.data; |
Igor Sysoev | 297c048 | 2003-11-14 16:52:04 +0000 | [diff] [blame] | 147 | |
Igor Sysoev | 54498db | 2004-02-11 17:08:49 +0000 | [diff] [blame] | 148 | ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0, |
| 149 | "gc path: \"%s\"", fname.data); |
Igor Sysoev | 297c048 | 2003-11-14 16:52:04 +0000 | [diff] [blame] | 150 | |
Igor Sysoev | f2e676a | 2003-11-16 21:49:42 +0000 | [diff] [blame] | 151 | 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 Sysoev | 297c048 | 2003-11-14 16:52:04 +0000 | [diff] [blame] | 157 | } |
| 158 | |
Igor Sysoev | f2e676a | 2003-11-16 21:49:42 +0000 | [diff] [blame] | 159 | if (ngx_de_is_dir(&dir)) { |
Igor Sysoev | 297c048 | 2003-11-14 16:52:04 +0000 | [diff] [blame] | 160 | |
Igor Sysoev | 54498db | 2004-02-11 17:08:49 +0000 | [diff] [blame] | 161 | ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0, |
| 162 | "gc enter dir \"%s\"", fname.data); |
Igor Sysoev | 297c048 | 2003-11-14 16:52:04 +0000 | [diff] [blame] | 163 | |
| 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 Sysoev | f2e676a | 2003-11-16 21:49:42 +0000 | [diff] [blame] | 168 | || len != ctx->path->level[level]) |
Igor Sysoev | 297c048 | 2003-11-14 16:52:04 +0000 | [diff] [blame] | 169 | { |
| 170 | if (ngx_collect_garbage(ctx, &fname, -1) == NGX_ABORT) { |
| 171 | return NGX_ABORT; |
| 172 | } |
| 173 | |
Igor Sysoev | f2e676a | 2003-11-16 21:49:42 +0000 | [diff] [blame] | 174 | fname.data[fname.len] = '\0'; |
| 175 | |
Igor Sysoev | 297c048 | 2003-11-14 16:52:04 +0000 | [diff] [blame] | 176 | 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 Sysoev | f2e676a | 2003-11-16 21:49:42 +0000 | [diff] [blame] | 186 | ctx->freed += ngx_de_size(&dir); |
Igor Sysoev | 297c048 | 2003-11-14 16:52:04 +0000 | [diff] [blame] | 187 | } |
| 188 | |
| 189 | continue; |
| 190 | } |
| 191 | |
| 192 | if (ngx_collect_garbage(ctx, &fname, level + 1) == NGX_ABORT) { |
| 193 | return NGX_ABORT; |
| 194 | } |
| 195 | |
Igor Sysoev | f2e676a | 2003-11-16 21:49:42 +0000 | [diff] [blame] | 196 | } else if (ngx_de_is_file(&dir)) { |
| 197 | |
Igor Sysoev | 54498db | 2004-02-11 17:08:49 +0000 | [diff] [blame] | 198 | ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0, |
| 199 | "gc file \"%s\"", fname.data); |
Igor Sysoev | 297c048 | 2003-11-14 16:52:04 +0000 | [diff] [blame] | 200 | |
| 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 Sysoev | f2e676a | 2003-11-16 21:49:42 +0000 | [diff] [blame] | 210 | ctx->freed += ngx_de_size(&dir); |
Igor Sysoev | 297c048 | 2003-11-14 16:52:04 +0000 | [diff] [blame] | 211 | } |
| 212 | |
| 213 | continue; |
| 214 | } |
| 215 | |
Igor Sysoev | f2e676a | 2003-11-16 21:49:42 +0000 | [diff] [blame] | 216 | if (ctx->handler(ctx, &fname, &dir) == NGX_ABORT) { |
Igor Sysoev | 297c048 | 2003-11-14 16:52:04 +0000 | [diff] [blame] | 217 | 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 Sysoev | f2e676a | 2003-11-16 21:49:42 +0000 | [diff] [blame] | 229 | ctx->freed += ngx_de_size(&dir); |
Igor Sysoev | 297c048 | 2003-11-14 16:52:04 +0000 | [diff] [blame] | 230 | } |
| 231 | } |
| 232 | } |
| 233 | |
Igor Sysoev | f2e676a | 2003-11-16 21:49:42 +0000 | [diff] [blame] | 234 | 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 Sysoev | 297c048 | 2003-11-14 16:52:04 +0000 | [diff] [blame] | 244 | } |
| 245 | |
| 246 | |
Igor Sysoev | 1b138ed | 2003-11-18 21:34:08 +0000 | [diff] [blame] | 247 | int ngx_garbage_collector_temp_handler(ngx_gc_t *ctx, ngx_str_t *name, |
| 248 | ngx_dir_t *dir) |
Igor Sysoev | 297c048 | 2003-11-14 16:52:04 +0000 | [diff] [blame] | 249 | { |
| 250 | /* |
Igor Sysoev | 54498db | 2004-02-11 17:08:49 +0000 | [diff] [blame] | 251 | * We use mtime only and do not use atime because: |
Igor Sysoev | 297c048 | 2003-11-14 16:52:04 +0000 | [diff] [blame] | 252 | * on NTFS access time has a resolution of 1 hour, |
| 253 | * on NT FAT access time has a resolution of 1 day, |
Igor Sysoev | 54498db | 2004-02-11 17:08:49 +0000 | [diff] [blame] | 254 | * Unices have the mount option "noatime". |
Igor Sysoev | 297c048 | 2003-11-14 16:52:04 +0000 | [diff] [blame] | 255 | */ |
| 256 | |
Igor Sysoev | f2e676a | 2003-11-16 21:49:42 +0000 | [diff] [blame] | 257 | if (ngx_cached_time - ngx_de_mtime(dir) < 3600) { |
Igor Sysoev | 297c048 | 2003-11-14 16:52:04 +0000 | [diff] [blame] | 258 | 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 Sysoev | f2e676a | 2003-11-16 21:49:42 +0000 | [diff] [blame] | 271 | ctx->freed += ngx_de_size(dir); |
Igor Sysoev | 1b138ed | 2003-11-18 21:34:08 +0000 | [diff] [blame] | 272 | |
Igor Sysoev | 297c048 | 2003-11-14 16:52:04 +0000 | [diff] [blame] | 273 | return NGX_OK; |
| 274 | } |