pd_messages.h

RomKaz, 12/20/2010 09:19 pm

Download (48 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

262

263
                //union                    // 64 bits
264
        //{
265
        //    uint8                _Value0[8];
266
        //    uint16                _Value1[4];
267
        //    uint32                _Value2[2];
268
        //    uint64                _Value3[1];
269
        //};
270

271

272

273
                // update 20101119 by packpro
274
        if (sizeof(value) == 1) {sz = 0; memcpy(&(_Value0[0]), &value, sizeof(value));}
275
        else if (sizeof(value) == 2)
276
                { 
277
            sz = 1; 
278
            memcpy(&(_Value1[0]), &value, sizeof(value));
279
        }
280
        else if (sizeof(value) == 4)
281
                { 
282
            sz = 2;
283
            memcpy(&(_Value2[0]), &value, sizeof(value));
284
        }
285
        else if (sizeof(value) == 8)
286
                { 
287
            sz = 3; 
288
            memcpy(&(_Value3[0]), &value, sizeof(value));
289
        }
290

291
//                if (sizeof(value) == 1)                        { sz = 0; _Value0[0] = *(uint8*)(&value); }
292
//                else if (sizeof(value) == 2)        { sz = 1; _Value1[0] = *(uint16*)(&value); }
293
//                else if (sizeof(value) == 4)        { sz = 2; _Value2[0] = *(uint32*)(&value); }
294
//                else if (sizeof(value) == 8)        { sz = 3; _Value3[0] = *(uint64*)(&value); }
295

296
                _ColumnAndSize = (uint16)(column | (sz << 14));
297
}
298

299
        /// update value
300
    template<typename T>
301
    void                    updateValue(TColumnIndex column, const T& value, const NLMISC::CEntityId& objectId)
302
{
303
        setHeader(UpdateValue);
304
                uint        sz;
305

306
                
307
// update 20101119 by packpro
308
                if (sizeof(value) == 1){sz = 0; memcpy(&(_Value0[0]), &value, sizeof(value));}
309
        else if (sizeof(value) == 2)
310
                { 
311
            sz = 1; 
312
            memcpy(&(_Value1[0]), &value, sizeof(value));
313
        }
314
        else if (sizeof(value) == 4)
315
                { 
316
            sz = 2;
317
            memcpy(&(_Value2[0]), &value, sizeof(value));
318
        }
319
        else if (sizeof(value) == 8)
320
                { 
321
            sz = 3; 
322
            memcpy(&(_Value3[0]), &value, sizeof(value));
323
        }
324
//                if (sizeof(value) == 1)                        { sz = 0; _Value0[0] = *(uint8*)(&value); }
325
//                else if (sizeof(value) == 2)        { sz = 1; _Value1[0] = *(uint16*)(&value); }
326
//                else if (sizeof(value) == 4)        { sz = 2; _Value2[0] = *(uint32*)(&value); }
327
//                else if (sizeof(value) == 8)        { sz = 3; _Value3[0] = *(uint64*)(&value); }
328

329
                _ColumnAndSize = (uint16)(column | (sz << 14));
330

331
//_MapTableRow |= MESSAGE_REMAP_ENTITYID_PRESENT;
332
                _ObjectIdPresent = true;
333
                _ObjectId = objectId;
334
}
335

336
        /// set parent
337
        void                                        setParent(TColumnIndex column, const CObjectIndex& parent)
338
        {
339
                setHeader(SetParent);
340

341
                _ColumnAndSize = (uint16)column;
342
                _Value3[0] = *(uint64*)(&parent);
343
        }
344

345
        /// set parent, only child object has an entityId as key
346
        void                                        setParent(TColumnIndex column, const CObjectIndex& parent, const NLMISC::CEntityId& objectId)
347
        {
348
                setHeader(SetParent);
349

350
                _ColumnAndSize = (uint16)column;
351
                _Value3[0] = *(uint64*)(&parent);
352

353
                //_MapTableRow |= MESSAGE_REMAP_ENTITYID_PRESENT;
354
                _ObjectIdPresent = true;
355
                _ObjectId = objectId;
356
        }
357

358
        /// set parent, only parent object has an entityId as key
359
        void                                        setParent(TColumnIndex column, const CObjectIndex& parent, const NLMISC::CEntityId& newParentId, const NLMISC::CEntityId& previousParentId)
360
        {
361
                setHeader(SetParent);
362

363
                _ColumnAndSize = (uint16)column;
364
                _Value3[0] = *(uint64*)(&parent);
365

366
                _ColumnAndSize |= MESSAGE_SETPARENT_ENTITYID_PRESENT;
367
                _NewParentId = newParentId;
368
                _PreviousParentId = previousParentId;
369
        }
370

371
        /// set parent, both child and parent objects have an entityId as key
372
        void                                        setParent(TColumnIndex column, const CObjectIndex& parent, const NLMISC::CEntityId& objectId, const NLMISC::CEntityId& newParentId, const NLMISC::CEntityId& previousParentId)
