local lrucache = require"resty.lrucache.pureffi" local c, err = lrucache.new(200) ifnot c then error("failed to create the cache: " .. (err or"unknown")) end
-- 根据size来初始化cache, function _M.new(size, load_factor) if size < 1then returnnil, "size too small" end
-- Determine bucket size, which must be power of two. local load_f = load_factor ifnot load_factor then load_f = 0.5 elseif load_factor > 1then load_f = 1 elseif load_factor < 0.1then load_f = 0.1 end
-- bucket_sz的值为最小的大于bs_min的2的倍数 local bs_min = size / load_f -- The bucket_sz *MUST* be a power-of-two. See the hash_string(). local bucket_sz = 1 repeat bucket_sz = bucket_sz * 2 until bucket_sz >= bs_min
local self = { size = size, bucket_sz = bucket_sz, free_queue = queue_init(size), cache_queue = queue_init(0), node_v = nil, key_v = new_tab(size, 0), val_v = new_tab(size, 0), bucket_v = ffi_new(int_array_t, bucket_sz), num_items = 0, } -- "note_v" is an array of all the nodes used in the LRU queue. Exprpession -- node_v[i] evaluates to the element of ID "i". self.node_v = self.free_queue
-- Allocate the array-part of the key_v, val_v, bucket_v. --local key_v = self.key_v --local val_v = self.val_v --local bucket_v = self.bucket_v ffi_fill(self.bucket_v, ffi_sizeof(int_t, bucket_sz), 0)
returnsetmetatable(self, mt) end
localfunction(size) ifnot size then size = 0 end -- 调用ffi.new开辟一块内存空间 local q = ffi_new(queue_arr_type, size + 1) -- 填充lrucache_pureffi_queue_t数组数据 ffi_fill(q, ffi_sizeof(queue_type, size + 1), 0) -- 如果size=0,则q是一个只有一个node双向链表 if size == 0then q[0].prev = q q[0].next = q -- 构造双向链表 else local prev = q[0] for i = 1, size do local e = q[i] e.id = i e.user_flags = 0 prev.next = e e.prev = prev prev = e end
local last = q[size] last.next = q q[0].prev = last end
-- 如果有ttl参数,则将node的expire设置为距离当前时间+ttl,否则则设置为-1(不过期) if ttl then node.expire = ngx_now() + ttl else node.expire = -1 end --如果flags为数字,且大于0,则设置node的user_flags为flags,否则设置为0 iftype(flags) == "number"and flags >= 0then node.user_flags = flags else node.user_flags = 0 end end
localfunctionfind_key(self, key) -- 获取key的hash值,并计算key在bucket_v的哪个索引上 local key_hash = hash_string(self, key) -- 获取bucket_v中存储的node_id值 return _find_node_in_bucket(key, self.key_v, self.node_v, self.bucket_v[key_hash]) end
localfunction _find_node_in_bucket(key, key_v, node_v, bucket_hdr_id) -- 获取bucket_v中存的node_id值(bucket_v存的是node的id), -- 如果id不等于0,则代表key已经存在了 -- 如果id等于0,则代表key不存在 if bucket_hdr_id ~= 0then local prev = 0 local cur = bucket_hdr_id -- 1. 如果key相同,则返回node的id, -- 2. 如果key不相同,说明hash冲突了,一直往下找,直到key相同或者node_id等于0 while cur ~= 0and key_v[cur] ~= key do prev = cur -- confilict记录的是上一个node的id值 cur = node_v[cur].conflict end -- 如果node_id不等于0,则返回node_id if cur ~= 0then return cur, prev end end end
localfunctionremove_key(self, key) local key_v = self.key_v local val_v = self.val_v local node_v = self.node_v local bucket_v = self.bucket_v
local key_hash = hash_string(self, key) -- 找到要清除的node_id local cur, prev = _find_node_in_bucket(key, key_v, node_v, bucket_v[key_hash])
if cur then -- 清除key和value key_v[cur] = nil val_v[cur] = nil self.num_items = self.num_items - 1
-- Remove the node from the hash table -- 获取要清除的node的conflict(也即上一个node的node_id) local next_node = node_v[cur].conflict if prev ~= 0then node_v[prev].conflict = next_node else bucket_v[key_hash] = next_node end node_v[cur].conflict = 0
return cur end end
localfunctioninsert_key(self, key, val, node) -- Bind the key/val with the node local node_id = node.id -- key_v val_v相应位置进行赋值 self.key_v[node_id] = key self.val_v[node_id] = val
-- Insert the node into the hash-table local key_hash = hash_string(self, key) local bucket_v = self.bucket_v -- 第一次node.conflict = 0 node.conflict = bucket_v[key_hash] -- 将node_id存到bucket_v中 bucket_v[key_hash] = node_id self.num_items = self.num_items + 1 end