예제 #1
0
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;
}
예제 #2
0
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;
}
예제 #3
0
bool ConcurrentTableSharedStore::store(const String& key, CVarRef 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;
    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 || !limit_ttl));
          sval->var->decRef();
          update = true;
        } else {
          // mark the inFile copy invalid since we are updating the key
          sval->sAddr = nullptr;
          sval->sSize = 0;
        }
      } else {
        svar->decRef();
        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 (!update) {
      stats_on_add(key.get(), sval, adjustedTtl, false, false);
    }
  }
  if (expiry) {
    addToExpirationQueue(key.data(), expiry);
  }
  if (apcExtension::ExpireOnSets) {
    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;
}