373
        {
374
                setHeader(SetParent);
375

376
                _ColumnAndSize = (uint16)column;
377
                _Value3[0] = *(uint64*)(&parent);
378

379
                //_MapTableRow |= MESSAGE_REMAP_ENTITYID_PRESENT;
380
                _ObjectIdPresent = true;
381
                _ObjectId = objectId;
382

383
                _ColumnAndSize |= MESSAGE_SETPARENT_ENTITYID_PRESENT;
384
                _NewParentId = newParentId;
385
                _PreviousParentId = previousParentId;
386
        }
387

388
        /// Is Object EntityId present
389
        bool                                        objectEntityIdPresent() const
390
        {
391
                //return (_MapTableRow & MESSAGE_REMAP_ENTITYID_PRESENT) != 0;
392
                return _ObjectIdPresent;
393
        }
394

395
        /// Are Parents EntityId present
396
        bool                                        parentsEntityIdPresent() const
397
        {
398
                return (_ColumnAndSize & MESSAGE_SETPARENT_ENTITYID_PRESENT) != 0;
399
        }
400

401
        /// allocate row
402
        void                                        allocRow(uint64 key)
403
        {
404
                setHeader(AllocRow);
405

406
                _Value3[0] = key;
407
        }
408

409
        /// deallocate row
410
        void                                        deallocRow()
411
        {
412
                setHeader(DeallocRow);
413
        }
414

415
        /// allocate row
416
        void                                        allocRow(uint64 key, const NLMISC::CEntityId& objectId)
417
        {
418
                setHeader(AllocRow);
419

420
                //_MapTableRow |= MESSAGE_REMAP_ENTITYID_PRESENT;
421
                _ObjectIdPresent = true;
422
                _ObjectId = objectId;
423

424
                _Value3[0] = key;
425
        }
426

427
        /// deallocate row
428
        void                                        deallocRow(const NLMISC::CEntityId& objectId)
429
        {
430
                setHeader(DeallocRow);
431

432
                //_MapTableRow |= MESSAGE_REMAP_ENTITYID_PRESENT;
433
                _ObjectIdPresent = true;
434
                _ObjectId = objectId;
435
        }
436

437
        /// load row
438
        void                                        loadRow(TTableIndex table, uint64 key)
439
        {
440
                setHeader(LoadRow);
441

442
                _ObjectIndex.set((uint8)table, 0);
443
                //_Table = (uint8)table;
444
                _Value3[0] = key;
445
        }
446

447

448

449
        /// Add string
450
        void                                        addString(uint64 skey, const ucstring& str)
451
        {
452
                setHeader(AddString);
453

454
                _Value3[0] = skey;
455
                _String = str;
456
        }
457

458
        /// Add string
459
        void                                        unmapString(uint64 skey)
460
        {
461
                setHeader(UnmapString);
462

463
                _Value3[0] = skey;
464
        }
465

466
        /// Release a row in memory
467
        void                                        releaseRow()
468
        {
469
                setHeader(ReleaseRow);
470
        }
471

472

473

474

475

476
        /// Log message
477
        void                                        log(uint logId, uint bufferByteSize)
478
        {
479
                setHeader(Log);
480
                _LogId = logId;
481
                _LogBuffer.resize(bufferByteSize);
482
        }
483

484
        /// Push Log Parameter
485
        template<typename T>
486
        void                                        pushParameter(uint byteOffset, const T& parameter)
487
        {
488
                nlassertex(byteOffset+sizeof(T) <= _LogBuffer.size(), ("Internal error! failed to push parameter at %d (size=%d), beyond buffer limit (%d)", byteOffset, sizeof(T), _LogBuffer.size()));
489
                memcpy(&(_LogBuffer[byteOffset]), &parameter, sizeof(parameter));
490
        }
491

492
        /// Push Log Parameter (string)
493
        void                                        pushParameter(uint byteOffset, const std::string& parameter)
494
        {
495
                nlassertex(byteOffset+sizeof(uint16) <= _LogBuffer.size(), ("Internal error! failed to push parameter at %d (size=%d), beyond buffer limit (%d)", byteOffset, sizeof(uint16), _LogBuffer.size()));
496
                // get current string index
497
                uint16        bo = (uint16)_ExtLogBuffer.size();
498
                _ExtLogBuffer.resize(bo+parameter.size()+1);
499
                memcpy(&(_ExtLogBuffer[bo]), parameter.c_str(), parameter.size()+1);
500
                memcpy(&(_LogBuffer[byteOffset]), &bo, sizeof(uint16));
501
        }
502

503
        /// Push Log Context
504
        void                                        pushContext()
505
        {
506
                setHeader(PushContext);
507
        }
508

509
        /// Pop Log Context
510
        void                                        popContext()
511
        {
512
                setHeader(PopContext);
513
        }
514

515

516

517

518
        /// Log Chat sentence
519
        void                                        logChat(const ucstring& sentence, const NLMISC::CEntityId& sender, const std::vector<NLMISC::CEntityId>& receivers)
