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/>.
20 #include "nel/misc/shared_memory.h"
21 #include "change_tracker_base.h"
25 * Create the mutex (either create or use existing)
27 bool CChangeTrackerBase::createMutex( sint32 mutid
, bool createNew
)
33 trackerMutex().init();
38 bool res
= _TrackerMutex
.createByName( NLMISC::toString( "%dM", mutid
).c_str() );
40 bool res
= _TrackerMutex
.createByKey( mutid
, createNew
);
44 MIRROR_DEBUG( "MIRROR: TRACKER: Mutex %s (id %d) ", createNew
?"created":"accessed", mutid
);
53 void CChangeTrackerBase::recordChange( TDataSetIndex entityIndex
)
55 // Note: could be shorter to link backwards but we need to link forward
56 // to read the changes in order (for partial sending)
58 nlassertex( (entityIndex
!= INVALID_DATASET_INDEX
) && (entityIndex
!= LAST_CHANGED
), ("E%d", entityIndex
) );
61 // Protect consistency of two parallel calls to recordChange() for the same tracker
62 // and between recordChange() and popFirstChanged()
63 trackerMutex().enter();
65 // Test if the entity is already or not flagged as changed
66 if ( _Array
[entityIndex
].NextChanged
==INVALID_DATASET_INDEX
)
68 //nldebug( "Tracker (smid %u): adding change E%d", smid(), entityIndex );
69 // Set the entityIndex as changed, and last one
70 _Array
[entityIndex
].NextChanged
= LAST_CHANGED
;
72 if ( _Header
->Last
!=INVALID_DATASET_INDEX
)
74 // Link the previous last one to the new last one
75 //nlassertex( _Header->Last != entityIndex, ( "Looping at %u", entityIndex ) );
76 _Array
[_Header
->Last
].NextChanged
= entityIndex
;
77 //nldebug( "Tracker %p: E%d -> %d", _Array, _Header->Last, entityIndex );
81 // Set the first one if not set
82 _Header
->First
= entityIndex
;
83 //nldebug( "Tracker %p: FIRST = %d", _Array, entityIndex );
84 //nldebug( "_Array = %p, _Array[%d].NextChanged = %d", _Array, entityIndex, _Array[entityIndex].NextChanged );
87 // Set the new last one
88 _Header
->Last
= entityIndex
;
90 #ifdef COUNT_MIRROR_PROP_CHANGES
91 ++_Header
->NbDistinctChanges
;
95 // nldebug( "Tracker %p: E%d already in list (%d)", _Array, entityIndex, _Array[entityIndex].NextChanged );
97 #ifdef COUNT_MIRROR_PROP_CHANGES
98 //++_Header->NbValuesSet; // should be atomic!
100 //nldebug( "Tracker (smid %u): E%d already in list (pointing to %d)", smid(), entityIndex, _Array[entityIndex].NextChanged );
101 trackerMutex().leave();
107 * Remove a change (slow) (assumes isAllocated())
109 void CChangeTrackerBase::cancelChange( TDataSetIndex entityIndex
)
112 nlassertex( (entityIndex
!= INVALID_DATASET_INDEX
) && (entityIndex
!= LAST_CHANGED
), ("E%d", entityIndex
) );
115 trackerMutex().enter();
117 // Find the change before the specified one, to make the link skip it
118 TDataSetIndex row
= _Header
->First
;
119 if ( row
!= LAST_CHANGED
)
121 if ( row
== entityIndex
)
123 // It was the first one
124 _Header
->First
= _Array
[entityIndex
].NextChanged
;
125 _Array
[entityIndex
].NextChanged
= INVALID_DATASET_INDEX
;
126 if ( _Header
->First
== LAST_CHANGED
) // and it was the only one
127 _Header
->Last
= INVALID_DATASET_INDEX
;
128 nldebug( "Cancelling change of E%u", entityIndex
);
132 // It wasn't the first one
133 while ( (_Array
[row
].NextChanged
!= entityIndex
) && (_Array
[row
].NextChanged
!= LAST_CHANGED
) )
135 row
= _Array
[row
].NextChanged
;
137 if ( _Array
[row
].NextChanged
== entityIndex
)
139 _Array
[row
].NextChanged
= _Array
[entityIndex
].NextChanged
;
140 _Array
[entityIndex
].NextChanged
= INVALID_DATASET_INDEX
;
141 if ( _Header
->Last
== entityIndex
) // it was the last one
143 nldebug( "Cancelling change of E%u", entityIndex
);
147 trackerMutex().leave();
152 * Return the number of changes (slow)
154 sint32
CChangeTrackerBase::nbChanges() const
157 TDataSetRow
entityIndex (getFirstChanged());
158 while ( entityIndex
.getIndex() != LAST_CHANGED
)
161 entityIndex
= getNextChanged( entityIndex
);
168 * Display debug info (1 line)
170 void CChangeTrackerBase::displayTrackerInfo( const char *headerStr
, const char *footerStrNotAllocd
, NLMISC::CLog
*log
) const
173 log
->displayNL( "%sAllocated, %d changes, smid %d mutid %d", headerStr
, nbChanges(), smid(), mutid() );
175 log
->displayNL( "%sNot allocated%s", headerStr
, footerStrNotAllocd
);