// Ryzom - MMORPG Framework
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see .
#ifndef NL_MIRROR_H
#define NL_MIRROR_H
#include
#include
#include // for service callbacks
#include "nel/net/service.h"
#include "mirror_misc_types.h"
#include "property_allocator_client.h"
#include "nel/net/transport_class.h"
class CMirror;
/**
* Callback type for the functions called when the mirror system is ready.
*
* Mirror ready at level 1: the datasets can be initialized (declaring
* entity types owning, properties, etc.) => callback passed to
* CMirror::init().
*
* Mirror ready at level 2: the row management and properties can be used
* => when mirrorIsReady() returns true (callbacks passed to
* CMirror::addCallbackWhenMirrorReadyForUse()).
*
* Example of such a function:
*
* void cbMirrorIsReady( CMirror *mirror )
* {
* // User code
* }
*/
typedef void (*TMirrorReadyCallback) (CMirror*);
/**
* Callback type for notification function
* Example:
* void cbProcessMirrorChanges()
* {
* MainDataSet->beginAddedEntities();
* (...)
* MainDataSet->endAddedEntities();
*
* MainDataSet->beginRemovedEntities();
* (...)
* MainDataSet->endRemovedEntities();
*
* (...) // optional property changes notifications
* }
*/
typedef void (*TNotificationCallback) (void);
/**
* This class allows a service to share, access and modify the values
* of any property of any entity in a shard.
*
* A property belongs to one dataset (see CMirroredDataSet), and is stored
* and addressed using a TPropertyIndex.
* An entity added in a dataset is stored and addressed using a TDataSetRow.
*
* The mirror system handles the sharing of entities and the sharing of
* properties between services, using shared memory for services on the
* same physical machine, and network communication for remote services.
* It handles the notification (if required) of the service when a value
* has changed or an entity has been added or removed.
*
* Several services are allowed to create distinct entities that have
* the same type (i.e. that will have the same dataset(s)). In a dataset,
* each service will have a specific range of rows to avoid conflicts.
* See declareEntityTypeOwner(), addEntity(), removeEntity().
*
* The datasets are loaded at init(). They can be browsed using dsBegin()
* and dsEnd(), and a specific dataset can be retrieved by name
* (getDataSet()).
*
* The recommended way to use this class is to declare a CMirror object
* as a member of an instanciated singleton class. However, if you use it
* by declaring a static CMirror object, you must not forget to call
* the release() method in your release code.
*
* Mirror initialization and readiness:
* 1. In your service's init(), call CMirror::init() passing the datasets
* to load and the callback for mirror initialization at level 1.
* 2. The mirror gets ready at level 1 and calls the callback. In this
* callback, declare entity types owning, datasets, and so on.
* 3. The mirror gets ready at level 2. It calls the callbacks passed
* to addCallbackWhenMirrorReadyForUse() (if any), then executes the
* commands in StartCommandsWhenMirrorReady in the config file (if any),
* and mirrorIsReady() returns true.
* 4. Then you can add/remove entities, check notifications, read/write
* property values, and so on.
*
* Note:
* The mirror uses IService::setClosureClearanceCallback().
* Currently you can't use it along with the mirror.
*
* \seealso CMirrorredDataSet
* \seealso CMirrorPropValue
* \seealso CMirrorPropValueCF
* \seealso CMirrorPropValueBaseCF
* \seealso CMirrorPropValueList
* \seealso CMirrorPropValueAlice
*
* \author Olivier Cado
* \author Nevrax France
* \date 2002
*/
class CMirror
{
public:
/// Constructor
CMirror();
/**
* Initialize. Call it in the init() method of your service.
*
* In dataSetsToLoad, give the names of the datasets the current service is interested in.
*
* You should provide a callback that will be called when the mirror system is ready
* for dataset initialization (level 1).
* Then, in the body of your callback, you can start using the mirror and dataset methods.
* Do not use the mirror before the callback has been called!
*
* The three other callbacks, if provided, will be called respectively when a tick update
* (incrementing the game cycle) is received, when a tick sync (value of the first game cycle)
* is received, and when the service is requested to exit AND it's ok to remove entities
* (mirror-synchronized time). Note: calling CMirror::release() in the tickReleaseFunc is
* allowed. Note: the service may still receive some messages, especially tick update, *after*
* the tickReleaseFunc has been called.
*
* Set the tag to a number >0 if the current service is not interested in receiving the entities
* (and their properties) of any other services having the same tag. Typically, you can duplicate
* a service DS (Dummy Service) in your shard: if every instance of DS has the same tag, it will
* not receive the entities created by the other DSes, thus reducing the network traffic between
* the machines where the DSes run. Practically, it will work well in the following conditions:
* - Service instances sharing a tag are run on a machine where there is no other mirrored service
* (including the case with a single service instance per machine).
* - One or more service instance(s) sharing the tag are run on *one* machine with other mirrored
* services: only one machine can have this case (otherwise the traffic won't be reduced, and entities
* added/changed will be communicated between services (run of different machines) sharing the tag).
* - If a tagged service modifies a property also modified by another service (with a different tag or
* AllTag), the property changed will not always be notified to a service having the same tag. Ex:
* A(1) B(AllTag) Then C(1) connects and wants to be notified of a property written by B. If B modifies
* the property then A modifies it (on the same entity), C won't be notified of it at connection.
* Forbidden value: ExcludedTag.
*/
void init( std::vector& dataSetsToLoad,
TMirrorReadyCallback cbLevel1,
TNotificationCallback tickUpdateFunc,
TNotificationCallback tickSyncFunc = NULL,
TNotificationCallback tickReleaseFunc = NULL,
TMTRTag tag=AllTag );
/**
* Deinitialize. You must call this method in your release code if your CMirror
* object is a static object!
*/
void release();
/**
* Set a callback to call when a particular service has its mirror system ready.
* The callback behaviour is identical to the one of NLNET::CUnifiedNetwork, except that
* your callback will not be called as soon as the service is up, but when it is able
* to use the mirror system functionalities (for example, adding entities).
*
* Call this method in the init() method of your service, otherwise you could miss if
* a service gets ready before your callback setting.
* Warning: if a service does not use the mirror system at all, no callback will ever
* be called for it.
*
* You can set more than one callback, each one will be called one after one.
* If the serviceName is "*", the callback will be call for any services. If you set
* the same callback for a specific service S and for "*", the callback might be called twice.
* You should always set back to true (it puts the specified callback at the end of the array).
*
* \param synchronizedCallback Set true if you want the callback to be called in a synchronized
* moment to allow you to spawn or despawn entities (see isRunningSynchronizedCode()), instead
* of calling it as soon as received.
*/
void setServiceMirrorUpCallback( const std::string &serviceName, NLNET::TUnifiedNetCallback cb, void *arg=0, bool back=true, bool synchronizedCallback=true );
/**
* This is the counterpart of setServiceMirrorUpCallback().
* If a service with the specified name is stopped, after its mirror system was ready,
* the provided callback(s) will be called.
*
* If the synchronizedCallback and back flags have the same value in both
* setServiceMirrorDownCallback() and setServiceDownCallback(), the callback(s) provided to
* setServiceMirrorDownCallback() will be called before the callback(s) provided to
* setServiceDownCallback(). In any case, these will still be called.
* For callbacks provided to CUnifiedNetwork::setServiceDownCallback(),
* the behaviour with a false synchronizedCallback flag are applied.
*/
void setServiceMirrorDownCallback( const std::string &serviceName, NLNET::TUnifiedNetCallback cb, void *arg=0, bool back=true, bool synchronizedCallback=true );
/**
* This is similar to CUnifiedNetwork::setServiceUpCallback() but it allows you to spawn or despawn
* entities in the callback if you set synchronizedCallback to true (see isRunningSynchronizedCode())
* \seealso setServiceMirrorUpCallback()
*/
void setServiceUpCallback( const std::string &serviceName, NLNET::TUnifiedNetCallback cb, void *arg=0, bool back=true, bool synchronizedCallback=true );
/**
* This is similar to CUnifiedNetwork::setServiceUpCallback() but it allows you to spawn or despawn
* entities in the callback if you set synchronizedCallback to true (see isRunningSynchronizedCode())
* \seealso setServiceMirrorDownCallback()
*/
void setServiceDownCallback( const std::string &serviceName, NLNET::TUnifiedNetCallback cb, void *arg=0, bool back=true, bool synchronizedCallback=true );
/**
* Call this method every cycle (in your update routine) if you use mirror watches
*/
void updateWatches();
//--- ENTITY ADDITION/REMOVAL --------------------------------------------------------------------------
/*
* Declare the current service as a user of the entities of the specified entity type.
* It means the current service wants to be receive the corresponding entities. It will
* be notified about their additions and removals.
* If more than one service is an owner of a particular entity type, declaring or not
* as a user the same entity type will specify if the service wants to receive or not
* the entities created by other owners; of course the service is always aware of the
* entities it creates, although the mirror system does not notify them to itself.
*/
//void declareEntityTypeUser( uint8 entityTypeId );
/**
* Declare the current service as an owner of the entities of the specified entity type.
* It means the current service will create (at most maxNbEntities entities) and remove
* this kind of entities (it can remove only the ones it has created) in all the datasets
* corresponding to the entity type.
* Another service can be a co-owner of the same entity type, but it will create and
* remove other entity ids (i.e. in a different range of rows).
* Call this method after all declareEntityTypeUser() calls.
*
* *Important*: after calling this method, wait until mirrorIsReady() (mirror ready
* level 2) returns true before adding any entity, otherwise the adding would fail.
*/
void declareEntityTypeOwner( uint8 entityTypeId, sint32 maxNbEntities );
/**
* Provide a callback that will be called the first time mirrorIsReady() returns true.
* You can provide several callbacks (ny calling several times this method).
*
* Note: immediately after having called all the callbacks passed to this method, the
* commands founds in StartCommandsWhenMirrorReady (in the config file) will be executed.
*/
void addCallbackWhenMirrorReadyForUse( TMirrorReadyCallback cbLevel2 );
/**
* Add an entity into the mirror. The caller must be an owner of the corresponding
* entity type and it must not create more entities than maxNbEntities (see
* declareEntityTypeOwner()). The entity will be added into all the datasets
* corresponding to the entity type (possibly with a different row in each one).
*
* The entity will not be declared to all services until you call declareEntity(),
* either in CMirror (global) or in CMirroredDataSet (per dataset).
*
* If fillEntityId is set to true, then the rowindex value for the first dataset is
* copied into the first 32 bits of the entityId id part. This is used for automatic
* id generation.
*
* Returns false if part or all of the process failed (for example, if the entity
* already exists in a dataset).
*/
bool createEntity( NLMISC::CEntityId& entityId, bool fillEntityId=false );
/**
* Declare the entity (previously added by createEntity()) in all datasets
* concerned by its entity type. This method is separated from createEntity()
* so that it allows for example to:
* - create an entity, set a few properties values, *then* declare it to other services;
* - create an entity and prevent from declaring it to other services!
*
* IMPORTANT: You are allowed to call this method only in code synchronized with the mirror.
* Refer to isRunningSynchronizedCode() to know the conditions.
*
* Returns false in case of failure.
*
* \seealso CMirroredDataSet::declareEntity() for alternate version.
*/
bool declareEntity( const NLMISC::CEntityId& entityId );
/**
* Create + declare an entity. Previously known as addEntity().
*
* IMPORTANT: You are allowed to call this method only in code synchronized with the mirror.
* Refer to isRunningSynchronizedCode() to know the conditions.
*
* Returns false if part or all of the process failed (for example, if the entity
* already exists in a dataset).
*/
bool createAndDeclareEntity( const NLMISC::CEntityId& entityId ) { return addEntity( false, const_cast(entityId), true ); }
/**
* Public for backward compatibility, usage is deprecated. See createAndDeclareEntity().
*
* IMPORTANT: You are allowed to call this method only in code synchronized with the mirror.
* Refer to isRunningSynchronizedCode() to know the conditions.
*/
bool addEntity( bool fillEntityId, NLMISC::CEntityId& entityId, bool declare=true );
/**
* Remove an entity from the mirror. The caller must be an owner of the corresponding
* entity type (see declareEntityTypeOwner()) and it must have added the specified
* entity before (see createEntity()).
*
* The entity will be automatically undeclared if it has been declared (see declareEntity())
*
* IMPORTANT: You are allowed to call this method only in code synchronized with the mirror.
* Refer to isRunningSynchronizedCode() to know the conditions.
*
* Returns false if part or all of the process failed.
*/
bool removeEntity( const NLMISC::CEntityId& entityId );
/**
* Provide a callback in which you will process the notifications of entities and property
* changes (see notification methods in CMirroredDataSet). You should not process the
* notifications outside this callback! The callback will be called only when mirrorIsReady().
*
* IMPORTANT: The notifications of entity additions must be browsed before the notifications
* of entity removals.
*/
void setNotificationCallback( TNotificationCallback cb ) { _NotificationCallback = cb; }
//--- MIRROR STATUS ------------------------------------------------------------------------------------
/**
* Return true if the mirror system and all requested properties are ready
* for use (level 2) (the level 1 means "ready for dataset initialization").
*/
bool mirrorIsReady() const { return _MirrorAllReady; }
/// Return true if the specified service is known as "mirror ready"
bool serviceHasMirrorReady( NLNET::TServiceId serviceId ) const;
/// Return the serviceId of the local Mirror Service
NLNET::TServiceId localMSId() const { return _PropAllocator.mirrorServiceId(); }
/// Info: display the properties allocated on the mirror
void displayProperties( NLMISC::CLog& log=*NLMISC::InfoLog ) const;
/// Info: display the number of active entities, created by the current mirror
void displayEntityTypesOwned( NLMISC::CLog& log=*NLMISC::InfoLog ) const;
/// Info: display the contents of the rows corresponding to the entity id
void displayRows( const NLMISC::CEntityId& entityId, NLMISC::CLog& log=*NLMISC::InfoLog ) const;
/// Debug: change a value from a string
void changeValue( const NLMISC::CEntityId& entityId, const std::string& propName, const std::string& valueStr );
/// Scan the entities to find if some are unknown by this service, and add them if requested (debug feature)
void rescanExistingEntities( CMirroredDataSet& dataset, NLMISC::CLog& log=*NLMISC::InfoLog, bool addUnknown=false );
/**
* Return true when we are running code synchronized with the mirror service.
* It will be always true when called:
* - in a callback provided to addCallbackWhenMirrorReadyForUse().
* - in a callback provided to setServiceMirrorUpCallback(), setServiceUpCallback() or setServiceDownCallback()
* if their parameter synchronizedCallback is set to true (default).
* - in a command when it is launched by "StartCommandsWhenMirrorReady".
* - in the tick update callback, if mirrorIsReady().
* - in the mirror notification callback.
* - in a callback of a message sent using sendMessageViaMirror().
* - in a callback of a CMirrorTransportClass object.
* - in the callback tickReleaseFunc provided to init(), called before quitting.
* It will be false in any other case.
*/
bool isRunningSynchronizedCode() const { return _IsExecutingSynchronizedCode; }
/// Return the Mirror Traffic Reduction tag
TMTRTag tag() const { return _MTRTag; }
//--- DATASETS ACCESSORS -------------------------------------------------------------------------------
/// Access the map of datasets (begin iteration). Use GET_NDATASET(it) to access the CMirroredDataSet object
TNDataSets::iterator dsBegin() { return _NDataSets.begin(); }
/// Access the map of datasets (test end of iteration)
TNDataSets::iterator dsEnd() { return _NDataSets.end(); }
/// Get a dataset by name. If not found, throws EMirror() (does not create a new dataset).
CMirroredDataSet& getDataSet( const std::string& dataSetName ) { return _NDataSets[dataSetName]; }
/// Check if a dataset exist
bool isDataSetExist(const std::string &dataSetName) { return _NDataSets.find(dataSetName) != _NDataSets.end(); }
/// Return the number of dataSet availables
uint32 getDataSetCount() const { return _NDataSets.size(); }
/// Destructor
~CMirror();
typedef uint8 TServiceEventType;
protected:
/// Set the local MS id if the service reported by cbServiceDown("MS") or cbServiceUp("MS") is the local Mirror Service
bool detectLocalMS( NLNET::TServiceId serviceId, bool upOrDown );
/// Return true if the mirror service is up and the entity ranges are ready
bool mirrorIsUp() const { return mirrorServiceIsUp() && (_PendingEntityTypesRanges == 0); }
/// Return true if the specified property is ready
bool propIsAllocated( const std::string& propName ) const { return _PropAllocator.getPropertySegment( propName ) != NULL; }
/// Receiving green light for level1
void initAfterMirrorUp();
/// Init mirror, level1
void doInitMirrorLevel1();
/// Set _MirrorAllReady (level2) to true if the conditions are met
void testMirrorReadyStatus();
/// Set the segment pointer in the property container
void setPropertyInfo( std::string& propName, void *segmentPt, uint32 dataTypeSize );
/// Access segments for non-subscribed properties allocated on the local MS (useful for cleaning a whole row when creating an entity)
void applyListOfOtherProperties( NLNET::CMessage& msgin, uint nbProps, const char *msgName, bool isInitial );
/// Return the dataset corresponding to a property (or NULL if not found)
CMirroredDataSet *getDataSetByPropName( std::string& propName, TPropertyIndex& propIndex ) { return _PropAllocator._PropertiesInMirror.getDataSetByPropName( propName, propIndex ); }
/// Return true if the local MS was found
bool mirrorServiceIsUp() const { return (localMSId() != NLNET::TServiceId(~0)); }
/// Return the inited state (ready at level 1)
bool mirrorInited() const { return _MirrorGotReadyLevel1; }
/// Receive the broadcasting of a service that has its mirror system ready
void receiveServiceHasMirrorReady( const std::string& serviceName, NLNET::TServiceId serviceId, NLNET::CMessage& msgin );
/// Return a property value as string
void getPropValueStr ( const NLMISC::CEntityId& entityId, const std::string& propName, std::string& result ) const;
/// Send to a reconnecting MS the state of our mirror info
void resyncMirrorInfo();
/// Main mirror update
void updateMirrorAndReceiveMessages( NLNET::CMessage& msgin );
/// Return true if the dataset is found in the entity types owned
bool datasetMatchesEntityTypesOwned( const CMirroredDataSet& dataset ) const;
/// Execute user callback when receiving first game cycle
void userSyncCallback();
/// Rescan
void scanAndResyncEntitiesExceptIgnored( const std::vector& creatorIdsToIgnore );
/// Execute start callbacks & commands
void executeMirrorReady2CallbacksAndStartCommands();
/// Execute commands when mirror is released
void executeMirrorReleaseCommands();
/// Tick update
void onTick();
/// Closure clearance callback
bool requestClosure();
/// Set service mirror/up/down callback
void setServiceMUDCallback( const std::string &serviceName, NLNET::TUnifiedNetCallback cb, void *arg, bool back, bool synchronizedCallback, TServiceEventType et );
/// React to a service mirror/up/down event
void processServiceEvent( const std::string &serviceName, NLNET::TServiceId serviceId, TServiceEventType et );
void pushEntityRanges( NLNET::CMessage& msgout );
void receiveSMIdToAccessPropertySegment( NLNET::CMessage& msgin );
void receiveRangesForEntityType( NLNET::CMessage& msgin );
void receiveTracker( bool entitiesOrProp, NLNET::CMessage& msgin );
void releaseTrackers( NLNET::CMessage& msgin );
void receiveAcknowledgeAddEntityTracker( NLNET::CMessage& msgin, NLNET::TServiceId serviceId );
void receiveAcknowledgeAddPropTracker( NLNET::CMessage& msgin, NLNET::TServiceId serviceId );
void deleteTracker( CChangeTrackerClient& tracker, std::vector& vect );
friend void cbMSUpDn( const std::string& serviceName, NLNET::TServiceId serviceId, void *upOrDn );
friend void cbAnyServiceUpDn( const std::string& serviceName, NLNET::TServiceId serviceId, void *vEventType );
friend void cbRecvSMIdToAccessPropertySegment( NLNET::CMessage& msgin, const std::string &serviceName, NLNET::TServiceId serviceId );
friend void cbRecvRangesForEntityType( NLNET::CMessage& msgin, const std::string &serviceName, NLNET::TServiceId serviceId );
friend void cbRecvAddPropTracker( NLNET::CMessage& msgin, const std::string &serviceName, NLNET::TServiceId serviceId );
friend void cbRecvAddEntityTracker( NLNET::CMessage& msgin, const std::string &serviceName, NLNET::TServiceId serviceId );
friend void cbRecvAcknowledgeAddEntityTracker( NLNET::CMessage& msgin, const std::string &serviceName, NLNET::TServiceId serviceId );
friend void cbRecvAcknowledgeAddPropTracker( NLNET::CMessage& msgin, const std::string &serviceName, NLNET::TServiceId serviceId );
friend void cbReleaseTrackers( NLNET::CMessage& msgin, const std::string &serviceName, NLNET::TServiceId serviceId );
friend void cbAllMirrorsOnline( NLNET::CMessage& msgin, const std::string &serviceName, NLNET::TServiceId serviceId );
friend void cbGrantStartService( NLNET::CMessage &msgin, const std::string&, NLNET::TServiceId );
friend void cbRecvServiceHasMirrorReadyBroadcast( NLNET::CMessage& msgin, const std::string &serviceName, NLNET::TServiceId serviceId );
friend void cbRecvServiceHasMirrorReadyReply( NLNET::CMessage& msgin, const std::string &serviceName, NLNET::TServiceId serviceId );
friend void cbUpdateMirrorAndReceiveMessages( NLNET::CMessage &msgin, const std::string&, NLNET::TServiceId );
friend void cbSyncGameCycle();
friend void cbServiceMirrorUpForSMIRUB( const std::string& serviceName, NLNET::TServiceId serviceId, void * );
friend void cbscanAndResyncEntitiesExceptIgnored( NLNET::CMessage &msgin, const std::string&, NLNET::TServiceId );
friend void cbApplyListOfOtherProperties( NLNET::CMessage &msgin, const std::string&, NLNET::TServiceId );
friend void cbAddListOfOtherProperties( NLNET::CMessage &msgin, const std::string&, NLNET::TServiceId );
friend void cbTickUpdateFunc();
friend bool cbRequestClosure();
private:
/// Type of callback and its user data
struct TCallbackArgItemM
{
NLNET::TUnifiedNetCallback Cb;
void* Arg;
bool Synchronized;
TServiceEventType EventType;
};
/// Instanciated callback item
struct TCallbackArgItemMExt : public TCallbackArgItemM
{
NLNET::TServiceId ServiceId;
std::string ServiceName;
TCallbackArgItemMExt( const TCallbackArgItemM& src, const std::string& servName, NLNET::TServiceId servId )
{
Cb = src.Cb;
Arg = src.Arg;
Synchronized = src.Synchronized;
EventType = src.EventType;
ServiceId = servId;
ServiceName = servName;
}
};
/// Type of map of service up callbacks with their user data.
typedef std::map< std::string, std::list > TNameMappedCallbackM;
/// Type of set of known 'service mirror up' (service ids)
typedef std::set< NLNET::TServiceId > TNotifiedServices;
/// Shared memory allocator
CPropertyAllocatorClient _PropAllocator;
/// Map of entity types and ranges owned
TEntityTypesOwned _EntityTypesOwned;
/// Number of entity types declared to the MS with no answer yet received
sint _PendingEntityTypesRanges;
/// The datasets with keys as strings (names)
TNDataSets _NDataSets;
/// Map of datasets with keys as CSheetId
TSDataSets _SDataSets;
/// Map of datasets sheets
TSDataSetSheets _SDataSetSheets;
/// Names of datasets to load
std::vector _DataSetsToLoad;
/// "Mirror ready at level 1" callback
TMirrorReadyCallback _ReadyL1Callback;
/// "Mirror ready at level 2" callbacks
std::vector _ReadyL2Callbacks;
/// Map of 'service mirror up' callbacks (by service name)
TNameMappedCallbackM _ServiceUpDnCallbacks;
/// 'Service mirror up' callbacks for *
std::vector _ServiceUpDnUniCallbacks;
// All defered callbacks for synchronized mode
std::vector _SynchronizedServiceUpDnCallbackQueue;
/// Set of services that are known 'mirror ready'
TNotifiedServices _ServicesMirrorUpNotified;
/// Tick update callback
TNotificationCallback _TickUpdateFunc;
/// Notification of mirror changes callback
TNotificationCallback _NotificationCallback;
/// User sync callback (called after the mirror one)
TNotificationCallback _UserSyncCallback;
/// Tick release callback
TNotificationCallback _TickReleaseFunc;
/// General status
bool _MirrorAllReady;
/// Status of mirror service detection and range mirror manager online state
bool _MirrorGotReadyLevel1;
/// Status of mirror start commands (to call them only once when mirror gets ready at level 2)
bool _MirrorGotReadyLevel2;
/// Status of expectation of the list of non-subscribed properties allocated on the local MS
bool _ListOfOtherPropertiesReceived;
/// Flag set between ReadyLevel2 and MirrorAllReady, to detect if the local MS is back (for resyncing)
bool _AwaitingAllMirrorsOnline;
/// True if we are in code synchronized with the mirror service
bool _IsExecutingSynchronizedCode;
/// True if the service wants to quit
bool _ClosureRequested;
/// Mirror Traffic Reduction Tag (corresponding to the tags of the 'self' trackers)
TMTRTag _MTRTag;
public:
/// A particular entity to use in mirror commands when no argument provided
NLMISC::CEntityId MonitoredEntity;
};
const CMirror::TServiceEventType ETMirrorUp=0, ETServiceUp=1, ETServiceDn=2, ETMirrorDn=3;
/*
* Tick update
*/
inline void CMirror::onTick()
{
_IsExecutingSynchronizedCode = true;
_TickUpdateFunc();
_IsExecutingSynchronizedCode = false;
}
#endif // NL_MIRROR_H
/* End of mirror.h */