blob: f10a5e09e6be5b0b9f4711748a426eaa17719a3f [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#ifndef GEODE_MAPENTRY_H_
#define GEODE_MAPENTRY_H_
#include <atomic>
#include <memory>
#include <utility>
#include <geode/CacheableKey.hpp>
#include <geode/ExceptionTypes.hpp>
#include <geode/Serializable.hpp>
#include <geode/internal/geode_globals.hpp>
#include "CacheImpl.hpp"
#include "CacheableToken.hpp"
#include "ExpiryTaskManager.hpp"
#include "RegionInternal.hpp"
#include "VersionStamp.hpp"
namespace apache {
namespace geode {
namespace client {
class MapEntry;
class MapEntryImpl;
class LRUEntryProperties;
class CacheImpl;
/**
* @brief This class encapsulates expiration specific properties for
* a MapEntry.
*/
class APACHE_GEODE_EXPORT ExpEntryProperties {
public:
typedef std::chrono::system_clock::time_point time_point;
inline explicit ExpEntryProperties(ExpiryTaskManager* expiryTaskManager)
: m_lastAccessTime(0),
m_lastModifiedTime(0),
m_expiryTaskId(-1),
m_expiryTaskManager(expiryTaskManager) {
// The reactor always gives +ve id while scheduling.
// -1 will indicate that an expiry task has not been scheduled
// for this entry. // TODO confirm
}
inline time_point getLastAccessTime() const {
return time_point(std::chrono::system_clock::duration(m_lastAccessTime));
}
inline time_point getLastModifiedTime() const {
return time_point(std::chrono::system_clock::duration(m_lastModifiedTime));
}
// moved time initialization outside of constructor to avoid
// the costly gettimeofday call in MapSegment spinlock
inline void initStartTime() {
time_point currentTime = std::chrono::system_clock::now();
m_lastAccessTime = currentTime.time_since_epoch().count();
m_lastModifiedTime = currentTime.time_since_epoch().count();
}
inline void updateLastAccessTime(time_point currTime) {
m_lastAccessTime = currTime.time_since_epoch().count();
}
inline void updateLastModifiedTime(time_point currTime) {
m_lastModifiedTime = currTime.time_since_epoch().count();
}
inline void setExpiryTaskId(ExpiryTaskManager::id_type id) {
m_expiryTaskId = id;
}
inline ExpiryTaskManager::id_type getExpiryTaskId() const {
return m_expiryTaskId;
}
inline void cancelExpiryTaskId(
const std::shared_ptr<CacheableKey>& key) const {
LOGDEBUG("Cancelling expiration task for key [%s] with id [%z]",
Utils::nullSafeToString(key).c_str(), m_expiryTaskId);
m_expiryTaskManager->cancelTask(m_expiryTaskId);
}
protected:
// this constructor deliberately skips initializing any fields
inline explicit ExpEntryProperties(bool)
: m_lastAccessTime(0), m_lastModifiedTime(0) {}
private:
/** last access time in secs, 32bit.. */
std::atomic<time_point::duration::rep> m_lastAccessTime;
/** last modified time in secs, 32bit.. */
std::atomic<time_point::duration::rep> m_lastModifiedTime;
/** The expiry task id for this particular entry.. **/
ExpiryTaskManager::id_type m_expiryTaskId;
ExpiryTaskManager* m_expiryTaskManager;
};
/**
* @brief Interface class for region mapped entry value.
*/
class APACHE_GEODE_EXPORT MapEntry {
public:
virtual ~MapEntry() {}
virtual void getKey(std::shared_ptr<CacheableKey>& result) const = 0;
virtual void getValue(std::shared_ptr<Cacheable>& result) const = 0;
virtual void setValue(const std::shared_ptr<Cacheable>& value) = 0;
virtual std::shared_ptr<MapEntryImpl> getImplPtr() = 0;
virtual LRUEntryProperties& getLRUProperties() = 0;
virtual ExpEntryProperties& getExpProperties() = 0;
virtual VersionStamp& getVersionStamp() = 0;
/**
* Adds a tracker to this MapEntry for any updates.
* Returns the current update sequence number of this entry.
* Returns by reference any updated MapEntry to be rebound while an
* unchanged return value implies this MapEntry should be continued with.
* Note that the contract says that the return value should not be
* touched if this MapEntry is to be continued with.
*
* The design of tracking is thus:
* Each entry will have two fields, one indicating the current number of
* operations tracking this entry, and second indicating the sequence
* number for number of updates since tracking was started. The idea is
* to start tracking an entry before going for a long remote operation
* and check whether the update sequence has remained unchanged upon
* return. If the entry has been updated in the interim period then
* the current update is not applied. When the number of operations
* tracking an entry goes down to zero, then the update sequence number
* is also reset to zero.
*/
virtual int addTracker(std::shared_ptr<MapEntry>& newEntry) = 0;
/**
* Removes a tracker for this MapEntry and returns a pair:
* 1) the first element of the pair is a boolean that indicates whether
* or not the entry should be replaced with the underlying MapEntryImpl
* object in the map
* 2) the second element is the updated number of trackers for this entry
*/
virtual std::pair<bool, int> removeTracker() = 0;
/**
* Increment the number of updates to this entry.
* Returns the current update sequence number of this entry.
* Returns by reference any updated MapEntry to be rebound while an
* unchanged return value implies this MapEntry should be continued with.
* Note that the contract says that the return value should not be
* touched if this MapEntry is to be continued with.
*/
virtual int incrementUpdateCount(std::shared_ptr<MapEntry>& newEntry) = 0;
/**
* Get the current tracking number of this entry. A return value of zero
* indicates that the entry is not being tracked.
*/
virtual int getTrackingNumber() const = 0;
/**
* Get the current number of updates since tracking was started for
* this entry.
*/
virtual int getUpdateCount() const = 0;
/**
* Any cleanup required (e.g. removing from LRUList) for the entry.
*/
virtual void cleanup(const CacheEventFlags eventFlags) = 0;
protected:
inline MapEntry() {}
inline explicit MapEntry(bool) {}
};
/**
* @brief Hold region mapped entry value. subclass will hold lru flags.
* Another holds expiration timestamps.
*/
class MapEntryImpl : public MapEntry,
public std::enable_shared_from_this<MapEntryImpl> {
public:
~MapEntryImpl() override = default;
MapEntryImpl(const MapEntryImpl&) = delete;
MapEntryImpl& operator=(const MapEntryImpl&) = delete;
inline void getKeyI(std::shared_ptr<CacheableKey>& result) const {
result = m_key;
}
inline void getValueI(std::shared_ptr<Cacheable>& result) const {
// If value is destroyed, then this returns nullptr
if (CacheableToken::isDestroyed(m_value)) {
result = nullptr;
} else {
result = m_value;
}
}
inline void setValueI(const std::shared_ptr<Cacheable>& value) {
m_value = value;
}
void getKey(std::shared_ptr<CacheableKey>& result) const override {
getKeyI(result);
}
void getValue(std::shared_ptr<Cacheable>& result) const override {
getValueI(result);
}
void setValue(const std::shared_ptr<Cacheable>& value) override {
setValueI(value);
}
std::shared_ptr<MapEntryImpl> getImplPtr() override {
return shared_from_this();
}
LRUEntryProperties& getLRUProperties() override {
throw FatalInternalException(
"MapEntry::getLRUProperties called for "
"non-LRU MapEntry");
}
ExpEntryProperties& getExpProperties() override {
throw FatalInternalException(
"MapEntry::getExpProperties called for "
"non-expiration MapEntry");
}
VersionStamp& getVersionStamp() override {
throw FatalInternalException(
"MapEntry::getVersionStamp called for "
"non-versioned MapEntry");
}
void cleanup(const CacheEventFlags) override{};
protected:
inline explicit MapEntryImpl(bool) : MapEntry(true) {}
inline explicit MapEntryImpl(const std::shared_ptr<CacheableKey>& key)
: MapEntry(), m_key(key) {}
std::shared_ptr<Cacheable> m_value;
std::shared_ptr<CacheableKey> m_key;
};
class APACHE_GEODE_EXPORT VersionedMapEntryImpl : public MapEntryImpl,
public VersionStamp {
public:
virtual ~VersionedMapEntryImpl() {}
virtual VersionStamp& getVersionStamp() { return *this; }
protected:
inline explicit VersionedMapEntryImpl(bool) : MapEntryImpl(true) {}
inline explicit VersionedMapEntryImpl(
const std::shared_ptr<CacheableKey>& key)
: MapEntryImpl(key) {}
private:
// disabled
VersionedMapEntryImpl(const VersionedMapEntryImpl&);
VersionedMapEntryImpl& operator=(const VersionedMapEntryImpl&);
};
class APACHE_GEODE_EXPORT EntryFactory {
public:
explicit EntryFactory(const bool concurrencyChecksEnabled)
: m_concurrencyChecksEnabled(concurrencyChecksEnabled) {}
virtual ~EntryFactory() {}
virtual void newMapEntry(ExpiryTaskManager* expiryTaskManager,
const std::shared_ptr<CacheableKey>& key,
std::shared_ptr<MapEntryImpl>& result) const;
protected:
bool m_concurrencyChecksEnabled;
};
} // namespace client
} // namespace geode
} // namespace apache
#endif // GEODE_MAPENTRY_H_