| /* |
| * 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_ |