bool ConcurrentTableSharedStore::get(const String& key, Variant& value) { const StoreValue *sval; APCHandle *svar = nullptr; ReadLock l(m_lock); bool expired = false; bool promoteObj = false; { Map::const_accessor acc; if (!m_vars.find(acc, tagStringData(key.get()))) { 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 (auto const handle = sval->data.left()) { svar = handle; } else { std::lock_guard<SmallLock> sval_lock(sval->lock); if (auto const handle = sval->data.left()) { svar = handle; } else { /* * Note that unserialize can run arbitrary php code via a __wakeup * routine, which could try to access this same key, and we're * holding various locks here. This is only for promoting primed * values to in-memory values, so it's basically not a real * problem, but ... :) */ svar = unserialize(key, const_cast<StoreValue*>(sval)); if (!svar) return false; } } if (apcExtension::AllowObj && svar->type() == KindOfObject && !svar->objAttempted()) { // Hold ref here for later promoting the object svar->reference(); promoteObj = true; } value = svar->toLocal(); } } } if (expired) { eraseImpl(key, true, apcExtension::UseUncounted ? HPHP::Treadmill::getOldestStartTime() : 0); return false; } if (promoteObj) { handlePromoteObj(key, svar, value); // release the extra ref svar->unreference(); } 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; }