pd_messages.h

packpro, 12/23/2010 01:57 pm

Download (32.4 kB)

 
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
                // update 20101119 by packpro
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
                //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

288
                _ColumnAndSize = (uint16)(column | (sz << 14));
289
        }
290

291
        /// update value
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
                // update 20101119 by packpro
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
                //if (sizeof(value) == 1)                        { sz = 0; _Value0[0] = *(uint8*)(&value); }
321
                //else if (sizeof(value) == 2)        { sz = 1; _Value1[0] = *(uint16*)(&value); }
322
                //else if (sizeof(value) == 4)        { sz = 2; _Value2[0] = *(uint32*)(&value); }
323
                //else if (sizeof(value) == 8)        { sz = 3; _Value3[0] = *(uint64*)(&value); }
324

325
                _ColumnAndSize = (uint16)(column | (sz << 14));
326

327
                //_MapTableRow |= MESSAGE_REMAP_ENTITYID_PRESENT;
328
                _ObjectIdPresent = true;
329
                _ObjectId = objectId;
330
        }
331

332
        /// set parent
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
        /// set parent, only child object has an entityId as key
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
                //_MapTableRow |= MESSAGE_REMAP_ENTITYID_PRESENT;
350
                _ObjectIdPresent = true;
351
                _ObjectId = objectId;
352
        }
353

354
        /// set parent, only parent object has an entityId as key
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
        /// set parent, both child and parent objects have an entityId as key
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
                //_MapTableRow |= MESSAGE_REMAP_ENTITYID_PRESENT;
376
                _ObjectIdPresent = true;
377
                _ObjectId = objectId;
378

379
                _ColumnAndSize |= MESSAGE_SETPARENT_ENTITYID_PRESENT;
380
                _NewParentId = newParentId;
381
                _PreviousParentId = previousParentId;
382
        }
383

384
        /// Is Object EntityId present
385
        bool                                        objectEntityIdPresent() const
386
        {
387
                //return (_MapTableRow & MESSAGE_REMAP_ENTITYID_PRESENT) != 0;
388
                return _ObjectIdPresent;
389
        }
390

391
        /// Are Parents EntityId present
392
        bool                                        parentsEntityIdPresent() const
393
        {
394
                return (_ColumnAndSize & MESSAGE_SETPARENT_ENTITYID_PRESENT) != 0;
395
        }
396

397
        /// allocate row
398
        void                                        allocRow(uint64 key)
399
        {
400
                setHeader(AllocRow);
401

402
                _Value3[0] = key;
403
        }
404

405
        /// deallocate row
406
        void                                        deallocRow()
407
        {
408
                setHeader(DeallocRow);
409
        }
410

411
        /// allocate row
412
        void                                        allocRow(uint64 key, const NLMISC::CEntityId& objectId)
413
        {
414
                setHeader(AllocRow);
415

416
                //_MapTableRow |= MESSAGE_REMAP_ENTITYID_PRESENT;
417
                _ObjectIdPresent = true;
418
                _ObjectId = objectId;
419

420
                _Value3[0] = key;
421
        }
422

423
        /// deallocate row
424
        void                                        deallocRow(const NLMISC::CEntityId& objectId)
425
        {
426
                setHeader(DeallocRow);
427

428
                //_MapTableRow |= MESSAGE_REMAP_ENTITYID_PRESENT;
429
                _ObjectIdPresent = true;
430
                _ObjectId = objectId;
431
        }
432

433
        /// load row
434
        void                                        loadRow(TTableIndex table, uint64 key)
435
        {
436
                setHeader(LoadRow);
437

438
                _ObjectIndex.set((uint8)table, 0);
439
                //_Table = (uint8)table;
440
                _Value3[0] = key;
441
        }
442

443

444

445
        /// Add string
446
        void                                        addString(uint64 skey, const ucstring& str)
447
        {
448
                setHeader(AddString);
449

450
                _Value3[0] = skey;
451
                _String = str;
452
        }
453

454
        /// Add string
455
        void                                        unmapString(uint64 skey)
456
        {
457
                setHeader(UnmapString);
458

459
                _Value3[0] = skey;
460
        }
461

462
        /// Release a row in memory
463
        void                                        releaseRow()
464
        {
465
                setHeader(ReleaseRow);
466
        }
467

468

469

470

471

472
        /// Log message
473
        void                                        log(uint logId, uint bufferByteSize)
