int64 ConcurrentTableSharedStore::inc(CStrRef key, int64 step, bool &found) {
  found = false;
  int64 ret = 0;
  ReadLock l(m_lock);
  StoreValue *val;
  {
    Map::accessor acc;
    if (m_vars.find(acc, key.data())) {
      val = &acc->second;
      if (val->expired()) {
        eraseAcc(acc);
      } else {
        Variant v = val->var->toLocal();
        ret = v.toInt64() + step;
        v = ret;
        SharedVariant *var = construct(key, v);
        val->var->decRef();
        val->var = var;
        found = true;
      }
    }
  }

  if (RuntimeOption::EnableStats && RuntimeOption::EnableAPCStats) {
    ServerStats::Log("apc.inc", 1);
  }
  return ret;
}
예제 #2
0
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;
}
예제 #3
0
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->unreferenceRoot();
        sval->var = var;
        success = true;
      }
    }
  }
  return success;
}
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;
}
예제 #5
0
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->unreferenceRoot();
        sval->var = svar;
        found = true;
      }
    }
  }
  return ret;
}
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;
}
예제 #7
0
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;
}