bool ConcurrentTableSharedStore::store(const String& key, const Variant& value, int64_t ttl, bool overwrite /* = true */, bool limit_ttl /* = true */) { StoreValue *sval; APCHandle* svar = construct(value); ConditionalReadLock l(m_lock, !apcExtension::ConcurrentTableLockFree || 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; 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()) { sval->var->unreferenceRoot(); } else { // mark the inFile copy invalid since we are updating the key sval->sAddr = nullptr; sval->sSize = 0; } } else { svar->unreferenceRoot(); return false; } } int64_t adjustedTtl = adjust_ttl(ttl, overwritePrime || !limit_ttl); if (check_noTTL(key.data(), key.size())) { adjustedTtl = 0; } sval->set(svar, adjustedTtl); expiry = sval->expiry; } if (expiry) { addToExpirationQueue(key.data(), expiry); } if (apcExtension::ExpireOnSets) { purgeExpired(); } return true; }
bool ConcurrentTableSharedStore::storeImpl(const String& key, const Variant& value, int64_t ttl, bool overwrite, bool limit_ttl) { StoreValue *sval; auto svar = APCHandle::Create(value, false, APCHandleLevel::Outer, false); auto keyLen = key.size(); ReadLock l(m_lock); char* const kcp = strdup(key.data()); bool present; time_t expiry = 0; bool overwritePrime = false; { Map::accessor acc; APCHandle* current = nullptr; present = !m_vars.insert(acc, kcp); sval = &acc->second; if (present) { free(kcp); if (!overwrite && !sval->expired()) { svar.handle->unreferenceRoot(svar.size); return false; } sval->data.match( [&] (APCHandle* handle) { current = handle; // If ApcTTLLimit is set, then only primed keys can have // expire == 0. overwritePrime = sval->expire == 0; }, [&] (char*) { // Was inFile, but won't be anymore. sval->data = nullptr; sval->dataSize = 0; overwritePrime = true; } ); } else { APCStats::getAPCStats().addKey(keyLen); } int64_t adjustedTtl = adjust_ttl(ttl, overwritePrime || !limit_ttl); if (check_noTTL(key.data(), key.size())) { adjustedTtl = 0; } if (current) { if (sval->expire == 0 && adjustedTtl != 0) { APCStats::getAPCStats().removeAPCValue( sval->dataSize, current, true, sval->expired()); APCStats::getAPCStats().addAPCValue(svar.handle, svar.size, false); } else { APCStats::getAPCStats().updateAPCValue( svar.handle, svar.size, current, sval->dataSize, sval->expire == 0, sval->expired()); } current->unreferenceRoot(sval->dataSize); } else { APCStats::getAPCStats().addAPCValue(svar.handle, svar.size, present); } sval->set(svar.handle, adjustedTtl); sval->dataSize = svar.size; expiry = sval->expire; if (expiry) { auto ikey = intptr_t(acc->first); if (m_expMap.insert({ ikey, 0 })) { m_expQueue.push({ ikey, expiry }); } } } if (apcExtension::ExpireOnSets) { purgeExpired(); } return true; }
bool ConcurrentTableSharedStore::store(CStrRef key, CVarRef val, int64 ttl, bool overwrite /* = true */) { bool stats = RuntimeOption::EnableStats && RuntimeOption::EnableAPCStats; bool statsDetail = RuntimeOption::EnableAPCSizeStats && RuntimeOption::EnableAPCSizeGroup; StoreValue *sval; SharedVariant* var = construct(key, val); ReadLock l(m_lock); const char *kcp = strdup(key.data()); bool present; time_t expiry; { Map::accessor acc; present = !m_vars.insert(acc, kcp); sval = &acc->second; if (present) { free((void *)kcp); if (overwrite || sval->expired()) { if (statsDetail) { SharedStoreStats::onDelete(key.get(), sval->var, true); } sval->var->decRef(); if (RuntimeOption::EnableAPCSizeStats && !check_skip(key.data())) { int32 size = var->getSpaceUsage(); SharedStoreStats::updateDirect(sval->size, size); sval->size = size; } } else { var->decRef(); return false; } } else { if (RuntimeOption::EnableAPCSizeStats) { int32 size = var->getSpaceUsage(); SharedStoreStats::addDirect(key.size(), size); sval->size = size; } } sval->set(var, ttl); expiry = sval->expiry; if (statsDetail) { SharedStoreStats::onStore(key.get(), var, ttl, false); } } if (RuntimeOption::ApcExpireOnSets) { if (ttl) { addToExpirationQueue(key.data(), expiry); } purgeExpired(); } if (stats) { if (present) { ServerStats::Log("apc.update", 1); } else { ServerStats::Log("apc.new", 1); if (RuntimeOption::EnableStats && RuntimeOption::EnableAPCKeyStats) { string prefix = "apc.new."; prefix += GetSkeleton(key); ServerStats::Log(prefix, 1); } } } return true; }
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; }