474
        {
475
                setHeader(Log);
476
                _LogId = logId;
477
                _LogBuffer.resize(bufferByteSize);
478
        }
479

480
        /// Push Log Parameter
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]), &parameter, sizeof(parameter));
486
        }
487

488
        /// Push Log Parameter (string)
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
                // get current string index
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
        /// Push Log Context
500
        void                                        pushContext()
501
        {
502
                setHeader(PushContext);
503
        }
504

505
        /// Pop Log Context
506
        void                                        popContext()
507
        {
508
                setHeader(PopContext);
509
        }
510

511

512

513

514
        /// Log Chat sentence
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
        /// Get message type
540
        THeaderType                                        getType() const                                        { return _Type; }
541

542
        /// Set Type of message
543
        void                                                setType(THeaderType type)                { _Type = type; }
544

545

546

547
        /// \name common part methods
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
        /// \name Update database value specific methods
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
        /// \name Log analysis/display
602
        // @{
603

604
        /// Dump Message content to string as a human readable message
605
        void                                                getHRContent(const CDBDescriptionParser& description, std::string& result) const;
606

607
        /// Does message contains CEntityId?
608
        bool                                                contains(const CDBDescriptionParser& description, const NLMISC::CEntityId& id);
609

610
        /// Does message contains string?
611
        bool                                                contains(const CDBDescriptionParser& description, const std::string& str);
612

613
        /// Build Log string
614
        std::string                                        buildLogString(const CDBDescriptionParser& description) const;
615

616
        /// Is Value modified
617
        bool                                                valueModified(uint table, uint column)
618
        {
619
                return ((getType() == UpdateValue || getType() == SetParent) && getTable() == table && getColumn() == column);
620
        }
621

622
        /// Is message selected
623
        bool                                                Selected;
624
        /// Message context depth
625
        uint16                                                ContextDepth;
626

627
        // @}
628

629
        /// \name Serializing
630
        // @{
631

632
        /// Serial message
633
        void                                        serial(NLMISC::IStream &f, TObjectIndexCircMapper& indexMapper, TEntityIdCircMapper& eidMapper);
634

635
        /// Get Message Header Size
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                                        // 32 bits
654
        {
655
                uint32                                _StringId;
656
                uint16                                _LogId;
657
        };
658

659
        /// \name Extra info
660
        // @{
661

662
        uint16                                        _ColumnAndSize;
663

664
        CMsgObjectIndex                        _ObjectIndex;
665

666
        union                                        // 64 bits
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
        /// Type of messages in folder
756
        uint8        _Type;
757

758
        /// Number of messages in folder
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
                // build folders first if writing to stream
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
                //f.serialCont(_BackRemap);
855

856
                TEntityIdCircMapper                EIdMapper;
857
                TObjectIndexCircMapper        IndexMapper;
858

859
                // for each folder, write message stored in it
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
                // remap messages
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
        /// List of messages
899
        std::vector<CDbMessage>                        _Messages;
900

901
        /// List of folders
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
                // here, queue allows to map message
971
                CDbMessage&        msg = _Queues.back().nextMessage();
972

973
                msg.setupTableAndRow(table, row);
974

975
                // and return it
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
        /// Used Queues
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
        /// UpdateId sent by client for this update
1067
        uint32                                                UpdateId;
1068

1069
        /// Start date for this update
1070
        CTimestamp                                        StartStamp;
1071

1072
        /// Start date for this update
1073
        CTimestamp                                        EndStamp;
1074

1075
        /// Serial log
1076
        void                                                serial(NLMISC::IStream& f);
1077

1078
        /// Display UpdateLog content (using a database description)
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
                /// process log, return true if some messages were selected
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
        /// Updates contained in message
1224
        CDbMessageQueue*                        _Updates;
1225

1226
        /// Release Updates (and delete if owned)
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
// CDbMessage inline methods
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
                        // serial owner CEntityId if present
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
                        // serial object CEntityId if present
1280
                        if (objectEntityIdPresent())
1281
                                eidMapper.serial(f, _ObjectId);
1282

1283
                        // serial parents CEntityId if present
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
                        // serial owner CEntityId if present
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
                        // serial owner CEntityId if present
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
                // serial chat sentence
1378
                f.serial(_String);
1379
                // serial sender
1380
                f.serial(_Value3[0]);
1381
                // serial receivers list (whole buffer as uint8*)
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
}; // RY_PDS
1464

1465
#endif //RY_PD_MESSAGES_H
1466