blob: 2528897e5bd58b8485c6a440b5671419f1c5c060 [file] [log] [blame]
#ifndef __GEMFIRE_IMPL_MAPENTRY_T_HPP__
#define __GEMFIRE_IMPL_MAPENTRY_T_HPP__
/*=========================================================================
* Copyright (c) 2002-2014 Pivotal Software, Inc. All Rights Reserved.
* This product is protected by U.S. and international copyright
* and intellectual property laws. Pivotal products are covered by
* more patents listed at http://www.pivotal.io/patents.
*========================================================================
*/
#include "../gfcpp_globals.hpp"
#include "MapEntry.hpp"
#include "TrackedMapEntry.hpp"
#define GF_TRACK_MAX 4
#define GF_UPDATE_MAX 8
namespace gemfire
{
// 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.
*
* @author sumedh
*/
template<typename TBase, int NUM_TRACKERS, int UPDATE_COUNT>
class MapEntryT: public TBase
{
public:
inline explicit MapEntryT(bool noInit) :
TBase(true)
{
}
virtual ~MapEntryT() { }
virtual int addTracker(MapEntryPtr& newEntry)
{
return MapEntryST<TBase, NUM_TRACKERS, UPDATE_COUNT>::addTracker(this);
}
virtual std::pair<bool, int> removeTracker()
{
return std::make_pair(false,
MapEntryST<TBase, NUM_TRACKERS, UPDATE_COUNT>::removeTracker(this));
}
virtual int incrementUpdateCount(MapEntryPtr& newEntry)
{
return MapEntryST<TBase, NUM_TRACKERS, UPDATE_COUNT>::incUpdateCount(
this);
}
virtual int getTrackingNumber() const
{
return NUM_TRACKERS;
}
virtual int getUpdateCount() const
{
return UPDATE_COUNT;
}
inline static MapEntryT* create(const CacheableKeyPtr& key)
{
MapEntryT* entry;
GF_NEW(entry, MapEntryT(key));
return entry;
}
protected:
inline MapEntryT(const CacheableKeyPtr& key) :
TBase(key)
{
}
private:
// disabled
MapEntryT(const MapEntryT&);
MapEntryT& operator =(const MapEntryT&);
};
// 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>: public TBase
{
public:
inline explicit MapEntryT(bool noInit) :
TBase(true)
{
}
virtual ~MapEntryT() { }
virtual int addTracker(MapEntryPtr& newEntry)
{
return MapEntryST<TBase, NUM_TRACKERS, GF_UPDATE_MAX>::addTracker(this);
}
virtual std::pair<bool, int> removeTracker()
{
return std::make_pair(false,
MapEntryST<TBase, NUM_TRACKERS, GF_UPDATE_MAX>::removeTracker(this));
}
virtual int incrementUpdateCount(MapEntryPtr& newEntry)
{
// fallback to TrackedMapEntry
GF_NEW(newEntry, TrackedMapEntry(this, NUM_TRACKERS, GF_UPDATE_MAX + 1));
return (GF_UPDATE_MAX + 1);
}
virtual int getTrackingNumber() const
{
return NUM_TRACKERS;
}
virtual int getUpdateCount() const
{
return GF_UPDATE_MAX;
}
private:
// disabled
MapEntryT(const MapEntryT&);
MapEntryT& operator =(const MapEntryT&);
};
// 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> : public TBase
{
public:
inline explicit MapEntryT(bool noInit) :
TBase(true)
{
}
virtual ~MapEntryT() { }
virtual int addTracker(MapEntryPtr& newEntry)
{
// fallback to TrackedMapEntry
GF_NEW(newEntry, TrackedMapEntry(this, GF_TRACK_MAX + 1, UPDATE_COUNT));
return UPDATE_COUNT;
}
virtual std::pair<bool, int> removeTracker()
{
return std::make_pair(false,
MapEntryST<TBase, GF_TRACK_MAX, UPDATE_COUNT>::removeTracker(this));
}
virtual int incrementUpdateCount(MapEntryPtr& newEntry)
{
return MapEntryST<TBase, GF_TRACK_MAX, UPDATE_COUNT>::incUpdateCount(
this);
}
virtual int getTrackingNumber() const
{
return GF_TRACK_MAX;
}
virtual int getUpdateCount() const
{
return UPDATE_COUNT;
}
private:
// disabled
MapEntryT(const MapEntryT&);
MapEntryT& operator =(const MapEntryT&);
};
// 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> : public TBase
{
public:
inline explicit MapEntryT(bool noInit) :
TBase(true)
{
}
virtual ~MapEntryT() { }
virtual int addTracker(MapEntryPtr& newEntry)
{
// fallback to TrackedMapEntry
GF_NEW(newEntry, TrackedMapEntry(this, GF_TRACK_MAX + 1, GF_UPDATE_MAX));
return GF_UPDATE_MAX;
}
virtual std::pair<bool, int> removeTracker()
{
return std::make_pair(false,
MapEntryST<TBase, GF_TRACK_MAX, GF_UPDATE_MAX>::removeTracker(this));
}
virtual int incrementUpdateCount(MapEntryPtr& newEntry)
{
// fallback to TrackedMapEntry
GF_NEW(newEntry, TrackedMapEntry(this, GF_TRACK_MAX, GF_UPDATE_MAX + 1));
return (GF_UPDATE_MAX + 1);
}
virtual int getTrackingNumber() const
{
return GF_TRACK_MAX;
}
virtual int getUpdateCount() const
{
return GF_UPDATE_MAX;
}
private:
// disabled
MapEntryT(const MapEntryT&);
MapEntryT& operator =(const MapEntryT&);
};
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* loc)
{
return 0;
}
template<typename TBase, int UPDATE_COUNT>
inline int MapEntryST<TBase, 0, UPDATE_COUNT>::incUpdateCount(TBase* loc)
{
return UPDATE_COUNT;
}
}
#endif // __GEMFIRE_IMPL_MAPENTRY_T_HPP__