bool ConcurrentTableSharedStore::exists(CStrRef key) { const StoreValue *sval; ConditionalReadLock l(m_lock, !RuntimeOption::ApcConcurrentTableLockFree || m_lockingFlag); bool expired = false; { Map::const_accessor acc; if (!m_vars.find(acc, key.data())) { log_apc(std_apc_miss); return false; } else { sval = &acc->second; if (sval->expired()) { // Because it only has a read lock on the data, deletion from // expiration has to happen after the lock is released expired = true; } else { // No need toLocal() here, avoiding the copy if (sval->inMem()) { stats_on_get(key.get(), sval->var); } } } } if (expired) { log_apc(std_apc_miss); eraseImpl(key, true); return false; } log_apc(std_apc_hit); return true; }
bool ConcurrentTableSharedStore::get(const String& key, Variant &value) { const StoreValue *sval; APCHandle *svar = nullptr; ConditionalReadLock l(m_lock, !apcExtension::ConcurrentTableLockFree || m_lockingFlag); bool expired = false; bool promoteObj = false; { Map::const_accessor acc; if (!m_vars.find(acc, tagStringData(key.get()))) { log_apc(std_apc_miss); return false; } else { sval = &acc->second; if (sval->expired()) { // Because it only has a read lock on the data, deletion from // expiration has to happen after the lock is released expired = true; } else { if (!sval->inMem()) { std::lock_guard<SmallLock> sval_lock(sval->lock); if (!sval->inMem()) { svar = unserialize(key, sval); if (!svar) return false; } else { svar = sval->var; } } else { svar = sval->var; } if (apcExtension::AllowObj && svar->is(KindOfObject) && !svar->getObjAttempted()) { // Hold ref here for later promoting the object svar->incRef(); promoteObj = true; } value = svar->toLocal(); stats_on_get(key.get(), svar); } } } if (expired) { log_apc(std_apc_miss); eraseImpl(key, true); return false; } log_apc(std_apc_hit); if (promoteObj) { handlePromoteObj(key, svar, value); // release the extra ref svar->decRef(); } return true; }
bool ConcurrentTableSharedStore::cas(CStrRef key, int64 old, int64 val) { bool success = false; ConditionalReadLock l(m_lock, !RuntimeOption::ApcConcurrentTableLockFree || m_lockingFlag); StoreValue *sval; { Map::accessor acc; if (m_vars.find(acc, key.data())) { sval = &acc->second; if (!sval->expired() && get_int64_value(sval) == old) { SharedVariant *var = construct(Variant(val)); sval->var->decRef(); sval->var = var; success = true; log_apc(std_apc_cas); } } } return success; }
bool ConcurrentTableSharedStore::cas(const String& key, int64_t old, int64_t val) { bool success = false; ConditionalReadLock l(m_lock, !apcExtension::ConcurrentTableLockFree || m_lockingFlag); StoreValue *sval; { Map::accessor acc; if (m_vars.find(acc, tagStringData(key.get()))) { sval = &acc->second; if (!sval->expired() && get_int64_value(sval) == old) { APCHandle *var = construct(Variant(val)); sval->var->decRef(); sval->var = var; success = true; log_apc(std_apc_cas); } } } return success; }
int64 ConcurrentTableSharedStore::inc(CStrRef key, int64 step, bool &found) { found = false; int64 ret = 0; ConditionalReadLock l(m_lock, !RuntimeOption::ApcConcurrentTableLockFree || m_lockingFlag); StoreValue *sval; { Map::accessor acc; if (m_vars.find(acc, key.data())) { sval = &acc->second; if (!sval->expired()) { ret = get_int64_value(sval) + step; SharedVariant *svar = construct(Variant(ret)); sval->var->decRef(); sval->var = svar; found = true; log_apc(std_apc_hit); } } } return ret; }
int64_t ConcurrentTableSharedStore::inc(const String& key, int64_t step, bool &found) { found = false; int64_t ret = 0; ConditionalReadLock l(m_lock, !apcExtension::ConcurrentTableLockFree || m_lockingFlag); StoreValue *sval; { Map::accessor acc; if (m_vars.find(acc, tagStringData(key.get()))) { sval = &acc->second; if (!sval->expired()) { ret = get_int64_value(sval) + step; APCHandle *svar = construct(Variant(ret)); sval->var->decRef(); sval->var = svar; found = true; log_apc(std_apc_hit); } } } return ret; }
bool ConcurrentTableSharedStore::store(CStrRef key, CVarRef value, int64 ttl, bool overwrite /* = true */) { StoreValue *sval; SharedVariant* svar = construct(value); ConditionalReadLock l(m_lock, !RuntimeOption::ApcConcurrentTableLockFree || m_lockingFlag); const char *kcp = strdup(key.data()); bool present; time_t expiry = 0; bool overwritePrime = false; { Map::accessor acc; present = !m_vars.insert(acc, kcp); sval = &acc->second; bool update = false; if (present) { free((void *)kcp); if (overwrite || sval->expired()) { // if ApcTTLLimit is set, then only primed keys can have expiry == 0 overwritePrime = (sval->expiry == 0); if (sval->inMem()) { stats_on_update(key.get(), sval, svar, adjust_ttl(ttl, overwritePrime)); sval->var->decRef(); update = true; } else { // mark the inFile copy invalid since we are updating the key sval->sAddr = NULL; sval->sSize = 0; } } else { svar->decRef(); return false; } } int64 adjustedTtl = adjust_ttl(ttl, overwritePrime); if (check_noTTL(key.data())) { adjustedTtl = 0; } sval->set(svar, adjustedTtl); expiry = sval->expiry; if (!update) { stats_on_add(key.get(), sval, adjustedTtl, false, false); } } if (expiry) { addToExpirationQueue(key.data(), expiry); } if (RuntimeOption::ApcExpireOnSets) { purgeExpired(); } if (present) { log_apc(std_apc_update); } else { log_apc(std_apc_new); if (RuntimeOption::EnableStats && RuntimeOption::EnableAPCKeyStats) { string prefix = "apc.new." + GetSkeleton(key); ServerStats::Log(prefix, 1); } } return true; }