Resolve "Toggle Free Look with Hotkey"
[ryzomcore.git] / ryzom / server / src / pd_lib / pd_messages.h
blob71ba33b58fa4dc4d77cdd9e8228273cab2aea5d8
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/>.
17 #ifndef RY_PD_MESSAGES_H
18 #define RY_PD_MESSAGES_H
21 * NeL Includes
23 #include <nel/misc/types_nl.h>
24 #include <nel/misc/common.h>
25 #include <nel/misc/time_nl.h>
26 #include <nel/misc/stream.h>
27 #include <nel/misc/entity_id.h>
28 #include <nel/misc/sheet_id.h>
29 #include <nel/misc/variable.h>
30 #include <nel/misc/hierarchical_timer.h>
33 * PD Lib Includes
35 #include "pd_utils.h"
36 #include "db_description_parser.h"
37 #include "timestamp.h"
39 namespace RY_PDS
42 #define MAX_MESSAGE_REMAP 32767
43 #define MESSAGE_REMAP_MASK 0x7fff
44 #define MESSAGE_REMAP_ENTITYID_PRESENT 0x8000
45 #define MESSAGE_SETPARENT_ENTITYID_PRESENT 0x8000
48 /**
49 * Object Circular Mapper
50 * Allows to map an object value through little sized uint (uint8 or uint16), allowing to reallocate
51 * mapping when all values are used.
52 * This is used to map long values (CEntityIds for instance) that are expected to appear frequently
53 * in a stream with short keys, without making sure all values fit in mapping table.
54 * For instance, if using uint8 as mapping key, when all 256 values are used, previously used key
55 * 0 is remapped to the new object value that appears in stream and so on (reallocations are done
56 * circularly through key values). Mask value is for test purposes only, not to be changed!
58 template<typename Key, typename Object, uint32 Mask = 0xffffffff, typename TBackMap = std::map<Object, Key> >
59 class CObjCircMapper
61 public:
63 CObjCircMapper()
65 _Next = 0;
66 _Max = 0;
67 // prepare mapping table
68 _FrontMap.resize(getMappingSize()+1);
71 /**
72 * Serialise object from stream
74 void serial(NLMISC::IStream& s, Object& o)
76 Key fakeFlags = 0;
77 serial(s, o, fakeFlags);
80 /**
81 * Serialise object from stream, with flags added to msbits
82 * WARNING: flags should NEVER interfere with Mask!
83 * WARNING: when stream is reading, lower bits of flags are unspecified!
85 void serial(NLMISC::IStream& s, Object& o, Key& flags)
87 if (s.isReading())
89 Key k;
90 s.serial(flags);
92 // remove flags from read key
93 k = (flags & Mask);
95 // if key is next value to be mapped
96 if (k == _Next)
98 // serial in object value to map
99 _Next = ((_Next+1)&Mask);
100 s.serial(o);
101 // and map it to key
102 _FrontMap[k] = o;
104 else
106 // already seen key? just copy object value
107 o = _FrontMap[k];
110 else
112 // search for object value in map
113 typename TBackMap::iterator it = _BackMap.find(o);
114 // not yet found or mapping key is just next key to alloc
115 if (it == _BackMap.end() || (*it).second == _Next)
117 // if mapping key is next, we have to force reallocation
118 // as serial in code can't know if value is new or not...
119 Key k = _Next;
120 _Next = ((_Next+1)&Mask);
121 // if new key as already circle'd down, unmap previous association
122 if (k < _Max)
124 #ifdef NL_DEBUG
125 typename TBackMap::iterator it = _BackMap.find(_FrontMap[k]);
126 nlassert(it != _BackMap.end() && (*it).second == k);
127 _BackMap.erase(it);
128 #else
129 _BackMap.erase(_FrontMap[k]);
130 #endif
132 else
134 // else just increase max seen key...
135 _Max = ((uint)k)+1;
137 // do mapping
138 _BackMap[o] = k;
139 _FrontMap[k] = o;
140 // serial mapping
141 k |= (flags & (~Mask));
142 s.serial(k);
143 s.serial(o);
145 else
147 // mapping found and correct, only serial key out
148 Key k = ((*it).second | (flags & (~Mask)));
149 s.serial(k);
154 private:
156 /// Back Mapping, from object values to keys
157 TBackMap _BackMap;
159 /// Front Mapping, from keys to object values
160 typedef typename std::vector<Object> TFrontMap;
161 TFrontMap _FrontMap;
163 /// Next Key to map
164 Key _Next;
165 /// Max mapped Key
166 uint _Max;
168 uint getMappingSize() const
170 return (((uint)1)<<(sizeof(Key)*8))-1;
174 typedef CObjCircMapper<uint8, NLMISC::CEntityId> TEntityIdCircMapper;
177 class CMsgObjectIndex
179 public:
181 CMsgObjectIndex() : Raw(0) {}
182 CMsgObjectIndex(uint8 table, uint32 row)
184 Raw = 0;
185 set(table, row);
188 void set(uint8 table, uint32 row)
190 Table = table;
191 Row = row;
194 union
196 uint64 Raw;
198 struct
200 uint32 Row;
201 uint8 Table;
205 void serial(NLMISC::IStream& f) { f.serial(Table, Row); }
207 bool operator < (const CMsgObjectIndex& a) const
209 return Raw < a.Raw;
213 typedef CObjCircMapper<uint8, CMsgObjectIndex, 0x7f> TObjectIndexCircMapper;
216 * Database update message
218 class CDbMessage
220 public:
222 CDbMessage() : Selected(false), ContextDepth(0), _ObjectIdPresent(false) { }
225 /// Type of message, 4bits -> 16 message types available
226 enum THeaderType
228 UpdateValue = 0,
229 SetParent = 1,
230 AllocRow = 2,
231 DeallocRow = 3,
232 ReleaseRow = 4,
234 EndRemapMessages = 4,
236 LoadRow = 5,
237 AddString = 6,
238 UnmapString = 7,
240 Log = 8,
241 PushContext = 9,
242 PopContext = 10,
244 LogChat = 11,
250 /// \name setup message methods
251 // @{
253 /// update value
254 template<typename T>
255 void updateValue(TColumnIndex column, const T& value)
257 setHeader(UpdateValue);
259 uint sz = 0;
261 // update 20101119 by packpro
262 if (sizeof(value) == 1)
264 sz = 0;
265 memcpy(&(_Value0[0]), &value, sizeof(value));
267 else if (sizeof(value) == 2)
269 sz = 1;
270 memcpy(&(_Value1[0]), &value, sizeof(value));
272 else if (sizeof(value) == 4)
274 sz = 2;
275 memcpy(&(_Value2[0]), &value, sizeof(value));
277 else if (sizeof(value) == 8)
279 sz = 3;
280 memcpy(&(_Value3[0]), &value, sizeof(value));
283 //if (sizeof(value) == 1) { sz = 0; _Value0[0] = *(uint8*)(&value); }
284 //else if (sizeof(value) == 2) { sz = 1; _Value1[0] = *(uint16*)(&value); }
285 //else if (sizeof(value) == 4) { sz = 2; _Value2[0] = *(uint32*)(&value); }
286 //else if (sizeof(value) == 8) { sz = 3; _Value3[0] = *(uint64*)(&value); }
287 _ColumnAndSize = (uint16)(column | (sz << 14));
290 /// update value
291 template<typename T>
292 void updateValue(TColumnIndex column, const T& value, const NLMISC::CEntityId& objectId)
294 setHeader(UpdateValue);
296 uint sz;
298 // update 20101119 by packpro
299 if (sizeof(value) == 1)
301 sz = 0;
302 memcpy(&(_Value0[0]), &value, sizeof(value));
304 else if (sizeof(value) == 2)
306 sz = 1;
307 memcpy(&(_Value1[0]), &value, sizeof(value));
309 else if (sizeof(value) == 4)
311 sz = 2;
312 memcpy(&(_Value2[0]), &value, sizeof(value));
314 else if (sizeof(value) == 8)
316 sz = 3;
317 memcpy(&(_Value3[0]), &value, sizeof(value));
319 //if (sizeof(value) == 1) { sz = 0; _Value0[0] = *(uint8*)(&value); }
320 //else if (sizeof(value) == 2) { sz = 1; _Value1[0] = *(uint16*)(&value); }
321 //else if (sizeof(value) == 4) { sz = 2; _Value2[0] = *(uint32*)(&value); }
322 //else if (sizeof(value) == 8) { sz = 3; _Value3[0] = *(uint64*)(&value); }
324 _ColumnAndSize = (uint16)(column | (sz << 14));
326 //_MapTableRow |= MESSAGE_REMAP_ENTITYID_PRESENT;
327 _ObjectIdPresent = true;
328 _ObjectId = objectId;
331 /// set parent
332 void setParent(TColumnIndex column, const CObjectIndex& parent)
334 setHeader(SetParent);
336 _ColumnAndSize = (uint16)column;
337 _Value3[0] = *(uint64*)(&parent);
340 /// set parent, only child object has an entityId as key
341 void setParent(TColumnIndex column, const CObjectIndex& parent, const NLMISC::CEntityId& objectId)
343 setHeader(SetParent);
345 _ColumnAndSize = (uint16)column;
346 _Value3[0] = *(uint64*)(&parent);
348 //_MapTableRow |= MESSAGE_REMAP_ENTITYID_PRESENT;
349 _ObjectIdPresent = true;
350 _ObjectId = objectId;
353 /// set parent, only parent object has an entityId as key
354 void setParent(TColumnIndex column, const CObjectIndex& parent, const NLMISC::CEntityId& newParentId, const NLMISC::CEntityId& previousParentId)
356 setHeader(SetParent);
358 _ColumnAndSize = (uint16)column;
359 _Value3[0] = *(uint64*)(&parent);
361 _ColumnAndSize |= MESSAGE_SETPARENT_ENTITYID_PRESENT;
362 _NewParentId = newParentId;
363 _PreviousParentId = previousParentId;
366 /// set parent, both child and parent objects have an entityId as key
367 void setParent(TColumnIndex column, const CObjectIndex& parent, const NLMISC::CEntityId& objectId, const NLMISC::CEntityId& newParentId, const NLMISC::CEntityId& previousParentId)
369 setHeader(SetParent);
371 _ColumnAndSize = (uint16)column;
372 _Value3[0] = *(uint64*)(&parent);
374 //_MapTableRow |= MESSAGE_REMAP_ENTITYID_PRESENT;
375 _ObjectIdPresent = true;
376 _ObjectId = objectId;
378 _ColumnAndSize |= MESSAGE_SETPARENT_ENTITYID_PRESENT;
379 _NewParentId = newParentId;
380 _PreviousParentId = previousParentId;
383 /// Is Object EntityId present
384 bool objectEntityIdPresent() const
386 //return (_MapTableRow & MESSAGE_REMAP_ENTITYID_PRESENT) != 0;
387 return _ObjectIdPresent;
390 /// Are Parents EntityId present
391 bool parentsEntityIdPresent() const
393 return (_ColumnAndSize & MESSAGE_SETPARENT_ENTITYID_PRESENT) != 0;
396 /// allocate row
397 void allocRow(uint64 key)
399 setHeader(AllocRow);
401 _Value3[0] = key;
404 /// deallocate row
405 void deallocRow()
407 setHeader(DeallocRow);
410 /// allocate row
411 void allocRow(uint64 key, const NLMISC::CEntityId& objectId)
413 setHeader(AllocRow);
415 //_MapTableRow |= MESSAGE_REMAP_ENTITYID_PRESENT;
416 _ObjectIdPresent = true;
417 _ObjectId = objectId;
419 _Value3[0] = key;
422 /// deallocate row
423 void deallocRow(const NLMISC::CEntityId& objectId)
425 setHeader(DeallocRow);
427 //_MapTableRow |= MESSAGE_REMAP_ENTITYID_PRESENT;
428 _ObjectIdPresent = true;
429 _ObjectId = objectId;
432 /// load row
433 void loadRow(TTableIndex table, uint64 key)
435 setHeader(LoadRow);
437 _ObjectIndex.set((uint8)table, 0);
438 //_Table = (uint8)table;
439 _Value3[0] = key;
444 /// Add string
445 void addString(uint64 skey, const ucstring& str)
447 setHeader(AddString);
449 _Value3[0] = skey;
450 _String = str;
453 /// Add string
454 void unmapString(uint64 skey)
456 setHeader(UnmapString);
458 _Value3[0] = skey;
461 /// Release a row in memory
462 void releaseRow()
464 setHeader(ReleaseRow);
471 /// Log message
472 void log(uint logId, uint bufferByteSize)
474 setHeader(Log);
475 _LogId = logId;
476 _LogBuffer.resize(bufferByteSize);
479 /// Push Log Parameter
480 template<typename T>
481 void pushParameter(uint byteOffset, const T& parameter)
483 nlassertex(byteOffset+sizeof(T) <= _LogBuffer.size(), ("Internal error! failed to push parameter at %d (size=%d), beyond buffer limit (%d)", byteOffset, sizeof(T), _LogBuffer.size()));
484 memcpy(&(_LogBuffer[byteOffset]), &parameter, sizeof(parameter));
487 /// Push Log Parameter (string)
488 void pushParameter(uint byteOffset, const std::string& parameter)
490 nlassertex(byteOffset+sizeof(uint16) <= _LogBuffer.size(), ("Internal error! failed to push parameter at %d (size=%d), beyond buffer limit (%d)", byteOffset, sizeof(uint16), _LogBuffer.size()));
491 // get current string index
492 uint16 bo = (uint16)_ExtLogBuffer.size();
493 _ExtLogBuffer.resize(bo+parameter.size()+1);
494 memcpy(&(_ExtLogBuffer[bo]), parameter.c_str(), parameter.size()+1);
495 memcpy(&(_LogBuffer[byteOffset]), &bo, sizeof(uint16));
498 /// Push Log Context
499 void pushContext()
501 setHeader(PushContext);
504 /// Pop Log Context
505 void popContext()
507 setHeader(PopContext);
513 /// Log Chat sentence
514 void logChat(const ucstring& sentence, const NLMISC::CEntityId& sender, const std::vector<NLMISC::CEntityId>& receivers)
516 setHeader(LogChat);
517 _String = sentence;
518 *(NLMISC::CEntityId*)(&(_Value3[0])) = sender;
520 uint bufferSize = (uint)receivers.size()*sizeof(NLMISC::CEntityId);
521 if (bufferSize > 0)
523 _LogBuffer.resize(bufferSize);
524 NLMISC::CEntityId* srcBuffer = (NLMISC::CEntityId*)(&(receivers[0]));
525 NLMISC::CEntityId* dstBuffer = (NLMISC::CEntityId*)(&(_LogBuffer[0]));
526 memcpy(dstBuffer, srcBuffer, bufferSize);
528 else
530 _LogBuffer.clear();
535 // @}
538 /// Get message type
539 THeaderType getType() const { return _Type; }
541 /// Set Type of message
542 void setType(THeaderType type) { _Type = type; }
546 /// \name common part methods
547 // @{
549 TTableIndex getTable() const { return (TTableIndex)_ObjectIndex.Table; }
550 TRowIndex getRow() const { return (TRowIndex)_ObjectIndex.Row; }
551 uint32 getStringId() const { return _StringId; }
553 // @}
557 /// \name Update database value specific methods
558 // @{
560 TColumnIndex getColumn() const { return (TColumnIndex)(_ColumnAndSize&0x3fff); }
561 const void* getData() const { return &_Value0[0]; }
562 uint getDatasize() const { return 1 << (_ColumnAndSize>>14); }
563 uint8 getValue8bits() const { return _Value0[0]; }
564 uint16 getValue16bits() const { return _Value1[0]; }
565 uint32 getValue32bits() const { return _Value2[0]; }
566 uint64 getValue64bits() const { return _Value3[0]; }
567 CObjectIndex getObjectIndex() const { return *(CObjectIndex*)(&(_Value3[0])); }
568 const ucstring& getString() const { return _String; }
570 bool asBool() const { return _Value0[0] != 0; }
571 char asChar() const { return (char)_Value0[0]; }
572 ucchar asUCChar() const { return (ucchar)_Value1[0]; }
573 uint8 asUint8() const { return (uint8)_Value0[0]; }
574 uint16 asUint16() const { return (uint16)_Value1[0]; }
575 uint32 asUint32() const { return (uint32)_Value2[0]; }
576 uint64 asUint64() const { return (uint64)_Value3[0]; }
577 sint8 asSint8() const { return (sint8)_Value0[0]; }
578 sint16 asSint16() const { return (sint16)_Value1[0]; }
579 sint32 asSint32() const { return (sint32)_Value2[0]; }
580 sint64 asSint64() const { return (sint64)_Value3[0]; }
581 float asFloat() const { return (float)_ValueFloat[0]; }
582 double asDouble() const { return (double)_ValueDouble[0]; }
583 const NLMISC::CSheetId& asSheetId() const { return *(NLMISC::CSheetId*)(&_Value2[0]); }
584 const NLMISC::CEntityId& asEntityId() const { return *(NLMISC::CEntityId*)(&_Value3[0]); }
586 const NLMISC::CEntityId& getObjectId() const { return _ObjectId; }
587 const NLMISC::CEntityId& getNewParentId() const { return _NewParentId; }
588 const NLMISC::CEntityId& getPreviousParentId() const { return _PreviousParentId; }
590 uint16 getLogId() const { return _LogId; }
591 const std::vector<uint8>& getLogBuffer() const { return _LogBuffer; }
593 void setupTableAndRow(TTableIndex table, TRowIndex row)
595 _ObjectIndex.set((uint8)table, (uint32)row);
598 // @}
600 /// \name Log analysis/display
601 // @{
603 /// Dump Message content to string as a human readable message
604 void getHRContent(const CDBDescriptionParser& description, std::string& result) const;
606 /// Does message contains CEntityId?
607 bool contains(const CDBDescriptionParser& description, const NLMISC::CEntityId& id);
609 /// Does message contains string?
610 bool contains(const CDBDescriptionParser& description, const std::string& str);
612 /// Build Log string
613 std::string buildLogString(const CDBDescriptionParser& description) const;
615 /// Is Value modified
616 bool valueModified(uint table, uint column)
618 return ((getType() == UpdateValue || getType() == SetParent) && getTable() == table && getColumn() == column);
621 /// Is message selected
622 bool Selected;
623 /// Message context depth
624 uint16 ContextDepth;
626 // @}
628 /// \name Serializing
629 // @{
631 /// Serial message
632 void serial(NLMISC::IStream &f, TObjectIndexCircMapper& indexMapper, TEntityIdCircMapper& eidMapper);
634 /// Get Message Header Size
635 uint32 getMessageHeaderSize();
637 // @}
639 private:
642 * Type of message
643 * Type is not serialised directly in message, but in containing folder
645 THeaderType _Type;
649 * Message Id
650 * Refers to the 'entity' used/updated by the message
652 union // 32 bits
654 uint32 _StringId;
655 uint16 _LogId;
658 /// \name Extra info
659 // @{
661 uint16 _ColumnAndSize;
663 CMsgObjectIndex _ObjectIndex;
665 union // 64 bits
667 uint8 _Value0[8];
668 uint16 _Value1[4];
669 uint32 _Value2[2];
670 uint64 _Value3[1];
671 float _ValueFloat[2];
672 double _ValueDouble[1];
675 bool _ObjectIdPresent;
676 NLMISC::CEntityId _ObjectId;
677 NLMISC::CEntityId _NewParentId;
678 NLMISC::CEntityId _PreviousParentId;
680 ucstring _String;
681 std::vector<uint8> _LogBuffer;
682 std::vector<uint8> _ExtLogBuffer;
684 // @}
686 void setHeader(THeaderType type) { _Type = type; }
695 * A Folder a Db Messages, all of the same kind.
696 * Based on the assumption that update value messages are the main kind of messages
697 * and that the follow in series...
698 * Thus, it should save one byte per message...
700 class CDbMessageFolder
702 public:
704 CDbMessageFolder()
706 _Type = 0xff;
707 _NumMessages = 0;
711 * Constructor
713 CDbMessageFolder(uint8 type)
715 _Type = type;
716 _NumMessages = 0;
721 * Get Folder Type
723 uint8 getType() const { return _Type; }
726 * Get Number of messages in folder
728 uint32 getNumMessages() const { return _NumMessages; }
731 * Folder is full
733 bool full() const { return _NumMessages == MAX_MESSAGE_REMAP; }
736 * Add a message to folder
738 void addMessage(const CDbMessage& msg)
740 nlassert(_NumMessages < MAX_MESSAGE_REMAP);
741 nlassert(msg.getType() == _Type);
742 ++_NumMessages;
746 * Serialise folder
748 void serial(NLMISC::IStream& f)
750 f.serial(_Type, _NumMessages);
751 nlassert(_Type < CDbMessage::End);
754 private:
756 /// Type of messages in folder
757 uint8 _Type;
759 /// Number of messages in folder
760 uint16 _NumMessages;
771 * A Queue of messages
773 class CDbMessageQueue
775 public:
778 * Constructor
780 CDbMessageQueue()
782 clear();
786 * Clear
788 void clear()
790 _Messages.clear();
791 _Folders.clear();
795 * Get Next Message to be written
797 CDbMessage& nextMessage()
799 _Messages.resize(_Messages.size()+1);
800 return _Messages.back();
804 * Get Current Message to be written
806 CDbMessage& currentMessage()
808 nlassert(!_Messages.empty());
809 return _Messages.back();
814 * Get Number of Messages in queue
816 uint32 getNumMessages() const
818 return (uint32)_Messages.size();
822 * Get Message
824 CDbMessage& getMessage(uint32 message)
826 nlassert(message < _Messages.size());
827 return _Messages[message];
831 * Serialise message queue
833 void serial(NLMISC::IStream& f)
835 H_AUTO(PDLIB_MsgQueue_serial);
837 // build folders first if writing to stream
838 if (!f.isReading())
840 buildFolders();
843 uint32 numFolders = (uint32)_Folders.size();
844 uint32 numMessages = (uint32)_Messages.size();
846 f.serial(numFolders);
847 f.serial(numMessages);
849 if (f.isReading())
851 _Folders.resize(numFolders);
852 _Messages.resize(numMessages);
855 //f.serialCont(_BackRemap);
857 TEntityIdCircMapper EIdMapper;
858 TObjectIndexCircMapper IndexMapper;
860 // for each folder, write message stored in it
861 uint i, message = 0;
862 for (i=0; i<_Folders.size(); ++i)
864 CDbMessageFolder& folder = _Folders[i];
865 f.serial(folder);
867 uint j;
868 for (j=0; j<folder.getNumMessages(); ++j)
870 nlassert(message < numMessages);
872 CDbMessage& msg = _Messages[message++];
873 msg.setType((CDbMessage::THeaderType)folder.getType());
875 msg.serial(f, IndexMapper, EIdMapper);
879 // remap messages
880 if (f.isReading())
882 uint currentDepth = 0;
883 for (i=0; i<_Messages.size(); ++i)
885 CDbMessage& msg = _Messages[i];
887 if (msg.getType() == CDbMessage::PopContext)
888 --currentDepth;
889 msg.ContextDepth = currentDepth;
890 if (msg.getType() == CDbMessage::PushContext)
891 ++currentDepth;
897 private:
899 /// List of messages
900 std::vector<CDbMessage> _Messages;
902 /// List of folders
903 std::vector<CDbMessageFolder> _Folders;
907 * Build message folders
909 void buildFolders()
911 _Folders.clear();
913 uint i;
914 for (i=0; i<_Messages.size(); ++i)
916 if (_Folders.empty() || _Folders.back().full() || _Messages[i].getType() != _Folders.back().getType())
917 _Folders.push_back(CDbMessageFolder(_Messages[i].getType()));
919 _Folders.back().addMessage(_Messages[i]);
930 * A Split Queue
931 * Handle multiple queues, so one update may be splitted into multiple messages
933 class CDbMessageSplitQueue
935 public:
938 * Constructor
940 CDbMessageSplitQueue()
945 * Clearup
947 void clear()
949 _Queues.clear();
953 * Get Next Message to be written, no mapping to be done
955 CDbMessage& nextMessage()
957 if (empty())
958 forceNextQueue();
960 return _Queues.back().nextMessage();
964 * Get Next Remappable Message to be written
966 CDbMessage& nextMessage(uint8 table, uint32 row)
968 if (empty())
969 forceNextQueue();
971 // here, queue allows to map message
972 CDbMessage& msg = _Queues.back().nextMessage();
974 msg.setupTableAndRow(table, row);
976 // and return it
977 return msg;
981 * Get Current Message
983 CDbMessage& currentMessage()
985 return _Queues.back().currentMessage();
989 * Force MsgQueue to fill next queue
991 void forceNextQueue()
993 if (_Queues.empty() || _Queues.back().getNumMessages() > 0)
995 _Queues.push_back(CDbMessageQueue());
1000 * Is Queue Empty?
1002 bool empty() const
1004 return _Queues.empty();
1008 * Number of message in queue
1010 uint32 getNumMessagesEnqueued() const
1012 std::list<CDbMessageQueue>::const_iterator it;
1013 uint32 totalMessages = 0;
1014 for (it=_Queues.begin(); it!=_Queues.end(); ++it)
1015 totalMessages += (*it).getNumMessages();
1017 return totalMessages;
1022 * begin()
1024 std::list<CDbMessageQueue>::iterator begin() { return _Queues.begin(); }
1027 * end()
1029 std::list<CDbMessageQueue>::iterator end() { return _Queues.end(); }
1032 * size()
1034 uint size() const { return (uint)_Queues.size(); }
1037 * get()
1039 CDbMessageQueue& get(uint i)
1041 std::list<CDbMessageQueue>::iterator it = _Queues.begin();
1042 while (i-- > 0)
1043 ++it;
1044 return (*it);
1048 private:
1050 /// Used Queues
1051 std::list<CDbMessageQueue> _Queues;
1059 class CUpdateLog
1061 public:
1063 CUpdateLog() : UpdateId(0xffffffff), _OwnUpdates(false), _Updates(NULL) { }
1065 ~CUpdateLog();
1067 /// UpdateId sent by client for this update
1068 uint32 UpdateId;
1070 /// Start date for this update
1071 CTimestamp StartStamp;
1073 /// Start date for this update
1074 CTimestamp EndStamp;
1076 /// Serial log
1077 void serial(NLMISC::IStream& f);
1079 /// Display UpdateLog content (using a database description)
1080 void display(const CDBDescriptionParser& description, NLMISC::CLog& log, bool onlySelected = false);
1086 * Check log timestamp boundaries
1088 bool checkTimestampBoundaries(const CTimestamp& begin, const CTimestamp& end);
1091 * Is Empty
1093 bool isEmpty();
1096 * Select contexts and messages containing a given entityId
1097 * return true if there were at least one message selected
1099 bool selectMessages(const CDBDescriptionParser& description, const NLMISC::CEntityId& id);
1102 * Select contexts and messages containing a given string
1103 * return true if there were at least one message selected
1105 bool selectMessages(const CDBDescriptionParser& description, const std::string& str);
1108 * Select contexts and messages containing modification of a value for a given entityId
1109 * return true if there were at least one message selected
1111 bool selectMessages(const CDBDescriptionParser& description, const NLMISC::CEntityId& id, const std::string& valuePath);
1114 * Select contexts and messages containing a list of entityIds (limited at most to 32 entityIds)
1115 * return true if there were at least one message selected
1117 bool selectMessages(const CDBDescriptionParser& description, const std::vector<NLMISC::CEntityId>& ids);
1119 class CLogProcessor
1121 public:
1122 /// process log, return true if some messages were selected
1123 virtual bool processLog(CUpdateLog& log, const CDBDescriptionParser& description) = 0;
1127 * Apply process on log files
1129 static void processLogs(const std::string& path,
1130 const CTimestamp& begin,
1131 const CTimestamp& end,
1132 NLMISC::CLog& log,
1133 CLogProcessor* processor,
1134 float* progress = NULL);
1137 * Display log for a given entity id, between 2 dates
1139 static void displayLogs(const CDBDescriptionParser& description,
1140 const NLMISC::CEntityId& id,
1141 const CTimestamp& begin,
1142 const CTimestamp& end,
1143 const std::string& path,
1144 NLMISC::CLog& log,
1145 float* progress = NULL);
1148 * Display log between 2 dates
1150 static void displayLogs(const std::string& path,
1151 const CTimestamp& begin,
1152 const CTimestamp& end,
1153 NLMISC::CLog& log,
1154 float* progress = NULL);
1157 * Display log for a given entity id, between 2 dates
1159 static void displayLogs(const std::string& path,
1160 const NLMISC::CEntityId& id,
1161 const CTimestamp& begin,
1162 const CTimestamp& end,
1163 NLMISC::CLog& log,
1164 float* progress = NULL);
1167 * Display log for a given entity id and a specified value to be modified, between 2 dates
1169 static void displayLogs(const std::string& path,
1170 const NLMISC::CEntityId& id,
1171 const std::string& valuePath,
1172 const CTimestamp& begin,
1173 const CTimestamp& end,
1174 NLMISC::CLog& log,
1175 float* progress = NULL);
1178 * Display log for a list of given entity id, between 2 dates
1180 static void displayLogs(const std::string& path,
1181 const std::vector<NLMISC::CEntityId>& ids,
1182 const CTimestamp& begin,
1183 const CTimestamp& end,
1184 NLMISC::CLog& log,
1185 float* progress = NULL);
1188 * Display log for a list of given entity id, between 2 dates
1190 static void displayLogs(const std::string& path,
1191 const std::string& str,
1192 const CTimestamp& begin,
1193 const CTimestamp& end,
1194 NLMISC::CLog& log,
1195 float* progress = NULL);
1198 * Elect matching description
1200 static std::string electDescription(const std::string& logFile);
1206 * Set updates
1208 void setUpdates(CDbMessageQueue* updates);
1211 * Create updates
1213 void createUpdates();
1216 * Get Updates
1218 CDbMessageQueue* getUpdates() { return _Updates; }
1220 private:
1222 bool _OwnUpdates;
1224 /// Updates contained in message
1225 CDbMessageQueue* _Updates;
1227 /// Release Updates (and delete if owned)
1228 void releaseUpdates()
1230 if (_OwnUpdates && _Updates != NULL)
1231 delete _Updates;
1233 _Updates = NULL;
1234 _OwnUpdates = false;
1243 // CDbMessage inline methods
1246 inline void CDbMessage::serial(NLMISC::IStream &f, TObjectIndexCircMapper& indexMapper, TEntityIdCircMapper& eidMapper)
1248 switch (_Type)
1250 case UpdateValue:
1252 uint8 flags = (objectEntityIdPresent() ? 0x80 : 0);
1253 indexMapper.serial(f, _ObjectIndex, flags);
1254 _ObjectIdPresent = ((flags & 0x80) != 0);
1256 f.serial(_ColumnAndSize);
1258 switch (_ColumnAndSize & 0xc000)
1260 case 0x0000: f.serial(_Value0[0]); break;
1261 case 0x4000: f.serial(_Value1[0]); break;
1262 case 0x8000: f.serial(_Value2[0]); break;
1263 case 0xc000: f.serial(_Value3[0]); break;
1266 // serial owner CEntityId if present
1267 if (objectEntityIdPresent())
1268 eidMapper.serial(f, _ObjectId);
1270 break;
1272 case SetParent:
1274 uint8 flags = (objectEntityIdPresent() ? 0x80 : 0);
1275 indexMapper.serial(f, _ObjectIndex, flags);
1276 _ObjectIdPresent = ((flags & 0x80) != 0);
1277 f.serial(_ColumnAndSize);
1278 f.serial(_Value3[0]);
1280 // serial object CEntityId if present
1281 if (objectEntityIdPresent())
1282 eidMapper.serial(f, _ObjectId);
1284 // serial parents CEntityId if present
1285 if ((_ColumnAndSize & MESSAGE_SETPARENT_ENTITYID_PRESENT) != 0)
1287 eidMapper.serial(f, _NewParentId);
1288 eidMapper.serial(f, _PreviousParentId);
1291 break;
1293 case AllocRow:
1295 uint8 flags = (objectEntityIdPresent() ? 0x80 : 0);
1296 indexMapper.serial(f, _ObjectIndex, flags);
1297 _ObjectIdPresent = ((flags & 0x80) != 0);
1298 f.serial(_Value3[0]);
1300 // serial owner CEntityId if present
1301 if (objectEntityIdPresent())
1302 eidMapper.serial(f, _ObjectId);
1304 break;
1306 case DeallocRow:
1308 uint8 flags = (objectEntityIdPresent() ? 0x80 : 0);
1309 indexMapper.serial(f, _ObjectIndex, flags);
1310 _ObjectIdPresent = ((flags & 0x80) != 0);
1311 // serial owner CEntityId if present
1312 if (objectEntityIdPresent())
1313 eidMapper.serial(f, _ObjectId);
1315 break;
1317 case LoadRow:
1318 f.serial(_ObjectIndex.Table);
1319 f.serial(_Value3[0]);
1320 break;
1322 case AddString:
1323 f.serial(_Value3[0]);
1324 f.serial(_String);
1325 break;
1327 case UnmapString:
1328 f.serial(_Value3[0]);
1329 break;
1331 case ReleaseRow:
1332 indexMapper.serial(f, _ObjectIndex);
1333 break;
1335 case Log:
1337 f.serial(_LogId);
1339 if (f.isReading())
1341 uint8 sz;
1343 f.serial(sz);
1344 _LogBuffer.resize(sz);
1345 if (sz > 0)
1346 f.serialBuffer(&(_LogBuffer[0]), sz);
1348 f.serial(sz);
1349 _ExtLogBuffer.resize(sz);
1350 if (sz > 0)
1351 f.serialBuffer(&(_ExtLogBuffer[0]), sz);
1353 else
1355 uint8 sz;
1356 nlassert(_LogBuffer.size() <= 255);
1357 sz = (uint8)_LogBuffer.size();
1358 f.serial(sz);
1359 if (sz > 0)
1360 f.serialBuffer(&(_LogBuffer[0]), sz);
1362 nlassert(_ExtLogBuffer.size() <= 255);
1363 sz = (uint8)_ExtLogBuffer.size();
1364 f.serial(sz);
1365 if (sz > 0)
1366 f.serialBuffer(&(_ExtLogBuffer[0]), sz);
1369 break;
1371 case PushContext:
1372 break;
1374 case PopContext:
1375 break;
1377 case LogChat:
1378 // serial chat sentence
1379 f.serial(_String);
1380 // serial sender
1381 f.serial(_Value3[0]);
1382 // serial receivers list (whole buffer as uint8*)
1383 f.serialCont(_LogBuffer);
1384 break;
1386 default:
1387 nlerror("CDbMessage::serial(): unable to serial message type '%d'", _Type);
1388 break;
1393 * Get Message Header Size
1395 inline uint32 CDbMessage::getMessageHeaderSize()
1397 uint size = 0;
1399 switch (_Type)
1401 case UpdateValue:
1402 case SetParent:
1403 size += sizeof(_ObjectIndex.Table)+sizeof(_ObjectIndex.Row);
1404 size += sizeof(_ColumnAndSize);
1405 break;
1407 case AllocRow:
1408 size += sizeof(_ObjectIndex.Table)+sizeof(_ObjectIndex.Row);
1409 break;
1411 case DeallocRow:
1412 size += sizeof(_ObjectIndex.Table)+sizeof(_ObjectIndex.Row);
1413 break;
1415 case LoadRow:
1416 size += sizeof(_ObjectIndex.Table);
1417 size += sizeof(_Value3[0]);
1418 break;
1420 case ReleaseRow:
1421 size += sizeof(_ObjectIndex.Table)+sizeof(_ObjectIndex.Row);
1422 break;
1424 case Log:
1425 size += sizeof(_LogId);
1426 size += 2;
1427 break;
1429 default:
1430 break;
1433 return size;
1437 * Serial log
1439 inline void CUpdateLog::serial(NLMISC::IStream& f)
1441 f.serialCheck(NELID("ULOG"));
1443 uint version = f.serialVersion(1);
1445 f.serial(UpdateId);
1447 if (version >= 1)
1449 f.serial(StartStamp);
1450 f.serial(EndStamp);
1453 if (f.isReading())
1455 releaseUpdates();
1456 _Updates = new RY_PDS::CDbMessageQueue();
1457 _OwnUpdates = true;
1460 f.serial(*_Updates);
1464 }; // RY_PDS
1466 #endif //RY_PD_MESSAGES_H