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