1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
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.
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.
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/>.
17 #ifndef RY_PD_SERVER_UTILS_H
18 #define RY_PD_SERVER_UTILS_H
23 #include <nel/misc/types_nl.h>
24 #include <nel/misc/stream.h>
25 #include <nel/misc/common.h>
26 #include <nel/misc/bit_set.h>
27 #include <nel/misc/variable.h>
34 #include "timestamp.h"
38 * CRefIndex, permanent info about the database
39 * This class is not intended to be modified, only create when a valid
41 * To store volatile data, see CDatabaseState.
50 /// Numeral index of the reference
53 /// Directory path of the reference, this MUST local path from root database path
56 /// Timestamp, in the form 'YYYY.MM.DD.hh.mm.ss'
57 //std::string Timestamp;
60 void serial(NLMISC::IStream
& s
)
62 s
.xmlPush("reference");
64 s
.serialCheck(NELID("RIDX"));
65 uint version
= s
.serialVersion(0);
67 s
.xmlPush("database");
79 s
.xmlPush("timestamp");
84 Timestamp
.fromString(ts
.c_str());
88 std::string ts
= Timestamp
.toString();
91 //s.serial(Timestamp);
98 CRefIndex(uint32 databaseId
) : DatabaseId(databaseId
), Index(0)
106 Path
= "ref."+NLMISC::toString("%08X", Index
);
117 * Load a Reference index file
119 bool load(const std::string
& filename
);
122 * Load a Reference index file
127 * Save a Reference index file
132 * Save a Reference index file
134 bool save(const std::string
& filename
);
137 * Build next Reference index file
142 * Get next Reference index file
147 * Get (and setup if needed) database root path
149 std::string
getRootPath();
154 std::string
getPath();
157 * Set As Valid Reference
159 bool setAsValidRef();
162 * Get Nominal Root Path
164 std::string
getNominalRootPath();
168 * Get Seconds update path
170 std::string
getSecondsUpdatePath();
173 * Get Minutes update path
175 std::string
getMinutesUpdatePath();
178 * Get Hours update path
180 std::string
getHoursUpdatePath();
185 std::string
getLogPath();
190 * Setup reference directory
192 bool setupDirectory();
197 bool checkDirectory(const std::string
& path
);
205 * This class contains 'volatile' state of the database
206 * This class is update at each update, and written on HD at the end of update.
207 * File on HD is used when database is checked at startup (and if it fails,
208 * database should not be initialised unless maintenance fixes the problem)
226 /// Current Valid Index
229 /// End Database Update Timestamp
230 CTimestamp EndTimestamp
;
234 void serial(NLMISC::IStream
& s
);
237 bool save(CRefIndex
& ref
);
240 bool load(CRefIndex
& ref
, bool usePrevious
= false);
243 bool load(const std::string
& rootpath
, bool usePrevious
= false);
245 /// State exists in path
246 static bool exists(const std::string
& rootpath
);
249 /// Get state filename
250 static std::string
fileName() { return "state"; }
252 /// Get state filename
253 static std::string
fileName(CRefIndex
& ref
) { return ref
.getRootPath()+"state"; }
266 class CMixedStreamFile
: public NLMISC::IStream
271 CMixedStreamFile() : NLMISC::IStream(false), _File(NULL
)
276 virtual ~CMixedStreamFile()
281 bool open(const char* filename
, const char* mode
= "rb")
286 _File
= NLMISC::nlfopen(filename
, mode
);
308 /// standard FILE handler
311 bool readBuffer(void* buf
, uint len
) { if (_File
== NULL
) return false; uint32 rb
= (uint32
)fread(buf
, 1, len
, _File
); _ReadBytes
+= rb
; return rb
== len
; }
312 bool writeBuffer(const void* buf
, uint len
) { if (_File
== NULL
) return false; uint32 wb
= (uint32
)fwrite(buf
, 1, len
, _File
); _WrittenBytes
+= wb
; return wb
== len
; }
313 bool readBuffer(void* buf
, uint len
, uint
& readlen
) { if (_File
== NULL
) return false; readlen
= (uint
)fread(buf
, 1, len
, _File
); return readlen
== len
; }
315 static uint64 _ReadBytes
;
316 static uint64 _WrittenBytes
;
319 bool readValue(T
& v
) { return readBuffer(&v
, sizeof(v
)); }
322 bool writeValue(const T
& v
) { return writeBuffer(&v
, sizeof(v
)); }
326 virtual void serialBuffer(uint8
*buf
, uint len
)
329 throw NLMISC::EStream("CMixedStreamFile not opened");
333 if (!readBuffer(buf
, len
))
334 throw NLMISC::EStream("file error "+NLMISC::toString(ferror(_File
)));
338 if (!writeBuffer(buf
, len
))
339 throw NLMISC::EStream("file error "+NLMISC::toString(ferror(_File
)));
343 virtual void serialBit(bool &bit
)
373 void link(CRowMapper
* link
) { _Link
= link
; }
382 * Declares a row as allocated
384 bool allocate(RY_PDS::TRowIndex row
);
387 * Declares a row as deallocated
389 bool deallocate(RY_PDS::TRowIndex row
);
392 * Checks if a row is allocated
394 bool allocated(RY_PDS::TRowIndex row
) const;
397 * Get Number of Allocated rows
399 uint32
numAllocated() const { return _AllocatedRows
; }
402 * Get Max row index used
404 RY_PDS::TRowIndex
maxRowIndex() const { return _RowState
.size(); }
407 * Get Next Unalloocated row
409 RY_PDS::TRowIndex
nextUnallocatedRow() const;
414 * Map a key to an Row
416 bool map(TKey key
, const RY_PDS::CObjectIndex
& index
);
421 bool isMapped(TKey key
);
426 RY_PDS::CObjectIndex
get(TKey key
) const;
429 * Unmap a key of an Row
431 bool unmap(TKey key
);
434 * Get Number of Mapped rows
436 uint32
numMapped() const { return (uint32
)_KeyMap
.size(); }
443 * Bitset of allocated rows, each bit indicates if corresponding row is allocated
445 typedef NLMISC::CBitSet TRowState
;
448 /// Total number of allocated rows
449 uint32 _AllocatedRows
;
455 size_t operator() (const TKey
& key
) const { return ((uint32
)key
) ^ ((uint32
)(key
>> 32)); }
458 typedef CHashMap
<TKey
, RY_PDS::CObjectIndex
> TKeyMap
;
461 /// Row Mapper link, in case of mapped table that inherit from another
469 * Debug/Log Interface
475 CPDSLogger() : _ParentLogger(NULL
) { }
477 void setParentLogger(const CPDSLogger
* parent
) { _ParentLogger
= parent
; }
481 * Get Contextual Identifier String
483 std::string
getContextualIndentifier() const;
488 * Get Internal Logger Identifier
489 * An identifier should ressemble like 'type:id', where type is the 'class'
490 * of the logger, and id is a unique identifier of the instanciated object of 'class'
492 virtual std::string
getLoggerIdentifier() const = 0;
497 const CPDSLogger
* _ParentLogger
;
501 #define PDS_FULL_DEBUG_LEVEL 3
502 #define PDS_NORMAL_DEBUG_LEVEL 2
503 #define PDS_MINIMAL_DEBUG_LEVEL 1
504 #define PDS_NO_DEBUG_LEVEL 0
507 #define PDS_DEBUG_LEVEL PDS_FULL_DEBUG_LEVEL
510 #define PDS_DEBUG_IN_L(obj, level) if (level <= 0 || !RY_PDS::PDVerbose || level > RY_PDS::PDVerboseLevel) {} else NLMISC::createDebug (), NLMISC::DebugLog->setPosition( __LINE__, __FILE__ ), NLMISC::DebugLog->display("%s:", obj->getContextualIndentifier().c_str()), NLMISC::DebugLog->displayNL
512 #define PDS_DEBUG_IN(obj) PDS_DEBUG_IN_L(obj, PDS_DEBUG_LEVEL)
513 #define PDS_INFO_IN(obj) NLMISC::createDebug (), NLMISC::InfoLog->setPosition( __LINE__, __FILE__ ), NLMISC::InfoLog->display("%s:", obj->getContextualIndentifier().c_str()), NLMISC::InfoLog->displayNL
514 #define PDS_WARNING_IN(obj) NLMISC::createDebug (), NLMISC::WarningLog->setPosition( __LINE__, __FILE__ ), NLMISC::WarningLog->display("%s:", obj->getContextualIndentifier().c_str()), NLMISC::WarningLog->displayNL
516 #define PDS_DEBUG_L(level) PDS_DEBUG_IN_L(this, level)
518 #define PDS_FULL_DEBUG PDS_DEBUG_L(PDS_FULL_DEBUG_LEVEL)
519 #define PDS_DEBUG PDS_DEBUG_L(PDS_DEBUG_LEVEL)
520 #define PDS_INFO PDS_INFO_IN(this)
521 #define PDS_WARNING PDS_WARNING_IN(this)
523 #define PDS_LOG_DEBUG(level) if (level <= 0 || !RY_PDS::PDVerbose || level > RY_PDS::PDVerboseLevel) {} else nldebug
538 * Get Contextual Identifier String
540 inline std::string
CPDSLogger::getContextualIndentifier() const
542 if (_ParentLogger
!= NULL
)
543 return _ParentLogger
->getContextualIndentifier()+"|"+getLoggerIdentifier();
545 return getLoggerIdentifier();
553 inline CRowMapper::CRowMapper()
561 inline void CRowMapper::clear()
565 _RowState
.clearAll();
570 * Declares a row as allocated
572 inline bool CRowMapper::allocate(RY_PDS::TRowIndex row
)
575 if (row
>= _RowState
.size())
576 _RowState
.resizeNoReset(row
+1);
578 // row already allocated?
579 if (_RowState
.get(row
))
589 * Declares a row as deallocated
591 inline bool CRowMapper::deallocate(RY_PDS::TRowIndex row
)
593 // check bit not outside bitset
594 if (row
>= _RowState
.size())
598 if (!_RowState
.get(row
))
601 _RowState
.clear(row
);
608 * Checks if a row is allocated
610 inline bool CRowMapper::allocated(RY_PDS::TRowIndex row
) const
612 return row
< _RowState
.size() && _RowState
.get(row
);
617 * Get Next Unalloocated row
619 inline RY_PDS::TRowIndex
CRowMapper::nextUnallocatedRow() const
621 RY_PDS::TRowIndex row
;
623 // go through all rows till found a free row
624 for (row
=0; allocated(row
); ++row
)
634 * Map a key to an Row
636 inline bool CRowMapper::map(TKey key
, const RY_PDS::CObjectIndex
& index
)
640 return _Link
->map(key
, index
);
643 if (_KeyMap
.find(key
) != _KeyMap
.end())
645 nlwarning("CRowMapper::map(): cannot map '%016" NL_I64
"X' to '%d', already mapped", key
, index
.toString().c_str());
649 _KeyMap
[key
] = index
;
657 inline bool CRowMapper::isMapped(TKey key
)
661 return _Link
->isMapped(key
);
664 return (_KeyMap
.find(key
) != _KeyMap
.end());
670 inline RY_PDS::CObjectIndex
CRowMapper::get(TKey key
) const
674 return _Link
->get(key
);
677 TKeyMap::const_iterator it
= _KeyMap
.find(key
);
679 if (it
== _KeyMap
.end())
681 PDS_LOG_DEBUG(1)("CRowMapper::get(): key '%016" NL_I64
"X' not mapped", key
);
682 return RY_PDS::CObjectIndex::null();
689 * Unmap a key of an Row
691 inline bool CRowMapper::unmap(TKey key
)
695 return _Link
->unmap(key
);
698 TKeyMap::iterator it
= _KeyMap
.find(key
);
700 if (it
== _KeyMap
.end())
702 nlwarning("CRowMapper::unmap(): key '%016" NL_I64
"X' not mapped", key
);
712 #endif //RY_PDS_LIB_H