520
        {
521
                setHeader(LogChat);
522
                _String = sentence;
523
                *(NLMISC::CEntityId*)(&(_Value3[0])) = sender;
524

525
                uint        bufferSize = (uint)receivers.size()*sizeof(NLMISC::CEntityId);
526
                if (bufferSize > 0)
527
                {
528
                        _LogBuffer.resize(bufferSize);
529
                        NLMISC::CEntityId*        srcBuffer = (NLMISC::CEntityId*)(&(receivers[0]));
530
                        NLMISC::CEntityId*        dstBuffer = (NLMISC::CEntityId*)(&(_LogBuffer[0]));
531
                        memcpy(dstBuffer, srcBuffer, bufferSize);
532
                }
533
                else
534
                {
535
                        _LogBuffer.clear();
536
                }
537
        }
538

539

540
        // @}
541

542

543
        /// Get message type
544
        THeaderType                                        getType() const                                        { return _Type; }
545

546
        /// Set Type of message
547
        void                                                setType(THeaderType type)                { _Type = type; }
548

549

550

551
        /// \name common part methods
552
        // @{
553

554
        TTableIndex                                        getTable() const                                { return (TTableIndex)_ObjectIndex.Table; }
555
        TRowIndex                                        getRow() const                                        { return (TRowIndex)_ObjectIndex.Row; }
556
        uint32                                                getStringId() const                                { return _StringId; }
557

558
        // @}
559

560

561

562
        /// \name Update database value specific methods
563
        // @{
564

565
        TColumnIndex                                getColumn() const                        { return (TColumnIndex)(_ColumnAndSize&0x3fff); }
566
        const void*                                        getData() const                                { return &_Value0[0]; }
567
        uint                                                getDatasize() const                        { return 1 << (_ColumnAndSize>>14); }
568
        uint8                                                getValue8bits() const                { return _Value0[0]; }
569
        uint16                                                getValue16bits() const                { return _Value1[0]; }
570
        uint32                                                getValue32bits() const                { return _Value2[0]; }
571
        uint64                                                getValue64bits() const                { return _Value3[0]; }
572
        CObjectIndex                                getObjectIndex() const                { return *(CObjectIndex*)(&(_Value3[0])); }
573
        const ucstring&                                getString() const                        { return _String; }
574

575
        bool                                                asBool() const                                { return _Value0[0] != 0; }
576
        char                                                asChar() const                                { return (char)_Value0[0]; }
577
        ucchar                                                asUCChar() const                        { return (ucchar)_Value1[0]; }
578
        uint8                                                asUint8() const                                { return (uint8)_Value0[0]; }
579
        uint16                                                asUint16() const                        { return (uint16)_Value1[0]; }
580
        uint32                                                asUint32() const                        { return (uint32)_Value2[0]; }
581
        uint64                                                asUint64() const                        { return (uint64)_Value3[0]; }
582
        sint8                                                asSint8() const                                { return (sint8)_Value0[0]; }
583
        sint16                                                asSint16() const                        { return (sint16)_Value1[0]; }
584
        sint32                                                asSint32() const                        { return (sint32)_Value2[0]; }
585
        sint64                                                asSint64() const                        { return (sint64)_Value3[0]; }
586
        float                                                asFloat() const                                { return *(float*)(&_Value2[0]); }
587
        double                                                asDouble() const                        { return *(double*)(&_Value3[0]); }
588
        const NLMISC::CSheetId&                asSheetId() const                        { return *(NLMISC::CSheetId*)(&_Value2[0]); }
589
        const NLMISC::CEntityId&        asEntityId() const                        { return *(NLMISC::CEntityId*)(&_Value3[0]); }
590

591
        const NLMISC::CEntityId&        getObjectId() const                        { return _ObjectId; }
592
        const NLMISC::CEntityId&        getNewParentId() const                { return _NewParentId; }
593
        const NLMISC::CEntityId&        getPreviousParentId() const        { return _PreviousParentId; }
594

595
        uint16                                                getLogId() const                        { return _LogId; }
596
        const std::vector<uint8>&        getLogBuffer() const                { return _LogBuffer; }
597

598
        void        setupTableAndRow(TTableIndex table, TRowIndex row)
599
        {
600
                _ObjectIndex.set((uint8)table, (uint32)row);
601
        }
602

603
        // @}
604

605
        /// \name Log analysis/display
606
        // @{
607

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

611
        /// Does message contains CEntityId?
612
        bool                                                contains(const CDBDescriptionParser& description, const NLMISC::CEntityId& id);
613

614
        /// Does message contains string?
615
        bool                                                contains(const CDBDescriptionParser& description, const std::string& str);
616

617
        /// Build Log string
618
        std::string                                        buildLogString(const CDBDescriptionParser& description) const;
619

620
        /// Is Value modified
621
        bool                                                valueModified(uint table, uint column)
622
        {
623
                return ((getType() == UpdateValue || getType() == SetParent) && getTable() == table && getColumn() == column);
624
        }
625

626
        /// Is message selected
627
        bool                                                Selected;
628
        /// Message context depth
