Ejemplo n.º 1
0
// Should be called outside m_lock
void ConcurrentTableSharedStore::purgeExpired() {
  if (m_purgeCounter.fetch_add(1, std::memory_order_relaxed) %
      apcExtension::PurgeFrequency != 0) {
    return;
  }
  time_t now = time(nullptr);
  int64_t oldestLive = apcExtension::UseUncounted ?
      HPHP::Treadmill::getOldestStartTime() : 0;
  ExpirationPair tmp;
  int i = 0;
  while (apcExtension::PurgeRate < 0 || i < apcExtension::PurgeRate) {
    if (!m_expQueue.try_pop(tmp)) {
      break;
    }
    if (tmp.second > now) {
      m_expQueue.push(tmp);
      break;
    }
    if (apcExtension::UseFileStorage &&
        strcmp(tmp.first, apcExtension::FileStorageFlagKey.c_str()) == 0) {
      s_apc_file_storage.adviseOut();
      addToExpirationQueue(apcExtension::FileStorageFlagKey.c_str(),
                           time(nullptr) +
                           apcExtension::FileStorageAdviseOutPeriod);
      continue;
    }
    m_expMap.erase(tmp.first);
    eraseImpl(tmp.first, true, oldestLive);
    free((void *)tmp.first);
    ++i;
  }
}
Ejemplo n.º 2
0
// Should be called outside m_lock
void ConcurrentTableSharedStore::purgeExpired() {
  if ((atomic_add(m_purgeCounter, (uint64)1) %
       RuntimeOption::ApcPurgeFrequency) != 0) return;
  time_t now = time(NULL);
  ExpirationPair tmp;
  struct timespec tsBegin, tsEnd;
  gettime(CLOCK_MONOTONIC, &tsBegin);
  int i = 0;
  while (RuntimeOption::ApcPurgeRate < 0 || i < RuntimeOption::ApcPurgeRate) {
    if (!m_expQueue.try_pop(tmp)) {
      break;
    }
    if (tmp.second > now) {
      m_expQueue.push(tmp);
      break;
    }
    if (RuntimeOption::ApcUseFileStorage &&
        strcmp(tmp.first, RuntimeOption::ApcFileStorageFlagKey.c_str()) == 0) {
      s_apc_file_storage.adviseOut();
      addToExpirationQueue(RuntimeOption::ApcFileStorageFlagKey.c_str(),
                           time(NULL) +
                           RuntimeOption::ApcFileStorageAdviseOutPeriod);
      continue;
    }
    m_expMap.erase(tmp.first);
    eraseImpl(tmp.first, true);
    free((void *)tmp.first);
    ++i;
  }
  gettime(CLOCK_MONOTONIC, &tsEnd);
  int64 elapsed = gettime_diff_us(tsBegin, tsEnd);
  SharedStoreStats::addPurgingTime(elapsed);
  // Size could be inaccurate, but for stats reporting, it is good enough
  SharedStoreStats::setExpireQueueSize(m_expQueue.size());
}
Ejemplo n.º 3
0
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;
}
Ejemplo n.º 4
0
// Should be called outside m_lock
void ConcurrentTableSharedStore::purgeExpired() {
  if (m_purgeCounter.fetch_add(1, std::memory_order_relaxed) %
      apcExtension::PurgeFrequency != 0) {
    return;
  }
  time_t now = time(nullptr);
  int64_t oldestLive = apcExtension::UseUncounted ?
      HPHP::Treadmill::getOldestStartTime() : 0;
  ExpirationPair tmp;
  int i = 0;
  while (apcExtension::PurgeRate < 0 || i < apcExtension::PurgeRate) {
    if (!m_expQueue.try_pop(tmp)) {
      break;
    }
    if (tmp.second > now) {
      m_expQueue.push(tmp);
      break;
    }
    if (UNLIKELY(tmp.first ==
                 intptr_t(apcExtension::FileStorageFlagKey.c_str()))) {
      adviseOut();
      tmp.second = time(nullptr) + apcExtension::FileStorageAdviseOutPeriod;
      m_expQueue.push(tmp);
      continue;
    }
    ExpMap::accessor acc;
    if (m_expMap.find(acc, tmp.first)) {
      eraseImpl((char*)tmp.first, true, oldestLive, &acc);
    }
    ++i;
  }
}
Ejemplo n.º 5
0
bool ConcurrentTableSharedStore::exists(CStrRef key) {
  const StoreValue *sval;
  ConditionalReadLock l(m_lock, !RuntimeOption::ApcConcurrentTableLockFree ||
                                m_lockingFlag);
  bool expired = false;
  {
    Map::const_accessor acc;
    if (!m_vars.find(acc, key.data())) {
      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 {
        // No need toLocal() here, avoiding the copy
        if (sval->inMem()) {
          stats_on_get(key.get(), sval->var);
        }
      }
    }
  }
  if (expired) {
    log_apc(std_apc_miss);
    eraseImpl(key, true);
    return false;
  }
  log_apc(std_apc_hit);
  return true;
}
Ejemplo n.º 6
0
bool ConcurrentTableSharedStore::exists(const String& keyStr) {
  const StoreValue *sval;
  ReadLock l(m_lock);
  bool expired = false;
  auto tag = tagStringData(keyStr.get());
  {
    Map::const_accessor acc;
    if (!m_vars.find(acc, tag)) {
      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;
      }
    }
  }
  if (expired) {
    eraseImpl(tag, true,
              apcExtension::UseUncounted ?
              HPHP::Treadmill::getOldestStartTime() : 0, nullptr);
    return false;
  }
  return true;
}
Ejemplo n.º 7
0
bool SharedStore::erase(CStrRef key, bool expired /* = false */) {
  bool success = eraseImpl(key, expired);

  if (RuntimeOption::EnableStats && RuntimeOption::EnableAPCStats) {
    ServerStats::Log(success ? "apc.erased" : "apc.erase", 1);
  }
  return success;
}
Ejemplo n.º 8
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;
}
Ejemplo n.º 9
0
bool
InMemoryStorageFifo::evictItem()
{
  if (!m_cleanupIndex.get<byArrival>().empty()) {
    CleanupIndex::index<byArrival>::type::iterator it = m_cleanupIndex.get<byArrival>().begin();
    eraseImpl((*it)->getFullName());
    m_cleanupIndex.get<byArrival>().erase(it);
    return true;
  }

  return false;
}
bool
InMemoryStorageLfu::evictItem()
{
  if (!m_cleanupIndex.get<byFrequency>().empty()) {
    CleanupIndex::index<byFrequency>::type::iterator it = m_cleanupIndex.get<byFrequency>().begin();
    eraseImpl(((*it).entry)->getFullName());
    m_cleanupIndex.get<byFrequency>().erase(it);
    return true;
  }

  return false;
}
Ejemplo n.º 11
0
bool ConcurrentTableSharedStore::exists(CStrRef key) {
 bool stats = RuntimeOption::EnableStats && RuntimeOption::EnableAPCStats;
 bool statsFetch = RuntimeOption::EnableAPCSizeStats &&
                   RuntimeOption::EnableAPCFetchStats;
 const StoreValue *val;
 ReadLock l(m_lock);
 bool expired = false;
 {
   Map::const_accessor acc;
   if (!m_vars.find(acc, key.data())) {
     if (stats) ServerStats::Log("apc.miss", 1);
     return false;
   } else {
     val = &acc->second;
     if (val->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 {
       // No need toLocal() here, avoiding the copy
       if (statsFetch) {
         SharedStoreStats::onGet(key.get(), val->var);
       }
     }
   }
 }
 if (expired) {
   if (stats) {
     ServerStats::Log("apc.miss", 1);
   }
   eraseImpl(key, true);
   return false;
 }
 if (stats) {
   ServerStats::Log("apc.hit", 1);
 }
 return true;
}
Ejemplo n.º 12
0
// Should be called outside m_lock
void ConcurrentTableSharedStore::purgeExpired() {
  if ((atomic_add(m_purgeCounter, (uint64)1) %
       RuntimeOption::ApcPurgeFrequency) != 0) return;
  time_t now = time(NULL);
  {
    // Check if there's work to do
    ReadLock lock(m_expirationQueueLock);
    if (m_expirationQueue.empty() || m_expirationQueue.top().second > now) {
      // No work
      return;
    }
  }
  // Purge items n at a time. The only operation under the write lock is
  // the pop
#define PURGE_RATE 256
  const char* s[PURGE_RATE];
  while (true) {
    int i;
    {
      WriteLock lock(m_expirationQueueLock);
      const ExpirationPair *p = NULL;
      for (i = 0; i < PURGE_RATE && !m_expirationQueue.empty() &&
           (p = &m_expirationQueue.top())->second < now;
           ++i, m_expirationQueue.pop()) {
        s[i] = p->first;
      }
    }
    for (int j = 0; j < i; ++j) {
      eraseImpl(s[j], true);
      free((void *)s[j]);
    }
    if (i < PURGE_RATE) {
      // No work left
      break;
    }
  }
}
Ejemplo n.º 13
0
// Should be called outside m_lock
void ConcurrentTableSharedStore::purgeExpired() {
  if (m_purgeCounter.fetch_add(1, std::memory_order_relaxed) %
      apcExtension::PurgeFrequency != 0) {
    return;
  }
  time_t now = time(nullptr);
  ExpirationPair tmp;
  struct timespec tsBegin, tsEnd;
  Timer::GetMonotonicTime(tsBegin);
  int i = 0;
  while (apcExtension::PurgeRate < 0 || i < apcExtension::PurgeRate) {
    if (!m_expQueue.try_pop(tmp)) {
      break;
    }
    if (tmp.second > now) {
      m_expQueue.push(tmp);
      break;
    }
    if (apcExtension::UseFileStorage &&
        strcmp(tmp.first, apcExtension::FileStorageFlagKey.c_str()) == 0) {
      s_apc_file_storage.adviseOut();
      addToExpirationQueue(apcExtension::FileStorageFlagKey.c_str(),
                           time(nullptr) +
                           apcExtension::FileStorageAdviseOutPeriod);
      continue;
    }
    m_expMap.erase(tmp.first);
    eraseImpl(tmp.first, true);
    free((void *)tmp.first);
    ++i;
  }
  Timer::GetMonotonicTime(tsEnd);
  int64_t elapsed = gettime_diff_us(tsBegin, tsEnd);
  SharedStoreStats::addPurgingTime(elapsed);
  // Size could be inaccurate, but for stats reporting, it is good enough
  SharedStoreStats::setExpireQueueSize(m_expQueue.size());
}
Ejemplo n.º 14
0
	bool erase(const T_KeysTPL keysTuple) {
	    return eraseImpl(keysTuple);	    
	}
Ejemplo n.º 15
0
bool ConcurrentTableSharedStore::eraseKey(const String& key) {
  assert(!key.isNull());
  return eraseImpl(tagStringData(key.get()), false, 0, nullptr);
}
Ejemplo n.º 16
0
bool ConcurrentTableSharedStore::get(CStrRef key, Variant &value) {
  bool stats = RuntimeOption::EnableStats && RuntimeOption::EnableAPCStats;
  bool statsFetch = RuntimeOption::EnableAPCSizeStats &&
                    RuntimeOption::EnableAPCFetchStats;
  const StoreValue *val;
  SharedVariant *svar = NULL;
  ReadLock l(m_lock);
  bool expired = false;
  {
    Map::const_accessor acc;
    if (!m_vars.find(acc, key.data())) {
      if (stats) ServerStats::Log("apc.miss", 1);
      return false;
    } else {
      val = &acc->second;
      if (val->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 {
        svar = val->var;
        if (RuntimeOption::ApcAllowObj) {
          // Hold ref here
          svar->incRef();
        }
        value = svar->toLocal();
        if (statsFetch) {
          SharedStoreStats::onGet(key.get(), svar);
        }
      }
    }
  }
  if (expired) {
    if (stats) {
      ServerStats::Log("apc.miss", 1);
    }
    eraseImpl(key, true);
    return false;
  }
  if (stats) {
    ServerStats::Log("apc.hit", 1);
  }

  if (RuntimeOption::ApcAllowObj)  {
    bool statsDetail = RuntimeOption::EnableAPCSizeStats &&
                       RuntimeOption::EnableAPCSizeGroup;
    SharedVariant *converted = svar->convertObj(value);
    if (converted) {
      Map::accessor acc;
      m_vars.find(acc, key.data()); // start a write lock
      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->isUnserializedObj()) {
        if (statsDetail) {
          SharedStoreStats::onDelete(key.get(), sv, true);
        }
        sval->var = converted;
        sv->decRef();
        if (RuntimeOption::EnableAPCSizeStats) {
          int32 newSize = converted->getSpaceUsage();
          SharedStoreStats::updateDirect(sval->size, newSize);
          sval->size = newSize;
        }
        if (statsDetail) {
          int64 ttl = sval->expiry ? sval->expiry - time(NULL) : 0;
          SharedStoreStats::onStore(key.get(), converted, ttl, false);
        }
      } else {
        converted->decRef();
      }
    }
    // release the extra ref
    svar->decRef();
  }
  return true;
}
Ejemplo n.º 17
0
bool ConcurrentTableSharedStore::erase(const String& key) {
    return eraseImpl(key, false, 0);
}
Ejemplo n.º 18
0
bool ConcurrentTableSharedStore::erase(const String& key,
                                       bool expired /* = false */) {
  return eraseImpl(key, expired);
}
Ejemplo n.º 19
0
	/***************************************************************************
         * erase
         ***************************************************************************/
	bool erase(const T_Keys ...keys) {
	    return eraseImpl(hana::make_tuple(keys...));
	}