bool ConcurrentTableSharedStore::handlePromoteObj(CStrRef key, SharedVariant* svar, CVarRef value) { SharedVariant *converted = svar->convertObj(value); if (converted) { Map::accessor acc; if (!m_vars.find(acc, key.data())) { // There is a chance another thread deletes the key when this thread is // converting the object. In that case, we just bail converted->decRef(); return false; } // A write lock was acquired during find 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 == svar && !sv->isUnserializedObj()) { int64 ttl = sval->expiry ? sval->expiry - time(NULL) : 0; stats_on_update(key.get(), sval, converted, ttl); sval->var = converted; sv->decRef(); return true; } converted->decRef(); } return false; }
bool ConcurrentTableSharedStore::handlePromoteObj(const String& key, APCHandle* svar, CVarRef value) { APCHandle *converted = APCObject::MakeAPCObject(svar, value); if (converted) { Map::accessor acc; if (!m_vars.find(acc, tagStringData(key.get()))) { // There is a chance another thread deletes the key when this thread is // converting the object. In that case, we just bail converted->decRef(); return false; } // A write lock was acquired during find StoreValue *sval = &acc->second; APCHandle *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 == svar && !sv->getIsObj()) { int64_t ttl = sval->expiry ? sval->expiry - time(nullptr) : 0; stats_on_update(key.get(), sval, converted, ttl); sval->var = converted; sv->decRef(); return true; } converted->decRef(); } return false; }
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; }