629
        uint16                                                ContextDepth;
630

631
        // @}
632

633
        /// \name Serializing
634
        // @{
635

636
        /// Serial message
637
        void                                        serial(NLMISC::IStream &f, TObjectIndexCircMapper& indexMapper, TEntityIdCircMapper& eidMapper);
638

639
        /// Get Message Header Size
640
        uint32                                        getMessageHeaderSize();
641

642
        // @}
643

644
private:
645

646
        /**
647
         * Type of message
648
         * Type is not serialised directly in message, but in containing folder
649
         */
650
        THeaderType                                _Type;
651

652

653
        /**
654
         * Message Id
655
         * Refers to the 'entity' used/updated by the message
656
         */
657
        union                                        // 32 bits
658
        {
659
                uint32                                _StringId;
660
                uint16                                _LogId;
661
        };
662

663
        /// \name Extra info
664
        // @{
665

666
        uint16                                        _ColumnAndSize;
667

668
        CMsgObjectIndex                        _ObjectIndex;
669

670
        union                                        // 64 bits
671
        {
672
                uint8                                _Value0[8];
673
                uint16                                _Value1[4];
674
                uint32                                _Value2[2];
675
                uint64                                _Value3[1];
676
        };
677

678
        bool                                        _ObjectIdPresent;
679
        NLMISC::CEntityId                _ObjectId;
680
        NLMISC::CEntityId                _NewParentId;
681
        NLMISC::CEntityId                _PreviousParentId;
682

683
        ucstring                                _String;
684
        std::vector<uint8>                _LogBuffer;
685
        std::vector<uint8>                _ExtLogBuffer;
686

687
        // @}
688

689
        void                                        setHeader(THeaderType type)        { _Type = type; }
690
};
691

692

693

694

695

696

697
/**
698
 * A Folder a Db Messages, all of the same kind.
699
 * Based on the assumption that update value messages are the main kind of messages
700
 * and that the follow in series...
701
 * Thus, it should save one byte per message...
702
 */
703
class CDbMessageFolder
704
{
705
public:
706

707
        CDbMessageFolder()
708
        {
709
                _Type = 0xff;
710
                _NumMessages = 0;
711
        }
712

713
        /**
714
         * Constructor
715
         */
716
        CDbMessageFolder(uint8 type)
717
        {
718
                _Type = type;
719
                _NumMessages = 0;
720
        }
721

722

723
        /**
724
         * Get Folder Type
725
         */
726
        uint8        getType() const                        { return _Type; }
727

728
        /**
729
         * Get Number of messages in folder
730
         */
731
        uint32        getNumMessages() const        { return _NumMessages; }
732

733
        /**
734
         * Folder is full
735
         */
736
        bool        full() const                        { return _NumMessages == MAX_MESSAGE_REMAP; }
737

738
        /**
739
         * Add a message to folder
740
         */
741
        void        addMessage(const CDbMessage& msg)
742
        {
743
                nlassert(_NumMessages < MAX_MESSAGE_REMAP);
744
                nlassert(msg.getType() == _Type);
745
                ++_NumMessages;
746
        }
747

748
        /**
749
         * Serialise folder
750
         */
751
        void        serial(NLMISC::IStream& f)
752
        {
753
                f.serial(_Type, _NumMessages);
754
                nlassert(_Type < CDbMessage::End);
755
        }
756

757
private:
758

759
        /// Type of messages in folder
760
        uint8        _Type;
761

762
        /// Number of messages in folder
763
        uint16        _NumMessages;
764
};
765

766

767

768

769

770

771

772

773
/**
774
 * A Queue of messages
775
 */
