1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
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.
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
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
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
;
54 /// Fast mutex (TODO: use multi-processor version)
55 volatile NLMISC::CFastMutex FastMutex
;
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;
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();
76 struct TChangeTrackerItem
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
;
89 * Base class for change tracker
91 * \author Olivier Cado
92 * \author Nevrax France
95 class CChangeTrackerBase
100 CChangeTrackerBase() : _SMId(-1), _MutId(-1), _Header(NULL
), _Array(NULL
) {}
102 /// Assignment operator
103 CChangeTrackerBase
& operator = ( const CChangeTrackerBase
& src
)
109 #ifndef USE_FAST_MUTEX
110 _TrackerMutex
= src
._TrackerMutex
; // contains only the mutex handle
113 _Header
= src
._Header
; // leave the pointed data where they are (in shared memory)
114 _Array
= src
._Array
; // same
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();
144 nlassert( _Header
->First
!= LAST_CHANGED
);
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
;
156 trackerMutex().leave();
159 /// Return the number of changes (assumes isAllocated()) (slow)
160 sint32
nbChanges() const;
162 #ifdef USE_FAST_MUTEX
164 volatile NLMISC::CFastMutex
& trackerMutex() { return _Header
->FastMutex
; }
167 NLMISC::CSharedMutex
& trackerMutex() { return _TrackerMutex
; }
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;
180 void serial( NLMISC::IStream
& s
)
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
194 #ifndef USE_FAST_MUTEX
196 NLMISC::CSharedMutex _TrackerMutex
;
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 */