pd_messages.h
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.
|
13 |
//
|
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/>.
|
16 |
|
17 |
#ifndef RY_PD_MESSAGES_H
|
18 |
#define RY_PD_MESSAGES_H
|
19 |
|
20 |
/*
|
21 |
* NeL Includes |
22 |
*/ |
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> |
31 |
|
32 |
/*
|
33 |
* PD Lib Includes |
34 |
*/ |
35 |
#include "pd_utils.h" |
36 |
#include "db_description_parser.h" |
37 |
#include "timestamp.h" |
38 |
|
39 |
namespace RY_PDS |
40 |
{ |
41 |
|
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 |
46 |
|
47 |
|
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! |
57 |
*/ |
58 |
template<typename Key, typename Object, int Mask = 0xffffffff, typename TBackMap = std::map<Object, Key> > |
59 |
class CObjCircMapper |
60 |
{ |
61 |
public:
|
62 |
|
63 |
CObjCircMapper() |
64 |
{ |
65 |
_Next = 0;
|
66 |
_Max = 0;
|
67 |
// prepare mapping table
|
68 |
_FrontMap.resize(getMappingSize()+1);
|
69 |
} |
70 |
|
71 |
/**
|
72 |
* Serialise object from stream |
73 |
*/ |
74 |
void serial(NLMISC::IStream& s, Object& o)
|
75 |
{ |
76 |
Key fakeFlags = 0;
|
77 |
serial(s, o, fakeFlags); |
78 |
} |
79 |
|
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! |
84 |
*/ |
85 |
void serial(NLMISC::IStream& s, Object& o, Key& flags)
|
86 |
{ |
87 |
if (s.isReading())
|
88 |
{ |
89 |
Key k; |
90 |
s.serial(flags); |
91 |
|
92 |
// remove flags from read key
|
93 |
k = (flags & Mask); |
94 |
|
95 |
// if key is next value to be mapped
|
96 |
if (k == _Next)
|
97 |
{ |
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; |
103 |
} |
104 |
else
|
105 |
{ |
106 |
// already seen key? just copy object value
|
107 |
o = _FrontMap[k]; |
108 |
} |
109 |
} |
110 |
else
|
111 |
{ |
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)
|
116 |
{ |
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)
|
123 |
{ |
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
|
131 |
} |
132 |
else
|
133 |
{ |
134 |
// else just increase max seen key...
|
135 |
_Max = ((uint)k)+1;
|
136 |
} |
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); |
144 |
} |
145 |
else
|
146 |
{ |
147 |
// mapping found and correct, only serial key out
|
148 |
Key k = ((*it).second | (flags & (~Mask))); |
149 |
s.serial(k); |
150 |
} |
151 |
} |
152 |
} |
153 |
|
154 |
private:
|
155 |
|
156 |
/// Back Mapping, from object values to keys
|
157 |
TBackMap _BackMap; |
158 |
|
159 |
/// Front Mapping, from keys to object values
|
160 |
typedef typename std::vector<Object> TFrontMap;
|
161 |
TFrontMap _FrontMap; |
162 |
|
163 |
/// Next Key to map
|
164 |
Key _Next; |
165 |
/// Max mapped Key
|
166 |
uint _Max; |
167 |
|
168 |
uint getMappingSize() const
|
169 |
{ |
170 |
return (((uint)1)<<(sizeof(Key)*8))-1; |
171 |
} |
172 |
}; |
173 |
|
174 |
typedef CObjCircMapper<uint8, NLMISC::CEntityId> TEntityIdCircMapper;
|
175 |
|
176 |
|
177 |
class CMsgObjectIndex |
178 |
{ |
179 |
public:
|
180 |
|
181 |
CMsgObjectIndex() : Raw(0) {}
|
182 |
CMsgObjectIndex(uint8 table, uint32 row) |
183 |
{ |
184 |
Raw = 0;
|
185 |
set(table, row); |
186 |
} |
187 |
|
188 |
void set(uint8 table, uint32 row)
|
189 |
{ |
190 |
Table = table; |
191 |
Row = row; |
192 |
} |
193 |
|
194 |
union
|
195 |
{ |
196 |
uint64 Raw; |
197 |
|
198 |
struct
|
199 |
{ |
200 |
uint32 Row; |
201 |
uint8 Table; |
202 |
}; |
203 |
}; |
204 |
|
205 |
void serial(NLMISC::IStream& f) { f.serial(Table, Row); }
|
206 |
|
207 |
bool operator < (const CMsgObjectIndex& a) const |
208 |
{ |
209 |
return Raw < a.Raw;
|
210 |
} |
211 |
}; |
212 |
|
213 |
typedef CObjCircMapper<uint8, CMsgObjectIndex, 0x7f> TObjectIndexCircMapper; |
214 |
|
215 |
/**
|
216 |
* Database update message |
217 |
*/ |
218 |
class CDbMessage |
219 |
{ |
220 |
public:
|
221 |
|
222 |
CDbMessage() : Selected(false), ContextDepth(0), _ObjectIdPresent(false) { } |
223 |
|
224 |
|
225 |
/// Type of message, 4bits -> 16 message types available
|
226 |
enum THeaderType
|
227 |
{ |
228 |
UpdateValue = 0,
|
229 |
SetParent = 1,
|
230 |
AllocRow = 2,
|
231 |
DeallocRow = 3,
|
232 |
ReleaseRow = 4,
|
233 |
|
234 |
EndRemapMessages = 4,
|
235 |
|
236 |
LoadRow = 5,
|
237 |
AddString = 6,
|
238 |
UnmapString = 7,
|
239 |
|
240 |
Log = 8,
|
241 |
PushContext = 9,
|
242 |
PopContext = 10,
|
243 |
|
244 |
LogChat = 11,
|
245 |
|
246 |
End |
247 |
}; |
248 |
|
249 |
|
250 |
/// \name setup message methods
|
251 |
// @{
|
252 |
|
253 |
/// update value
|
254 |
template<typename T> |
255 |
void updateValue(TColumnIndex column, const T& value) |
256 |
{ |
257 |
setHeader(UpdateValue); |
258 |
|
259 |
uint sz = 0;
|
260 |
|
261 |
|
262 |
|
263 |
//union // 64 bits
|
264 |
//{
|
265 |
// uint8 _Value0[8];
|
266 |
// uint16 _Value1[4];
|
267 |
// uint32 _Value2[2];
|
268 |
// uint64 _Value3[1];
|
269 |
//};
|
270 |
|
271 |
|
272 |
|
273 |
// update 20101119 by packpro
|
274 |
if (sizeof(value) == 1) {sz = 0; memcpy(&(_Value0[0]), &value, sizeof(value));} |
275 |
else if (sizeof(value) == 2) |
276 |
{ |
277 |
sz = 1;
|
278 |
memcpy(&(_Value1[0]), &value, sizeof(value)); |
279 |
} |
280 |
else if (sizeof(value) == 4) |
281 |
{ |
282 |
sz = 2;
|
283 |
memcpy(&(_Value2[0]), &value, sizeof(value)); |
284 |
} |
285 |
else if (sizeof(value) == 8) |
286 |
{ |
287 |
sz = 3;
|
288 |
memcpy(&(_Value3[0]), &value, sizeof(value)); |
289 |
} |
290 |
|
291 |
// if (sizeof(value) == 1) { sz = 0; _Value0[0] = *(uint8*)(&value); }
|
292 |
// else if (sizeof(value) == 2) { sz = 1; _Value1[0] = *(uint16*)(&value); }
|
293 |
// else if (sizeof(value) == 4) { sz = 2; _Value2[0] = *(uint32*)(&value); }
|
294 |
// else if (sizeof(value) == 8) { sz = 3; _Value3[0] = *(uint64*)(&value); }
|
295 |
|
296 |
_ColumnAndSize = (uint16)(column | (sz << 14));
|
297 |
} |
298 |
|
299 |
/// update value
|
300 |
template<typename T> |
301 |
void updateValue(TColumnIndex column, const T& value, const NLMISC::CEntityId& objectId) |
302 |
{ |
303 |
setHeader(UpdateValue); |
304 |
uint sz; |
305 |
|
306 |
|
307 |
// update 20101119 by packpro
|
308 |
if (sizeof(value) == 1){sz = 0; memcpy(&(_Value0[0]), &value, sizeof(value));} |
309 |
else if (sizeof(value) == 2) |
310 |
{ |
311 |
sz = 1;
|
312 |
memcpy(&(_Value1[0]), &value, sizeof(value)); |
313 |
} |
314 |
else if (sizeof(value) == 4) |
315 |
{ |
316 |
sz = 2;
|
317 |
memcpy(&(_Value2[0]), &value, sizeof(value)); |
318 |
} |
319 |
else if (sizeof(value) == 8) |
320 |
{ |
321 |
sz = 3;
|
322 |
memcpy(&(_Value3[0]), &value, sizeof(value)); |
323 |
} |
324 |
// if (sizeof(value) == 1) { sz = 0; _Value0[0] = *(uint8*)(&value); }
|
325 |
// else if (sizeof(value) == 2) { sz = 1; _Value1[0] = *(uint16*)(&value); }
|
326 |
// else if (sizeof(value) == 4) { sz = 2; _Value2[0] = *(uint32*)(&value); }
|
327 |
// else if (sizeof(value) == 8) { sz = 3; _Value3[0] = *(uint64*)(&value); }
|
328 |
|
329 |
_ColumnAndSize = (uint16)(column | (sz << 14));
|
330 |
|
331 |
//_MapTableRow |= MESSAGE_REMAP_ENTITYID_PRESENT;
|
332 |
_ObjectIdPresent = true;
|
333 |
_ObjectId = objectId; |
334 |
} |
335 |
|
336 |
/// set parent
|
337 |
void setParent(TColumnIndex column, const CObjectIndex& parent) |
338 |
{ |
339 |
setHeader(SetParent); |
340 |
|
341 |
_ColumnAndSize = (uint16)column; |
342 |
_Value3[0] = *(uint64*)(&parent);
|
343 |
} |
344 |
|
345 |
/// set parent, only child object has an entityId as key
|
346 |
void setParent(TColumnIndex column, const CObjectIndex& parent, const NLMISC::CEntityId& objectId) |
347 |
{ |
348 |
setHeader(SetParent); |
349 |
|
350 |
_ColumnAndSize = (uint16)column; |
351 |
_Value3[0] = *(uint64*)(&parent);
|
352 |
|
353 |
//_MapTableRow |= MESSAGE_REMAP_ENTITYID_PRESENT;
|
354 |
_ObjectIdPresent = true;
|
355 |
_ObjectId = objectId; |
356 |
} |
357 |
|
358 |
/// set parent, only parent object has an entityId as key
|
359 |
void setParent(TColumnIndex column, const CObjectIndex& parent, const NLMISC::CEntityId& newParentId, const NLMISC::CEntityId& previousParentId) |
360 |
{ |
361 |
setHeader(SetParent); |
362 |
|
363 |
_ColumnAndSize = (uint16)column; |
364 |
_Value3[0] = *(uint64*)(&parent);
|
365 |
|
366 |
_ColumnAndSize |= MESSAGE_SETPARENT_ENTITYID_PRESENT; |
367 |
_NewParentId = newParentId; |
368 |
_PreviousParentId = previousParentId; |
369 |
} |
370 |
|
371 |
/// set parent, both child and parent objects have an entityId as key
|
372 |
void setParent(TColumnIndex column, const CObjectIndex& parent, const NLMISC::CEntityId& objectId, const NLMISC::CEntityId& newParentId, const NLMISC::CEntityId& previousParentId) |
373 |
{ |
374 |
setHeader(SetParent); |
375 |
|
376 |
_ColumnAndSize = (uint16)column; |
377 |
_Value3[0] = *(uint64*)(&parent);
|
378 |
|
379 |
//_MapTableRow |= MESSAGE_REMAP_ENTITYID_PRESENT;
|
380 |
_ObjectIdPresent = true;
|
381 |
_ObjectId = objectId; |
382 |
|
383 |
_ColumnAndSize |= MESSAGE_SETPARENT_ENTITYID_PRESENT; |
384 |
_NewParentId = newParentId; |
385 |
_PreviousParentId = previousParentId; |
386 |
} |
387 |
|
388 |
/// Is Object EntityId present
|
389 |
bool objectEntityIdPresent() const |
390 |
{ |
391 |
//return (_MapTableRow & MESSAGE_REMAP_ENTITYID_PRESENT) != 0;
|
392 |
return _ObjectIdPresent;
|
393 |
} |
394 |
|
395 |
/// Are Parents EntityId present
|
396 |
bool parentsEntityIdPresent() const |
397 |
{ |
398 |
return (_ColumnAndSize & MESSAGE_SETPARENT_ENTITYID_PRESENT) != 0; |
399 |
} |
400 |
|
401 |
/// allocate row
|
402 |
void allocRow(uint64 key)
|
403 |
{ |
404 |
setHeader(AllocRow); |
405 |
|
406 |
_Value3[0] = key;
|
407 |
} |
408 |
|
409 |
/// deallocate row
|
410 |
void deallocRow()
|
411 |
{ |
412 |
setHeader(DeallocRow); |
413 |
} |
414 |
|
415 |
/// allocate row
|
416 |
void allocRow(uint64 key, const NLMISC::CEntityId& objectId) |
417 |
{ |
418 |
setHeader(AllocRow); |
419 |
|
420 |
//_MapTableRow |= MESSAGE_REMAP_ENTITYID_PRESENT;
|
421 |
_ObjectIdPresent = true;
|
422 |
_ObjectId = objectId; |
423 |
|
424 |
_Value3[0] = key;
|
425 |
} |
426 |
|
427 |
/// deallocate row
|
428 |
void deallocRow(const NLMISC::CEntityId& objectId) |
429 |
{ |
430 |
setHeader(DeallocRow); |
431 |
|
432 |
//_MapTableRow |= MESSAGE_REMAP_ENTITYID_PRESENT;
|
433 |
_ObjectIdPresent = true;
|
434 |
_ObjectId = objectId; |
435 |
} |
436 |
|
437 |
/// load row
|
438 |
void loadRow(TTableIndex table, uint64 key)
|
439 |
{ |
440 |
setHeader(LoadRow); |
441 |
|
442 |
_ObjectIndex.set((uint8)table, 0);
|
443 |
//_Table = (uint8)table;
|
444 |
_Value3[0] = key;
|
445 |
} |
446 |
|
447 |
|
448 |
|
449 |
/// Add string
|
450 |
void addString(uint64 skey, const ucstring& str) |
451 |
{ |
452 |
setHeader(AddString); |
453 |
|
454 |
_Value3[0] = skey;
|
455 |
_String = str; |
456 |
} |
457 |
|
458 |
/// Add string
|
459 |
void unmapString(uint64 skey)
|
460 |
{ |
461 |
setHeader(UnmapString); |
462 |
|
463 |
_Value3[0] = skey;
|
464 |
} |
465 |
|
466 |
/// Release a row in memory
|
467 |
void releaseRow()
|
468 |
{ |
469 |
setHeader(ReleaseRow); |
470 |
} |
471 |
|
472 |
|
473 |
|
474 |
|
475 |
|
476 |
/// Log message
|
477 |
void log(uint logId, uint bufferByteSize)
|
478 |
{ |
479 |
setHeader(Log); |
480 |
_LogId = logId; |
481 |
_LogBuffer.resize(bufferByteSize); |
482 |
} |
483 |
|
484 |
/// Push Log Parameter
|
485 |
template<typename T> |
486 |
void pushParameter(uint byteOffset, const T& parameter) |
487 |
{ |
488 |
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())); |
489 |
memcpy(&(_LogBuffer[byteOffset]), ¶meter, sizeof(parameter));
|
490 |
} |
491 |
|
492 |
/// Push Log Parameter (string)
|
493 |
void pushParameter(uint byteOffset, const std::string& parameter) |
494 |
{ |
495 |
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())); |
496 |
// get current string index
|
497 |
uint16 bo = (uint16)_ExtLogBuffer.size(); |
498 |
_ExtLogBuffer.resize(bo+parameter.size()+1);
|
499 |
memcpy(&(_ExtLogBuffer[bo]), parameter.c_str(), parameter.size()+1);
|
500 |
memcpy(&(_LogBuffer[byteOffset]), &bo, sizeof(uint16));
|
501 |
} |
502 |
|
503 |
/// Push Log Context
|
504 |
void pushContext()
|
505 |
{ |
506 |
setHeader(PushContext); |
507 |
} |
508 |
|
509 |
/// Pop Log Context
|
510 |
void popContext()
|
511 |
{ |
512 |
setHeader(PopContext); |
513 |
} |
514 |
|
515 |
|
516 |
|
517 |
|
518 |
/// Log Chat sentence
|
519 |
void logChat(const ucstring& sentence, const NLMISC::CEntityId& sender, const std::vector<NLMISC::CEntityId>& receivers) |
520 |
{ |
521 |
setHeader(LogChat); |
522 |
_String = sentence; |
523 |
*(NLMISC::CEntityId*)(&(_Value3[0])) = sender;
|
524 |
|
525 |
uint bufferSize = (uint)receivers.size()*sizeof(NLMISC::CEntityId);
|
526 |
if (bufferSize > 0) |
527 |
{ |
528 |
_LogBuffer.resize(bufferSize); |
529 |
NLMISC::CEntityId* srcBuffer = (NLMISC::CEntityId*)(&(receivers[0]));
|
530 |
NLMISC::CEntityId* dstBuffer = (NLMISC::CEntityId*)(&(_LogBuffer[0]));
|
531 |
memcpy(dstBuffer, srcBuffer, bufferSize); |
532 |
} |
533 |
else
|
534 |
{ |
535 |
_LogBuffer.clear(); |
536 |
} |
537 |
} |
538 |
|
539 |
|
540 |
// @}
|
541 |
|
542 |
|
543 |
/// Get message type
|
544 |
THeaderType getType() const { return _Type; } |
545 |
|
546 |
/// Set Type of message
|
547 |
void setType(THeaderType type) { _Type = type; }
|
548 |
|
549 |
|
550 |
|
551 |
/// \name common part methods
|
552 |
// @{
|
553 |
|
554 |
TTableIndex getTable() const { return (TTableIndex)_ObjectIndex.Table; } |
555 |
TRowIndex getRow() const { return (TRowIndex)_ObjectIndex.Row; } |
556 |
uint32 getStringId() const { return _StringId; } |
557 |
|
558 |
// @}
|
559 |
|
560 |
|
561 |
|
562 |
/// \name Update database value specific methods
|
563 |
// @{
|
564 |
|
565 |
TColumnIndex getColumn() const { return (TColumnIndex)(_ColumnAndSize&0x3fff); } |
566 |
const void* getData() const { return &_Value0[0]; } |
567 |
uint getDatasize() const { return 1 << (_ColumnAndSize>>14); } |
568 |
uint8 getValue8bits() const { return _Value0[0]; } |
569 |
uint16 getValue16bits() const { return _Value1[0]; } |
570 |
uint32 getValue32bits() const { return _Value2[0]; } |
571 |
uint64 getValue64bits() const { return _Value3[0]; } |
572 |
CObjectIndex getObjectIndex() const { return *(CObjectIndex*)(&(_Value3[0])); } |
573 |
const ucstring& getString() const { return _String; } |
574 |
|
575 |
bool asBool() const { return _Value0[0] != 0; } |
576 |
char asChar() const { return (char)_Value0[0]; } |
577 |
ucchar asUCChar() const { return (ucchar)_Value1[0]; } |
578 |
uint8 asUint8() const { return (uint8)_Value0[0]; } |
579 |
uint16 asUint16() const { return (uint16)_Value1[0]; } |
580 |
uint32 asUint32() const { return (uint32)_Value2[0]; } |
581 |
uint64 asUint64() const { return (uint64)_Value3[0]; } |
582 |
sint8 asSint8() const { return (sint8)_Value0[0]; } |
583 |
sint16 asSint16() const { return (sint16)_Value1[0]; } |
584 |
sint32 asSint32() const { return (sint32)_Value2[0]; } |
585 |
sint64 asSint64() const { return (sint64)_Value3[0]; } |
586 |
float asFloat() const { return *(float*)(&_Value2[0]); } |
587 |
double asDouble() const { return *(double*)(&_Value3[0]); } |
588 |
const NLMISC::CSheetId& asSheetId() const { return *(NLMISC::CSheetId*)(&_Value2[0]); } |
589 |
const NLMISC::CEntityId& asEntityId() const { return *(NLMISC::CEntityId*)(&_Value3[0]); } |
590 |
|
591 |
const NLMISC::CEntityId& getObjectId() const { return _ObjectId; } |
592 |
const NLMISC::CEntityId& getNewParentId() const { return _NewParentId; } |
593 |
const NLMISC::CEntityId& getPreviousParentId() const { return _PreviousParentId; } |
594 |
|
595 |
uint16 getLogId() const { return _LogId; } |
596 |
const std::vector<uint8>& getLogBuffer() const { return _LogBuffer; } |
597 |
|
598 |
void setupTableAndRow(TTableIndex table, TRowIndex row)
|
599 |
{ |
600 |
_ObjectIndex.set((uint8)table, (uint32)row); |
601 |
} |
602 |
|
603 |
// @}
|
604 |
|
605 |
/// \name Log analysis/display
|
606 |
// @{
|
607 |
|
608 |
/// Dump Message content to string as a human readable message
|
609 |
void getHRContent(const CDBDescriptionParser& description, std::string& result) const; |
610 |
|
611 |
/// Does message contains CEntityId?
|
612 |
bool contains(const CDBDescriptionParser& description, const NLMISC::CEntityId& id); |
613 |
|
614 |
/// Does message contains string?
|
615 |
bool contains(const CDBDescriptionParser& description, const std::string& str); |
616 |
|
617 |
/// Build Log string
|
618 |
std::string buildLogString(const CDBDescriptionParser& description) const; |
619 |
|
620 |
/// Is Value modified
|
621 |
bool valueModified(uint table, uint column)
|
622 |
{ |
623 |
return ((getType() == UpdateValue || getType() == SetParent) && getTable() == table && getColumn() == column);
|
624 |
} |
625 |
|
626 |
/// Is message selected
|
627 |
bool Selected;
|
628 |
/// Message context depth
|
629 |
uint16 ContextDepth; |
630 |
|
631 |
// @}
|
632 |
|
633 |
/// \name Serializing
|
634 |
// @{
|
635 |
|
636 |
/// Serial message
|
637 |
void serial(NLMISC::IStream &f, TObjectIndexCircMapper& indexMapper, TEntityIdCircMapper& eidMapper);
|
638 |
|
639 |
/// Get Message Header Size
|
640 |
uint32 getMessageHeaderSize(); |
641 |
|
642 |
// @}
|
643 |
|
644 |
private:
|
645 |
|
646 |
/**
|
647 |
* Type of message |
648 |
* Type is not serialised directly in message, but in containing folder |
649 |
*/ |
650 |
THeaderType _Type; |
651 |
|
652 |
|
653 |
/**
|
654 |
* Message Id |
655 |
* Refers to the 'entity' used/updated by the message |
656 |
*/ |
657 |
union // 32 bits |
658 |
{ |
659 |
uint32 _StringId; |
660 |
uint16 _LogId; |
661 |
}; |
662 |
|
663 |
/// \name Extra info
|
664 |
// @{
|
665 |
|
666 |
uint16 _ColumnAndSize; |
667 |
|
668 |
CMsgObjectIndex _ObjectIndex; |
669 |
|
670 |
union // 64 bits |
671 |
{ |
672 |
uint8 _Value0[8];
|
673 |
uint16 _Value1[4];
|
674 |
uint32 _Value2[2];
|
675 |
uint64 _Value3[1];
|
676 |
}; |
677 |
|
678 |
bool _ObjectIdPresent;
|
679 |
NLMISC::CEntityId _ObjectId; |
680 |
NLMISC::CEntityId _NewParentId; |
681 |
NLMISC::CEntityId _PreviousParentId; |
682 |
|
683 |
ucstring _String; |
684 |
std::vector<uint8> _LogBuffer; |
685 |
std::vector<uint8> _ExtLogBuffer; |
686 |
|
687 |
// @}
|
688 |
|
689 |
void setHeader(THeaderType type) { _Type = type; }
|
690 |
}; |
691 |
|
692 |
|
693 |
|
694 |
|
695 |
|
696 |
|
697 |
/**
|
698 |
* A Folder a Db Messages, all of the same kind. |
699 |
* Based on the assumption that update value messages are the main kind of messages |
700 |
* and that the follow in series... |
701 |
* Thus, it should save one byte per message... |
702 |
*/ |
703 |
class CDbMessageFolder |
704 |
{ |
705 |
public:
|
706 |
|
707 |
CDbMessageFolder() |
708 |
{ |
709 |
_Type = 0xff;
|
710 |
_NumMessages = 0;
|
711 |
} |
712 |
|
713 |
/**
|
714 |
* Constructor |
715 |
*/ |
716 |
CDbMessageFolder(uint8 type) |
717 |
{ |
718 |
_Type = type; |
719 |
_NumMessages = 0;
|
720 |
} |
721 |
|
722 |
|
723 |
/**
|
724 |
* Get Folder Type |
725 |
*/ |
726 |
uint8 getType() const { return _Type; } |
727 |
|
728 |
/**
|
729 |
* Get Number of messages in folder |
730 |
*/ |
731 |
uint32 getNumMessages() const { return _NumMessages; } |
732 |
|
733 |
/**
|
734 |
* Folder is full |
735 |
*/ |
736 |
bool full() const { return _NumMessages == MAX_MESSAGE_REMAP; } |
737 |
|
738 |
/**
|
739 |
* Add a message to folder |
740 |
*/ |
741 |
void addMessage(const CDbMessage& msg) |
742 |
{ |
743 |
nlassert(_NumMessages < MAX_MESSAGE_REMAP); |
744 |
nlassert(msg.getType() == _Type); |
745 |
++_NumMessages; |
746 |
} |
747 |
|
748 |
/**
|
749 |
* Serialise folder |
750 |
*/ |
751 |
void serial(NLMISC::IStream& f)
|
752 |
{ |
753 |
f.serial(_Type, _NumMessages); |
754 |
nlassert(_Type < CDbMessage::End); |
755 |
} |
756 |
|
757 |
private:
|
758 |
|
759 |
/// Type of messages in folder
|
760 |
uint8 _Type; |
761 |
|
762 |
/// Number of messages in folder
|
763 |
uint16 _NumMessages; |
764 |
}; |
765 |
|
766 |
|
767 |
|
768 |
|
769 |
|
770 |
|
771 |
|
772 |
|
773 |
/**
|
774 |
* A Queue of messages |
775 |
*/ |
776 |
class CDbMessageQueue |
777 |
{ |
778 |
public:
|
779 |
|
780 |
/**
|
781 |
* Constructor |
782 |
*/ |
783 |
CDbMessageQueue() |
784 |
{ |
785 |
clear(); |
786 |
} |
787 |
|
788 |
/**
|
789 |
* Clear |
790 |
*/ |
791 |
void clear()
|
792 |
{ |
793 |
_Messages.clear(); |
794 |
_Folders.clear(); |
795 |
} |
796 |
|
797 |
/**
|
798 |
* Get Next Message to be written |
799 |
*/ |
800 |
CDbMessage& nextMessage() |
801 |
{ |
802 |
_Messages.resize(_Messages.size()+1);
|
803 |
return _Messages.back();
|
804 |
} |
805 |
|
806 |
/**
|
807 |
* Get Current Message to be written |
808 |
*/ |
809 |
CDbMessage& currentMessage() |
810 |
{ |
811 |
nlassert(!_Messages.empty()); |
812 |
return _Messages.back();
|
813 |
} |
814 |
|
815 |
|
816 |
/**
|
817 |
* Get Number of Messages in queue |
818 |
*/ |
819 |
uint32 getNumMessages() const
|
820 |
{ |
821 |
return (uint32)_Messages.size();
|
822 |
} |
823 |
|
824 |
/**
|
825 |
* Get Message |
826 |
*/ |
827 |
CDbMessage& getMessage(uint32 message) |
828 |
{ |
829 |
nlassert(message < _Messages.size()); |
830 |
return _Messages[message];
|
831 |
} |
832 |
|
833 |
/**
|
834 |
* Serialise message queue |
835 |
*/ |
836 |
void serial(NLMISC::IStream& f)
|
837 |
{ |
838 |
H_AUTO(PDLIB_MsgQueue_serial); |
839 |
|
840 |
// build folders first if writing to stream
|
841 |
if (!f.isReading())
|
842 |
{ |
843 |
buildFolders(); |
844 |
} |
845 |
|
846 |
uint32 numFolders = (uint32)_Folders.size(); |
847 |
uint32 numMessages = (uint32)_Messages.size(); |
848 |
|
849 |
f.serial(numFolders); |
850 |
f.serial(numMessages); |
851 |
|
852 |
if (f.isReading())
|
853 |
{ |
854 |
_Folders.resize(numFolders); |
855 |
_Messages.resize(numMessages); |
856 |
} |
857 |
|
858 |
//f.serialCont(_BackRemap);
|
859 |
|
860 |
TEntityIdCircMapper EIdMapper; |
861 |
TObjectIndexCircMapper IndexMapper; |
862 |
|
863 |
// for each folder, write message stored in it
|
864 |
uint i, message = 0;
|
865 |
for (i=0; i<_Folders.size(); ++i) |
866 |
{ |
867 |
CDbMessageFolder& folder = _Folders[i]; |
868 |
f.serial(folder); |
869 |
|
870 |
uint j; |
871 |
for (j=0; j<folder.getNumMessages(); ++j) |
872 |
{ |
873 |
nlassert(message < numMessages); |
874 |
|
875 |
CDbMessage& msg = _Messages[message++]; |
876 |
msg.setType((CDbMessage::THeaderType)folder.getType()); |
877 |
|
878 |
msg.serial(f, IndexMapper, EIdMapper); |
879 |
} |
880 |
} |
881 |
|
882 |
// remap messages
|
883 |
if (f.isReading())
|
884 |
{ |
885 |
uint currentDepth = 0;
|
886 |
for (i=0; i<_Messages.size(); ++i) |
887 |
{ |
888 |
CDbMessage& msg = _Messages[i]; |
889 |
|
890 |
if (msg.getType() == CDbMessage::PopContext)
|
891 |
--currentDepth; |
892 |
msg.ContextDepth = currentDepth; |
893 |
if (msg.getType() == CDbMessage::PushContext)
|
894 |
++currentDepth; |
895 |
} |
896 |
} |
897 |
} |
898 |
|
899 |
|
900 |
private:
|
901 |
|
902 |
/// List of messages
|
903 |
std::vector<CDbMessage> _Messages; |
904 |
|
905 |
/// List of folders
|
906 |
std::vector<CDbMessageFolder> _Folders; |
907 |
|
908 |
|
909 |
/**
|
910 |
* Build message folders |
911 |
*/ |
912 |
void buildFolders()
|
913 |
{ |
914 |
_Folders.clear(); |
915 |
|
916 |
uint i; |
917 |
for (i=0; i<_Messages.size(); ++i) |
918 |
{ |
919 |
if (_Folders.empty() || _Folders.back().full() || _Messages[i].getType() != _Folders.back().getType())
|
920 |
_Folders.push_back(CDbMessageFolder(_Messages[i].getType())); |
921 |
|
922 |
_Folders.back().addMessage(_Messages[i]); |
923 |
} |
924 |
} |
925 |
|
926 |
}; |
927 |
|
928 |
|
929 |
|
930 |
|
931 |
|
932 |
/**
|
933 |
* A Split Queue |
934 |
* Handle multiple queues, so one update may be splitted into multiple messages |
935 |
*/ |
936 |
class CDbMessageSplitQueue |
937 |
{ |
938 |
public:
|
939 |
|
940 |
/**
|
941 |
* Constructor |
942 |
*/ |
943 |
CDbMessageSplitQueue() |
944 |
{ |
945 |
} |
946 |
|
947 |
/**
|
948 |
* Clearup |
949 |
*/ |
950 |
void clear()
|
951 |
{ |
952 |
_Queues.clear(); |
953 |
} |
954 |
|
955 |
/**
|
956 |
* Get Next Message to be written, no mapping to be done |
957 |
*/ |
958 |
CDbMessage& nextMessage() |
959 |
{ |
960 |
if (empty())
|
961 |
forceNextQueue(); |
962 |
|
963 |
return _Queues.back().nextMessage();
|
964 |
} |
965 |
|
966 |
/**
|
967 |
* Get Next Remappable Message to be written |
968 |
*/ |
969 |
CDbMessage& nextMessage(uint8 table, uint32 row) |
970 |
{ |
971 |
if (empty())
|
972 |
forceNextQueue(); |
973 |
|
974 |
// here, queue allows to map message
|
975 |
CDbMessage& msg = _Queues.back().nextMessage(); |
976 |
|
977 |
msg.setupTableAndRow(table, row); |
978 |
|
979 |
// and return it
|
980 |
return msg;
|
981 |
} |
982 |
|
983 |
/**
|
984 |
* Get Current Message |
985 |
*/ |
986 |
CDbMessage& currentMessage() |
987 |
{ |
988 |
return _Queues.back().currentMessage();
|
989 |
} |
990 |
|
991 |
/**
|
992 |
* Force MsgQueue to fill next queue |
993 |
*/ |
994 |
void forceNextQueue()
|
995 |
{ |
996 |
if (_Queues.empty() || _Queues.back().getNumMessages() > 0) |
997 |
{ |
998 |
_Queues.push_back(CDbMessageQueue()); |
999 |
} |
1000 |
} |
1001 |
|
1002 |
/**
|
1003 |
* Is Queue Empty? |
1004 |
*/ |
1005 |
bool empty() const |
1006 |
{ |
1007 |
return _Queues.empty();
|
1008 |
} |
1009 |
|
1010 |
/**
|
1011 |
* Number of message in queue |
1012 |
*/ |
1013 |
uint32 getNumMessagesEnqueued() const
|
1014 |
{ |
1015 |
std::list<CDbMessageQueue>::const_iterator it; |
1016 |
uint32 totalMessages = 0;
|
1017 |
for (it=_Queues.begin(); it!=_Queues.end(); ++it)
|
1018 |
totalMessages += (*it).getNumMessages(); |
1019 |
|
1020 |
return totalMessages;
|
1021 |
} |
1022 |
|
1023 |
|
1024 |
/**
|
1025 |
* begin() |
1026 |
*/ |
1027 |
std::list<CDbMessageQueue>::iterator begin() { return _Queues.begin(); }
|
1028 |
|
1029 |
/**
|
1030 |
* end() |
1031 |
*/ |
1032 |
std::list<CDbMessageQueue>::iterator end() { return _Queues.end(); }
|
1033 |
|
1034 |
/**
|
1035 |
* size() |
1036 |
*/ |
1037 |
uint size() const { return (uint)_Queues.size(); } |
1038 |
|
1039 |
/**
|
1040 |
* get() |
1041 |
*/ |
1042 |
CDbMessageQueue& get(uint i) |
1043 |
{ |
1044 |
std::list<CDbMessageQueue>::iterator it = _Queues.begin(); |
1045 |
while (i-- > 0) |
1046 |
++it; |
1047 |
return (*it);
|
1048 |
} |
1049 |
|
1050 |
|
1051 |
private:
|
1052 |
|
1053 |
/// Used Queues
|
1054 |
std::list<CDbMessageQueue> _Queues; |
1055 |
|
1056 |
}; |
1057 |
|
1058 |
|
1059 |
|
1060 |
|
1061 |
|
1062 |
class CUpdateLog |
1063 |
{ |
1064 |
public:
|
1065 |
|
1066 |
CUpdateLog() : UpdateId(0xffffffff), _OwnUpdates(false), _Updates(NULL) { } |
1067 |
|
1068 |
~CUpdateLog(); |
1069 |
|
1070 |
/// UpdateId sent by client for this update
|
1071 |
uint32 UpdateId; |
1072 |
|
1073 |
/// Start date for this update
|
1074 |
CTimestamp StartStamp; |
1075 |
|
1076 |
/// Start date for this update
|
1077 |
CTimestamp EndStamp; |
1078 |
|
1079 |
/// Serial log
|
1080 |
void serial(NLMISC::IStream& f);
|
1081 |
|
1082 |
/// Display UpdateLog content (using a database description)
|
1083 |
void display(const CDBDescriptionParser& description, NLMISC::CLog& log, bool onlySelected = false); |
1084 |
|
1085 |
|
1086 |
|
1087 |
|
1088 |
/**
|
1089 |
* Check log timestamp boundaries |
1090 |
*/ |
1091 |
bool checkTimestampBoundaries(const CTimestamp& begin, const CTimestamp& end); |
1092 |
|
1093 |
/**
|
1094 |
* Is Empty |
1095 |
*/ |
1096 |
bool isEmpty();
|
1097 |
|
1098 |
/**
|
1099 |
* Select contexts and messages containing a given entityId |
1100 |
* return true if there were at least one message selected |
1101 |
*/ |
1102 |
bool selectMessages(const CDBDescriptionParser& description, const NLMISC::CEntityId& id); |
1103 |
|
1104 |
/**
|
1105 |
* Select contexts and messages containing a given string |
1106 |
* return true if there were at least one message selected |
1107 |
*/ |
1108 |
bool selectMessages(const CDBDescriptionParser& description, const std::string& str); |
1109 |
|
1110 |
/**
|
1111 |
* Select contexts and messages containing modification of a value for a given entityId |
1112 |
* return true if there were at least one message selected |
1113 |
*/ |
1114 |
bool selectMessages(const CDBDescriptionParser& description, const NLMISC::CEntityId& id, const std::string& valuePath); |
1115 |
|
1116 |
/**
|
1117 |
* Select contexts and messages containing a list of entityIds (limited at most to 32 entityIds) |
1118 |
* return true if there were at least one message selected |
1119 |
*/ |
1120 |
bool selectMessages(const CDBDescriptionParser& description, const std::vector<NLMISC::CEntityId>& ids); |
1121 |
|
1122 |
class CLogProcessor |
1123 |
{ |
1124 |
public:
|
1125 |
/// process log, return true if some messages were selected
|
1126 |
virtual bool processLog(CUpdateLog& log, const CDBDescriptionParser& description) = 0; |
1127 |
}; |
1128 |
|
1129 |
/**
|
1130 |
* Apply process on log files |
1131 |
*/ |
1132 |
static void processLogs(const std::string& path, |
1133 |
const CTimestamp& begin,
|
1134 |
const CTimestamp& end,
|
1135 |
NLMISC::CLog& log, |
1136 |
CLogProcessor* processor, |
1137 |
float* progress = NULL); |
1138 |
|
1139 |
/**
|
1140 |
* Display log for a given entity id, between 2 dates |
1141 |
*/ |
1142 |
static void displayLogs(const CDBDescriptionParser& description, |
1143 |
const NLMISC::CEntityId& id,
|
1144 |
const CTimestamp& begin,
|
1145 |
const CTimestamp& end,
|
1146 |
const std::string& path,
|
1147 |
NLMISC::CLog& log, |
1148 |
float* progress = NULL); |
1149 |
|
1150 |
/**
|
1151 |
* Display log between 2 dates |
1152 |
*/ |
1153 |
static void displayLogs(const std::string& path, |
1154 |
const CTimestamp& begin,
|
1155 |
const CTimestamp& end,
|
1156 |
NLMISC::CLog& log, |
1157 |
float* progress = NULL); |
1158 |
|
1159 |
/**
|
1160 |
* Display log for a given entity id, between 2 dates |
1161 |
*/ |
1162 |
static void displayLogs(const std::string& path, |
1163 |
const NLMISC::CEntityId& id,
|
1164 |
const CTimestamp& begin,
|
1165 |
const CTimestamp& end,
|
1166 |
NLMISC::CLog& log, |
1167 |
float* progress = NULL); |
1168 |
|
1169 |
/**
|
1170 |
* Display log for a given entity id and a specified value to be modified, between 2 dates |
1171 |
*/ |
1172 |
static void displayLogs(const std::string& path, |
1173 |
const NLMISC::CEntityId& id,
|
1174 |
const std::string& valuePath,
|
1175 |
const CTimestamp& begin,
|
1176 |
const CTimestamp& end,
|
1177 |
NLMISC::CLog& log, |
1178 |
float* progress = NULL); |
1179 |
|
1180 |
/**
|
1181 |
* Display log for a list of given entity id, between 2 dates |
1182 |
*/ |
1183 |
static void displayLogs(const std::string& path, |
1184 |
const std::vector<NLMISC::CEntityId>& ids,
|
1185 |
const CTimestamp& begin,
|
1186 |
const CTimestamp& end,
|
1187 |
NLMISC::CLog& log, |
1188 |
float* progress = NULL); |
1189 |
|
1190 |
/**
|
1191 |
* Display log for a list of given entity id, between 2 dates |
1192 |
*/ |
1193 |
static void displayLogs(const std::string& path, |
1194 |
const std::string& str,
|
1195 |
const CTimestamp& begin,
|
1196 |
const CTimestamp& end,
|
1197 |
NLMISC::CLog& log, |
1198 |
float* progress = NULL); |
1199 |
|
1200 |
/**
|
1201 |
* Elect matching description |
1202 |
*/ |
1203 |
static std::string electDescription(const std::string& logFile); |
1204 |
|
1205 |
|
1206 |
|
1207 |
|
1208 |
/**
|
1209 |
* Set updates |
1210 |
*/ |
1211 |
void setUpdates(CDbMessageQueue* updates);
|
1212 |
|
1213 |
/**
|
1214 |
* Create updates |
1215 |
*/ |
1216 |
void createUpdates();
|
1217 |
|
1218 |
/**
|
1219 |
* Get Updates |
1220 |
*/ |
1221 |
CDbMessageQueue* getUpdates() { return _Updates; }
|
1222 |
|
1223 |
private:
|
1224 |
|
1225 |
bool _OwnUpdates;
|
1226 |
|
1227 |
/// Updates contained in message
|
1228 |
CDbMessageQueue* _Updates; |
1229 |
|
1230 |
/// Release Updates (and delete if owned)
|
1231 |
void releaseUpdates()
|
1232 |
{ |
1233 |
if (_OwnUpdates && _Updates != NULL) |
1234 |
delete _Updates; |
1235 |
|
1236 |
_Updates = NULL;
|
1237 |
_OwnUpdates = false;
|
1238 |
} |
1239 |
}; |
1240 |
|
1241 |
|
1242 |
|
1243 |
|
1244 |
|
1245 |
//
|
1246 |
// CDbMessage inline methods
|
1247 |
//
|
1248 |
|
1249 |
inline void CDbMessage::serial(NLMISC::IStream &f, TObjectIndexCircMapper& indexMapper, TEntityIdCircMapper& eidMapper) |
1250 |
{ |
1251 |
switch (_Type)
|
1252 |
{ |
1253 |
case UpdateValue:
|
1254 |
{ |
1255 |
uint8 flags = (objectEntityIdPresent() ? 0x80 : 0); |
1256 |
indexMapper.serial(f, _ObjectIndex, flags); |
1257 |
_ObjectIdPresent = ((flags & 0x80) != 0); |
1258 |
|
1259 |
f.serial(_ColumnAndSize); |
1260 |
|
1261 |
switch (_ColumnAndSize & 0xc000) |
1262 |
{ |
1263 |
case 0x0000: f.serial(_Value0[0]); break; |
1264 |
case 0x4000: f.serial(_Value1[0]); break; |
1265 |
case 0x8000: f.serial(_Value2[0]); break; |
1266 |
case 0xc000: f.serial(_Value3[0]); break; |
1267 |
} |
1268 |
|
1269 |
// serial owner CEntityId if present
|
1270 |
if (objectEntityIdPresent())
|
1271 |
eidMapper.serial(f, _ObjectId); |
1272 |
} |
1273 |
break;
|
1274 |
|
1275 |
case SetParent:
|
1276 |
{ |
1277 |
uint8 flags = (objectEntityIdPresent() ? 0x80 : 0); |
1278 |
indexMapper.serial(f, _ObjectIndex, flags); |
1279 |
_ObjectIdPresent = ((flags & 0x80) != 0); |
1280 |
f.serial(_ColumnAndSize); |
1281 |
f.serial(_Value3[0]);
|
1282 |
|
1283 |
// serial object CEntityId if present
|
1284 |
if (objectEntityIdPresent())
|
1285 |
eidMapper.serial(f, _ObjectId); |
1286 |
|
1287 |
// serial parents CEntityId if present
|
1288 |
if ((_ColumnAndSize & MESSAGE_SETPARENT_ENTITYID_PRESENT) != 0) |
1289 |
{ |
1290 |
eidMapper.serial(f, _NewParentId); |
1291 |
eidMapper.serial(f, _PreviousParentId); |
1292 |
} |
1293 |
} |
1294 |
break;
|
1295 |
|
1296 |
case AllocRow:
|
1297 |
{ |
1298 |
uint8 flags = (objectEntityIdPresent() ? 0x80 : 0); |
1299 |
indexMapper.serial(f, _ObjectIndex, flags); |
1300 |
_ObjectIdPresent = ((flags & 0x80) != 0); |
1301 |
f.serial(_Value3[0]);
|
1302 |
|
1303 |
// serial owner CEntityId if present
|
1304 |
if (objectEntityIdPresent())
|
1305 |
eidMapper.serial(f, _ObjectId); |
1306 |
} |
1307 |
break;
|
1308 |
|
1309 |
case DeallocRow:
|
1310 |
{ |
1311 |
uint8 flags = (objectEntityIdPresent() ? 0x80 : 0); |
1312 |
indexMapper.serial(f, _ObjectIndex, flags); |
1313 |
_ObjectIdPresent = ((flags & 0x80) != 0); |
1314 |
// serial owner CEntityId if present
|
1315 |
if (objectEntityIdPresent())
|
1316 |
eidMapper.serial(f, _ObjectId); |
1317 |
} |
1318 |
break;
|
1319 |
|
1320 |
case LoadRow:
|
1321 |
f.serial(_ObjectIndex.Table); |
1322 |
f.serial(_Value3[0]);
|
1323 |
break;
|
1324 |
|
1325 |
case AddString:
|
1326 |
f.serial(_Value3[0]);
|
1327 |
f.serial(_String); |
1328 |
break;
|
1329 |
|
1330 |
case UnmapString:
|
1331 |
f.serial(_Value3[0]);
|
1332 |
break;
|
1333 |
|
1334 |
case ReleaseRow:
|
1335 |
indexMapper.serial(f, _ObjectIndex); |
1336 |
break;
|
1337 |
|
1338 |
case Log:
|
1339 |
{ |
1340 |
f.serial(_LogId); |
1341 |
|
1342 |
if (f.isReading())
|
1343 |
{ |
1344 |
uint8 sz; |
1345 |
|
1346 |
f.serial(sz); |
1347 |
_LogBuffer.resize(sz); |
1348 |
if (sz > 0) |
1349 |
f.serialBuffer(&(_LogBuffer[0]), sz);
|
1350 |
|
1351 |
f.serial(sz); |
1352 |
_ExtLogBuffer.resize(sz); |
1353 |
if (sz > 0) |
1354 |
f.serialBuffer(&(_ExtLogBuffer[0]), sz);
|
1355 |
} |
1356 |
else
|
1357 |
{ |
1358 |
uint8 sz; |
1359 |
nlassert(_LogBuffer.size() <= 255);
|
1360 |
sz = (uint8)_LogBuffer.size(); |
1361 |
f.serial(sz); |
1362 |
if (sz > 0) |
1363 |
f.serialBuffer(&(_LogBuffer[0]), sz);
|
1364 |
|
1365 |
nlassert(_ExtLogBuffer.size() <= 255);
|
1366 |
sz = (uint8)_ExtLogBuffer.size(); |
1367 |
f.serial(sz); |
1368 |
if (sz > 0) |
1369 |
f.serialBuffer(&(_ExtLogBuffer[0]), sz);
|
1370 |
} |
1371 |
} |
1372 |
break;
|
1373 |
|
1374 |
case PushContext:
|
1375 |
break;
|
1376 |
|
1377 |
case PopContext:
|
1378 |
break;
|
1379 |
|
1380 |
case LogChat:
|
1381 |
// serial chat sentence
|
1382 |
f.serial(_String); |
1383 |
// serial sender
|
1384 |
f.serial(_Value3[0]);
|
1385 |
// serial receivers list (whole buffer as uint8*)
|
1386 |
f.serialCont(_LogBuffer); |
1387 |
break;
|
1388 |
|
1389 |
default:
|
1390 |
nlerror("CDbMessage::serial(): unable to serial message type '%d'", _Type);
|
1391 |
break;
|
1392 |
} |
1393 |
} |
1394 |
|
1395 |
/*
|
1396 |
* Get Message Header Size |
1397 |
*/ |
1398 |
inline uint32 CDbMessage::getMessageHeaderSize()
|
1399 |
{ |
1400 |
uint size = 0;
|
1401 |
|
1402 |
switch (_Type)
|
1403 |
{ |
1404 |
case UpdateValue:
|
1405 |
case SetParent:
|
1406 |
size += sizeof(_ObjectIndex.Table)+sizeof(_ObjectIndex.Row); |
1407 |
size += sizeof(_ColumnAndSize);
|
1408 |
break;
|
1409 |
|
1410 |
case AllocRow:
|
1411 |
size += sizeof(_ObjectIndex.Table)+sizeof(_ObjectIndex.Row); |
1412 |
break;
|
1413 |
|
1414 |
case DeallocRow:
|
1415 |
size += sizeof(_ObjectIndex.Table)+sizeof(_ObjectIndex.Row); |
1416 |
break;
|
1417 |
|
1418 |
case LoadRow:
|
1419 |
size += sizeof(_ObjectIndex.Table);
|
1420 |
size += sizeof(_Value3[0]); |
1421 |
break;
|
1422 |
|
1423 |
case ReleaseRow:
|
1424 |
size += sizeof(_ObjectIndex.Table)+sizeof(_ObjectIndex.Row); |
1425 |
break;
|
1426 |
|
1427 |
case Log:
|
1428 |
size += sizeof(_LogId);
|
1429 |
size += 2;
|
1430 |
break;
|
1431 |
|
1432 |
default:
|
1433 |
break;
|
1434 |
} |
1435 |
|
1436 |
return size;
|
1437 |
} |
1438 |
|
1439 |
/*
|
1440 |
* Serial log |
1441 |
*/ |
1442 |
inline void CUpdateLog::serial(NLMISC::IStream& f) |
1443 |
{ |
1444 |
f.serialCheck((uint32)'ULOG'); |
1445 |
|
1446 |
uint version = f.serialVersion(1);
|
1447 |
|
1448 |
f.serial(UpdateId); |
1449 |
|
1450 |
if (version >= 1) |
1451 |
{ |
1452 |
f.serial(StartStamp); |
1453 |
f.serial(EndStamp); |
1454 |
} |
1455 |
|
1456 |
if (f.isReading())
|
1457 |
{ |
1458 |
releaseUpdates(); |
1459 |
_Updates = new RY_PDS::CDbMessageQueue(); |
1460 |
_OwnUpdates = true;
|
1461 |
} |
1462 |
|
1463 |
f.serial(*_Updates); |
1464 |
} |
1465 |
|
1466 |
|
1467 |
}; // RY_PDS
|
1468 |
|
1469 |
#endif //RY_PD_MESSAGES_H |
1470 |
|
1471 |
|