776
class CDbMessageQueue
777
{
778
public:
779

780
        /**
781
         * Constructor
782
         */
783
        CDbMessageQueue()
784
        {
785
                clear();
786
        }
787

788
        /**
789
         * Clear
790
         */
791
        void                        clear()
792
        {
793
                _Messages.clear();
794
                _Folders.clear();
795
        }
796

797
        /**
798
         * Get Next Message to be written
799
         */
800
        CDbMessage&                nextMessage()
801
        {
802
                _Messages.resize(_Messages.size()+1);
803
                return _Messages.back();
804
        }
805

806
        /**
807
         * Get Current Message to be written
808
         */
809
        CDbMessage&                currentMessage()
810
        {
811
                nlassert(!_Messages.empty());
812
                return _Messages.back();
813
        }
814

815

816
        /**
817
         * Get Number of Messages in queue
818
         */
819
        uint32                        getNumMessages() const
820
        {
821
                return (uint32)_Messages.size();
822
        }
823

824
        /**
825
         * Get Message
826
         */
827
        CDbMessage&                getMessage(uint32 message)
828
        {
829
                nlassert(message < _Messages.size());
830
                return _Messages[message];
831
        }
832

833
        /**
834
         * Serialise message queue
835
         */
836
        void                        serial(NLMISC::IStream& f)
837
        {
838
                H_AUTO(PDLIB_MsgQueue_serial);
839

840
                // build folders first if writing to stream
841
                if (!f.isReading())
842
                {
843
                        buildFolders();
844
                }
845

846
                uint32        numFolders = (uint32)_Folders.size();
847
                uint32        numMessages = (uint32)_Messages.size();
848

849
                f.serial(numFolders);
850
                f.serial(numMessages);
851

852
                if (f.isReading())
853
                {
854
                        _Folders.resize(numFolders);
855
                        _Messages.resize(numMessages);
856
                }
857

858
                //f.serialCont(_BackRemap);
859

860
                TEntityIdCircMapper                EIdMapper;
861
                TObjectIndexCircMapper        IndexMapper;
862

863
                // for each folder, write message stored in it
864
                uint        i, message = 0;
865
                for (i=0; i<_Folders.size(); ++i)
866
                {
867
                        CDbMessageFolder&        folder = _Folders[i];
868
                        f.serial(folder);
869

870
                        uint        j;
871
                        for (j=0; j<folder.getNumMessages(); ++j)
872
                        {
873
                                nlassert(message < numMessages);
874

875
                                CDbMessage&                msg = _Messages[message++];
876
                                msg.setType((CDbMessage::THeaderType)folder.getType());
877

878
                                msg.serial(f, IndexMapper, EIdMapper);
879
                        }
880
                }
881

882
                // remap messages
883
                if (f.isReading())
884
                {
885
                        uint        currentDepth = 0;
886
                        for (i=0; i<_Messages.size(); ++i)
887
                        {
888
                                CDbMessage&                msg = _Messages[i];
889

890
                                if (msg.getType() == CDbMessage::PopContext)
891
                                        --currentDepth;
892
                                msg.ContextDepth = currentDepth;
893
                                if (msg.getType() == CDbMessage::PushContext)
894
                                        ++currentDepth;
895
                        }
896
                }
897
        }
898

899

900
private:
901

902
        /// List of messages
903
        std::vector<CDbMessage>                        _Messages;
904

905
        /// List of folders
906
        std::vector<CDbMessageFolder>        _Folders;
907

908

909
        /**
910
         * Build message folders
911
         */
912
        void                        buildFolders()
913
        {
914
                _Folders.clear();
915

916
                uint        i;
917
                for (i=0; i<_Messages.size(); ++i)
918
                {
919
                        if (_Folders.empty() || _Folders.back().full() || _Messages[i].getType() != _Folders.back().getType())
920
                                _Folders.push_back(CDbMessageFolder(_Messages[i].getType()));
921

922
                        _Folders.back().addMessage(_Messages[i]);
923
                }
924
        }
925

926
};
927

928

929

930

931

932
/**
933
 * A Split Queue
934
 * Handle multiple queues, so one update may be splitted into multiple messages
935
 */
936
class CDbMessageSplitQueue
937
{
938
public:
939

940
        /**
941
         * Constructor
942
         */
943
        CDbMessageSplitQueue()
944
        {
945
        }
946

947
        /**
948
         * Clearup
949
         */
950
        void        clear()
951
        {
952
                _Queues.clear();
953
        }
954

955
        /**
956
         * Get Next Message to be written, no mapping to be done
957
         */
958
        CDbMessage&        nextMessage()
959
        {
960
                if (empty())
961
                        forceNextQueue();
962

963
                return _Queues.back().nextMessage();
964
        }
965

966
        /**
967
         * Get Next Remappable Message to be written
968
         */
969
        CDbMessage&        nextMessage(uint8 table, uint32 row)
970
        {
971
                if (empty())
972
                        forceNextQueue();
973

974
                // here, queue allows to map message
975
                CDbMessage&        msg = _Queues.back().nextMessage();
976

977
                msg.setupTableAndRow(table, row);
978

979
                // and return it
980
                return msg;
981
        }
982

983
        /**
984
         * Get Current Message
985
         */
986
        CDbMessage&        currentMessage()
987
        {
988
                return _Queues.back().currentMessage();
989
        }
990

991
        /**
992
         * Force MsgQueue to fill next queue
993
         */
994
        void                forceNextQueue()
995
        {
996
                if (_Queues.empty() || _Queues.back().getNumMessages() > 0)
997
                {
998
                        _Queues.push_back(CDbMessageQueue());
999
                }
1000
        }
1001

1002
        /**
1003
         * Is Queue Empty?
1004
         */
1005
        bool                empty() const
1006
        {
1007
                return _Queues.empty();
1008
        }
1009

1010
        /**
1011
         * Number of message in queue
1012
         */
1013
        uint32                getNumMessagesEnqueued() const
1014
        {
1015
                std::list<CDbMessageQueue>::const_iterator        it;
1016
                uint32        totalMessages = 0;
1017
                for (it=_Queues.begin(); it!=_Queues.end(); ++it)
1018
                        totalMessages += (*it).getNumMessages();
1019

1020
                return totalMessages;
1021
        }
1022

1023

1024
        /**
1025
         * begin()
1026
         */
1027
        std::list<CDbMessageQueue>::iterator        begin()                { return _Queues.begin(); }
1028

1029
        /**
1030
         * end()
1031
         */
1032
        std::list<CDbMessageQueue>::iterator        end()                { return _Queues.end(); }
1033

1034
        /**
1035
         * size()
1036
         */
1037
        uint                                                                        size() const        { return (uint)_Queues.size(); }
1038

1039
        /**
1040
         * get()
1041
         */
1042
        CDbMessageQueue&                                                get(uint i)
1043
        {
1044
                std::list<CDbMessageQueue>::iterator        it = _Queues.begin();
1045
                while (i-- > 0)
1046
                        ++it;
1047
                return (*it);
1048
        }
1049

1050

1051
private:
1052

1053
        /// Used Queues
1054
        std::list<CDbMessageQueue>                _Queues;
1055

1056
};
1057

