std::pair<const MockMc::Item*, uint64_t> MockMc::gets(folly::StringPiece key) { auto it = findUnexpired(key); if (it == citems_.end() || it->second.state != CacheItem::CACHE) { return std::make_pair<Item*, uint64_t>(nullptr, 0); } return std::make_pair(&it->second.item, it->second.casToken); }
/** * @return: (item, 0) On a hit. * (stale_item, token) On a miss. * (stale_item, 1) On a hot miss (another lease outstanding). */ std::pair<MockMc::Item*, uint64_t> MockMc::leaseGet(folly::StringPiece key) { auto it = findUnexpired(key); if (it == citems_.end()) { /* Lease get on a non-existing item: create a new empty item and put it in TLRU with valid token */ it = citems_.insert( std::make_pair(key.str(), CacheItem(Item(folly::IOBuf::copyBuffer(""))))).first; it->second.state = CacheItem::TLRU; it->second.updateToken(); } auto& citem = it->second; switch (citem.state) { case CacheItem::CACHE: /* Regular hit */ return std::make_pair(&citem.item, 0); case CacheItem::TLRU: /* First lease-get for a TLRU item, return with a valid token */ citem.state = CacheItem::TLRU_HOT; return std::make_pair(&citem.item, citem.token); case CacheItem::TLRU_HOT: /* TLRU item with other lease-gets pending, return a hot miss token (special value 1). Note: in real memcached this state would revert to TLRU after a timeout. */ return std::make_pair(&citem.item, 1); } CHECK(false); }
MockMc::Item* MockMc::get(folly::StringPiece key) { auto it = findUnexpired(key); if (it == citems_.end() || it->second.state != CacheItem::CACHE) { return nullptr; } return &it->second.item; }
bool MockMc::append(folly::StringPiece key, Item suffix) { auto it = findUnexpired(key); if (it == citems_.end() || it->second.state != CacheItem::CACHE) { return false; } auto& item = it->second.item; item.value->appendChain(std::move(suffix.value)); return true; }
bool MockMc::touch(folly::StringPiece key, int32_t newExptime) { auto it = findUnexpired(key); if (it == citems_.end() || it->second.state != CacheItem::CACHE) { return false; } it->second.item.exptime = newExptime != 0 && newExptime <= 60 * 60 * 24 * 30 ? newExptime + time(nullptr) : newExptime; return true; }
std::pair<bool, int64_t> MockMc::arith(folly::StringPiece key, int64_t delta) { auto it = findUnexpired(key); if (it == citems_.end() || it->second.state != CacheItem::CACHE) { return std::make_pair(false, 0); } auto oldval = folly::to<uint64_t>(coalesceAndGetRange(it->second.item.value)); auto newval = folly::to<std::string>(oldval + delta); it->second.updateCasToken(); it->second.item.value = folly::IOBuf::copyBuffer(newval); return std::make_pair(true, oldval + delta); }
MockMc::CasResult MockMc::cas(folly::StringPiece key, Item item, uint64_t token) { auto it = findUnexpired(key); if (it == citems_.end() || it->second.state != CacheItem::CACHE) { return CasResult::NOT_FOUND; } if (it->second.casToken != token) { return CasResult::EXISTS; } set(key, std::move(item)); return CasResult::STORED; }
bool MockMc::del(folly::StringPiece key) { auto it = findUnexpired(key); if (it != citems_.end()) { bool deleted = false; /* Delete moves items from CACHE to TLRU, and always bumps lease tokens */ if (it->second.state == CacheItem::CACHE) { deleted = true; it->second.state = CacheItem::TLRU; } it->second.updateToken(); return deleted; } return false; }
MockMc::LeaseSetResult MockMc::leaseSet(folly::StringPiece key, Item item, uint64_t token) { auto it = findUnexpired(key); if (it == citems_.end()) { /* Item doesn't exist in cache or TLRU */ return LeaseSetResult::NOT_STORED; } auto& citem = it->second; if (citem.state == CacheItem::CACHE || citem.leaseToken == token) { /* Either the item is a hit, or the token is valid. Regular set */ set(key, std::move(item)); return LeaseSetResult::STORED; } else { /* The token is not valid (expired or wrong), but the value is in TLRU. Update the value but don't promote to cache. */ citem.item = std::move(item); return LeaseSetResult::STALE_STORED; } }