Resolve "Toggle Free Look with Hotkey"
[ryzomcore.git] / ryzom / server / src / pd_lib / pd_server_utils.h
blob47bab34ddbb8030e055b7052f20e220b90204769
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.
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
21 * Includes
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>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string>
33 #include "pd_utils.h"
34 #include "timestamp.h"
37 /**
38 * CRefIndex, permanent info about the database
39 * This class is not intended to be modified, only create when a valid
40 * reference is ready
41 * To store volatile data, see CDatabaseState.
43 class CRefIndex
45 public:
47 /// Database Id
48 uint32 DatabaseId;
50 /// Numeral index of the reference
51 uint32 Index;
53 /// Directory path of the reference, this MUST local path from root database path
54 std::string Path;
56 /// Timestamp, in the form 'YYYY.MM.DD.hh.mm.ss'
57 //std::string Timestamp;
58 CTimestamp 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");
68 s.serial(DatabaseId);
69 s.xmlPop();
71 s.xmlPush("index");
72 s.serial(Index);
73 s.xmlPop();
75 s.xmlPush("path");
76 s.serial(Path);
77 s.xmlPop();
79 s.xmlPush("timestamp");
80 if (s.isReading())
82 std::string ts;
83 s.serial(ts);
84 Timestamp.fromString(ts.c_str());
86 else
88 std::string ts = Timestamp.toString();
89 s.serial(ts);
91 //s.serial(Timestamp);
92 s.xmlPop();
94 s.xmlPop();
97 /// Constructor
98 CRefIndex(uint32 databaseId) : DatabaseId(databaseId), Index(0)
100 setup();
103 /// Setup
104 void setup()
106 Path = "ref."+NLMISC::toString("%08X", Index);
107 setTimestamp();
111 * Set Time stamp
113 void setTimestamp();
117 * Load a Reference index file
119 bool load(const std::string& filename);
122 * Load a Reference index file
124 bool load();
127 * Save a Reference index file
129 bool save();
132 * Save a Reference index file
134 bool save(const std::string& filename);
137 * Build next Reference index file
139 bool buildNext();
142 * Get next Reference index file
144 void getNext();
147 * Get (and setup if needed) database root path
149 std::string getRootPath();
152 * Get reference path
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();
183 * Get Log path
185 std::string getLogPath();
187 private:
190 * Setup reference directory
192 bool setupDirectory();
195 * Check directory
197 bool checkDirectory(const std::string& path);
204 * CDatabaseState
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)
210 class CDatabaseState
212 public:
214 /// Constructor
215 CDatabaseState();
217 /// Database Name
218 std::string Name;
220 /// Database Id
221 uint32 Id;
223 /// Last Update Id
224 uint32 LastUpdateId;
226 /// Current Valid Index
227 uint32 CurrentIndex;
229 /// End Database Update Timestamp
230 CTimestamp EndTimestamp;
233 /// Serial method
234 void serial(NLMISC::IStream& s);
236 /// Save State
237 bool save(CRefIndex& ref);
239 /// Load State
240 bool load(CRefIndex& ref, bool usePrevious = false);
242 /// Load State
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"; }
256 private:
266 class CMixedStreamFile : public NLMISC::IStream
268 public:
270 /// Constructor
271 CMixedStreamFile() : NLMISC::IStream(false), _File(NULL)
275 /// Destructor
276 virtual ~CMixedStreamFile()
278 close();
281 bool open(const char* filename, const char* mode = "rb")
283 if (_File != NULL)
284 return false;
286 _File = NLMISC::nlfopen(filename, mode);
287 if (_File == NULL)
288 return false;
290 return true;
293 virtual void close()
295 if (_File != NULL)
296 fclose(_File);
297 _File = NULL;
300 void flush()
302 if (_File != NULL)
303 fflush(_File);
306 protected:
308 /// standard FILE handler
309 FILE* _File;
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;
318 template<typename T>
319 bool readValue(T& v) { return readBuffer(&v, sizeof(v)); }
321 template<typename T>
322 bool writeValue(const T& v) { return writeBuffer(&v, sizeof(v)); }
324 public:
326 virtual void serialBuffer(uint8 *buf, uint len)
328 if (_File == NULL)
329 throw NLMISC::EStream("CMixedStreamFile not opened");
331 if (isReading())
333 if (!readBuffer(buf, len))
334 throw NLMISC::EStream("file error "+NLMISC::toString(ferror(_File)));
336 else
338 if (!writeBuffer(buf, len))
339 throw NLMISC::EStream("file error "+NLMISC::toString(ferror(_File)));
343 virtual void serialBit(bool &bit)
345 if (isReading())
347 uint8 b;
348 serial(b);
349 bit = (b != 0);
351 else
353 uint8 b = bit;
354 serial(b);
362 class CRowMapper
364 public:
366 /// Constructor
367 CRowMapper();
369 /// Clear up mapper
370 void clear();
372 /// Set link
373 void link(CRowMapper* link) { _Link = link; }
376 /// Key
377 typedef uint64 TKey;
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);
419 * Is Row Mapped
421 bool isMapped(TKey key);
424 * Get Row from 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(); }
440 private:
443 * Bitset of allocated rows, each bit indicates if corresponding row is allocated
445 typedef NLMISC::CBitSet TRowState;
446 TRowState _RowState;
448 /// Total number of allocated rows
449 uint32 _AllocatedRows;
451 /// Key Hash
452 class CKeyHash
454 public:
455 size_t operator() (const TKey& key) const { return ((uint32)key) ^ ((uint32)(key >> 32)); }
458 typedef CHashMap<TKey, RY_PDS::CObjectIndex> TKeyMap;
459 TKeyMap _KeyMap;
461 /// Row Mapper link, in case of mapped table that inherit from another
462 CRowMapper* _Link;
469 * Debug/Log Interface
471 class CPDSLogger
473 public:
475 CPDSLogger() : _ParentLogger(NULL) { }
477 void setParentLogger(const CPDSLogger* parent) { _ParentLogger = parent; }
481 * Get Contextual Identifier String
483 std::string getContextualIndentifier() const;
485 protected:
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;
494 private:
496 /// Parent Logger
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
533 * Inlines
538 * Get Contextual Identifier String
540 inline std::string CPDSLogger::getContextualIndentifier() const
542 if (_ParentLogger != NULL)
543 return _ParentLogger->getContextualIndentifier()+"|"+getLoggerIdentifier();
544 else
545 return getLoggerIdentifier();
551 * Constructor
553 inline CRowMapper::CRowMapper()
555 clear();
559 * Clear up mapper
561 inline void CRowMapper::clear()
563 _Link = NULL;
564 _AllocatedRows = 0;
565 _RowState.clearAll();
566 _KeyMap.clear();
570 * Declares a row as allocated
572 inline bool CRowMapper::allocate(RY_PDS::TRowIndex row)
574 // check for room
575 if (row >= _RowState.size())
576 _RowState.resizeNoReset(row+1);
578 // row already allocated?
579 if (_RowState.get(row))
580 return false;
582 _RowState.set(row);
583 ++_AllocatedRows;
585 return true;
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())
595 return false;
597 // row allocated?
598 if (!_RowState.get(row))
599 return false;
601 _RowState.clear(row);
602 --_AllocatedRows;
604 return true;
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)
627 return row;
634 * Map a key to an Row
636 inline bool CRowMapper::map(TKey key, const RY_PDS::CObjectIndex& index)
638 if (_Link != NULL)
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());
646 return false;
649 _KeyMap[key] = index;
651 return true;
655 * Is Row Mapped
657 inline bool CRowMapper::isMapped(TKey key)
659 if (_Link != NULL)
661 return _Link->isMapped(key);
664 return (_KeyMap.find(key) != _KeyMap.end());
668 * Get Row from key
670 inline RY_PDS::CObjectIndex CRowMapper::get(TKey key) const
672 if (_Link != NULL)
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();
685 return (*it).second;
689 * Unmap a key of an Row
691 inline bool CRowMapper::unmap(TKey key)
693 if (_Link != NULL)
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);
703 return false;
706 _KeyMap.erase(it);
708 return true;
712 #endif //RY_PDS_LIB_H