1058

1059

1060

1061

1062
class CUpdateLog
1063
{
1064
public:
1065

1066
        CUpdateLog() : UpdateId(0xffffffff), _OwnUpdates(false), _Updates(NULL)                { }
1067

1068
        ~CUpdateLog();
1069

1070
        /// UpdateId sent by client for this update
1071
        uint32                                                UpdateId;
1072

1073
        /// Start date for this update
1074
        CTimestamp                                        StartStamp;
1075

1076
        /// Start date for this update
1077
        CTimestamp                                        EndStamp;
1078

1079
        /// Serial log
1080
        void                                                serial(NLMISC::IStream& f);
1081

1082
        /// Display UpdateLog content (using a database description)
1083
        void                                                display(const CDBDescriptionParser& description, NLMISC::CLog& log, bool onlySelected = false);
1084

1085

1086

1087

1088
        /**
1089
         * Check log timestamp boundaries
1090
         */
1091
        bool                                                checkTimestampBoundaries(const CTimestamp& begin, const CTimestamp& end);
1092

1093
        /**
1094
         * Is Empty
1095
         */
1096
        bool                                                isEmpty();
1097

1098
        /**
1099
         * Select contexts and messages containing a given entityId
1100
         * return true if there were at least one message selected
1101
         */
1102
        bool                                                selectMessages(const CDBDescriptionParser& description, const NLMISC::CEntityId& id);
1103

1104
        /**
1105
         * Select contexts and messages containing a given string
1106
         * return true if there were at least one message selected
1107
         */
1108
        bool                                                selectMessages(const CDBDescriptionParser& description, const std::string& str);
1109

1110
        /**
1111
         * Select contexts and messages containing modification of a value for a given entityId
1112
         * return true if there were at least one message selected
1113
         */
1114
        bool                                                selectMessages(const CDBDescriptionParser& description, const NLMISC::CEntityId& id, const std::string& valuePath);
1115

1116
        /**
1117
         * Select contexts and messages containing a list of entityIds (limited at most to 32 entityIds)
1118
         * return true if there were at least one message selected
1119
         */
1120
        bool                                                selectMessages(const CDBDescriptionParser& description, const std::vector<NLMISC::CEntityId>& ids);
1121

1122
        class CLogProcessor
1123
        {
1124
        public:
1125
                /// process log, return true if some messages were selected
1126
                virtual bool        processLog(CUpdateLog& log, const CDBDescriptionParser& description) = 0;
1127
        };
1128

1129
        /**
1130
         * Apply process on log files
1131
         */
1132
        static void                                        processLogs(const std::string& path,
1133
                                                                                        const CTimestamp& begin,
1134
                                                                                        const CTimestamp& end,
1135
                                                                                        NLMISC::CLog& log,
1136
                                                                                        CLogProcessor* processor,
1137
                                                                                        float* progress = NULL);
1138

1139
        /**
1140
         * Display log for a given entity id, between 2 dates
1141
         */
1142
        static void                                        displayLogs(const CDBDescriptionParser& description,
1143
                                                                                        const NLMISC::CEntityId& id,
1144
                                                                                        const CTimestamp& begin,
1145
                                                                                        const CTimestamp& end,
1146
                                                                                        const std::string& path,
1147
                                                                                        NLMISC::CLog& log,
1148
                                                                                        float* progress = NULL);
1149

1150
        /**
1151
         * Display log between 2 dates
1152
         */
1153
        static void                                        displayLogs(const std::string& path,
1154
                                                                                        const CTimestamp& begin,
1155
                                                                                        const CTimestamp& end,
1156
                                                                                        NLMISC::CLog& log,
1157
                                                                                        float* progress = NULL);
1158

1159
        /**
1160
         * Display log for a given entity id, between 2 dates
1161
         */
1162
        static void                                        displayLogs(const std::string& path,
1163
                                                                                        const NLMISC::CEntityId& id,
1164
                                                                                        const CTimestamp& begin,
1165
                                                                                        const CTimestamp& end,
1166
                                                                                        NLMISC::CLog& log,
1167
                                                                                        float* progress = NULL);
1168

1169
        /**
1170
         * Display log for a given entity id and a specified value to be modified, between 2 dates
1171
         */
1172
        static void                                        displayLogs(const std::string& path,
1173
                                                                                        const NLMISC::CEntityId& id,
1174
                                                                                        const std::string& valuePath,
1175
                                                                                        const CTimestamp& begin,
1176
                                                                                        const CTimestamp& end,
1177
                                                                                        NLMISC::CLog& log,
1178
                                                                                        float* progress = NULL);
1179

1180
        /**
1181
         * Display log for a list of given entity id, between 2 dates
1182
         */
1183
        static void                                        displayLogs(const std::string& path,
1184
                                                                                        const std::vector<NLMISC::CEntityId>& ids,
1185
                                                                                        const CTimestamp& begin,
1186
                                                                                        const CTimestamp& end,
1187
                                                                                        NLMISC::CLog& log,
1188
                                                                                        float* progress = NULL);
1189

1190
        /**
1191
         * Display log for a list of given entity id, between 2 dates
1192
         */
1193
        static void                                        displayLogs(const std::string& path,
1194
                                                                                        const std::string& str,
1195
                                                                                        const CTimestamp& begin,
1196
                                                                                        const CTimestamp& end,
1197
                                                                                        NLMISC::CLog& log,
1198
                                                                                        float* progress = NULL);
1199

1200
        /**
1201
         * Elect matching description
1202
         */
1203
        static std::string                        electDescription(const std::string& logFile);
1204

1205

1206

1207

1208
        /**
1209
         * Set updates
1210
         */
1211
        void                                                setUpdates(CDbMessageQueue* updates);
1212

1213
        /**
1214
         * Create updates
1215
         */
1216
        void                                                createUpdates();
1217

1218
        /**
1219
         * Get Updates
1220
         */
1221
        CDbMessageQueue*                        getUpdates()        { return _Updates; }
1222

1223
private:
1224

1225
        bool                                                _OwnUpdates;
1226

1227
        /// Updates contained in message
1228
        CDbMessageQueue*                        _Updates;
1229

1230
        /// Release Updates (and delete if owned)
1231
        void                                                releaseUpdates()
1232
        {
1233
                if (_OwnUpdates && _Updates != NULL)
1234
                        delete _Updates;
1235

1236
                _Updates = NULL;
1237
                _OwnUpdates = false;
1238
        }
1239
};
1240

