diff options
author | antirez <antirez@gmail.com> | 2020-06-10 11:06:24 +0200 |
---|---|---|
committer | antirez <antirez@gmail.com> | 2020-06-10 11:06:24 +0200 |
commit | 0c9a325d08389905a02750f014e55e0c5ff759de (patch) | |
tree | 0d389ab5e8ba7697866d14cc590421c52ac89b3d | |
parent | 9bd8f02fe1ead3b3dca0a7b04706fd131bf5a192 (diff) | |
download | redis-threaded-core-commands.tar.gz |
TCC: protect dictionaries from changing while accessed.threaded-core-commands
Certain Redis objects may change upon read only access. This is the
case, for instance, of hash tables, that may continue to incrementally
rehash after a rehashing operation. A similar problem also happens with
the PFCOUNT operation and other operations that may write as a side
effect of reading. In the case of PFCOUNT probably the right approach
would be to flag the command in a special way in the command table, so
that the operation is blocked as it if was a write operation.
-rw-r--r-- | src/db.c | 23 |
1 files changed, 22 insertions, 1 deletions
@@ -1797,6 +1797,17 @@ int lockKey(client *c, robj *key, int locktype, robj **optr) { lk->obj = lookupKeyReadWithFlags(c->db,key,LOOKUP_NOTOUCH); dictAdd(c->db->locked_keys,key,lk); incrRefCount(key); + + /* Make the object immutable. In the trivial case of hash tables + * we just increment the iterators count, to prevent rehashing + * when the object is accessed in read-only. */ + if (lk->obj) { + if (lk->obj->encoding == OBJ_ENCODING_HT) { + ((dict*)lk->obj->ptr)->iterators++; + } else if (lk->obj->encoding == OBJ_ENCODING_SKIPLIST) { + ((zset*)lk->obj->ptr)->dict->iterators++; + } + } } else { /* If there is already a lock, it is incompatible with a new lock * both in the case the lock is of write type, or we want to lock @@ -1948,7 +1959,17 @@ void unlockKey(client *c, robj *key, uint64_t owner_id) { listDelNode(lk->waiting,ln); } - /* Frre the lock state. */ + /* If we modified the object in order to make it immutable during + * read operations, restore it in its normal state. */ + if (lk->obj) { + if (lk->obj->encoding == OBJ_ENCODING_HT) { + ((dict*)lk->obj->ptr)->iterators--; + } else if (lk->obj->encoding == OBJ_ENCODING_SKIPLIST) { + ((zset*)lk->obj->ptr)->dict->iterators--; + } + } + + /* Free the lock state. */ listRelease(lk->owners); listRelease(lk->waiting); zfree(lk); |