blob: aa6c019a83cc9afc04f91ff4cd7d17e15bdd8bbb [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_MAPENTRYT_H_
#define GEODE_MAPENTRYT_H_
#include <geode/internal/geode_globals.hpp>
#include "MapEntry.hpp"
#include "TrackedMapEntry.hpp"
#define GF_TRACK_MAX 4
#define GF_UPDATE_MAX 8
namespace apache {
namespace geode {
namespace client {
// this class encapsulates the common functionality of the MapEntryT<>
// generic template class and its specializations
template <typename TBase, int NUM_TRACKERS, int UPDATE_COUNT>
class MapEntryST {
public:
static int addTracker(TBase* loc);
static int removeTracker(TBase* loc);
static int incUpdateCount(TBase* loc);
private:
// disabled
MapEntryST();
MapEntryST(const MapEntryST&);
MapEntryST& operator=(const MapEntryST&);
};
// specialization of MapEntryST for NUM_TRACKERS==0 to terminate
// removeTracker
template <typename TBase, int UPDATE_COUNT>
class MapEntryST<TBase, 0, UPDATE_COUNT> {
public:
static int addTracker(TBase* loc);
static int removeTracker(TBase* loc);
static int incUpdateCount(TBase* loc);
private:
// disabled
MapEntryST();
MapEntryST(const MapEntryST&);
MapEntryST& operator=(const MapEntryST&);
};
/**
* We use the tracking of entries to deal with updates coming in while
* another region operation is in progress. Specifically the issue to be
* tackled is to ensure that updates that come in while remote server part
* of an operation is in progress should not be overwritten, particularly
* the notifications. The approach being used is to set a tracking number
* on the entry before starting the remote operation which will lead to any
* updates incrementing an "update counter" of the entry. When the operation
* tries to perform the local cache update part, then it checks the
* "update counter" and goes ahead only if that has not changed.
*
* This template class encapsulates the tracking number and update counter.
* It completely avoids storing member variables for the above two by
* having a series of classes each returning a fixed value for these two
* and using placement new to convert "this" into another type which will
* return a new tracking number and update counter. This recursive template
* definition is terminated using specializations so that beyond
* "GF_TRACK_MAX" and "GF_UPDATE_MAX" we make use of a wrapper
* <code>TrackedMapEntry</code> class that will store the tracking number
* and update counter as separate fields in addition to the actual MapEntry.
* The assumption is that "GF_TRACK_MAX" or "GF_UPDATE_MAX" will be violated
* very rarely.
*
*
*/
template <typename TBase, int NUM_TRACKERS, int UPDATE_COUNT>
class MapEntryT final : public TBase {
public:
inline explicit MapEntryT(bool) : TBase(true) {}
~MapEntryT() final = default;
MapEntryT(const MapEntryT&) = delete;
MapEntryT& operator=(const MapEntryT&) = delete;
int addTracker(std::shared_ptr<MapEntry>&) final {
return MapEntryST<TBase, NUM_TRACKERS, UPDATE_COUNT>::addTracker(this);
}
std::pair<bool, int> removeTracker() final {
return std::make_pair(
false,
MapEntryST<TBase, NUM_TRACKERS, UPDATE_COUNT>::removeTracker(this));
}
int incrementUpdateCount(std::shared_ptr<MapEntry>&) final {
return MapEntryST<TBase, NUM_TRACKERS, UPDATE_COUNT>::incUpdateCount(this);
}
int getTrackingNumber() const final { return NUM_TRACKERS; }
int getUpdateCount() const final { return UPDATE_COUNT; }
inline static std::shared_ptr<MapEntryT> create(
const std::shared_ptr<CacheableKey>& key) {
return std::make_shared<MapEntryT>(key);
}
inline static std::shared_ptr<MapEntryT> create(
ExpiryTaskManager* expiryTaskManager,
const std::shared_ptr<CacheableKey>& key) {
return std::make_shared<MapEntryT>(expiryTaskManager, key);
}
inline explicit MapEntryT(const std::shared_ptr<CacheableKey>& key)
: TBase(key) {}
inline MapEntryT(ExpiryTaskManager* expiryTaskManager,
const std::shared_ptr<CacheableKey>& key)
: TBase(expiryTaskManager, key) {}
};
// specialization of MapEntryT to terminate the recursive template definition
// for update counter == GF_UPDATE_MAX
template <typename TBase, int NUM_TRACKERS>
class MapEntryT<TBase, NUM_TRACKERS, GF_UPDATE_MAX> final : public TBase {
public:
inline explicit MapEntryT(bool) : TBase(true) {}
~MapEntryT() final = default;
MapEntryT(const MapEntryT&) = delete;
MapEntryT& operator=(const MapEntryT&) = delete;
int addTracker(std::shared_ptr<MapEntry>&) final {
return MapEntryST<TBase, NUM_TRACKERS, GF_UPDATE_MAX>::addTracker(this);
}
std::pair<bool, int> removeTracker() final {
return std::make_pair(
false,
MapEntryST<TBase, NUM_TRACKERS, GF_UPDATE_MAX>::removeTracker(this));
}
int incrementUpdateCount(std::shared_ptr<MapEntry>& newEntry) final {
// fallback to TrackedMapEntry
newEntry = std::make_shared<TrackedMapEntry>(
this->shared_from_this(), NUM_TRACKERS, GF_UPDATE_MAX + 1);
return (GF_UPDATE_MAX + 1);
}
int getTrackingNumber() const final { return NUM_TRACKERS; }
int getUpdateCount() const final { return GF_UPDATE_MAX; }
};
// specialization of MapEntryT to terminate the recursive template definition
// for tracking number == GF_TRACK_MAX
template <typename TBase, int UPDATE_COUNT>
class MapEntryT<TBase, GF_TRACK_MAX, UPDATE_COUNT> final : public TBase {
public:
inline explicit MapEntryT(bool) : TBase(true) {}
~MapEntryT() final = default;
MapEntryT(const MapEntryT&) = delete;
MapEntryT& operator=(const MapEntryT&) = delete;
int addTracker(std::shared_ptr<MapEntry>& newEntry) final {
// fallback to TrackedMapEntry
newEntry = std::make_shared<TrackedMapEntry>(
this->shared_from_this(), GF_TRACK_MAX + 1, UPDATE_COUNT);
return UPDATE_COUNT;
}
std::pair<bool, int> removeTracker() final {
return std::make_pair(
false,
MapEntryST<TBase, GF_TRACK_MAX, UPDATE_COUNT>::removeTracker(this));
}
int incrementUpdateCount(std::shared_ptr<MapEntry>&) final {
return MapEntryST<TBase, GF_TRACK_MAX, UPDATE_COUNT>::incUpdateCount(this);
}
int getTrackingNumber() const final { return GF_TRACK_MAX; }
int getUpdateCount() const final { return UPDATE_COUNT; }
};
// specialization of MapEntryT to terminate the recursive template definition
// for tracking number == GF_TRACK_MAX and update counter == GF_UPDATE_MAX
template <typename TBase>
class MapEntryT<TBase, GF_TRACK_MAX, GF_UPDATE_MAX> final : public TBase {
public:
inline explicit MapEntryT(bool) : TBase(true) {}
~MapEntryT() final = default;
MapEntryT(const MapEntryT&) = delete;
MapEntryT& operator=(const MapEntryT&) = delete;
int addTracker(std::shared_ptr<MapEntry>& newEntry) final {
// fallback to TrackedMapEntry
newEntry = std::make_shared<TrackedMapEntry>(
this->shared_from_this(), GF_TRACK_MAX + 1, GF_UPDATE_MAX);
return GF_UPDATE_MAX;
}
std::pair<bool, int> removeTracker() final {
return std::make_pair(
false,
MapEntryST<TBase, GF_TRACK_MAX, GF_UPDATE_MAX>::removeTracker(this));
}
int incrementUpdateCount(std::shared_ptr<MapEntry>& newEntry) final {
// fallback to TrackedMapEntry
newEntry = std::make_shared<TrackedMapEntry>(
this->shared_from_this(), GF_TRACK_MAX, GF_UPDATE_MAX + 1);
return (GF_UPDATE_MAX + 1);
}
int getTrackingNumber() const final { return GF_TRACK_MAX; }
int getUpdateCount() const final { return GF_UPDATE_MAX; }
};
template <typename TBase, int NUM_TRACKERS, int UPDATE_COUNT>
inline int MapEntryST<TBase, NUM_TRACKERS, UPDATE_COUNT>::addTracker(
TBase* loc) {
// use placement new to make vptr point to class that shall have
// tracking number incremented by one
// invoke the constructor that will avoid initializing *any* data
(void)new (loc) MapEntryT<TBase, NUM_TRACKERS + 1, UPDATE_COUNT>(true);
return UPDATE_COUNT;
}
template <typename TBase, int NUM_TRACKERS, int UPDATE_COUNT>
inline int MapEntryST<TBase, NUM_TRACKERS, UPDATE_COUNT>::removeTracker(
TBase* loc) {
// use placement new to make vptr point to class that shall have
// tracking number decremented by one
// invoke the constructor that will avoid initializing *any* data
if (NUM_TRACKERS == 1) {
// if all trackers have gone away then the update counter is no
// longer required, so reset it to zero
(void)new (loc) MapEntryT<TBase, 0, 0>(true);
} else {
(void)new (loc) MapEntryT<TBase, NUM_TRACKERS - 1, UPDATE_COUNT>(true);
}
return (NUM_TRACKERS - 1);
}
template <typename TBase, int NUM_TRACKERS, int UPDATE_COUNT>
inline int MapEntryST<TBase, NUM_TRACKERS, UPDATE_COUNT>::incUpdateCount(
TBase* loc) {
// use placement new to make vptr point to class that shall have
// update number incremented by one
// invoke the constructor that will avoid initializing *any* data
(void)new (loc) MapEntryT<TBase, NUM_TRACKERS, UPDATE_COUNT + 1>(true);
return (UPDATE_COUNT + 1);
}
template <typename TBase, int UPDATE_COUNT>
inline int MapEntryST<TBase, 0, UPDATE_COUNT>::addTracker(TBase* loc) {
// use placement new to make vptr point to class that shall have
// tracking number incremented by one
// invoke the constructor that will avoid initializing *any* data
(void)new (loc) MapEntryT<TBase, 1, UPDATE_COUNT>(true);
return UPDATE_COUNT;
}
template <typename TBase, int UPDATE_COUNT>
inline int MapEntryST<TBase, 0, UPDATE_COUNT>::removeTracker(TBase*) {
return 0;
}
template <typename TBase, int UPDATE_COUNT>
inline int MapEntryST<TBase, 0, UPDATE_COUNT>::incUpdateCount(TBase*) {
return UPDATE_COUNT;
}
} // namespace client
} // namespace geode
} // namespace apache
#endif // GEODE_MAPENTRYT_H_