1241

1242

1243

1244

1245
//
1246
// CDbMessage inline methods
1247
//
1248

1249
inline void        CDbMessage::serial(NLMISC::IStream &f, TObjectIndexCircMapper& indexMapper, TEntityIdCircMapper& eidMapper)
1250
{
1251
        switch (_Type)
1252
        {
1253
        case UpdateValue:
1254
                {
1255
                        uint8        flags = (objectEntityIdPresent() ? 0x80 : 0);
1256
                        indexMapper.serial(f, _ObjectIndex, flags);
1257
                        _ObjectIdPresent = ((flags & 0x80) != 0);
1258

1259
                        f.serial(_ColumnAndSize);
1260

1261
                        switch (_ColumnAndSize & 0xc000)
1262
                        {
1263
                        case 0x0000:        f.serial(_Value0[0]); break;
1264
                        case 0x4000:        f.serial(_Value1[0]); break;
1265
                        case 0x8000:        f.serial(_Value2[0]); break;
1266
                        case 0xc000:        f.serial(_Value3[0]); break;
1267
                        }
1268

1269
                        // serial owner CEntityId if present
1270
                        if (objectEntityIdPresent())
1271
                                eidMapper.serial(f, _ObjectId);
1272
                }
1273
                break;
1274

1275
        case SetParent:
1276
                {
1277
                        uint8        flags = (objectEntityIdPresent() ? 0x80 : 0);
1278
                        indexMapper.serial(f, _ObjectIndex, flags);
1279
                        _ObjectIdPresent = ((flags & 0x80) != 0);
1280
                        f.serial(_ColumnAndSize);
1281
                        f.serial(_Value3[0]);
1282

1283
                        // serial object CEntityId if present
1284
                        if (objectEntityIdPresent())
1285
                                eidMapper.serial(f, _ObjectId);
1286

1287
                        // serial parents CEntityId if present
1288
                        if ((_ColumnAndSize & MESSAGE_SETPARENT_ENTITYID_PRESENT) != 0)
1289
                        {
1290
                                eidMapper.serial(f, _NewParentId);
1291
                                eidMapper.serial(f, _PreviousParentId);
1292
                        }
1293
                }
1294
                break;
1295

1296
        case AllocRow:
1297
                {
1298
                        uint8        flags = (objectEntityIdPresent() ? 0x80 : 0);
1299
                        indexMapper.serial(f, _ObjectIndex, flags);
1300
                        _ObjectIdPresent = ((flags & 0x80) != 0);
1301
                        f.serial(_Value3[0]);
1302

1303
                        // serial owner CEntityId if present
1304
                        if (objectEntityIdPresent())
1305
                                eidMapper.serial(f, _ObjectId);
1306
                }
1307
                break;
1308

1309
        case DeallocRow:
1310
                {
1311
                        uint8        flags = (objectEntityIdPresent() ? 0x80 : 0);
1312
                        indexMapper.serial(f, _ObjectIndex, flags);
1313
                        _ObjectIdPresent = ((flags & 0x80) != 0);
1314
                        // serial owner CEntityId if present
1315
                        if (objectEntityIdPresent())
1316
                                eidMapper.serial(f, _ObjectId);
1317
                }
1318
                break;
1319

1320
        case LoadRow:
1321
                f.serial(_ObjectIndex.Table);
1322
                f.serial(_Value3[0]);
1323
                break;
1324

1325
        case AddString:
1326
                f.serial(_Value3[0]);
1327
                f.serial(_String);
1328
                break;
1329

1330
        case UnmapString:
1331
                f.serial(_Value3[0]);
1332
                break;
1333

1334
        case ReleaseRow:
1335
                indexMapper.serial(f, _ObjectIndex);
1336
                break;
1337

1338
        case Log:
1339
                {
1340
                        f.serial(_LogId);
1341

1342
                        if (f.isReading())
1343
                        {
1344
                                uint8        sz;
1345

1346
                                f.serial(sz);
1347
                                _LogBuffer.resize(sz);
1348
                                if (sz > 0)
1349
                                        f.serialBuffer(&(_LogBuffer[0]), sz);
1350

1351
                                f.serial(sz);
1352
                                _ExtLogBuffer.resize(sz);
1353
                                if (sz > 0)
1354
                                        f.serialBuffer(&(_ExtLogBuffer[0]), sz);
1355
                        }
1356
                        else
1357
                        {
1358
                                uint8        sz;
1359
                                nlassert(_LogBuffer.size() <= 255);
1360
                                sz = (uint8)_LogBuffer.size();
1361
                                f.serial(sz);
1362
                                if (sz > 0)
1363
                                        f.serialBuffer(&(_LogBuffer[0]), sz);
1364

1365
                                nlassert(_ExtLogBuffer.size() <= 255);
1366
                                sz = (uint8)_ExtLogBuffer.size();
1367
                                f.serial(sz);
1368
                                if (sz > 0)
1369
                                        f.serialBuffer(&(_ExtLogBuffer[0]), sz);
1370
                        }
1371
                }
1372
                break;
1373

1374
        case PushContext:
1375
                break;
1376

1377
        case PopContext:
1378
                break;
1379

1380
        case LogChat:
1381
                // serial chat sentence
1382
                f.serial(_String);
1383
                // serial sender
1384
                f.serial(_Value3[0]);
1385
                // serial receivers list (whole buffer as uint8*)
1386
                f.serialCont(_LogBuffer);
1387
                break;
1388

1389
        default:
1390
                nlerror("CDbMessage::serial(): unable to serial message type '%d'", _Type);
1391
                break;
1392
        }
1393
}
1394

