nginxが持っている機能のファイルキャッシュの追い出し方法について調べたので書いた。
ざっくり結論としてはキューを用いたLRUでキャッシュサイズが指定した値より大きい場合は要素の末尾を削除していくという実装
static time_t ngx_http_file_cache_expire(ngx_http_file_cache_t *cache) { for ( ;; ) { q = ngx_queue_last(&cache->sh->queue); fcn = ngx_queue_data(q, ngx_http_file_cache_node_t, queue); wait = fcn->expire - now; if (fcn->count == 0) { ngx_http_file_cache_delete(cache, q, name); goto next; }
キャッシュ自体の削除はこのへん。双方向リストでキューを実装しキャッシュへのアクセスがあるとキューの先頭へ持って行き削除時は末尾の要素の削除。
static void ngx_http_file_cache_delete(ngx_http_file_cache_t *cache, ngx_queue_t *q, u_char *name) { u_char *p; size_t len; ngx_path_t *path; ngx_http_file_cache_node_t *fcn; fcn = ngx_queue_data(q, ngx_http_file_cache_node_t, queue); if (fcn->exists) { cache->sh->size -= fcn->fs_size; path = cache->path; p = name + path->name.len + 1 + path->len; p = ngx_hex_dump(p, (u_char *) &fcn->node.key, sizeof(ngx_rbtree_key_t)); len = NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t); p = ngx_hex_dump(p, fcn->key, len); *p = '\0'; fcn->count++; fcn->deleting = 1; ngx_shmtx_unlock(&cache->shpool->mutex); len = path->name.len + 1 + path->len + 2 * NGX_HTTP_CACHE_KEY_LEN; ngx_create_hashed_filename(path, name, len); if (ngx_delete_file(name) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_CRIT, ngx_cycle->log, ngx_errno, ngx_delete_file_n " \"%s\" failed", name); } ngx_shmtx_lock(&cache->shpool->mutex); fcn->count--; fcn->deleting = 0; } if (fcn->count == 0) { ngx_queue_remove(q); ngx_rbtree_delete(&cache->sh->rbtree, &fcn->node); ngx_slab_free_locked(cache->shpool, fcn); cache->sh->count--; } }
キューの削除処理はマクロになっていた。
キューの実装自体は以下のように双方向リストとなっている。
typedef struct ngx_queue_s ngx_queue_t; struct ngx_queue_s { ngx_queue_t *prev; ngx_queue_t *next; };