Nginx 缓存机制 详解之二 缓存加载进程

上一篇博客已经详细讲解了缓存管理进程,接下来详细讲解缓存加载进程机制

缓存加载进程机制

ngx_cache_loader_process_handler函数

加载进程 和管理进程都是从函数ngx_cache_manager_process_cycle进入,只是接下来的流程函数不一样

ngx_process_events_and_timers()->ngx_event_expire_timers()->ngx_cache_loader_process_handler()
static ngx_cache_manager_ctx_t  ngx_cache_loader_ctx = {
    ngx_cache_loader_process_handler, "cache loader process", 60000
};
static void
ngx_cache_loader_process_handler(ngx_event_t *ev)
{
    ngx_uint_t     i;
    ngx_path_t   **path;
    ngx_cycle_t   *cycle;

    cycle = (ngx_cycle_t *) ngx_cycle;

    path = cycle->paths.elts;
    for (i = 0; i < cycle->paths.nelts; i++) {

        if (ngx_terminate || ngx_quit) {
            break;
        }

        if (path[i]->loader) {
            path[i]->loader(path[i]->data); //这里的 loader调用的 是ngx_http_file_cache_loader()
            ngx_time_update();
        }
    }

    exit(0);

ngx_http_file_cache_loader函数


static void
ngx_http_file_cache_loader(void *data)
{
    ngx_http_file_cache_t  *cache = data;

    ngx_tree_ctx_t  tree;

    if (!cache->sh->cold || cache->sh->loading) {
        return;
    }

    if (!ngx_atomic_cmp_set(&cache->sh->loading, 0, ngx_pid)) {
        return;
    }

    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
                   "http file cache loader");
   //设置回调
    tree.init_handler = NULL;
    tree.file_handler = ngx_http_file_cache_manage_file; // 对于每个cache文件调用这个回调
    tree.pre_tree_handler = ngx_http_file_cache_manage_directory;//主要用来遍历所有cache的 目录 
    tree.post_tree_handler = ngx_http_file_cache_noop;
    tree.spec_handler = ngx_http_file_cache_delete_file;
    //回调数据就是cache
    tree.data = cache;
    tree.alloc = 0;
    tree.log = ngx_cycle->log;
   //last为最后load时间
    cache->last = ngx_current_msec;
    cache->files = 0;
   //开始遍历
    if (ngx_walk_tree(&tree, &cache->path->name) == NGX_ABORT) {
        cache->sh->loading = 0;
        return;
    }

上面有一个ngx_tree_ctx_t数据结构

struct ngx_tree_ctx_s {
    off_t                      size;
    off_t                      fs_size;
    ngx_uint_t                 access;
    time_t                     mtime;

    ngx_tree_init_handler_pt   init_handler;
    ngx_tree_handler_pt        file_handler;
    ngx_tree_handler_pt        pre_tree_handler;
    ngx_tree_handler_pt        post_tree_handler;
    ngx_tree_handler_pt        spec_handler;

    void                      *data;
    size_t                     alloc;

    ngx_log_t                 *log;
};
/**ctx->init_handler() – see ctx->alloc
* ctx->file_handler() – file handler
* ctx->pre_tree_handler() – handler is called before entering directory
* ctx->post_tree_handler() – handler is called after leaving directory
* ctx->spec_handler() – special (socket, FIFO, etc.) file handler
*
* ctx->data – some data structure, it may be the same on all levels, or
* reallocated if ctx->alloc is nonzero
*
* ctx->alloc – a size of data structure that is allocated at every level
* and is initilialized by ctx->init_handler()
*
* ctx->log – a log*/

ngx_http_file_cache_manage_file函数

static ngx_int_t
ngx_http_file_cache_manage_file(ngx_tree_ctx_t *ctx, ngx_str_t *path)
{
    ngx_msec_t              elapsed;
    ngx_http_file_cache_t  *cache;

    cache = ctx->data;
//将文件添加进cache
    if (ngx_http_file_cache_add_file(ctx, path) != NGX_OK) {
        (void) ngx_http_file_cache_delete_file(ctx, path);
    }
//如果文件个数太大,则休眠并清理files计数
    if (++cache->files >= cache->loader_files) {
        ngx_http_file_cache_loader_sleep(cache);

    } else {
        ngx_time_update();
//否则看loader时间是不是过长,如果过长则又进入休眠
        elapsed = ngx_abs((ngx_msec_int_t) (ngx_current_msec - cache->last));

        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
                       "http file cache loader time elapsed: %M", elapsed);

        if (elapsed >= cache->loader_threshold) {
            ngx_http_file_cache_loader_sleep(cache);
        }
    }

    return (ngx_quit || ngx_terminate) ? NGX_ABORT : NGX_OK;
}

分别是ngx_http_file_cache_add_file和ngx_http_file_cache_loader_sleep。其中sleep函数比较简单,就是休眠,并重置对应的域。

ngx_http_file_cache_loader_sleep函数

static void
ngx_http_file_cache_loader_sleep(ngx_http_file_cache_t *cache)
{
    ngx_msleep(cache->loader_sleep);

    ngx_time_update();

    cache->last = ngx_current_msec;
    cache->files = 0;
}

ngx_http_file_cache_add_file函数

ngx_http_file_cache_add_file,它主要是通过文件名计算hash,然后调用ngx_http_file_cache_add将这个文件加入到cache管理中(也就是添加红黑树以及队列)

static ngx_int_t
ngx_http_file_cache_add(ngx_http_file_cache_t *cache, ngx_http_cache_t *c)
{
    ngx_http_file_cache_node_t  *fcn;

    ngx_shmtx_lock(&cache->shpool->mutex);
//首先查找
    fcn = ngx_http_file_cache_lookup(cache, c->key);

    if (fcn == NULL) {
//如果不存在,则新建结构
        fcn = ngx_slab_alloc_locked(cache->shpool,
                                    sizeof(ngx_http_file_cache_node_t));
        if (fcn == NULL) {
            ngx_shmtx_unlock(&cache->shpool->mutex);
            return NGX_ERROR;
        }

        ngx_memcpy((u_char *) &fcn->node.key, c->key, sizeof(ngx_rbtree_key_t));

        ngx_memcpy(fcn->key, &c->key[sizeof(ngx_rbtree_key_t)],
                   NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t));
//插入红黑树
        ngx_rbtree_insert(&cache->sh->rbtree, &fcn->node);

        fcn->uses = 1;
        fcn->count = 0;
        fcn->valid_msec = 0;
        fcn->error = 0;
        fcn->exists = 1;
        fcn->updating = 0;
        fcn->deleting = 0;
        fcn->uniq = 0;
        fcn->valid_sec = 0;
        fcn->body_start = 0;
        fcn->fs_size = c->fs_size;

        cache->sh->size += c->fs_size;

    } else {
//否则删除queue,后续会重新插入
        ngx_queue_remove(&fcn->queue);
    }

    fcn->expire = ngx_time() + cache->inactive;
//重新插入
    ngx_queue_insert_head(&cache->sh->queue, &fcn->queue);

    ngx_shmtx_unlock(&cache->shpool->mutex);

    return NGX_OK;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序猿阿三

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值