最近整理了下这个问题的详细描述,如下.
前提P1:
ngx.shared.DICT的API使得它有两种典型的用法:
1)存储重要的全局元数据,在其整个的生命周期内,是不能容忍被错误地删除、或者淘汰掉的,否则会导致系统的核心逻辑无法正常地执行下去,甚至逻辑出错;
2)用来存储全局的Cache,它的存在只是为了提高这种信息的缓存命中率,即使一些条目被淘汰掉掉了,也对系统的核心逻辑无致命的影响.
对于存储元数据的DICT,应对其使用{safe_set,safe_add}等安全的API,因为这些用法不会触发LRU淘汰策略;
而对于作为全局Cache存储的DICT,则可以使用所有类型的API,因为它可以容忍被淘汰.
如果P1是成立的,继续往下.
再看pthread_spin_lock的API:
// malloc and free
extern int pthread_spin_init (pthread_spinlock_t *__lock, int __pshared)
extern int pthread_spin_destroy (pthread_spinlock_t *__lock)
// op.
extern int pthread_spin_lock (pthread_spinlock_t *__lock)
extern int pthread_spin_trylock (pthread_spinlock_t *__lock)
extern int pthread_spin_unlock (pthread_spinlock_t *__lock)
基于DICT的全局锁与传统的进程间互斥锁的模型是有区别的:
DICT: 借助add类的操作,单个操作本身隐含了init和lock两个语义;
传统: 在init成功之后,再对已经分配到的锁进行trylock/lock,试图改变它的状态,以占有它.
关键:
DICT的抢锁,在init阶段也是可能失败的,这时应该返回分配失败,更不应该去淘汰别的锁成员.
问题:
官方lua-resty-lock的抢锁,使用ngx.shared.DICT.add来实现,这相当于把这个DICT当作Cache来使用(实际应该是重要的元数据).
如果这个DICT的容量不够大的时候,一旦add触发了淘汰机制,就会可能发生在临界区,同时有多个进程存在的情况,如果使用safe_add就不会有这种问题了.
不知道诸位怎么看待这个问题的呢?