Merge branch 'fixes' into main/rendor-staging
[ryzomcore.git] / ryzom / common / src / game_share / change_tracker_base.h
blob70298aadfab1a4ca5f10d7392b31cbc659787020
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #ifndef NL_CHANGE_TRACKER_BASE_H
20 #define NL_CHANGE_TRACKER_BASE_H
22 #include "nel/misc/types_nl.h"
23 #include "base_types.h"
24 #include <nel/misc/hierarchical_timer.h> // TEMP
27 //#ifdef NL_OS_WINDOWS
28 #define USE_FAST_MUTEX
29 //#endif
32 * Set this define for stats about the property changes (slower)
33 * Important note: all the user services and the mirror service should have the same value!
35 #define COUNT_MIRROR_PROP_CHANGES
38 /**
39 * Header of a tracker
41 struct TChangeTrackerHeader
43 /** First changed item (useful to read the changed from the beginning).
44 * When there is no change to read, First equals LAST_CHANGED.
46 volatile TDataSetIndex First;
48 /** Last changed item (useful to link the last changed to a newly changed item).
49 * When there is no change yet, Last equals INVALID_DATASET_ROW.
51 volatile TDataSetIndex Last;
53 #ifdef USE_FAST_MUTEX
54 /// Fast mutex (TODO: use multi-processor version)
55 volatile NLMISC::CFastMutex FastMutex;
56 #endif
58 * Number of values set (used in COUNT_MIRROR_CHANGES mode only, always allocated for mode interoperability)
59 * Currently, not implemented.
61 //volatile sint32 NbValuesSet;
63 /**
64 * Number of changes really recorded (used in COUNT_MIRROR_CHANGES mode only, always allocated for mode interoperability).
65 * NbValuesSet-NbDistinctChanges is the number of skipped changes.
67 volatile sint32 NbDistinctChanges;
71 const uint16 LOCAL_TRACKER_SERVICE_ID = std::numeric_limits<uint16>::max();
73 /**
74 * Item in a tracker
76 struct TChangeTrackerItem
78 /**
79 * If the item state is 'unchanged', NextChanged is INVALID_DATASET_ROW.
80 * If it is 'changed', NextChanged is either the index of the next changed
81 * item or the value LAST_CHANGED.
83 TDataSetIndex NextChanged;
88 /**
89 * Base class for change tracker
91 * \author Olivier Cado
92 * \author Nevrax France
93 * \date 2002
95 class CChangeTrackerBase
97 public:
99 /// Constructor
100 CChangeTrackerBase() : _SMId(-1), _MutId(-1), _Header(NULL), _Array(NULL) {}
102 /// Assignment operator
103 CChangeTrackerBase& operator = ( const CChangeTrackerBase& src )
105 if ( &src == this )
106 return *this;
108 _SMId = src._SMId;
109 #ifndef USE_FAST_MUTEX
110 _TrackerMutex = src._TrackerMutex; // contains only the mutex handle
111 #endif
112 _MutId = src._MutId;
113 _Header = src._Header; // leave the pointed data where they are (in shared memory)
114 _Array = src._Array; // same
115 return *this;
118 /// Return the shared memory id
119 const sint32& smid() const { return _SMId; }
121 /// Return true if the tracker header and item array are already allocated
122 bool isAllocated() const
123 { return _Array != NULL; }
125 /// Return the pointer to the header (root of the shared memory segment)
126 TChangeTrackerHeader *header() { return _Header; }
128 /// Record a change (push) (assumes isAllocated())
129 void recordChange( TDataSetIndex entityIndex );
131 /// Remove a change if found in the tracker (slow) (assumes isAllocated())
132 void cancelChange( TDataSetIndex entityIndex );
134 /// Get the entity index of the first changed (assumes isAllocated()). Returns LAST_CHANGED if there is no change.
135 uint32 getFirstChanged() const { /*nlinfo( "Array = %p, First = %d, _Array[First].NextChanged = %d, _Array[0].NextChanged = %d", _Array, _Header->First, _Array[_Header->First].NextChanged, _Array[0].NextChanged );*/ return _Header->First; }
137 /// Pop the first change out of the tracker. Do not call if getFirstChanged() returned LAST_CHANGED.
138 void popFirstChanged()
140 // Protect consistency of popFirstChanged() in parallel with recordChange()
141 // (there can't be two parallels calls to popFirstChanged()
142 trackerMutex().enter();
143 #ifdef NL_DEBUG
144 nlassert( _Header->First != LAST_CHANGED );
145 #endif
146 TChangeTrackerItem *queueFront = &(_Array[_Header->First]);
147 _Header->First = queueFront->NextChanged;
148 queueFront->NextChanged = INVALID_DATASET_INDEX;
149 if ( _Header->First == LAST_CHANGED )
151 _Header->Last = INVALID_DATASET_INDEX;
153 #ifdef COUNT_MIRROR_PROP_CHANGES
154 --_Header->NbDistinctChanges;
155 #endif
156 trackerMutex().leave();
159 /// Return the number of changes (assumes isAllocated()) (slow)
160 sint32 nbChanges() const;
162 #ifdef USE_FAST_MUTEX
163 /// Return the mutex
164 volatile NLMISC::CFastMutex& trackerMutex() { return _Header->FastMutex; }
165 #else
166 /// Return the mutex
167 NLMISC::CSharedMutex& trackerMutex() { return _TrackerMutex; }
168 #endif
170 /// Return the mutex id
171 const sint32& mutid() const { return _MutId; }
173 /// Create the mutex (either create or use existing)
174 bool createMutex( sint32 mutid, bool createNew );
176 /// Display debug info (1 line)
177 void displayTrackerInfo( const char *headerStr="", const char *footerStrNotAllocd="", NLMISC::CLog *log=NLMISC::InfoLog ) const;
179 /// Serial ids
180 void serial( NLMISC::IStream& s )
182 s.serial( _SMId );
183 s.serial( _MutId );
186 protected:
188 /// Get the entity index of the next changed (assumes isAllocated() and entityIndex is valid). Returns LAST_CHANGED if there is no more change.
189 TDataSetRow getNextChanged( const TDataSetRow& entityIndex ) const { /*nlinfo( "_Array[%d].NextChanged = %d", entityIndex, _Array[entityIndex].NextChanged );*/ return TDataSetRow(_Array[entityIndex.getIndex()].NextChanged); }
191 /// Shared memory numeric id
192 sint32 _SMId;
194 #ifndef USE_FAST_MUTEX
195 /// Mutex
196 NLMISC::CSharedMutex _TrackerMutex;
197 #endif
199 /// Mutex id
200 sint32 _MutId;
202 /// Pointer to the handling variables of the tracker (may be pointing to shared memory)
203 TChangeTrackerHeader *_Header;
205 /// Pointer to the array of entities, indexed by TDataSetRow (may be pointing to shared memory)
206 TChangeTrackerItem *_Array;
210 #endif // NL_CHANGE_TRACKER_BASE_H
212 /* End of change_tracker_base.h */