1395
/*
1396
 * Get Message Header Size
1397
 */
1398
inline uint32        CDbMessage::getMessageHeaderSize()
1399
{
1400
        uint        size = 0;
1401

1402
        switch (_Type)
1403
        {
1404
        case UpdateValue:
1405
        case SetParent:
1406
                size += sizeof(_ObjectIndex.Table)+sizeof(_ObjectIndex.Row);
1407
                size += sizeof(_ColumnAndSize);
1408
                break;
1409

1410
        case AllocRow:
1411
                size += sizeof(_ObjectIndex.Table)+sizeof(_ObjectIndex.Row);
1412
                break;
1413

1414
        case DeallocRow:
1415
                size += sizeof(_ObjectIndex.Table)+sizeof(_ObjectIndex.Row);
1416
                break;
1417

1418
        case LoadRow:
1419
                size += sizeof(_ObjectIndex.Table);
1420
                size += sizeof(_Value3[0]);
1421
                break;
1422

1423
        case ReleaseRow:
1424
                size += sizeof(_ObjectIndex.Table)+sizeof(_ObjectIndex.Row);
1425
                break;
1426

1427
        case Log:
1428
                size += sizeof(_LogId);
1429
                size += 2;
1430
                break;
1431

1432
        default:
1433
                break;
1434
        }
1435

1436
        return size;
1437
}
1438

1439
/*
1440
 * Serial log
1441
 */
1442
inline void        CUpdateLog::serial(NLMISC::IStream& f)
1443
{
1444
        f.serialCheck((uint32)'ULOG');
1445

1446
        uint        version = f.serialVersion(1);
1447

1448
        f.serial(UpdateId);
1449

1450
        if (version >= 1)
1451
        {
1452
                f.serial(StartStamp);
1453
                f.serial(EndStamp);
1454
        }
1455

1456
        if (f.isReading())
1457
        {
1458
                releaseUpdates();
1459
                _Updates = new RY_PDS::CDbMessageQueue();
1460
                _OwnUpdates = true;
1461
        }
1462

1463
        f.serial(*_Updates);
1464
}
1465

1466

1467
}; // RY_PDS
1468

1469
#endif //RY_PD_MESSAGES_H
1470

1471