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