ngx_open_file_cache.c

来自「Nginx是一个高性能的HTTP和反向代理服务器」· C语言 代码 · 共 820 行 · 第 1/2 页

C
820
字号
/* * Copyright (C) Igor Sysoev */#include <ngx_config.h>#include <ngx_core.h>#include <ngx_event.h>/* * open file cache caches *    open file handles with stat() info; *    directories stat() info; *    files and directories errors: not found, access denied, etc. */static void ngx_open_file_cache_cleanup(void *data);static ngx_int_t ngx_open_and_stat_file(u_char *name, ngx_open_file_info_t *of,    ngx_log_t *log);static void ngx_open_file_add_event(ngx_open_file_cache_t *cache,    ngx_cached_open_file_t *file, ngx_open_file_info_t *of, ngx_log_t *log);static void ngx_open_file_cleanup(void *data);static void ngx_close_cached_file(ngx_open_file_cache_t *cache,    ngx_cached_open_file_t *file, ngx_uint_t min_uses, ngx_log_t *log);static void ngx_open_file_del_event(ngx_cached_open_file_t *file);static void ngx_expire_old_cached_files(ngx_open_file_cache_t *cache,    ngx_uint_t n, ngx_log_t *log);static void ngx_open_file_cache_rbtree_insert_value(ngx_rbtree_node_t *temp,    ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);static ngx_cached_open_file_t *    ngx_open_file_lookup(ngx_open_file_cache_t *cache, ngx_str_t *name,    uint32_t hash);static void ngx_open_file_cache_remove(ngx_event_t *ev);ngx_open_file_cache_t *ngx_open_file_cache_init(ngx_pool_t *pool, ngx_uint_t max, time_t inactive){    ngx_pool_cleanup_t     *cln;    ngx_open_file_cache_t  *cache;    cache = ngx_palloc(pool, sizeof(ngx_open_file_cache_t));    if (cache == NULL) {        return NULL;    }    ngx_rbtree_init(&cache->rbtree, &cache->sentinel,                    ngx_open_file_cache_rbtree_insert_value);    ngx_queue_init(&cache->expire_queue);    cache->current = 0;    cache->max = max;    cache->inactive = inactive;    cln = ngx_pool_cleanup_add(pool, 0);    if (cln == NULL) {        return NULL;    }    cln->handler = ngx_open_file_cache_cleanup;    cln->data = cache;    return cache;}static voidngx_open_file_cache_cleanup(void *data){    ngx_open_file_cache_t  *cache = data;    ngx_queue_t             *q;    ngx_cached_open_file_t  *file;    ngx_log_debug0(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0,                   "open file cache cleanup");    for ( ;; ) {        if (ngx_queue_empty(&cache->expire_queue)) {            break;        }        q = ngx_queue_last(&cache->expire_queue);        file = ngx_queue_data(q, ngx_cached_open_file_t, queue);        ngx_queue_remove(q);        ngx_rbtree_delete(&cache->rbtree, &file->node);        cache->current--;        ngx_log_debug1(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0,                       "delete cached open file: %s", file->name);        if (!file->err && !file->is_dir) {            file->close = 1;            file->count = 0;            ngx_close_cached_file(cache, file, 0, ngx_cycle->log);        } else {            ngx_free(file->name);            ngx_free(file);        }    }    if (cache->current) {        ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,                      "%d items still leave in open file cache",                      cache->current);    }    if (cache->rbtree.root != cache->rbtree.sentinel) {        ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,                      "rbtree still is not empty in open file cache");    }}ngx_int_tngx_open_cached_file(ngx_open_file_cache_t *cache, ngx_str_t *name,    ngx_open_file_info_t *of, ngx_pool_t *pool){    time_t                          now;    uint32_t                        hash;    ngx_int_t                       rc;    ngx_pool_cleanup_t             *cln;    ngx_cached_open_file_t         *file;    ngx_pool_cleanup_file_t        *clnf;    ngx_open_file_cache_cleanup_t  *ofcln;    of->err = 0;    if (cache == NULL) {        cln = ngx_pool_cleanup_add(pool, sizeof(ngx_pool_cleanup_file_t));        if (cln == NULL) {            return NGX_ERROR;        }        rc = ngx_open_and_stat_file(name->data, of, pool->log);        if (rc == NGX_OK && !of->is_dir) {            cln->handler = ngx_pool_cleanup_file;            clnf = cln->data;            clnf->fd = of->fd;            clnf->name = name->data;            clnf->log = pool->log;        }        return rc;    }    cln = ngx_pool_cleanup_add(pool, sizeof(ngx_open_file_cache_cleanup_t));    if (cln == NULL) {        return NGX_ERROR;    }    now = ngx_time();    hash = ngx_crc32_long(name->data, name->len);    file = ngx_open_file_lookup(cache, name, hash);    if (file) {        file->uses++;        ngx_queue_remove(&file->queue);        if (file->fd == NGX_INVALID_FILE && file->err == 0 && !file->is_dir) {            /* file was not used often enough to keep open */            rc = ngx_open_and_stat_file(name->data, of, pool->log);            if (rc != NGX_OK && (of->err == 0 || !of->errors)) {                goto failed;            }            goto add_event;        }        if ((file->event && file->use_event)            || (file->event == NULL && now - file->created < of->valid))        {            if (file->err == 0) {                of->fd = file->fd;                of->uniq = file->uniq;                of->mtime = file->mtime;                of->size = file->size;                of->is_dir = file->is_dir;                of->is_file = file->is_file;                of->is_link = file->is_link;                of->is_exec = file->is_exec;                if (!file->is_dir) {                    file->count++;                    ngx_open_file_add_event(cache, file, of, pool->log);                }            } else {                of->err = file->err;            }            goto found;        }        ngx_log_debug4(NGX_LOG_DEBUG_CORE, pool->log, 0,                       "retest open file: %s, fd:%d, c:%d, e:%d",                       file->name, file->fd, file->count, file->err);        if (file->is_dir) {            /*             * chances that directory became file are very small             * so test_dir flag allows to use a single syscall             * in ngx_file_info() instead of three syscalls             */            of->test_dir = 1;        }        rc = ngx_open_and_stat_file(name->data, of, pool->log);        if (rc != NGX_OK && (of->err == 0 || !of->errors)) {            goto failed;        }        if (of->is_dir) {            if (file->is_dir || file->err) {                goto update;            }            /* file became directory */        } else if (of->err == 0) {  /* file */            if (file->is_dir || file->err) {                goto add_event;            }            if (of->uniq == file->uniq                && of->mtime == file->mtime                && of->size == file->size)            {                if (ngx_close_file(of->fd) == NGX_FILE_ERROR) {                    ngx_log_error(NGX_LOG_ALERT, pool->log, ngx_errno,                                  ngx_close_file_n " \"%s\" failed",                                  name->data);                }                of->fd = file->fd;                file->count++;                if (file->event) {                    file->use_event = 1;                    goto renew;                }                ngx_open_file_add_event(cache, file, of, pool->log);                goto renew;            }            /* file was changed */        } else { /* error to cache */            if (file->err || file->is_dir) {                goto update;            }            /* file was removed, etc. */        }        if (file->count == 0) {            ngx_open_file_del_event(file);            if (ngx_close_file(file->fd) == NGX_FILE_ERROR) {                ngx_log_error(NGX_LOG_ALERT, pool->log, ngx_errno,                              ngx_close_file_n " \"%s\" failed",                              name->data);            }            goto add_event;        }        ngx_rbtree_delete(&cache->rbtree, &file->node);        cache->current--;        file->close = 1;        goto create;    }    /* not found */    rc = ngx_open_and_stat_file(name->data, of, pool->log);    if (rc != NGX_OK && (of->err == 0 || !of->errors)) {        goto failed;    }create:    if (cache->current >= cache->max) {        ngx_expire_old_cached_files(cache, 0, pool->log);    }    file = ngx_alloc(sizeof(ngx_cached_open_file_t), pool->log);    if (file == NULL) {        goto failed;    }    file->name = ngx_alloc(name->len + 1, pool->log);    if (file->name == NULL) {        ngx_free(file);        file = NULL;        goto failed;    }    ngx_cpystrn(file->name, name->data, name->len + 1);    file->node.key = hash;    ngx_rbtree_insert(&cache->rbtree, &file->node);    cache->current++;    file->uses = 1;    file->count = 0;    file->use_event = 0;    file->event = NULL;add_event:    ngx_open_file_add_event(cache, file, of, pool->log);update:    file->fd = of->fd;    file->err = of->err;    if (of->err == 0) {        file->uniq = of->uniq;        file->mtime = of->mtime;        file->size = of->size;        file->close = 0;        file->is_dir = of->is_dir;        file->is_file = of->is_file;        file->is_link = of->is_link;        file->is_exec = of->is_exec;        if (!of->is_dir) {            file->count++;        }    }renew:    file->created = now;found:    file->accessed = now;    ngx_queue_insert_head(&cache->expire_queue, &file->queue);    ngx_log_debug5(NGX_LOG_DEBUG_CORE, pool->log, 0,                   "cached open file: %s, fd:%d, c:%d, e:%d, u:%d",                   file->name, file->fd, file->count, file->err, file->uses);    if (of->err == 0) {        if (!of->is_dir) {            cln->handler = ngx_open_file_cleanup;            ofcln = cln->data;            ofcln->cache = cache;            ofcln->file = file;            ofcln->min_uses = of->min_uses;            ofcln->log = pool->log;        }        return NGX_OK;    }    return NGX_ERROR;failed:    if (file) {        ngx_rbtree_delete(&cache->rbtree, &file->node);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?