+/* ==================== Disk store negative caching ========================
+ *
+ * When disk store is enabled, we need negative caching, that is, to remember
+ * keys that are for sure *not* on the disk key-value store.
+ *
+ * This is useful for two reasons:
+ *
+ * 1) Without negative caching cache misses will cost us a disk lookup, even
+ * if the same non existing key is accessed again and again. We negative
+ * caching we remember that the key is not on disk, so if it's not in memory
+ * and we have a negative cache entry, we don't try a disk access at all.
+ *
+ * 2) Negative caching is the way to fix a specific race condition. For instance
+ * think at the following sequence of commands:
+ *
+ * SET foo bar
+ * DEL foo
+ * GET foo
+ *
+ * After the SET, we'll mark the value as dirty, so it will be flushed
+ * on disk at some time. Later the key is deleted, so will be removed
+ * from memory. Another job will be created to remove the key from the disk
+ * store, but the removal is not synchronous, so may happen later in time.
+ *
+ * Finally we have a GET foo operation. This operation may result in
+ * reading back a value from disk that is not updated data, as the deletion
+ * operaiton against the disk KV store was still not completed, so we
+ * read old data.
+ *
+ * Remembering that the given key is deleted is important. We can discard this
+ * information once the key was really removed from the disk.
+ *
+ * So actually there are two kind of negative caching entries: entries that
+ * can be evicted when we need to reclaim memory, and entries that will
+ * not be evicted, for all the time we need this information to be available.
+ *
+ * The API allows to create both kind of negative caching. */
+
+int cacheKeyMayExist(redisDb *db, robj *key) {
+ return dictFind(db->io_negcache,key) == NULL;
+}
+
+void cacheSetKeyMayExist(redisDb *db, robj *key) {
+ dictDelete(db->io_negcache,key);
+}
+
+void cacheSetKeyDoesNotExist(redisDb *db, robj *key) {
+ struct dictEntry *de;
+
+ /* Don't overwrite negative cached entries with val set to 0, as this
+ * entries were created with cacheSetKeyDoesNotExistRemember(). */
+ de = dictFind(db->io_negcache,key);
+ if (de != NULL && dictGetEntryVal(de) == NULL) return;
+
+ if (dictReplace(db->io_negcache,key,(void*)time(NULL))) {
+ incrRefCount(key);
+ }
+}
+
+void cacheSetKeyDoesNotExistRemember(redisDb *db, robj *key) {
+ if (dictReplace(db->io_negcache,key,NULL)) {
+ incrRefCount(key);
+ }
+}
+
+/* ================== Disk store cache - Threaded I/O ====================== */