1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2015 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #ifndef RY_PDS_UTILS_H
21 #define RY_PDS_UTILS_H
26 #include <nel/misc/types_nl.h>
27 #include <nel/misc/common.h>
28 #include <nel/misc/time_nl.h>
29 #include <nel/misc/stream.h>
30 #include <nel/misc/entity_id.h>
31 #include <nel/misc/sheet_id.h>
32 #include <nel/misc/variable.h>
39 * Definition of streamable persistent data.
40 * Used to fetch data from PDS to service classes
42 typedef NLMISC::IStream CPData
;
49 * PD System Verbosity control
51 extern NLMISC::CVariable
<bool> PDVerbose
;
54 * PD System Verbosity level
56 extern NLMISC::CVariable
<sint
> PDVerboseLevel
;
59 * PDS Resolve Unmapped rows
60 * If true, PDS continue loading when it finds a row not mapped in a mapped table,
61 * and keeps it unmapped.
62 * Otherwise, loading fails.
64 extern NLMISC::CVariable
<bool> ResolveUnmappedRows
;
67 * PDS Resolve Double Mapped Rows
68 * If true, PDS continue loading when it finds a row already mapped, and keeps it unmapped.
69 * Otherwise, loading fails.
70 * See also ResolveDoubleMappedKeepOlder
72 extern NLMISC::CVariable
<bool> ResolveDoubleMappedRows
;
75 * PDS Resolve Double Mapped Keep Older
76 * If true, when finds a doubly mapped row at loading, keep only older row as mapped (lesser row index)
77 * See also ResolveDoubleMappedRows.
79 extern NLMISC::CVariable
<bool> ResolveDoubleMappedKeepOlder
;
82 * PDS Resolve Unallocated rows
83 * If true, when finds a reference to an unallocated row or an invalid row, force reference to null.
85 extern NLMISC::CVariable
<bool> ResolveInvalidRow
;
93 * Definition of Table indices
95 typedef uint16 TTableIndex
;
98 * Definition of Row indices
100 typedef uint32 TRowIndex
;
103 * Definition of Column indices
105 typedef uint16 TColumnIndex
;
108 * Definition of index Checksum validator
110 typedef uint16 TIndexChecksum
;
114 * Table & Row indices constants
116 const TTableIndex INVALID_TABLE_INDEX
= 0xffff;
117 const TRowIndex INVALID_ROW_INDEX
= 0xffffffff;
118 const TColumnIndex INVALID_COLUMN_INDEX
= 0xffff;
123 const TIndexChecksum VALID_INDEX_CHECKSUM
= 0xdead;
126 * Default Hashing Function
128 /*template<typename T>
132 size_t operator() (const T& value) const { return (uint32)value; }
136 * Table Container Interface
138 class ITableContainer
143 virtual TTableIndex
getTableIndex(const std::string
& tableName
) const = 0;
146 virtual std::string
getTableName(TTableIndex tableIndex
) const = 0;
152 * Definition of Object indices
153 * An object is pointed by a table index and a row index
154 * \author Benjamin Legros
155 * \author Nevrax France
162 /// Constructor of invalid index
163 explicit CObjectIndex(bool validateChecksum
= false) : _Row(INVALID_ROW_INDEX
), _Table(INVALID_TABLE_INDEX
), _Checksum((TIndexChecksum
)~VALID_INDEX_CHECKSUM
)
165 if (validateChecksum
)
172 CObjectIndex(TTableIndex table
, TRowIndex row
) : _Row(row
), _Table(table
) { validate(); }
175 CObjectIndex(const CObjectIndex
&index
) { *this = index
; }
182 operator uint64 () const { return _FullIndex
; }
185 TTableIndex
table() const { return _Table
; }
188 TRowIndex
row() const { return _Row
; }
194 CObjectIndex
& operator = (const CObjectIndex
&index
) { _FullIndex
= index
._FullIndex
; return *this; }
197 bool operator == (const CObjectIndex
&index
) const { return _FullIndex
== index
._FullIndex
; }
200 bool operator != (const CObjectIndex
&index
) const { return !(*this == index
); }
205 static CObjectIndex
null()
207 return CObjectIndex(true);
213 bool isChecksumValid() const
215 return getChecksum() == VALID_INDEX_CHECKSUM
;
221 return _Table
== INVALID_TABLE_INDEX
&& _Row
== INVALID_ROW_INDEX
&& isChecksumValid();
227 return _Table
!= INVALID_TABLE_INDEX
&& _Row
!= INVALID_ROW_INDEX
&& isChecksumValid();
233 /// transform to string
234 std::string
toString(const ITableContainer
* container
= NULL
) const
238 if (container
!= NULL
)
240 return NLMISC::toString("(%s:%u)", container
->getTableName(_Table
).c_str(), _Row
);
244 return NLMISC::toString("(%u:%u)", _Table
, _Row
);
253 return NLMISC::toString("(%u:%u <invalid>)", _Table
, _Row
);
258 void fromString(const char* str
, const ITableContainer
* container
= NULL
)
264 if (sscanf(str
, "(%d:%d:%d)", &table
, &row
, &valid
) == 3)
266 _Table
= (TTableIndex
)table
;
267 _Row
= (TRowIndex
)row
;
276 else if (sscanf(str
, "(%d:%d)", &table
, &row
) == 2)
278 _Table
= (TTableIndex
)table
;
279 _Row
= (TRowIndex
)row
;
284 else if (container
!= NULL
&& parseIndexWithName(str
, container
))
290 *this = CObjectIndex::null();
294 void serial(NLMISC::IStream
& f
)
296 f
.serial(_FullIndex
);
301 bool parseIndexWithName(const char* str
, const ITableContainer
* container
)
309 std::string tableName
;
311 while (*str
!= '\0' && *str
!= ':')
312 tableName
+= *(str
++);
317 table
= container
->getTableIndex(tableName
);
318 if (table
== INVALID_TABLE_INDEX
)
321 NLMISC::fromString(std::string(str
), row
);
323 while (*str
>= '0' && *str
<= '9')
338 #define PDS_ROW_LO_WORD 0
339 #define PDS_ROW_HI_WORD 1
340 #define PDS_TABLE_WORD 2
341 #define PDS_CHECKSUM_WORD 3
345 #define PDS_ROW_LO_WORD 0
346 #define PDS_ROW_HI_WORD 1
347 #define PDS_TABLE_WORD 2
348 #define PDS_CHECKSUM_WORD 3
358 TIndexChecksum _Checksum
;
364 /// Compute partial checksum of the index
365 TIndexChecksum
getPartialChecksum() const
367 return _Words
[PDS_ROW_LO_WORD
] ^ _Words
[PDS_ROW_HI_WORD
] ^ _Words
[PDS_TABLE_WORD
];
370 /// Get checksum of the index
371 TIndexChecksum
getChecksum() const
373 return getPartialChecksum() ^ _Words
[PDS_CHECKSUM_WORD
];
376 /// Force validation of an index
379 _Checksum
= getPartialChecksum() ^ VALID_INDEX_CHECKSUM
;
382 /// Force invalidation of an index
385 _Checksum
= getPartialChecksum() ^ (~VALID_INDEX_CHECKSUM
);
392 * Definition of column index
393 * \author Benjamin Legros
394 * \author Nevrax France
402 explicit CColumnIndex(TTableIndex table
= INVALID_TABLE_INDEX
, TRowIndex row
= INVALID_ROW_INDEX
, TColumnIndex column
= INVALID_COLUMN_INDEX
)
403 : _Table(table
), _Column(column
), _Row(row
)
408 explicit CColumnIndex(const CObjectIndex
& object
, TColumnIndex column
)
409 : _Table(INVALID_TABLE_INDEX
), _Column(INVALID_COLUMN_INDEX
), _Row(INVALID_ROW_INDEX
)
411 if (!object
.isValid())
414 _Table
= object
.table();
421 TTableIndex
table() const { return _Table
; }
423 TRowIndex
row() const { return _Row
; }
425 TColumnIndex
column() const { return _Column
; }
428 bool isNull() const { return _Table
== INVALID_TABLE_INDEX
&& _Row
== INVALID_ROW_INDEX
&& _Column
== INVALID_COLUMN_INDEX
; }
432 operator uint64() const { return _FullIndex
; }
435 uint32
hash() const { return (uint32
) ((_Table
<<2) ^ (_Row
<<1) ^ _Column
); }
438 bool operator < (const CColumnIndex
& b
) const { return _FullIndex
< b
._FullIndex
; }
440 /// transform to string
441 std::string
toString(const ITableContainer
* container
= NULL
) const
447 else if (container
!= NULL
)
449 return NLMISC::toString("(%s:%u:%u)", container
->getTableName(_Table
).c_str(), _Row
, _Column
);
453 return NLMISC::toString("(%u:%u:%u)", _Table
, _Row
, _Column
);
466 /// Column Index in row
467 TColumnIndex _Column
;
469 /// Row Index in table
473 /// Full 64 bits index
479 * Definition of set of object indexes
480 * This is actually a index on the first element of a list contained in each database
482 typedef std::vector
<CObjectIndex
> TIndexList
;
486 * A container of index lists
487 * \author Benjamin Legros
488 * \author Nevrax France
492 //#define DEBUG_SETMAP_ACCESSOR
494 struct CColumnIndexHashMapTraits
496 enum { bucket_size
= 4, min_buckets
= 8 };
497 CColumnIndexHashMapTraits() { }
498 size_t operator() (const CColumnIndex
&id
) const
502 bool operator()(const CColumnIndex
&left
, const CColumnIndex
&right
)
516 size_t operator() (const CColumnIndex& key) const { return (uint32)(key.hash()); }
520 typedef CHashMap
<CColumnIndex
, TIndexList
, CColumnIndexHashMapTraits
> TListMap
;
522 /// An Accessor on a list
527 /// Constructor, only builds invalid accessor
528 CAccessor() : _Valid(false) { }
531 bool isValid() const { return _Valid
; }
534 const TIndexList
& get() const { nlassert(isValid()); return (*_It
).second
; }
536 /// Test if object belongs to list
537 bool belongsTo(const CObjectIndex
& test
) const
540 return std::find((*_It
).second
.begin(), (*_It
).second
.end(), test
) != (*_It
).second
.end();
543 /// Add index to list
544 void add(const CObjectIndex
& index
)
547 if (!belongsTo(index
))
549 (*_It
).second
.push_back(index
);
553 /// Remove index from list
554 void erase(const CObjectIndex
& index
)
558 TIndexList
& iList
= (*_It
).second
;
559 TIndexList::iterator itr
;
560 for (itr
=iList
.begin(); itr
!=iList
.end(); )
561 itr
= ((*itr
== index
) ? iList
.erase(itr
) : (itr
+1));
563 // gcc can't resolve this:
564 //(*_It).second.erase(std::remove((*_It).second.begin(), (*_It).second.end(), index), (*_It).second.end());
572 nlinfo("<can't display set>");
576 #ifdef DEBUG_SETMAP_ACCESSOR
577 nlinfo("Set '%s' content:", _Debug
.toString().c_str());
579 nlinfo("Set content:");
581 TIndexList::const_iterator it
;
582 for (it
=(*_It
).second
.begin(); it
!=(*_It
).second
.end(); ++it
)
583 nlinfo("%s", (*it
).toString().c_str());
588 friend class CSetMap
;
590 /// Internal pointer to list
591 TListMap::iterator _It
;
596 #ifdef DEBUG_SETMAP_ACCESSOR
600 /// constructor for CIndexListMap
601 CAccessor(TListMap::iterator it
, const CColumnIndex
& index
) : _It(it
), _Valid(true), _Debug(index
) { }
605 /// constructor for CIndexListMap
606 CAccessor(TListMap::iterator it
, const CColumnIndex
& index
) : _It(it
), _Valid(true) { }
613 /// Get the list associated to this column
614 CAccessor
get(const CColumnIndex
& index
)
616 TListMap::iterator it
= _Map
.find(index
);
617 if (it
== _Map
.end())
619 it
= _Map
.insert(TListMap::value_type(index
, TIndexList())).first
;
621 return CAccessor(it
, index
);
624 /// Clear up whole map
625 void clear() { _Map
.clear(); }
629 friend class CAccessor
;
640 * Base class for Row accessible objects.
641 * Contains a Row index, used to represent the object in the database
642 * Classes that derive from this class are assumed to know their own Table index.
643 * \author Benjamin Legros
644 * \author Nevrax France
652 IPDBaseData() : __BaseRow(INVALID_ROW_INDEX
), __BaseTable(INVALID_TABLE_INDEX
) {}
655 TRowIndex
getRow() const { return __BaseRow
; }
658 TTableIndex
getTable() const { return __BaseTable
; }
663 TTableIndex __BaseTable
;
665 friend class CPDSLib
;
671 * A class that allocates and deallocate indices in PDS database.
672 * The allocator is able to init itself from a PDS command
673 * \author Benjamin Legros
674 * \author Nevrax France
677 class CIndexAllocator
681 CIndexAllocator() : _NextIndex(0) { }
685 // no index in stack, get next
686 if (_FreeIndices
.empty())
690 TRowIndex index
= _FreeIndices
.front();
691 _FreeIndices
.pop_front();
695 void deallocate(TRowIndex index
)
697 // push index on stack
698 _FreeIndices
.push_back(index
);
701 void forceAllocated(TRowIndex index
)
703 for (; _NextIndex
<index
; ++_NextIndex
)
704 _FreeIndices
.push_back(_NextIndex
);
706 // remove index from free if was there
707 std::deque
<TRowIndex
>::iterator it
= std::find(_FreeIndices
.begin(), _FreeIndices
.end(), index
);
708 if (it
!= _FreeIndices
.end())
709 _FreeIndices
.erase(it
);
711 if (_NextIndex
< index
+1)
712 _NextIndex
= index
+1;
718 _FreeIndices
.clear();
721 void serial(NLMISC::IStream
& f
)
723 f
.serialCheck(NELID("IALC"));
726 f
.serial(_NextIndex
);
727 f
.serialCont(_FreeIndices
);
733 TRowIndex _NextIndex
;
736 std::deque
<TRowIndex
> _FreeIndices
;
744 typedef IPDBaseData
* (*TPDFactory
)();
745 typedef void (*TPDFetch
)(IPDBaseData
*, CPData
&);
746 typedef void (*TPDFetchFailure
)(uint64 key
);
751 * Get Value as String
754 std::string
pdsToString(const T
& value
) { return NLMISC::toString(value
); }
756 inline std::string
pdsToString(const bool& value
) { return value
? std::string("true") : std::string("false"); }
757 inline std::string
pdsToString(const CObjectIndex
& value
) { return value
.toString(); }
758 inline std::string
pdsToString(const CColumnIndex
& value
) { return value
.toString(); }
759 inline std::string
pdsToString(const NLMISC::CSheetId
& value
) { return value
.toString(); }
760 inline std::string
pdsToString(const NLMISC::CEntityId
& value
) { return value
.toString(); }
765 #endif //RY_PDS_UTILS_H