bool ConcurrentTableSharedStore::get(CStrRef key, Variant &value) { const StoreValue *sval; SharedVariant *svar = NULL; ConditionalReadLock l(m_lock, !RuntimeOption::ApcConcurrentTableLockFree || m_lockingFlag); bool expired = false; bool promoteObj = 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 { 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 (RuntimeOption::ApcAllowObj && svar->is(KindOfObject)) { // 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; }
ThreadSharedVariant *ThreadSharedVariant::createAnother (CVarRef source, bool serialized, bool inner /* = false */) { SharedVariant *wrapped = source.getSharedVariant(); if (wrapped) { wrapped->incRef(); // static cast should be enough return (ThreadSharedVariant *)wrapped; } return new ThreadSharedVariant(source, serialized, inner); }
SharedVariant *SharedVariant::Create (CVarRef source, bool serialized, bool inner /* = false */, bool unserializeObj /* = false*/) { SharedVariant *wrapped = source.getSharedVariant(); if (wrapped && !unserializeObj) { wrapped->incRef(); // static cast should be enough return (SharedVariant *)wrapped; } return new SharedVariant(source, serialized, inner, unserializeObj); }
bool ConcurrentTableSharedStore::get(CStrRef key, Variant &value) { bool stats = RuntimeOption::EnableStats && RuntimeOption::EnableAPCStats; bool statsFetch = RuntimeOption::EnableAPCSizeStats && RuntimeOption::EnableAPCFetchStats; const StoreValue *val; SharedVariant *svar = NULL; ReadLock l(m_lock); bool expired = false; { Map::const_accessor acc; if (!m_vars.find(acc, key.data())) { if (stats) ServerStats::Log("apc.miss", 1); return false; } else { val = &acc->second; if (val->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 { svar = val->var; if (RuntimeOption::ApcAllowObj) { // Hold ref here svar->incRef(); } value = svar->toLocal(); if (statsFetch) { SharedStoreStats::onGet(key.get(), svar); } } } } if (expired) { if (stats) { ServerStats::Log("apc.miss", 1); } eraseImpl(key, true); return false; } if (stats) { ServerStats::Log("apc.hit", 1); } if (RuntimeOption::ApcAllowObj) { bool statsDetail = RuntimeOption::EnableAPCSizeStats && RuntimeOption::EnableAPCSizeGroup; SharedVariant *converted = svar->convertObj(value); if (converted) { Map::accessor acc; m_vars.find(acc, key.data()); // start a write lock StoreValue *sval = &acc->second; SharedVariant *sv = sval->var; // sv may not be same as svar here because some other thread may have // updated it already, check before updating if (!sv->isUnserializedObj()) { if (statsDetail) { SharedStoreStats::onDelete(key.get(), sv, true); } sval->var = converted; sv->decRef(); if (RuntimeOption::EnableAPCSizeStats) { int32 newSize = converted->getSpaceUsage(); SharedStoreStats::updateDirect(sval->size, newSize); sval->size = newSize; } if (statsDetail) { int64 ttl = sval->expiry ? sval->expiry - time(NULL) : 0; SharedStoreStats::onStore(key.get(), converted, ttl, false); } } else { converted->decRef(); } } // release the extra ref svar->decRef(); } return true; }