2 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
3 // Copyright (C) 2010-2021 Winch Gate Property Limited
5 // This program is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU Affero General Public License as
7 // published by the Free Software Foundation, either version 3 of the
8 // License, or (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU Affero General Public License for more details.
15 // You should have received a copy of the GNU Affero General Public License
16 // along with this program. If not, see <http://www.gnu.org/licenses/>.
18 /////////////////////////////////////////////////////////////////
19 // WARNING : this is a generated file, don't change it !
20 /////////////////////////////////////////////////////////////////
24 #include "database_mapping.h"
29 void CKnownUserPtr::linkPtr()
31 nlassert(_NextPtr
== NULL
);
32 nlassert(_PrevPtr
== NULL
);
35 _NextPtr
= _Ptr
->getFirstPtr();
38 _PrevPtr
= _NextPtr
->_PrevPtr
;
39 _PrevPtr
->_NextPtr
= this;
40 _NextPtr
->_PrevPtr
= this;
46 _Ptr
->setFirstPtr(this);
51 void CKnownUserPtr::unlinkPtr()
55 nlassert(_PrevPtr
== NULL
);
63 nlassert(_PrevPtr
== this);
65 _Ptr
->setFirstPtr(NULL
);
69 if (_Ptr
->getFirstPtr() == this)
71 // the first ptr is the current one, we need to switch to next one
72 _Ptr
->setFirstPtr(_NextPtr
);
79 nlassert(_PrevPtr
!= this);
81 _NextPtr
->_PrevPtr
= _PrevPtr
;
82 _PrevPtr
->_NextPtr
= _NextPtr
;
89 CKnownUser::TObjectCache
CKnownUser::_ObjectCache
;
90 CKnownUser::TReleasedObject
CKnownUser::_ReleasedObject
;
93 // Destructor, delete any children
94 CKnownUser::~CKnownUser()
96 // release childs reference
101 nlwarning("ERROR : someone try to delete this object, but there are still ptr on it !");
102 CKnownUserPtr
*ptr
= _PtrList
;
105 nlwarning(" Pointer created from '%s', line %u", ptr
->_FileName
, ptr
->_LineNum
);
106 ptr
= _PtrList
->getNextPtr();
107 } while(ptr
!= _PtrList
);
110 // remove object from cache map
111 if (_RelationId
!= NOPE::INVALID_OBJECT_ID
112 && _ObjectState
!= NOPE::os_removed
113 && _ObjectState
!= NOPE::os_transient
)
115 nldebug("NOPE: clearing CKnownUser @%p from cache with id %u", this, static_cast<uint32
>(_RelationId
));
116 nlverify(_ObjectCache
.erase(_RelationId
) == 1);
118 else if (_ObjectState
!= NOPE::os_transient
)
120 nlassert(_ObjectCache
.find(_RelationId
) == _ObjectCache
.end());
122 if (_ObjectState
== NOPE::os_released
)
124 removeFromReleased();
128 TReleasedObject::iterator
it(_ReleasedObject
.find(_ReleaseDate
));
129 if (it
!= _ReleasedObject
.end())
131 nlassert(it
->second
.find(this) == it
->second
.end());
136 void CKnownUser::removeFromReleased()
138 TReleasedObject::iterator
it(_ReleasedObject
.find(_ReleaseDate
));
139 nlassert(it
!= _ReleasedObject
.end());
140 TObjectSet
&os
= it
->second
;
142 nlverify(os
.erase(this) == 1);
144 // nb : _ReleasedObject time entry are removed by the cache update
147 bool CKnownUser::create(MSW::CConnection
&connection
)
149 nlassert(getPersistentState() == NOPE::os_transient
);
152 qs
= "INSERT INTO known_users (";
154 qs
+= "owner, targer_user, targer_character, relation_type, comments";
157 qs
+= "'"+MSW::escapeString(NLMISC::toString(_OwnerId
), connection
)+"'";
159 qs
+= "'"+MSW::escapeString(NLMISC::toString(_TargetUser
), connection
)+"'";
161 qs
+= "'"+MSW::escapeString(NLMISC::toString(_TargetCharacter
), connection
)+"'";
163 qs
+= _Relation
.isValid()
164 ? "'"+_Relation
.toString()+"'"
165 : "DEFAULT(relation_type)";
167 qs
+= "'"+MSW::escapeString(NLMISC::toString(_Comments
), connection
)+"'";
171 if (connection
.query(qs
))
173 uint32 _id_
= connection
.getLastGeneratedId();
177 setPersistentState(NOPE::os_clean
);
179 // update the parent class instance in cache if any
183 // need to update the parent class child list if it is in the cache
184 CRingUser
*parent
= CRingUser::loadFromCache(_OwnerId
, false);
185 if (parent
&& parent
->_KnownUsers
!= NULL
)
188 nlassert(std::find(parent
->_KnownUsers
->begin(), parent
->_KnownUsers
->end(), CKnownUserPtr(this, __FILE__
, __LINE__
)) == parent
->_KnownUsers
->end());
189 parent
->_KnownUsers
->push_back(CKnownUserPtr(this, __FILE__
, __LINE__
));
194 if (_TargetUser
!= 0)
196 // need to update the parent class child list if it is in the cache
197 CCharacter
*parent
= CCharacter::loadFromCache(_TargetUser
, false);
198 if (parent
&& parent
->_KnownBy
!= NULL
)
201 nlassert(std::find(parent
->_KnownBy
->begin(), parent
->_KnownBy
->end(), CKnownUserPtr(this, __FILE__
, __LINE__
)) == parent
->_KnownBy
->end());
202 parent
->_KnownBy
->push_back(CKnownUserPtr(this, __FILE__
, __LINE__
));
213 bool CKnownUser::update(MSW::CConnection
&connection
)
215 nlassert(getPersistentState() == NOPE::os_dirty
|| getPersistentState() == NOPE::os_clean
);
217 if (getPersistentState() == NOPE::os_clean
)
218 // the object is clean, just ignore the save
222 qs
= "UPDATE known_users SET ";
224 qs
+= "owner = '"+MSW::escapeString(NLMISC::toString(_OwnerId
), connection
)+"'";
226 qs
+= "targer_user = '"+MSW::escapeString(NLMISC::toString(_TargetUser
), connection
)+"'";
228 qs
+= "targer_character = '"+MSW::escapeString(NLMISC::toString(_TargetCharacter
), connection
)+"'";
230 qs
+= "relation_type = " + (_Relation
.isValid()
231 ? "'"+_Relation
.toString()+"'"
232 : "DEFAULT(relation_type)");
234 qs
+= "comments = '"+MSW::escapeString(NLMISC::toString(_Comments
), connection
)+"'";
236 qs
+= " WHERE Id = '"+NLMISC::toString(_RelationId
)+"'";
239 if (connection
.query(qs
))
241 if (connection
.getAffectedRows() == 1)
243 setPersistentState(NOPE::os_clean
);
251 bool CKnownUser::remove(MSW::CConnection
&connection
)
253 nlassert(getPersistentState() == NOPE::os_dirty
|| getPersistentState() == NOPE::os_clean
);
256 qs
= "DELETE FROM known_users ";
258 qs
+= " WHERE Id = '"+NLMISC::toString(_RelationId
)+"'";
261 if (connection
.query(qs
))
263 if (connection
.getAffectedRows() == 1)
267 // change the persistant state to 'removed'.
268 setPersistentState(NOPE::os_removed
);
270 // need to remove ref from parent class container (if any)
273 CRingUserPtr
parent(CRingUser::loadFromCache(_OwnerId
, true), __FILE__
, __LINE__
);
274 if (parent
!= NULL
&& parent
->_KnownUsers
!= NULL
)
277 std::vector
< CKnownUserPtr
>::iterator it
= std::find(parent
->_KnownUsers
->begin(), parent
->_KnownUsers
->end(), this);
278 if (it
!= parent
->_KnownUsers
->end())
280 parent
->_KnownUsers
->erase(it
);
287 CCharacterPtr
parent(CCharacter::loadFromCache(_TargetUser
, true), __FILE__
, __LINE__
);
288 if (parent
!= NULL
&& parent
->_KnownBy
!= NULL
)
291 std::vector
< CKnownUserPtr
>::iterator it
= std::find(parent
->_KnownBy
->begin(), parent
->_KnownBy
->end(), this);
292 if (it
!= parent
->_KnownBy
->end())
294 parent
->_KnownBy
->erase(it
);
300 // need to remove ref from parent (if any)
309 bool CKnownUser::removeById(MSW::CConnection
&connection
, uint32 id
)
311 CKnownUser
*object
= loadFromCache(id
, true);
314 return object
->remove(connection
);
316 // not in cache, run a SQL query
318 qs
= "DELETE FROM known_users ";
320 qs
+= " WHERE Id = '"+NLMISC::toString(id
)+"'";
323 if (connection
.query(qs
))
325 if (connection
.getAffectedRows() == 1)
327 // ok, the row is removed
336 // Try to load the specified object from the memory cache, return NULL if the object is not in the cache
337 CKnownUser
*CKnownUser::loadFromCache(uint32 objectId
, bool unrelease
)
340 TObjectCache::iterator
it(_ObjectCache
.find(objectId
));
341 if (it
== _ObjectCache
.end())
343 // not found, return null
348 CKnownUser
*object
= it
->second
;
350 if (object
->_ObjectState
== NOPE::os_released
)
354 // we need to remove this object from the released object set.
355 object
->removeFromReleased();
356 object
->_ObjectState
= NOPE::os_clean
;
363 // Receive and execute command from the cache manager.
364 uint32
CKnownUser::cacheCmd(NOPE::TCacheCmd cmd
)
366 if (cmd
== NOPE::cc_update
)
370 else if (cmd
== NOPE::cc_clear
)
374 else if (cmd
== NOPE::cc_dump
)
378 else if (cmd
== NOPE::cc_instance_count
)
380 return (uint32
)_ObjectCache
.size();
383 // default return value
387 void CKnownUser::dump()
389 nlinfo(" Cache info for class CKnownUser :");
390 nlinfo(" There are %u object instances in cache", _ObjectCache
.size());
392 // count the number of object in the released object set
393 uint32 nbReleased
= 0;
395 TReleasedObject::iterator
first(_ReleasedObject
.begin()), last(_ReleasedObject
.end());
396 for (; first
!= last
; ++first
)
398 nbReleased
+= (uint32
)first
->second
.size();
401 nlinfo(" There are %u object instances in cache not referenced (waiting deletion or re-use))", nbReleased
);
404 void CKnownUser::updateCache()
406 if (_ReleasedObject
.empty())
409 // 30 s hold in cache
410 const time_t MAX_CACHE_OLD_TIME
= 30;
412 time_t now
= NLMISC::CTime::getSecondsSince1970();
414 // look for object set older than MAX_CACHE_OLD_TIME and delete them
415 while (!_ReleasedObject
.empty() && _ReleasedObject
.begin()->first
< now
-MAX_CACHE_OLD_TIME
)
417 TObjectSet
&delSet
= _ReleasedObject
.begin()->second
;
418 // unload this objects
419 while (!delSet
.empty())
421 CKnownUser
*object
= *delSet
.begin();
425 _ReleasedObject
.erase(_ReleasedObject
.begin());
429 void CKnownUser::clearCache()
431 // remove any unreferenced object from the cache
432 while (!_ReleasedObject
.empty())
434 TObjectSet
&delSet
= _ReleasedObject
.begin()->second
;
435 // unload this objects
436 while (!delSet
.empty())
438 CKnownUser
*object
= *delSet
.begin();
442 _ReleasedObject
.erase(_ReleasedObject
.begin());
446 void CKnownUser::registerUpdatable()
448 static bool registered
= false;
451 NOPE::CPersistentCache::getInstance().registerCache(&CKnownUser::cacheCmd
);
457 // set the pointer on the first pointer of the pointer list (set to null when there is no more pointer)
458 void CKnownUser::setFirstPtr(CKnownUserPtr
*ptr
)
464 // this is the last pointer !
465 if (_ObjectState
== NOPE::os_transient
466 || _ObjectState
== NOPE::os_removed
)
468 // not a persistent object, or removed object, just delet it
471 else if (_ObjectState
!= NOPE::os_removed
)
473 setPersistentState(NOPE::os_released
);
478 // Set the persistent state of the object and do some house keeping
479 void CKnownUser::setPersistentState(NOPE::TObjectState state
)
481 nlassert(NOPE::AllowedTransition
[_ObjectState
][state
] == true);
483 if(_ObjectState
== NOPE::os_released
&& state
== NOPE::os_removed
)
485 // a release object gets removed (e.g. by remove by id)
494 if (_ObjectState
== NOPE::os_transient
&& state
!= NOPE::os_transient
)
496 nldebug("NOPE: inserting CKnownUser @%p in cache with id %u", this, static_cast<uint32
>(_RelationId
));
497 nlverify(_ObjectCache
.insert(std::make_pair(_RelationId
, this)).second
);
500 if (_ObjectState
!= NOPE::os_transient
)
501 nlassert(_ObjectCache
.find(_RelationId
) != _ObjectCache
.end());
503 _ObjectState
= state
;
505 if (state
== NOPE::os_released
)
507 _ReleaseDate
= NLMISC::CTime::getSecondsSince1970();
508 nlverify(_ReleasedObject
[_ReleaseDate
].insert(this).second
);
510 else if (state
== NOPE::os_removed
)
512 nldebug("NOPE: erasing CKnownUser @%p in cache with id %u", this, static_cast<uint32
>(_RelationId
));
513 nlverify(_ObjectCache
.erase(_RelationId
) == 1);
518 CKnownUserPtr
CKnownUser::load(MSW::CConnection
&connection
, uint32 id
, const char *filename
, uint32 lineNum
)
520 CKnownUser
*inCache
= loadFromCache(id
, true);
523 return CKnownUserPtr(inCache
, filename
, lineNum
);
529 qs
+= "Id, owner, targer_user, targer_character, relation_type, comments";
531 qs
+= " FROM known_users";
533 qs
+= " WHERE Id = '"+NLMISC::toString(id
)+"'";
535 if (!connection
.query(qs
))
540 MSW::CStoreResult
*result
= connection
.storeResult().release();
542 nlassert(result
->getNumRows() <= 1);
543 if (result
->getNumRows() == 1)
545 ret
.assign(new CKnownUser
, filename
, lineNum
);
546 // ok, we have an object
549 result
->getField(0, ret
->_RelationId
);
550 result
->getField(1, ret
->_OwnerId
);
551 result
->getField(2, ret
->_TargetUser
);
552 result
->getField(3, ret
->_TargetCharacter
);
555 result
->getField(4, s
);
556 ret
->_Relation
= TKnownUserRelation(s
);
558 result
->getField(5, ret
->_Comments
);
561 ret
->setPersistentState(NOPE::os_clean
);
570 bool CKnownUser::loadChildrenOfCRingUser(MSW::CConnection
&connection
, uint32 parentId
, std::vector
< CKnownUserPtr
> & container
, const char *filename
, uint32 lineNum
)
576 qs
+= "Id, owner, targer_user, targer_character, relation_type, comments";
578 qs
+= " FROM known_users";
579 qs
+= " WHERE owner = '"+NLMISC::toString(parentId
)+"'";
581 if (!connection
.query(qs
))
586 CUniquePtr
<MSW::CStoreResult
> result
= connection
.storeResult();
588 for (uint i
=0; i
<result
->getNumRows(); ++i
)
590 CKnownUser
*ret
= new CKnownUser();
591 // ok, we have an object
594 result
->getField(0, ret
->_RelationId
);
596 result
->getField(1, ret
->_OwnerId
);
598 result
->getField(2, ret
->_TargetUser
);
600 result
->getField(3, ret
->_TargetCharacter
);
604 result
->getField(4, s
);
605 ret
->_Relation
= TKnownUserRelation(s
);
608 result
->getField(5, ret
->_Comments
);
609 CKnownUser
*inCache
= loadFromCache(ret
->_RelationId
, true);
613 container
.push_back(CKnownUserPtr(inCache
, filename
, lineNum
));
620 ret
->setPersistentState(NOPE::os_clean
);
622 container
.push_back(CKnownUserPtr(ret
, filename
, lineNum
));
630 bool CKnownUser::loadChildrenOfCCharacter(MSW::CConnection
&connection
, uint32 parentId
, std::vector
< CKnownUserPtr
> & container
, const char *filename
, uint32 lineNum
)
636 qs
+= "Id, owner, targer_user, targer_character, relation_type, comments";
638 qs
+= " FROM known_users";
639 qs
+= " WHERE targer_user = '"+NLMISC::toString(parentId
)+"'";
641 if (!connection
.query(qs
))
646 CUniquePtr
<MSW::CStoreResult
> result
= connection
.storeResult();
648 for (uint i
=0; i
<result
->getNumRows(); ++i
)
650 CKnownUser
*ret
= new CKnownUser();
651 // ok, we have an object
654 result
->getField(0, ret
->_RelationId
);
656 result
->getField(1, ret
->_OwnerId
);
658 result
->getField(2, ret
->_TargetUser
);
660 result
->getField(3, ret
->_TargetCharacter
);
664 result
->getField(4, s
);
665 ret
->_Relation
= TKnownUserRelation(s
);
668 result
->getField(5, ret
->_Comments
);
669 CKnownUser
*inCache
= loadFromCache(ret
->_RelationId
, true);
673 container
.push_back(CKnownUserPtr(inCache
, filename
, lineNum
));
680 ret
->setPersistentState(NOPE::os_clean
);
682 container
.push_back(CKnownUserPtr(ret
, filename
, lineNum
));
690 void CSessionParticipantPtr::linkPtr()
692 nlassert(_NextPtr
== NULL
);
693 nlassert(_PrevPtr
== NULL
);
696 _NextPtr
= _Ptr
->getFirstPtr();
697 if (_NextPtr
!= NULL
)
699 _PrevPtr
= _NextPtr
->_PrevPtr
;
700 _PrevPtr
->_NextPtr
= this;
701 _NextPtr
->_PrevPtr
= this;
707 _Ptr
->setFirstPtr(this);
712 void CSessionParticipantPtr::unlinkPtr()
714 if (_NextPtr
== NULL
)
716 nlassert(_PrevPtr
== NULL
);
722 if (_NextPtr
== this)
724 nlassert(_PrevPtr
== this);
726 _Ptr
->setFirstPtr(NULL
);
730 if (_Ptr
->getFirstPtr() == this)
732 // the first ptr is the current one, we need to switch to next one
733 _Ptr
->setFirstPtr(_NextPtr
);
738 if (_NextPtr
!= this)
740 nlassert(_PrevPtr
!= this);
742 _NextPtr
->_PrevPtr
= _PrevPtr
;
743 _PrevPtr
->_NextPtr
= _NextPtr
;
750 CSessionParticipant::TObjectCache
CSessionParticipant::_ObjectCache
;
751 CSessionParticipant::TReleasedObject
CSessionParticipant::_ReleasedObject
;
754 // Destructor, delete any children
755 CSessionParticipant::~CSessionParticipant()
757 // release childs reference
760 if (_PtrList
!= NULL
)
762 nlwarning("ERROR : someone try to delete this object, but there are still ptr on it !");
763 CSessionParticipantPtr
*ptr
= _PtrList
;
766 nlwarning(" Pointer created from '%s', line %u", ptr
->_FileName
, ptr
->_LineNum
);
767 ptr
= _PtrList
->getNextPtr();
768 } while(ptr
!= _PtrList
);
771 // remove object from cache map
772 if (_Id
!= NOPE::INVALID_OBJECT_ID
773 && _ObjectState
!= NOPE::os_removed
774 && _ObjectState
!= NOPE::os_transient
)
776 nldebug("NOPE: clearing CSessionParticipant @%p from cache with id %u", this, static_cast<uint32
>(_Id
));
777 nlverify(_ObjectCache
.erase(_Id
) == 1);
779 else if (_ObjectState
!= NOPE::os_transient
)
781 nlassert(_ObjectCache
.find(_Id
) == _ObjectCache
.end());
783 if (_ObjectState
== NOPE::os_released
)
785 removeFromReleased();
789 TReleasedObject::iterator
it(_ReleasedObject
.find(_ReleaseDate
));
790 if (it
!= _ReleasedObject
.end())
792 nlassert(it
->second
.find(this) == it
->second
.end());
797 void CSessionParticipant::removeFromReleased()
799 TReleasedObject::iterator
it(_ReleasedObject
.find(_ReleaseDate
));
800 nlassert(it
!= _ReleasedObject
.end());
801 TObjectSet
&os
= it
->second
;
803 nlverify(os
.erase(this) == 1);
805 // nb : _ReleasedObject time entry are removed by the cache update
808 bool CSessionParticipant::create(MSW::CConnection
&connection
)
810 nlassert(getPersistentState() == NOPE::os_transient
);
813 qs
= "INSERT INTO session_participant (";
815 qs
+= "session_id, char_id, status, kicked";
818 qs
+= "'"+MSW::escapeString(NLMISC::toString(_SessionId
), connection
)+"'";
820 qs
+= "'"+MSW::escapeString(NLMISC::toString(_CharId
), connection
)+"'";
822 qs
+= _Status
.isValid()
823 ? "'"+_Status
.toString()+"'"
826 qs
+= "'"+MSW::escapeString(NLMISC::toString(_Kicked
), connection
)+"'";
830 if (connection
.query(qs
))
832 uint32 _id_
= connection
.getLastGeneratedId();
836 setPersistentState(NOPE::os_clean
);
838 // update the parent class instance in cache if any
842 // need to update the parent class child list if it is in the cache
843 CCharacter
*parent
= CCharacter::loadFromCache(_CharId
, false);
844 if (parent
&& parent
->_SessionParticipants
!= NULL
)
847 nlassert(std::find(parent
->_SessionParticipants
->begin(), parent
->_SessionParticipants
->end(), CSessionParticipantPtr(this, __FILE__
, __LINE__
)) == parent
->_SessionParticipants
->end());
848 parent
->_SessionParticipants
->push_back(CSessionParticipantPtr(this, __FILE__
, __LINE__
));
855 // need to update the parent class child list if it is in the cache
856 CSession
*parent
= CSession::loadFromCache(_SessionId
, false);
857 if (parent
&& parent
->_SessionParticipants
!= NULL
)
860 nlassert(std::find(parent
->_SessionParticipants
->begin(), parent
->_SessionParticipants
->end(), CSessionParticipantPtr(this, __FILE__
, __LINE__
)) == parent
->_SessionParticipants
->end());
861 parent
->_SessionParticipants
->push_back(CSessionParticipantPtr(this, __FILE__
, __LINE__
));
872 bool CSessionParticipant::update(MSW::CConnection
&connection
)
874 nlassert(getPersistentState() == NOPE::os_dirty
|| getPersistentState() == NOPE::os_clean
);
876 if (getPersistentState() == NOPE::os_clean
)
877 // the object is clean, just ignore the save
881 qs
= "UPDATE session_participant SET ";
883 qs
+= "session_id = '"+MSW::escapeString(NLMISC::toString(_SessionId
), connection
)+"'";
885 qs
+= "char_id = '"+MSW::escapeString(NLMISC::toString(_CharId
), connection
)+"'";
887 qs
+= "status = " + (_Status
.isValid()
888 ? "'"+_Status
.toString()+"'"
889 : "DEFAULT(status)");
891 qs
+= "kicked = '"+MSW::escapeString(NLMISC::toString(_Kicked
), connection
)+"'";
893 qs
+= " WHERE Id = '"+NLMISC::toString(_Id
)+"'";
896 if (connection
.query(qs
))
898 if (connection
.getAffectedRows() == 1)
900 setPersistentState(NOPE::os_clean
);
908 bool CSessionParticipant::remove(MSW::CConnection
&connection
)
910 nlassert(getPersistentState() == NOPE::os_dirty
|| getPersistentState() == NOPE::os_clean
);
913 qs
= "DELETE FROM session_participant ";
915 qs
+= " WHERE Id = '"+NLMISC::toString(_Id
)+"'";
918 if (connection
.query(qs
))
920 if (connection
.getAffectedRows() == 1)
924 // change the persistant state to 'removed'.
925 setPersistentState(NOPE::os_removed
);
927 // need to remove ref from parent class container (if any)
930 CCharacterPtr
parent(CCharacter::loadFromCache(_CharId
, true), __FILE__
, __LINE__
);
931 if (parent
!= NULL
&& parent
->_SessionParticipants
!= NULL
)
934 std::vector
< CSessionParticipantPtr
>::iterator it
= std::find(parent
->_SessionParticipants
->begin(), parent
->_SessionParticipants
->end(), this);
935 if (it
!= parent
->_SessionParticipants
->end())
937 parent
->_SessionParticipants
->erase(it
);
944 CSessionPtr
parent(CSession::loadFromCache(_SessionId
, true), __FILE__
, __LINE__
);
945 if (parent
!= NULL
&& parent
->_SessionParticipants
!= NULL
)
948 std::vector
< CSessionParticipantPtr
>::iterator it
= std::find(parent
->_SessionParticipants
->begin(), parent
->_SessionParticipants
->end(), this);
949 if (it
!= parent
->_SessionParticipants
->end())
951 parent
->_SessionParticipants
->erase(it
);
957 // need to remove ref from parent (if any)
966 bool CSessionParticipant::removeById(MSW::CConnection
&connection
, uint32 id
)
968 CSessionParticipant
*object
= loadFromCache(id
, true);
971 return object
->remove(connection
);
973 // not in cache, run a SQL query
975 qs
= "DELETE FROM session_participant ";
977 qs
+= " WHERE Id = '"+NLMISC::toString(id
)+"'";
980 if (connection
.query(qs
))
982 if (connection
.getAffectedRows() == 1)
984 // ok, the row is removed
993 // Try to load the specified object from the memory cache, return NULL if the object is not in the cache
994 CSessionParticipant
*CSessionParticipant::loadFromCache(uint32 objectId
, bool unrelease
)
997 TObjectCache::iterator
it(_ObjectCache
.find(objectId
));
998 if (it
== _ObjectCache
.end())
1000 // not found, return null
1005 CSessionParticipant
*object
= it
->second
;
1007 if (object
->_ObjectState
== NOPE::os_released
)
1011 // we need to remove this object from the released object set.
1012 object
->removeFromReleased();
1013 object
->_ObjectState
= NOPE::os_clean
;
1020 // Receive and execute command from the cache manager.
1021 uint32
CSessionParticipant::cacheCmd(NOPE::TCacheCmd cmd
)
1023 if (cmd
== NOPE::cc_update
)
1027 else if (cmd
== NOPE::cc_clear
)
1031 else if (cmd
== NOPE::cc_dump
)
1035 else if (cmd
== NOPE::cc_instance_count
)
1037 return (uint32
)_ObjectCache
.size();
1040 // default return value
1044 void CSessionParticipant::dump()
1046 nlinfo(" Cache info for class CSessionParticipant :");
1047 nlinfo(" There are %u object instances in cache", _ObjectCache
.size());
1049 // count the number of object in the released object set
1050 uint32 nbReleased
= 0;
1052 TReleasedObject::iterator
first(_ReleasedObject
.begin()), last(_ReleasedObject
.end());
1053 for (; first
!= last
; ++first
)
1055 nbReleased
+= (uint32
)first
->second
.size();
1058 nlinfo(" There are %u object instances in cache not referenced (waiting deletion or re-use))", nbReleased
);
1061 void CSessionParticipant::updateCache()
1063 if (_ReleasedObject
.empty())
1066 // 30 s hold in cache
1067 const time_t MAX_CACHE_OLD_TIME
= 30;
1069 time_t now
= NLMISC::CTime::getSecondsSince1970();
1071 // look for object set older than MAX_CACHE_OLD_TIME and delete them
1072 while (!_ReleasedObject
.empty() && _ReleasedObject
.begin()->first
< now
-MAX_CACHE_OLD_TIME
)
1074 TObjectSet
&delSet
= _ReleasedObject
.begin()->second
;
1075 // unload this objects
1076 while (!delSet
.empty())
1078 CSessionParticipant
*object
= *delSet
.begin();
1082 _ReleasedObject
.erase(_ReleasedObject
.begin());
1086 void CSessionParticipant::clearCache()
1088 // remove any unreferenced object from the cache
1089 while (!_ReleasedObject
.empty())
1091 TObjectSet
&delSet
= _ReleasedObject
.begin()->second
;
1092 // unload this objects
1093 while (!delSet
.empty())
1095 CSessionParticipant
*object
= *delSet
.begin();
1099 _ReleasedObject
.erase(_ReleasedObject
.begin());
1103 void CSessionParticipant::registerUpdatable()
1105 static bool registered
= false;
1108 NOPE::CPersistentCache::getInstance().registerCache(&CSessionParticipant::cacheCmd
);
1114 // set the pointer on the first pointer of the pointer list (set to null when there is no more pointer)
1115 void CSessionParticipant::setFirstPtr(CSessionParticipantPtr
*ptr
)
1121 // this is the last pointer !
1122 if (_ObjectState
== NOPE::os_transient
1123 || _ObjectState
== NOPE::os_removed
)
1125 // not a persistent object, or removed object, just delet it
1128 else if (_ObjectState
!= NOPE::os_removed
)
1130 setPersistentState(NOPE::os_released
);
1135 // Set the persistent state of the object and do some house keeping
1136 void CSessionParticipant::setPersistentState(NOPE::TObjectState state
)
1138 nlassert(NOPE::AllowedTransition
[_ObjectState
][state
] == true);
1140 if(_ObjectState
== NOPE::os_released
&& state
== NOPE::os_removed
)
1142 // a release object gets removed (e.g. by remove by id)
1144 // delete the object
1151 if (_ObjectState
== NOPE::os_transient
&& state
!= NOPE::os_transient
)
1153 nldebug("NOPE: inserting CSessionParticipant @%p in cache with id %u", this, static_cast<uint32
>(_Id
));
1154 nlverify(_ObjectCache
.insert(std::make_pair(_Id
, this)).second
);
1157 if (_ObjectState
!= NOPE::os_transient
)
1158 nlassert(_ObjectCache
.find(_Id
) != _ObjectCache
.end());
1160 _ObjectState
= state
;
1162 if (state
== NOPE::os_released
)
1164 _ReleaseDate
= NLMISC::CTime::getSecondsSince1970();
1165 nlverify(_ReleasedObject
[_ReleaseDate
].insert(this).second
);
1167 else if (state
== NOPE::os_removed
)
1169 nldebug("NOPE: erasing CSessionParticipant @%p in cache with id %u", this, static_cast<uint32
>(_Id
));
1170 nlverify(_ObjectCache
.erase(_Id
) == 1);
1175 CSessionParticipantPtr
CSessionParticipant::load(MSW::CConnection
&connection
, uint32 id
, const char *filename
, uint32 lineNum
)
1177 CSessionParticipant
*inCache
= loadFromCache(id
, true);
1178 if (inCache
!= NULL
)
1180 return CSessionParticipantPtr(inCache
, filename
, lineNum
);
1186 qs
+= "Id, session_id, char_id, status, kicked";
1188 qs
+= " FROM session_participant";
1190 qs
+= " WHERE Id = '"+NLMISC::toString(id
)+"'";
1191 CSessionParticipantPtr ret
;
1192 if (!connection
.query(qs
))
1197 MSW::CStoreResult
*result
= connection
.storeResult().release();
1199 nlassert(result
->getNumRows() <= 1);
1200 if (result
->getNumRows() == 1)
1202 ret
.assign(new CSessionParticipant
, filename
, lineNum
);
1203 // ok, we have an object
1206 result
->getField(0, ret
->_Id
);
1207 result
->getField(1, ret
->_SessionId
);
1208 result
->getField(2, ret
->_CharId
);
1211 result
->getField(3, s
);
1212 ret
->_Status
= TSessionPartStatus(s
);
1214 result
->getField(4, ret
->_Kicked
);
1217 ret
->setPersistentState(NOPE::os_clean
);
1226 bool CSessionParticipant::loadChildrenOfCCharacter(MSW::CConnection
&connection
, uint32 parentId
, std::vector
< CSessionParticipantPtr
> & container
, const char *filename
, uint32 lineNum
)
1232 qs
+= "Id, session_id, char_id, status, kicked";
1234 qs
+= " FROM session_participant";
1235 qs
+= " WHERE char_id = '"+NLMISC::toString(parentId
)+"'";
1237 if (!connection
.query(qs
))
1242 CUniquePtr
<MSW::CStoreResult
> result
= connection
.storeResult();
1244 for (uint i
=0; i
<result
->getNumRows(); ++i
)
1246 CSessionParticipant
*ret
= new CSessionParticipant();
1247 // ok, we have an object
1250 result
->getField(0, ret
->_Id
);
1252 result
->getField(1, ret
->_SessionId
);
1254 result
->getField(2, ret
->_CharId
);
1258 result
->getField(3, s
);
1259 ret
->_Status
= TSessionPartStatus(s
);
1262 result
->getField(4, ret
->_Kicked
);
1263 CSessionParticipant
*inCache
= loadFromCache(ret
->_Id
, true);
1264 if (inCache
!= NULL
)
1267 container
.push_back(CSessionParticipantPtr(inCache
, filename
, lineNum
));
1274 ret
->setPersistentState(NOPE::os_clean
);
1276 container
.push_back(CSessionParticipantPtr(ret
, filename
, lineNum
));
1284 bool CSessionParticipant::loadChildrenOfCSession(MSW::CConnection
&connection
, uint32 parentId
, std::vector
< CSessionParticipantPtr
> & container
, const char *filename
, uint32 lineNum
)
1290 qs
+= "Id, session_id, char_id, status, kicked";
1292 qs
+= " FROM session_participant";
1293 qs
+= " WHERE session_id = '"+NLMISC::toString(parentId
)+"'";
1295 if (!connection
.query(qs
))
1300 CUniquePtr
<MSW::CStoreResult
> result
= connection
.storeResult();
1302 for (uint i
=0; i
<result
->getNumRows(); ++i
)
1304 CSessionParticipant
*ret
= new CSessionParticipant();
1305 // ok, we have an object
1308 result
->getField(0, ret
->_Id
);
1310 result
->getField(1, ret
->_SessionId
);
1312 result
->getField(2, ret
->_CharId
);
1316 result
->getField(3, s
);
1317 ret
->_Status
= TSessionPartStatus(s
);
1320 result
->getField(4, ret
->_Kicked
);
1321 CSessionParticipant
*inCache
= loadFromCache(ret
->_Id
, true);
1322 if (inCache
!= NULL
)
1325 container
.push_back(CSessionParticipantPtr(inCache
, filename
, lineNum
));
1332 ret
->setPersistentState(NOPE::os_clean
);
1334 container
.push_back(CSessionParticipantPtr(ret
, filename
, lineNum
));
1342 void CCharacterPtr::linkPtr()
1344 nlassert(_NextPtr
== NULL
);
1345 nlassert(_PrevPtr
== NULL
);
1348 _NextPtr
= _Ptr
->getFirstPtr();
1349 if (_NextPtr
!= NULL
)
1351 _PrevPtr
= _NextPtr
->_PrevPtr
;
1352 _PrevPtr
->_NextPtr
= this;
1353 _NextPtr
->_PrevPtr
= this;
1359 _Ptr
->setFirstPtr(this);
1364 void CCharacterPtr::unlinkPtr()
1366 if (_NextPtr
== NULL
)
1368 nlassert(_PrevPtr
== NULL
);
1374 if (_NextPtr
== this)
1376 nlassert(_PrevPtr
== this);
1378 _Ptr
->setFirstPtr(NULL
);
1382 if (_Ptr
->getFirstPtr() == this)
1384 // the first ptr is the current one, we need to switch to next one
1385 _Ptr
->setFirstPtr(_NextPtr
);
1390 if (_NextPtr
!= this)
1392 nlassert(_PrevPtr
!= this);
1394 _NextPtr
->_PrevPtr
= _PrevPtr
;
1395 _PrevPtr
->_NextPtr
= _NextPtr
;
1402 CCharacter::TObjectCache
CCharacter::_ObjectCache
;
1403 CCharacter::TReleasedObject
CCharacter::_ReleasedObject
;
1406 // Destructor, delete any children
1407 CCharacter::~CCharacter()
1409 // release childs reference
1410 if (_Sessions
!= NULL
)
1412 if (_SessionParticipants
!= NULL
)
1413 delete _SessionParticipants
;
1414 if (_KnownBy
!= NULL
)
1416 if (_PlayerRatings
!= NULL
)
1417 delete _PlayerRatings
;
1420 if (_PtrList
!= NULL
)
1422 nlwarning("ERROR : someone try to delete this object, but there are still ptr on it !");
1423 CCharacterPtr
*ptr
= _PtrList
;
1426 nlwarning(" Pointer created from '%s', line %u", ptr
->_FileName
, ptr
->_LineNum
);
1427 ptr
= _PtrList
->getNextPtr();
1428 } while(ptr
!= _PtrList
);
1431 // remove object from cache map
1432 if (_CharId
!= NOPE::INVALID_OBJECT_ID
1433 && _ObjectState
!= NOPE::os_removed
1434 && _ObjectState
!= NOPE::os_transient
)
1436 nldebug("NOPE: clearing CCharacter @%p from cache with id %u", this, static_cast<uint32
>(_CharId
));
1437 nlverify(_ObjectCache
.erase(_CharId
) == 1);
1439 else if (_ObjectState
!= NOPE::os_transient
)
1441 nlassert(_ObjectCache
.find(_CharId
) == _ObjectCache
.end());
1443 if (_ObjectState
== NOPE::os_released
)
1445 removeFromReleased();
1449 TReleasedObject::iterator
it(_ReleasedObject
.find(_ReleaseDate
));
1450 if (it
!= _ReleasedObject
.end())
1452 nlassert(it
->second
.find(this) == it
->second
.end());
1457 void CCharacter::removeFromReleased()
1459 TReleasedObject::iterator
it(_ReleasedObject
.find(_ReleaseDate
));
1460 nlassert(it
!= _ReleasedObject
.end());
1461 TObjectSet
&os
= it
->second
;
1463 nlverify(os
.erase(this) == 1);
1465 // nb : _ReleasedObject time entry are removed by the cache update
1468 bool CCharacter::create(MSW::CConnection
&connection
)
1470 nlassert(getPersistentState() == NOPE::os_transient
);
1472 nlassert(_CharId
!= 0);
1474 qs
= "INSERT INTO characters (";
1476 qs
+= "char_id, char_name, user_id, guild_id, best_combat_level, home_mainland_session_id, ring_access, race, civilisation, cult, current_session, rrp_am, rrp_masterless, rrp_author, newcomer, creation_date, last_played_date";
1479 qs
+= "'"+MSW::escapeString(NLMISC::toString(_CharId
), connection
)+"'";
1481 qs
+= "'"+MSW::escapeString(NLMISC::toString(_CharName
), connection
)+"'";
1483 qs
+= "'"+MSW::escapeString(NLMISC::toString(_UserId
), connection
)+"'";
1485 qs
+= "'"+MSW::escapeString(NLMISC::toString(_GuildId
), connection
)+"'";
1487 qs
+= "'"+MSW::escapeString(NLMISC::toString(_BestCombatLevel
), connection
)+"'";
1489 qs
+= "'"+MSW::escapeString(NLMISC::toString(_HomeMainlandSessionId
), connection
)+"'";
1491 qs
+= "'"+MSW::escapeString(NLMISC::toString(_RingAccess
), connection
)+"'";
1493 qs
+= _Race
.isValid()
1494 ? "'"+_Race
.toString()+"'"
1497 qs
+= _Civilisation
.isValid()
1498 ? "'"+_Civilisation
.toString()+"'"
1499 : "DEFAULT(civilisation)";
1501 qs
+= _Cult
.isValid()
1502 ? "'"+_Cult
.toString()+"'"
1505 qs
+= "'"+MSW::escapeString(NLMISC::toString(_CurrentSession
), connection
)+"'";
1507 qs
+= "'"+MSW::escapeString(NLMISC::toString(_RRPAM
), connection
)+"'";
1509 qs
+= "'"+MSW::escapeString(NLMISC::toString(_RRPMasterless
), connection
)+"'";
1511 qs
+= "'"+MSW::escapeString(NLMISC::toString(_RRPAuthor
), connection
)+"'";
1513 qs
+= "'"+MSW::escapeString(NLMISC::toString(_Newcomer
), connection
)+"'";
1515 qs
+= "'"+MSW::encodeDate(_CreationDate
)+"'";
1517 qs
+= "'"+MSW::encodeDate(_LastPlayedDate
)+"'";
1521 if (connection
.query(qs
))
1525 setPersistentState(NOPE::os_clean
);
1527 // update the parent class instance in cache if any
1531 // need to update the parent class child list if it is in the cache
1532 CRingUser
*parent
= CRingUser::loadFromCache(_UserId
, false);
1533 if (parent
&& parent
->_Characters
!= NULL
)
1536 nlverify(parent
->_Characters
->insert(std::make_pair(getObjectId(), CCharacterPtr(this, __FILE__
, __LINE__
))).second
);
1543 // need to update the parent class child list if it is in the cache
1544 CGuild
*parent
= CGuild::loadFromCache(_GuildId
, false);
1545 if (parent
&& parent
->_Characters
!= NULL
)
1548 nlassert(std::find(parent
->_Characters
->begin(), parent
->_Characters
->end(), CCharacterPtr(this, __FILE__
, __LINE__
)) == parent
->_Characters
->end());
1549 parent
->_Characters
->push_back(CCharacterPtr(this, __FILE__
, __LINE__
));
1560 bool CCharacter::update(MSW::CConnection
&connection
)
1562 nlassert(getPersistentState() == NOPE::os_dirty
|| getPersistentState() == NOPE::os_clean
);
1564 if (getPersistentState() == NOPE::os_clean
)
1565 // the object is clean, just ignore the save
1569 qs
= "UPDATE characters SET ";
1571 qs
+= "char_id = '"+MSW::escapeString(NLMISC::toString(_CharId
), connection
)+"'";
1573 qs
+= "char_name = '"+MSW::escapeString(NLMISC::toString(_CharName
), connection
)+"'";
1575 qs
+= "user_id = '"+MSW::escapeString(NLMISC::toString(_UserId
), connection
)+"'";
1577 qs
+= "guild_id = '"+MSW::escapeString(NLMISC::toString(_GuildId
), connection
)+"'";
1579 qs
+= "best_combat_level = '"+MSW::escapeString(NLMISC::toString(_BestCombatLevel
), connection
)+"'";
1581 qs
+= "home_mainland_session_id = '"+MSW::escapeString(NLMISC::toString(_HomeMainlandSessionId
), connection
)+"'";
1583 qs
+= "ring_access = '"+MSW::escapeString(NLMISC::toString(_RingAccess
), connection
)+"'";
1585 qs
+= "race = " + (_Race
.isValid()
1586 ? "'"+_Race
.toString()+"'"
1589 qs
+= "civilisation = " + (_Civilisation
.isValid()
1590 ? "'"+_Civilisation
.toString()+"'"
1591 : "DEFAULT(civilisation)");
1593 qs
+= "cult = " + (_Cult
.isValid()
1594 ? "'"+_Cult
.toString()+"'"
1597 qs
+= "current_session = '"+MSW::escapeString(NLMISC::toString(_CurrentSession
), connection
)+"'";
1599 qs
+= "rrp_am = '"+MSW::escapeString(NLMISC::toString(_RRPAM
), connection
)+"'";
1601 qs
+= "rrp_masterless = '"+MSW::escapeString(NLMISC::toString(_RRPMasterless
), connection
)+"'";
1603 qs
+= "rrp_author = '"+MSW::escapeString(NLMISC::toString(_RRPAuthor
), connection
)+"'";
1605 qs
+= "newcomer = '"+MSW::escapeString(NLMISC::toString(_Newcomer
), connection
)+"'";
1607 qs
+= "creation_date = '"+MSW::encodeDate(_CreationDate
)+"'";
1609 qs
+= "last_played_date = '"+MSW::encodeDate(_LastPlayedDate
)+"'";
1611 qs
+= " WHERE char_id = '"+NLMISC::toString(_CharId
)+"'";
1614 if (connection
.query(qs
))
1616 if (connection
.getAffectedRows() == 1)
1618 setPersistentState(NOPE::os_clean
);
1626 bool CCharacter::remove(MSW::CConnection
&connection
)
1628 nlassert(getPersistentState() == NOPE::os_dirty
|| getPersistentState() == NOPE::os_clean
);
1631 qs
= "DELETE FROM characters ";
1633 qs
+= " WHERE char_id = '"+NLMISC::toString(_CharId
)+"'";
1636 if (connection
.query(qs
))
1638 if (connection
.getAffectedRows() == 1)
1642 // cascading deletion for vector child SessionParticipants
1643 if (loadSessionParticipants(connection
, __FILE__
, __LINE__
))
1645 const std::vector
< CSessionParticipantPtr
> & childs
= getSessionParticipants();
1647 while (!childs
.empty())
1649 getSessionParticipantsByIndex((uint32
)childs
.size()-1)->remove(connection
);
1656 // cascading deletion for vector child KnownBy
1657 if (loadKnownBy(connection
, __FILE__
, __LINE__
))
1659 const std::vector
< CKnownUserPtr
> & childs
= getKnownBy();
1661 while (!childs
.empty())
1663 getKnownByByIndex((uint32
)childs
.size()-1)->remove(connection
);
1670 // unreference (and update) for vector child PlayerRatings
1671 if (loadPlayerRatings(connection
, __FILE__
, __LINE__
))
1673 const std::vector
< CPlayerRatingPtr
> & childs
= getPlayerRatings();
1675 for (uint i
=0; i
< childs
.size(); ++i
)
1678 getPlayerRatingsByIndex(i
)->setAuthor(0);
1679 getPlayerRatingsByIndex(i
)->update(connection
);
1685 // change the persistant state to 'removed'.
1686 setPersistentState(NOPE::os_removed
);
1688 // need to remove ref from parent class container (if any)
1691 CRingUserPtr
parent(CRingUser::loadFromCache(_UserId
, true), __FILE__
, __LINE__
);
1692 if (parent
!= NULL
&& parent
->_Characters
!= NULL
)
1695 parent
->_Characters
->erase(getObjectId());
1701 CGuildPtr
parent(CGuild::loadFromCache(_GuildId
, true), __FILE__
, __LINE__
);
1702 if (parent
!= NULL
&& parent
->_Characters
!= NULL
)
1705 std::vector
< CCharacterPtr
>::iterator it
= std::find(parent
->_Characters
->begin(), parent
->_Characters
->end(), this);
1706 if (it
!= parent
->_Characters
->end())
1708 parent
->_Characters
->erase(it
);
1714 // need to remove ref from parent (if any)
1723 bool CCharacter::removeById(MSW::CConnection
&connection
, uint32 id
)
1725 CCharacter
*object
= loadFromCache(id
, true);
1728 return object
->remove(connection
);
1730 // not in cache, run a SQL query
1732 qs
= "DELETE FROM characters ";
1734 qs
+= " WHERE char_id = '"+NLMISC::toString(id
)+"'";
1737 if (connection
.query(qs
))
1739 if (connection
.getAffectedRows() == 1)
1741 // ok, the row is removed
1750 // Try to load the specified object from the memory cache, return NULL if the object is not in the cache
1751 CCharacter
*CCharacter::loadFromCache(uint32 objectId
, bool unrelease
)
1753 // look in the cache
1754 TObjectCache::iterator
it(_ObjectCache
.find(objectId
));
1755 if (it
== _ObjectCache
.end())
1757 // not found, return null
1762 CCharacter
*object
= it
->second
;
1764 if (object
->_ObjectState
== NOPE::os_released
)
1768 // we need to remove this object from the released object set.
1769 object
->removeFromReleased();
1770 object
->_ObjectState
= NOPE::os_clean
;
1777 // Receive and execute command from the cache manager.
1778 uint32
CCharacter::cacheCmd(NOPE::TCacheCmd cmd
)
1780 if (cmd
== NOPE::cc_update
)
1784 else if (cmd
== NOPE::cc_clear
)
1788 else if (cmd
== NOPE::cc_dump
)
1792 else if (cmd
== NOPE::cc_instance_count
)
1794 return (uint32
)_ObjectCache
.size();
1797 // default return value
1801 void CCharacter::dump()
1803 nlinfo(" Cache info for class CCharacter :");
1804 nlinfo(" There are %u object instances in cache", _ObjectCache
.size());
1806 // count the number of object in the released object set
1807 uint32 nbReleased
= 0;
1809 TReleasedObject::iterator
first(_ReleasedObject
.begin()), last(_ReleasedObject
.end());
1810 for (; first
!= last
; ++first
)
1812 nbReleased
+= (uint32
)first
->second
.size();
1815 nlinfo(" There are %u object instances in cache not referenced (waiting deletion or re-use))", nbReleased
);
1818 void CCharacter::updateCache()
1820 if (_ReleasedObject
.empty())
1823 // 30 s hold in cache
1824 const time_t MAX_CACHE_OLD_TIME
= 30;
1826 time_t now
= NLMISC::CTime::getSecondsSince1970();
1828 // look for object set older than MAX_CACHE_OLD_TIME and delete them
1829 while (!_ReleasedObject
.empty() && _ReleasedObject
.begin()->first
< now
-MAX_CACHE_OLD_TIME
)
1831 TObjectSet
&delSet
= _ReleasedObject
.begin()->second
;
1832 // unload this objects
1833 while (!delSet
.empty())
1835 CCharacter
*object
= *delSet
.begin();
1839 _ReleasedObject
.erase(_ReleasedObject
.begin());
1843 void CCharacter::clearCache()
1845 // remove any unreferenced object from the cache
1846 while (!_ReleasedObject
.empty())
1848 TObjectSet
&delSet
= _ReleasedObject
.begin()->second
;
1849 // unload this objects
1850 while (!delSet
.empty())
1852 CCharacter
*object
= *delSet
.begin();
1856 _ReleasedObject
.erase(_ReleasedObject
.begin());
1860 void CCharacter::registerUpdatable()
1862 static bool registered
= false;
1865 NOPE::CPersistentCache::getInstance().registerCache(&CCharacter::cacheCmd
);
1871 // set the pointer on the first pointer of the pointer list (set to null when there is no more pointer)
1872 void CCharacter::setFirstPtr(CCharacterPtr
*ptr
)
1878 // this is the last pointer !
1879 if (_ObjectState
== NOPE::os_transient
1880 || _ObjectState
== NOPE::os_removed
)
1882 // not a persistent object, or removed object, just delet it
1885 else if (_ObjectState
!= NOPE::os_removed
)
1887 setPersistentState(NOPE::os_released
);
1892 // Set the persistent state of the object and do some house keeping
1893 void CCharacter::setPersistentState(NOPE::TObjectState state
)
1895 nlassert(NOPE::AllowedTransition
[_ObjectState
][state
] == true);
1897 if(_ObjectState
== NOPE::os_released
&& state
== NOPE::os_removed
)
1899 // a release object gets removed (e.g. by remove by id)
1901 // delete the object
1908 if (_ObjectState
== NOPE::os_transient
&& state
!= NOPE::os_transient
)
1910 nldebug("NOPE: inserting CCharacter @%p in cache with id %u", this, static_cast<uint32
>(_CharId
));
1911 nlverify(_ObjectCache
.insert(std::make_pair(_CharId
, this)).second
);
1914 if (_ObjectState
!= NOPE::os_transient
)
1915 nlassert(_ObjectCache
.find(_CharId
) != _ObjectCache
.end());
1917 _ObjectState
= state
;
1919 if (state
== NOPE::os_released
)
1921 _ReleaseDate
= NLMISC::CTime::getSecondsSince1970();
1922 nlverify(_ReleasedObject
[_ReleaseDate
].insert(this).second
);
1924 else if (state
== NOPE::os_removed
)
1926 nldebug("NOPE: erasing CCharacter @%p in cache with id %u", this, static_cast<uint32
>(_CharId
));
1927 nlverify(_ObjectCache
.erase(_CharId
) == 1);
1932 CCharacterPtr
CCharacter::load(MSW::CConnection
&connection
, uint32 id
, const char *filename
, uint32 lineNum
)
1934 CCharacter
*inCache
= loadFromCache(id
, true);
1935 if (inCache
!= NULL
)
1937 return CCharacterPtr(inCache
, filename
, lineNum
);
1943 qs
+= "char_id, char_name, user_id, guild_id, best_combat_level, home_mainland_session_id, ring_access, race, civilisation, cult, current_session, rrp_am, rrp_masterless, rrp_author, newcomer, creation_date, last_played_date";
1945 qs
+= " FROM characters";
1947 qs
+= " WHERE char_id = '"+NLMISC::toString(id
)+"'";
1949 if (!connection
.query(qs
))
1954 MSW::CStoreResult
*result
= connection
.storeResult().release();
1956 nlassert(result
->getNumRows() <= 1);
1957 if (result
->getNumRows() == 1)
1959 ret
.assign(new CCharacter
, filename
, lineNum
);
1960 // ok, we have an object
1963 result
->getField(0, ret
->_CharId
);
1964 result
->getField(1, ret
->_CharName
);
1965 result
->getField(2, ret
->_UserId
);
1966 result
->getField(3, ret
->_GuildId
);
1967 result
->getField(4, ret
->_BestCombatLevel
);
1968 result
->getField(5, ret
->_HomeMainlandSessionId
);
1969 result
->getField(6, ret
->_RingAccess
);
1972 result
->getField(7, s
);
1973 ret
->_Race
= CHARSYNC::TRace(s
);
1977 result
->getField(8, s
);
1978 ret
->_Civilisation
= CHARSYNC::TCivilisation(s
);
1982 result
->getField(9, s
);
1983 ret
->_Cult
= CHARSYNC::TCult(s
);
1985 result
->getField(10, ret
->_CurrentSession
);
1986 result
->getField(11, ret
->_RRPAM
);
1987 result
->getField(12, ret
->_RRPMasterless
);
1988 result
->getField(13, ret
->_RRPAuthor
);
1989 result
->getField(14, ret
->_Newcomer
);
1990 result
->getDateField(15, ret
->_CreationDate
);
1991 result
->getDateField(16, ret
->_LastPlayedDate
);
1994 ret
->setPersistentState(NOPE::os_clean
);
2003 bool CCharacter::loadChildrenOfCRingUser(MSW::CConnection
&connection
, uint32 parentId
, std::map
< uint32
, CCharacterPtr
> & container
, const char *filename
, uint32 lineNum
)
2009 qs
+= "char_id, char_name, user_id, guild_id, best_combat_level, home_mainland_session_id, ring_access, race, civilisation, cult, current_session, rrp_am, rrp_masterless, rrp_author, newcomer, creation_date, last_played_date";
2011 qs
+= " FROM characters";
2012 qs
+= " WHERE user_id = '"+NLMISC::toString(parentId
)+"'";
2014 if (!connection
.query(qs
))
2019 CUniquePtr
<MSW::CStoreResult
> result
= connection
.storeResult();
2021 for (uint i
=0; i
<result
->getNumRows(); ++i
)
2023 CCharacter
*ret
= new CCharacter();
2024 // ok, we have an object
2027 result
->getField(0, ret
->_CharId
);
2029 result
->getField(1, ret
->_CharName
);
2031 result
->getField(2, ret
->_UserId
);
2033 result
->getField(3, ret
->_GuildId
);
2035 result
->getField(4, ret
->_BestCombatLevel
);
2037 result
->getField(5, ret
->_HomeMainlandSessionId
);
2039 result
->getField(6, ret
->_RingAccess
);
2043 result
->getField(7, s
);
2044 ret
->_Race
= CHARSYNC::TRace(s
);
2049 result
->getField(8, s
);
2050 ret
->_Civilisation
= CHARSYNC::TCivilisation(s
);
2055 result
->getField(9, s
);
2056 ret
->_Cult
= CHARSYNC::TCult(s
);
2059 result
->getField(10, ret
->_CurrentSession
);
2061 result
->getField(11, ret
->_RRPAM
);
2063 result
->getField(12, ret
->_RRPMasterless
);
2065 result
->getField(13, ret
->_RRPAuthor
);
2067 result
->getField(14, ret
->_Newcomer
);
2069 result
->getDateField(15, ret
->_CreationDate
);
2071 result
->getDateField(16, ret
->_LastPlayedDate
);
2072 CCharacter
*inCache
= loadFromCache(ret
->_CharId
, true);
2073 if (inCache
!= NULL
)
2076 container
.insert(std::make_pair(inCache
->getObjectId(), CCharacterPtr(inCache
, filename
, lineNum
)));
2083 ret
->setPersistentState(NOPE::os_clean
);
2085 container
.insert(std::make_pair(ret
->getObjectId(), CCharacterPtr(ret
, filename
, lineNum
)));
2093 bool CCharacter::loadChildrenOfCGuild(MSW::CConnection
&connection
, uint32 parentId
, std::vector
< CCharacterPtr
> & container
, const char *filename
, uint32 lineNum
)
2099 qs
+= "char_id, char_name, user_id, guild_id, best_combat_level, home_mainland_session_id, ring_access, race, civilisation, cult, current_session, rrp_am, rrp_masterless, rrp_author, newcomer, creation_date, last_played_date";
2101 qs
+= " FROM characters";
2102 qs
+= " WHERE guild_id = '"+NLMISC::toString(parentId
)+"'";
2104 if (!connection
.query(qs
))
2109 CUniquePtr
<MSW::CStoreResult
> result
= connection
.storeResult();
2111 for (uint i
=0; i
<result
->getNumRows(); ++i
)
2113 CCharacter
*ret
= new CCharacter();
2114 // ok, we have an object
2117 result
->getField(0, ret
->_CharId
);
2119 result
->getField(1, ret
->_CharName
);
2121 result
->getField(2, ret
->_UserId
);
2123 result
->getField(3, ret
->_GuildId
);
2125 result
->getField(4, ret
->_BestCombatLevel
);
2127 result
->getField(5, ret
->_HomeMainlandSessionId
);
2129 result
->getField(6, ret
->_RingAccess
);
2133 result
->getField(7, s
);
2134 ret
->_Race
= CHARSYNC::TRace(s
);
2139 result
->getField(8, s
);
2140 ret
->_Civilisation
= CHARSYNC::TCivilisation(s
);
2145 result
->getField(9, s
);
2146 ret
->_Cult
= CHARSYNC::TCult(s
);
2149 result
->getField(10, ret
->_CurrentSession
);
2151 result
->getField(11, ret
->_RRPAM
);
2153 result
->getField(12, ret
->_RRPMasterless
);
2155 result
->getField(13, ret
->_RRPAuthor
);
2157 result
->getField(14, ret
->_Newcomer
);
2159 result
->getDateField(15, ret
->_CreationDate
);
2161 result
->getDateField(16, ret
->_LastPlayedDate
);
2162 CCharacter
*inCache
= loadFromCache(ret
->_CharId
, true);
2163 if (inCache
!= NULL
)
2166 container
.push_back(CCharacterPtr(inCache
, filename
, lineNum
));
2173 ret
->setPersistentState(NOPE::os_clean
);
2175 container
.push_back(CCharacterPtr(ret
, filename
, lineNum
));
2183 bool CCharacter::loadSessions(MSW::CConnection
&connection
, const char *filename
, uint32 lineNum
)
2186 if (_Sessions
!= NULL
)
2188 // the children are already loaded, just return true
2192 // allocate the container
2193 _Sessions
= new std::vector
< CSessionPtr
>;
2196 ret
&= CSession::loadChildrenOfCCharacter(connection
, getObjectId(), *_Sessions
, filename
, lineNum
);
2201 const std::vector
<CSessionPtr
> &CCharacter::getSessions() const
2203 nlassert(_Sessions
!= NULL
);
2207 CSessionPtr
&CCharacter::getSessionsByIndex(uint32 index
) const
2209 nlassert(_Sessions
!= NULL
);
2210 nlassert(index
< _Sessions
->size());
2211 return const_cast< CSessionPtr
& >(_Sessions
->operator[](index
));
2214 CSessionPtr
&CCharacter::getSessionsById(uint32 id
) const
2216 nlassert(_Sessions
!= NULL
);
2217 std::vector
<CSessionPtr
>::const_iterator
first(_Sessions
->begin()), last(_Sessions
->end());
2218 for (; first
!= last
; ++first
)
2220 const CSessionPtr
&child
= *first
;
2221 if (child
->getObjectId() == id
)
2223 return const_cast< CSessionPtr
& >(child
);
2227 // no object with this id, return a null pointer
2228 static CSessionPtr nilPtr
;
2234 bool CCharacter::loadSessionParticipants(MSW::CConnection
&connection
, const char *filename
, uint32 lineNum
)
2237 if (_SessionParticipants
!= NULL
)
2239 // the children are already loaded, just return true
2243 // allocate the container
2244 _SessionParticipants
= new std::vector
< CSessionParticipantPtr
>;
2247 ret
&= CSessionParticipant::loadChildrenOfCCharacter(connection
, getObjectId(), *_SessionParticipants
, filename
, lineNum
);
2252 const std::vector
<CSessionParticipantPtr
> &CCharacter::getSessionParticipants() const
2254 nlassert(_SessionParticipants
!= NULL
);
2255 return *_SessionParticipants
;
2258 CSessionParticipantPtr
&CCharacter::getSessionParticipantsByIndex(uint32 index
) const
2260 nlassert(_SessionParticipants
!= NULL
);
2261 nlassert(index
< _SessionParticipants
->size());
2262 return const_cast< CSessionParticipantPtr
& >(_SessionParticipants
->operator[](index
));
2265 CSessionParticipantPtr
&CCharacter::getSessionParticipantsById(uint32 id
) const
2267 nlassert(_SessionParticipants
!= NULL
);
2268 std::vector
<CSessionParticipantPtr
>::const_iterator
first(_SessionParticipants
->begin()), last(_SessionParticipants
->end());
2269 for (; first
!= last
; ++first
)
2271 const CSessionParticipantPtr
&child
= *first
;
2272 if (child
->getObjectId() == id
)
2274 return const_cast< CSessionParticipantPtr
& >(child
);
2278 // no object with this id, return a null pointer
2279 static CSessionParticipantPtr nilPtr
;
2285 bool CCharacter::loadKnownBy(MSW::CConnection
&connection
, const char *filename
, uint32 lineNum
)
2288 if (_KnownBy
!= NULL
)
2290 // the children are already loaded, just return true
2294 // allocate the container
2295 _KnownBy
= new std::vector
< CKnownUserPtr
>;
2298 ret
&= CKnownUser::loadChildrenOfCCharacter(connection
, getObjectId(), *_KnownBy
, filename
, lineNum
);
2303 const std::vector
<CKnownUserPtr
> &CCharacter::getKnownBy() const
2305 nlassert(_KnownBy
!= NULL
);
2309 CKnownUserPtr
&CCharacter::getKnownByByIndex(uint32 index
) const
2311 nlassert(_KnownBy
!= NULL
);
2312 nlassert(index
< _KnownBy
->size());
2313 return const_cast< CKnownUserPtr
& >(_KnownBy
->operator[](index
));
2316 CKnownUserPtr
&CCharacter::getKnownByById(uint32 id
) const
2318 nlassert(_KnownBy
!= NULL
);
2319 std::vector
<CKnownUserPtr
>::const_iterator
first(_KnownBy
->begin()), last(_KnownBy
->end());
2320 for (; first
!= last
; ++first
)
2322 const CKnownUserPtr
&child
= *first
;
2323 if (child
->getObjectId() == id
)
2325 return const_cast< CKnownUserPtr
& >(child
);
2329 // no object with this id, return a null pointer
2330 static CKnownUserPtr nilPtr
;
2336 bool CCharacter::loadPlayerRatings(MSW::CConnection
&connection
, const char *filename
, uint32 lineNum
)
2339 if (_PlayerRatings
!= NULL
)
2341 // the children are already loaded, just return true
2345 // allocate the container
2346 _PlayerRatings
= new std::vector
< CPlayerRatingPtr
>;
2349 ret
&= CPlayerRating::loadChildrenOfCCharacter(connection
, getObjectId(), *_PlayerRatings
, filename
, lineNum
);
2354 const std::vector
<CPlayerRatingPtr
> &CCharacter::getPlayerRatings() const
2356 nlassert(_PlayerRatings
!= NULL
);
2357 return *_PlayerRatings
;
2360 CPlayerRatingPtr
&CCharacter::getPlayerRatingsByIndex(uint32 index
) const
2362 nlassert(_PlayerRatings
!= NULL
);
2363 nlassert(index
< _PlayerRatings
->size());
2364 return const_cast< CPlayerRatingPtr
& >(_PlayerRatings
->operator[](index
));
2367 CPlayerRatingPtr
&CCharacter::getPlayerRatingsById(uint32 id
) const
2369 nlassert(_PlayerRatings
!= NULL
);
2370 std::vector
<CPlayerRatingPtr
>::const_iterator
first(_PlayerRatings
->begin()), last(_PlayerRatings
->end());
2371 for (; first
!= last
; ++first
)
2373 const CPlayerRatingPtr
&child
= *first
;
2374 if (child
->getObjectId() == id
)
2376 return const_cast< CPlayerRatingPtr
& >(child
);
2380 // no object with this id, return a null pointer
2381 static CPlayerRatingPtr nilPtr
;
2387 void CRingUserPtr::linkPtr()
2389 nlassert(_NextPtr
== NULL
);
2390 nlassert(_PrevPtr
== NULL
);
2393 _NextPtr
= _Ptr
->getFirstPtr();
2394 if (_NextPtr
!= NULL
)
2396 _PrevPtr
= _NextPtr
->_PrevPtr
;
2397 _PrevPtr
->_NextPtr
= this;
2398 _NextPtr
->_PrevPtr
= this;
2404 _Ptr
->setFirstPtr(this);
2409 void CRingUserPtr::unlinkPtr()
2411 if (_NextPtr
== NULL
)
2413 nlassert(_PrevPtr
== NULL
);
2419 if (_NextPtr
== this)
2421 nlassert(_PrevPtr
== this);
2423 _Ptr
->setFirstPtr(NULL
);
2427 if (_Ptr
->getFirstPtr() == this)
2429 // the first ptr is the current one, we need to switch to next one
2430 _Ptr
->setFirstPtr(_NextPtr
);
2435 if (_NextPtr
!= this)
2437 nlassert(_PrevPtr
!= this);
2439 _NextPtr
->_PrevPtr
= _PrevPtr
;
2440 _PrevPtr
->_NextPtr
= _NextPtr
;
2447 CRingUser::TObjectCache
CRingUser::_ObjectCache
;
2448 CRingUser::TReleasedObject
CRingUser::_ReleasedObject
;
2451 // Destructor, delete any children
2452 CRingUser::~CRingUser()
2454 // release childs reference
2455 if (_KnownUsers
!= NULL
)
2457 if (_Characters
!= NULL
)
2459 if (_Folders
!= NULL
)
2461 if (_FolderAccess
!= NULL
)
2462 delete _FolderAccess
;
2465 if (_PtrList
!= NULL
)
2467 nlwarning("ERROR : someone try to delete this object, but there are still ptr on it !");
2468 CRingUserPtr
*ptr
= _PtrList
;
2471 nlwarning(" Pointer created from '%s', line %u", ptr
->_FileName
, ptr
->_LineNum
);
2472 ptr
= _PtrList
->getNextPtr();
2473 } while(ptr
!= _PtrList
);
2476 // remove object from cache map
2477 if (_UserId
!= NOPE::INVALID_OBJECT_ID
2478 && _ObjectState
!= NOPE::os_removed
2479 && _ObjectState
!= NOPE::os_transient
)
2481 nldebug("NOPE: clearing CRingUser @%p from cache with id %u", this, static_cast<uint32
>(_UserId
));
2482 nlverify(_ObjectCache
.erase(_UserId
) == 1);
2484 else if (_ObjectState
!= NOPE::os_transient
)
2486 nlassert(_ObjectCache
.find(_UserId
) == _ObjectCache
.end());
2488 if (_ObjectState
== NOPE::os_released
)
2490 removeFromReleased();
2494 TReleasedObject::iterator
it(_ReleasedObject
.find(_ReleaseDate
));
2495 if (it
!= _ReleasedObject
.end())
2497 nlassert(it
->second
.find(this) == it
->second
.end());
2502 void CRingUser::removeFromReleased()
2504 TReleasedObject::iterator
it(_ReleasedObject
.find(_ReleaseDate
));
2505 nlassert(it
!= _ReleasedObject
.end());
2506 TObjectSet
&os
= it
->second
;
2508 nlverify(os
.erase(this) == 1);
2510 // nb : _ReleasedObject time entry are removed by the cache update
2513 bool CRingUser::create(MSW::CConnection
&connection
)
2515 nlassert(getPersistentState() == NOPE::os_transient
);
2517 nlassert(_UserId
!= 0);
2519 qs
= "INSERT INTO ring_users (";
2521 qs
+= "user_id, user_name, current_char, current_session, current_activity, current_status, public_level, account_type, content_access_level, description, lang, cookie, current_domain_id, add_privileges";
2524 qs
+= "'"+MSW::escapeString(NLMISC::toString(_UserId
), connection
)+"'";
2526 qs
+= "'"+MSW::escapeString(NLMISC::toString(_UserName
), connection
)+"'";
2528 qs
+= "'"+MSW::escapeString(NLMISC::toString(_CurrentCharacter
), connection
)+"'";
2530 qs
+= "'"+MSW::escapeString(NLMISC::toString(_CurrentSession
), connection
)+"'";
2532 qs
+= _CurrentActivity
.isValid()
2533 ? "'"+_CurrentActivity
.toString()+"'"
2534 : "DEFAULT(current_activity)";
2536 qs
+= _CurrentStatus
.isValid()
2537 ? "'"+_CurrentStatus
.toString()+"'"
2538 : "DEFAULT(current_status)";
2540 qs
+= _PublicLevel
.isValid()
2541 ? "'"+_PublicLevel
.toString()+"'"
2542 : "DEFAULT(public_level)";
2544 qs
+= _AccountType
.isValid()
2545 ? "'"+_AccountType
.toString()+"'"
2546 : "DEFAULT(account_type)";
2548 qs
+= "'"+MSW::escapeString(NLMISC::toString(_ContentAccessLevel
), connection
)+"'";
2550 qs
+= "'"+MSW::escapeString(NLMISC::toString(_Description
), connection
)+"'";
2552 qs
+= _Lang
.isValid()
2553 ? "'"+_Lang
.toString()+"'"
2556 qs
+= "'"+MSW::escapeString(NLMISC::toString(_Cookie
), connection
)+"'";
2558 qs
+= "'"+MSW::escapeString(NLMISC::toString(_CurrentDomainId
), connection
)+"'";
2560 qs
+= "'"+MSW::escapeString(NLMISC::toString(_AddedPrivileges
), connection
)+"'";
2564 if (connection
.query(qs
))
2568 setPersistentState(NOPE::os_clean
);
2570 // update the parent class instance in cache if any
2578 bool CRingUser::update(MSW::CConnection
&connection
)
2580 nlassert(getPersistentState() == NOPE::os_dirty
|| getPersistentState() == NOPE::os_clean
);
2582 if (getPersistentState() == NOPE::os_clean
)
2583 // the object is clean, just ignore the save
2587 qs
= "UPDATE ring_users SET ";
2589 qs
+= "user_id = '"+MSW::escapeString(NLMISC::toString(_UserId
), connection
)+"'";
2591 qs
+= "user_name = '"+MSW::escapeString(NLMISC::toString(_UserName
), connection
)+"'";
2593 qs
+= "current_char = '"+MSW::escapeString(NLMISC::toString(_CurrentCharacter
), connection
)+"'";
2595 qs
+= "current_session = '"+MSW::escapeString(NLMISC::toString(_CurrentSession
), connection
)+"'";
2597 qs
+= "current_activity = " + (_CurrentActivity
.isValid()
2598 ? "'"+_CurrentActivity
.toString()+"'"
2599 : "DEFAULT(current_activity)");
2601 qs
+= "current_status = " + (_CurrentStatus
.isValid()
2602 ? "'"+_CurrentStatus
.toString()+"'"
2603 : "DEFAULT(current_status)");
2605 qs
+= "public_level = " + (_PublicLevel
.isValid()
2606 ? "'"+_PublicLevel
.toString()+"'"
2607 : "DEFAULT(public_level)");
2609 qs
+= "account_type = " + (_AccountType
.isValid()
2610 ? "'"+_AccountType
.toString()+"'"
2611 : "DEFAULT(account_type)");
2613 qs
+= "content_access_level = '"+MSW::escapeString(NLMISC::toString(_ContentAccessLevel
), connection
)+"'";
2615 qs
+= "description = '"+MSW::escapeString(NLMISC::toString(_Description
), connection
)+"'";
2617 qs
+= "lang = " + (_Lang
.isValid()
2618 ? "'"+_Lang
.toString()+"'"
2621 qs
+= "cookie = '"+MSW::escapeString(NLMISC::toString(_Cookie
), connection
)+"'";
2623 qs
+= "current_domain_id = '"+MSW::escapeString(NLMISC::toString(_CurrentDomainId
), connection
)+"'";
2625 qs
+= "add_privileges = '"+MSW::escapeString(NLMISC::toString(_AddedPrivileges
), connection
)+"'";
2627 qs
+= " WHERE user_id = '"+NLMISC::toString(_UserId
)+"'";
2630 if (connection
.query(qs
))
2632 if (connection
.getAffectedRows() == 1)
2634 setPersistentState(NOPE::os_clean
);
2642 bool CRingUser::remove(MSW::CConnection
&connection
)
2644 nlassert(getPersistentState() == NOPE::os_dirty
|| getPersistentState() == NOPE::os_clean
);
2647 qs
= "DELETE FROM ring_users ";
2649 qs
+= " WHERE user_id = '"+NLMISC::toString(_UserId
)+"'";
2652 if (connection
.query(qs
))
2654 if (connection
.getAffectedRows() == 1)
2658 // cascading deletion for vector child KnownUsers
2659 if (loadKnownUsers(connection
, __FILE__
, __LINE__
))
2661 const std::vector
< CKnownUserPtr
> & childs
= getKnownUsers();
2663 while (!childs
.empty())
2665 getKnownUsersByIndex((uint32
)childs
.size()-1)->remove(connection
);
2672 // cascading deletion for map child Characters
2673 if (loadCharacters(connection
, __FILE__
, __LINE__
))
2675 const std::map
< uint32
, CCharacterPtr
> & childs
= getCharacters();
2677 while (!childs
.empty())
2679 getCharactersById(childs
.begin()->first
)->remove(connection
);
2685 // cascading deletion for single child GMStatus
2686 if (loadGMStatus(connection
, __FILE__
, __LINE__
))
2688 if (getGMStatus() != NULL
)
2689 getGMStatus()->remove(connection
);
2694 // unreference (and update) for vector child Folders
2695 if (loadFolders(connection
, __FILE__
, __LINE__
))
2697 const std::vector
< CFolderPtr
> & childs
= getFolders();
2699 for (uint i
=0; i
< childs
.size(); ++i
)
2702 getFoldersByIndex(i
)->setAuthor(0);
2703 getFoldersByIndex(i
)->update(connection
);
2709 // unreference (and update) for vector child FolderAccess
2710 if (loadFolderAccess(connection
, __FILE__
, __LINE__
))
2712 const std::vector
< CFolderAccessPtr
> & childs
= getFolderAccess();
2714 for (uint i
=0; i
< childs
.size(); ++i
)
2717 getFolderAccessByIndex(i
)->setUserId(0);
2718 getFolderAccessByIndex(i
)->update(connection
);
2724 // change the persistant state to 'removed'.
2725 setPersistentState(NOPE::os_removed
);
2727 // need to remove ref from parent class container (if any)
2729 // need to remove ref from parent (if any)
2738 bool CRingUser::removeById(MSW::CConnection
&connection
, uint32 id
)
2740 CRingUser
*object
= loadFromCache(id
, true);
2743 return object
->remove(connection
);
2745 // not in cache, run a SQL query
2747 qs
= "DELETE FROM ring_users ";
2749 qs
+= " WHERE user_id = '"+NLMISC::toString(id
)+"'";
2752 if (connection
.query(qs
))
2754 if (connection
.getAffectedRows() == 1)
2756 // ok, the row is removed
2765 // Try to load the specified object from the memory cache, return NULL if the object is not in the cache
2766 CRingUser
*CRingUser::loadFromCache(uint32 objectId
, bool unrelease
)
2768 // look in the cache
2769 TObjectCache::iterator
it(_ObjectCache
.find(objectId
));
2770 if (it
== _ObjectCache
.end())
2772 // not found, return null
2777 CRingUser
*object
= it
->second
;
2779 if (object
->_ObjectState
== NOPE::os_released
)
2783 // we need to remove this object from the released object set.
2784 object
->removeFromReleased();
2785 object
->_ObjectState
= NOPE::os_clean
;
2792 // Receive and execute command from the cache manager.
2793 uint32
CRingUser::cacheCmd(NOPE::TCacheCmd cmd
)
2795 if (cmd
== NOPE::cc_update
)
2799 else if (cmd
== NOPE::cc_clear
)
2803 else if (cmd
== NOPE::cc_dump
)
2807 else if (cmd
== NOPE::cc_instance_count
)
2809 return (uint32
)_ObjectCache
.size();
2812 // default return value
2816 void CRingUser::dump()
2818 nlinfo(" Cache info for class CRingUser :");
2819 nlinfo(" There are %u object instances in cache", _ObjectCache
.size());
2821 // count the number of object in the released object set
2822 uint32 nbReleased
= 0;
2824 TReleasedObject::iterator
first(_ReleasedObject
.begin()), last(_ReleasedObject
.end());
2825 for (; first
!= last
; ++first
)
2827 nbReleased
+= (uint32
)first
->second
.size();
2830 nlinfo(" There are %u object instances in cache not referenced (waiting deletion or re-use))", nbReleased
);
2833 void CRingUser::updateCache()
2835 if (_ReleasedObject
.empty())
2838 // 30 s hold in cache
2839 const time_t MAX_CACHE_OLD_TIME
= 30;
2841 time_t now
= NLMISC::CTime::getSecondsSince1970();
2843 // look for object set older than MAX_CACHE_OLD_TIME and delete them
2844 while (!_ReleasedObject
.empty() && _ReleasedObject
.begin()->first
< now
-MAX_CACHE_OLD_TIME
)
2846 TObjectSet
&delSet
= _ReleasedObject
.begin()->second
;
2847 // unload this objects
2848 while (!delSet
.empty())
2850 CRingUser
*object
= *delSet
.begin();
2854 _ReleasedObject
.erase(_ReleasedObject
.begin());
2858 void CRingUser::clearCache()
2860 // remove any unreferenced object from the cache
2861 while (!_ReleasedObject
.empty())
2863 TObjectSet
&delSet
= _ReleasedObject
.begin()->second
;
2864 // unload this objects
2865 while (!delSet
.empty())
2867 CRingUser
*object
= *delSet
.begin();
2871 _ReleasedObject
.erase(_ReleasedObject
.begin());
2875 void CRingUser::registerUpdatable()
2877 static bool registered
= false;
2880 NOPE::CPersistentCache::getInstance().registerCache(&CRingUser::cacheCmd
);
2886 // set the pointer on the first pointer of the pointer list (set to null when there is no more pointer)
2887 void CRingUser::setFirstPtr(CRingUserPtr
*ptr
)
2893 // this is the last pointer !
2894 if (_ObjectState
== NOPE::os_transient
2895 || _ObjectState
== NOPE::os_removed
)
2897 // not a persistent object, or removed object, just delet it
2900 else if (_ObjectState
!= NOPE::os_removed
)
2902 setPersistentState(NOPE::os_released
);
2907 // Set the persistent state of the object and do some house keeping
2908 void CRingUser::setPersistentState(NOPE::TObjectState state
)
2910 nlassert(NOPE::AllowedTransition
[_ObjectState
][state
] == true);
2912 if(_ObjectState
== NOPE::os_released
&& state
== NOPE::os_removed
)
2914 // a release object gets removed (e.g. by remove by id)
2916 // delete the object
2923 if (_ObjectState
== NOPE::os_transient
&& state
!= NOPE::os_transient
)
2925 nldebug("NOPE: inserting CRingUser @%p in cache with id %u", this, static_cast<uint32
>(_UserId
));
2926 nlverify(_ObjectCache
.insert(std::make_pair(_UserId
, this)).second
);
2929 if (_ObjectState
!= NOPE::os_transient
)
2930 nlassert(_ObjectCache
.find(_UserId
) != _ObjectCache
.end());
2932 _ObjectState
= state
;
2934 if (state
== NOPE::os_released
)
2936 _ReleaseDate
= NLMISC::CTime::getSecondsSince1970();
2937 nlverify(_ReleasedObject
[_ReleaseDate
].insert(this).second
);
2939 else if (state
== NOPE::os_removed
)
2941 nldebug("NOPE: erasing CRingUser @%p in cache with id %u", this, static_cast<uint32
>(_UserId
));
2942 nlverify(_ObjectCache
.erase(_UserId
) == 1);
2947 CRingUserPtr
CRingUser::load(MSW::CConnection
&connection
, uint32 id
, const char *filename
, uint32 lineNum
)
2949 CRingUser
*inCache
= loadFromCache(id
, true);
2950 if (inCache
!= NULL
)
2952 return CRingUserPtr(inCache
, filename
, lineNum
);
2958 qs
+= "user_id, user_name, current_char, current_session, current_activity, current_status, public_level, account_type, content_access_level, description, lang, cookie, current_domain_id, add_privileges";
2960 qs
+= " FROM ring_users";
2962 qs
+= " WHERE user_id = '"+NLMISC::toString(id
)+"'";
2964 if (!connection
.query(qs
))
2969 MSW::CStoreResult
*result
= connection
.storeResult().release();
2971 nlassert(result
->getNumRows() <= 1);
2972 if (result
->getNumRows() == 1)
2974 ret
.assign(new CRingUser
, filename
, lineNum
);
2975 // ok, we have an object
2978 result
->getField(0, ret
->_UserId
);
2979 result
->getField(1, ret
->_UserName
);
2980 result
->getField(2, ret
->_CurrentCharacter
);
2981 result
->getField(3, ret
->_CurrentSession
);
2984 result
->getField(4, s
);
2985 ret
->_CurrentActivity
= TCurrentActivity(s
);
2989 result
->getField(5, s
);
2990 ret
->_CurrentStatus
= TCurrentStatus(s
);
2994 result
->getField(6, s
);
2995 ret
->_PublicLevel
= TPublicLevel(s
);
2999 result
->getField(7, s
);
3000 ret
->_AccountType
= TAccountType(s
);
3002 result
->getField(8, ret
->_ContentAccessLevel
);
3003 result
->getField(9, ret
->_Description
);
3006 result
->getField(10, s
);
3007 ret
->_Lang
= TLanguage(s
);
3009 result
->getField(11, ret
->_Cookie
);
3010 result
->getField(12, ret
->_CurrentDomainId
);
3011 result
->getField(13, ret
->_AddedPrivileges
);
3014 ret
->setPersistentState(NOPE::os_clean
);
3023 bool CRingUser::loadKnownUsers(MSW::CConnection
&connection
, const char *filename
, uint32 lineNum
)
3026 if (_KnownUsers
!= NULL
)
3028 // the children are already loaded, just return true
3032 // allocate the container
3033 _KnownUsers
= new std::vector
< CKnownUserPtr
>;
3036 ret
&= CKnownUser::loadChildrenOfCRingUser(connection
, getObjectId(), *_KnownUsers
, filename
, lineNum
);
3041 const std::vector
<CKnownUserPtr
> &CRingUser::getKnownUsers() const
3043 nlassert(_KnownUsers
!= NULL
);
3044 return *_KnownUsers
;
3047 CKnownUserPtr
&CRingUser::getKnownUsersByIndex(uint32 index
) const
3049 nlassert(_KnownUsers
!= NULL
);
3050 nlassert(index
< _KnownUsers
->size());
3051 return const_cast< CKnownUserPtr
& >(_KnownUsers
->operator[](index
));
3054 CKnownUserPtr
&CRingUser::getKnownUsersById(uint32 id
) const
3056 nlassert(_KnownUsers
!= NULL
);
3057 std::vector
<CKnownUserPtr
>::const_iterator
first(_KnownUsers
->begin()), last(_KnownUsers
->end());
3058 for (; first
!= last
; ++first
)
3060 const CKnownUserPtr
&child
= *first
;
3061 if (child
->getObjectId() == id
)
3063 return const_cast< CKnownUserPtr
& >(child
);
3067 // no object with this id, return a null pointer
3068 static CKnownUserPtr nilPtr
;
3074 bool CRingUser::loadCharacters(MSW::CConnection
&connection
, const char *filename
, uint32 lineNum
)
3077 if (_Characters
!= NULL
)
3079 // the children are already loaded, just return true
3083 // allocate the container
3084 _Characters
= new std::map
< uint32
, CCharacterPtr
>;
3087 ret
&= CCharacter::loadChildrenOfCRingUser(connection
, getObjectId(), *_Characters
, filename
, lineNum
);
3092 const std::map
<uint32
, CCharacterPtr
> &CRingUser::getCharacters() const
3094 nlassert(_Characters
!= NULL
);
3095 return *_Characters
;
3098 CCharacterPtr
&CRingUser::getCharactersById(uint32 id
) const
3100 nlassert(_Characters
!= NULL
);
3101 std::map
<uint32
, CCharacterPtr
>::const_iterator
it(_Characters
->find(id
));
3103 if (it
== _Characters
->end())
3105 // no object with this id, return a null pointer
3106 static CCharacterPtr nilPtr
;
3110 return const_cast< CCharacterPtr
& >(it
->second
);
3114 bool CRingUser::loadFolders(MSW::CConnection
&connection
, const char *filename
, uint32 lineNum
)
3117 if (_Folders
!= NULL
)
3119 // the children are already loaded, just return true
3123 // allocate the container
3124 _Folders
= new std::vector
< CFolderPtr
>;
3127 ret
&= CFolder::loadChildrenOfCRingUser(connection
, getObjectId(), *_Folders
, filename
, lineNum
);
3132 const std::vector
<CFolderPtr
> &CRingUser::getFolders() const
3134 nlassert(_Folders
!= NULL
);
3138 CFolderPtr
&CRingUser::getFoldersByIndex(uint32 index
) const
3140 nlassert(_Folders
!= NULL
);
3141 nlassert(index
< _Folders
->size());
3142 return const_cast< CFolderPtr
& >(_Folders
->operator[](index
));
3145 CFolderPtr
&CRingUser::getFoldersById(uint32 id
) const
3147 nlassert(_Folders
!= NULL
);
3148 std::vector
<CFolderPtr
>::const_iterator
first(_Folders
->begin()), last(_Folders
->end());
3149 for (; first
!= last
; ++first
)
3151 const CFolderPtr
&child
= *first
;
3152 if (child
->getObjectId() == id
)
3154 return const_cast< CFolderPtr
& >(child
);
3158 // no object with this id, return a null pointer
3159 static CFolderPtr nilPtr
;
3165 bool CRingUser::loadFolderAccess(MSW::CConnection
&connection
, const char *filename
, uint32 lineNum
)
3168 if (_FolderAccess
!= NULL
)
3170 // the children are already loaded, just return true
3174 // allocate the container
3175 _FolderAccess
= new std::vector
< CFolderAccessPtr
>;
3178 ret
&= CFolderAccess::loadChildrenOfCRingUser(connection
, getObjectId(), *_FolderAccess
, filename
, lineNum
);
3183 const std::vector
<CFolderAccessPtr
> &CRingUser::getFolderAccess() const
3185 nlassert(_FolderAccess
!= NULL
);
3186 return *_FolderAccess
;
3189 CFolderAccessPtr
&CRingUser::getFolderAccessByIndex(uint32 index
) const
3191 nlassert(_FolderAccess
!= NULL
);
3192 nlassert(index
< _FolderAccess
->size());
3193 return const_cast< CFolderAccessPtr
& >(_FolderAccess
->operator[](index
));
3196 CFolderAccessPtr
&CRingUser::getFolderAccessById(uint32 id
) const
3198 nlassert(_FolderAccess
!= NULL
);
3199 std::vector
<CFolderAccessPtr
>::const_iterator
first(_FolderAccess
->begin()), last(_FolderAccess
->end());
3200 for (; first
!= last
; ++first
)
3202 const CFolderAccessPtr
&child
= *first
;
3203 if (child
->getObjectId() == id
)
3205 return const_cast< CFolderAccessPtr
& >(child
);
3209 // no object with this id, return a null pointer
3210 static CFolderAccessPtr nilPtr
;
3216 bool CRingUser::loadGMStatus(MSW::CConnection
&connection
, const char *filename
, uint32 lineNum
)
3218 if (_GMStatusLoaded
)
3220 // the child is already loaded, just return true
3223 bool ret
= CGmStatus::loadChildOfCRingUser(connection
, getObjectId(), _GMStatus
, filename
, lineNum
);
3224 _GMStatusLoaded
= true;
3228 /** Return the one child object (or null if not) */
3229 CGmStatusPtr
CRingUser::getGMStatus()
3231 nlassert(_GMStatusLoaded
);
3236 void CSessionPtr::linkPtr()
3238 nlassert(_NextPtr
== NULL
);
3239 nlassert(_PrevPtr
== NULL
);
3242 _NextPtr
= _Ptr
->getFirstPtr();
3243 if (_NextPtr
!= NULL
)
3245 _PrevPtr
= _NextPtr
->_PrevPtr
;
3246 _PrevPtr
->_NextPtr
= this;
3247 _NextPtr
->_PrevPtr
= this;
3253 _Ptr
->setFirstPtr(this);
3258 void CSessionPtr::unlinkPtr()
3260 if (_NextPtr
== NULL
)
3262 nlassert(_PrevPtr
== NULL
);
3268 if (_NextPtr
== this)
3270 nlassert(_PrevPtr
== this);
3272 _Ptr
->setFirstPtr(NULL
);
3276 if (_Ptr
->getFirstPtr() == this)
3278 // the first ptr is the current one, we need to switch to next one
3279 _Ptr
->setFirstPtr(_NextPtr
);
3284 if (_NextPtr
!= this)
3286 nlassert(_PrevPtr
!= this);
3288 _NextPtr
->_PrevPtr
= _PrevPtr
;
3289 _PrevPtr
->_NextPtr
= _NextPtr
;
3296 CSession::TObjectCache
CSession::_ObjectCache
;
3297 CSession::TReleasedObject
CSession::_ReleasedObject
;
3300 // Destructor, delete any children
3301 CSession::~CSession()
3303 // release childs reference
3304 if (_SessionParticipants
!= NULL
)
3305 delete _SessionParticipants
;
3306 if (_GuildInvites
!= NULL
)
3307 delete _GuildInvites
;
3308 if (_JournalEntries
!= NULL
)
3309 delete _JournalEntries
;
3312 if (_PtrList
!= NULL
)
3314 nlwarning("ERROR : someone try to delete this object, but there are still ptr on it !");
3315 CSessionPtr
*ptr
= _PtrList
;
3318 nlwarning(" Pointer created from '%s', line %u", ptr
->_FileName
, ptr
->_LineNum
);
3319 ptr
= _PtrList
->getNextPtr();
3320 } while(ptr
!= _PtrList
);
3323 // remove object from cache map
3324 if (_SessionId
!= NOPE::INVALID_OBJECT_ID
3325 && _ObjectState
!= NOPE::os_removed
3326 && _ObjectState
!= NOPE::os_transient
)
3328 nldebug("NOPE: clearing CSession @%p from cache with id %u", this, static_cast<uint32
>(_SessionId
));
3329 nlverify(_ObjectCache
.erase(_SessionId
) == 1);
3331 else if (_ObjectState
!= NOPE::os_transient
)
3333 nlassert(_ObjectCache
.find(_SessionId
) == _ObjectCache
.end());
3335 if (_ObjectState
== NOPE::os_released
)
3337 removeFromReleased();
3341 TReleasedObject::iterator
it(_ReleasedObject
.find(_ReleaseDate
));
3342 if (it
!= _ReleasedObject
.end())
3344 nlassert(it
->second
.find(this) == it
->second
.end());
3349 void CSession::removeFromReleased()
3351 TReleasedObject::iterator
it(_ReleasedObject
.find(_ReleaseDate
));
3352 nlassert(it
!= _ReleasedObject
.end());
3353 TObjectSet
&os
= it
->second
;
3355 nlverify(os
.erase(this) == 1);
3357 // nb : _ReleasedObject time entry are removed by the cache update
3360 bool CSession::create(MSW::CConnection
&connection
)
3362 nlassert(getPersistentState() == NOPE::os_transient
);
3365 qs
= "INSERT INTO sessions (";
3367 qs
+= "session_type, title, owner, plan_date, start_date, description, orientation, level, rule_type, access_type, state, host_shard_id, subscription_slots, reserved_slots, estimated_duration, final_duration, folder_id, lang, icone, anim_mode, race_filter, religion_filter, guild_filter, shard_filter, level_filter, subscription_closed, newcomer";
3370 qs
+= "'"+_SessionType
.toString()+"'";
3372 qs
+= "'"+MSW::escapeString(NLMISC::toString(_Title
), connection
)+"'";
3374 qs
+= "'"+MSW::escapeString(NLMISC::toString(_OwnerId
), connection
)+"'";
3376 qs
+= "'"+MSW::encodeDate(_PlanDate
)+"'";
3378 qs
+= "'"+MSW::encodeDate(_StartDate
)+"'";
3380 qs
+= "'"+MSW::escapeString(NLMISC::toString(_Description
), connection
)+"'";
3382 qs
+= _Orientation
.isValid()
3383 ? "'"+_Orientation
.toString()+"'"
3384 : "DEFAULT(orientation)";
3386 qs
+= _Level
.isValid()
3387 ? "'"+_Level
.toString()+"'"
3390 qs
+= _RuleType
.isValid()
3391 ? "'"+_RuleType
.toString()+"'"
3392 : "DEFAULT(rule_type)";
3394 qs
+= _AccessType
.isValid()
3395 ? "'"+_AccessType
.toString()+"'"
3396 : "DEFAULT(access_type)";
3398 qs
+= _State
.isValid()
3399 ? "'"+_State
.toString()+"'"
3402 qs
+= "'"+MSW::escapeString(NLMISC::toString(_HostShardId
), connection
)+"'";
3404 qs
+= "'"+MSW::escapeString(NLMISC::toString(_SubscriptionSlots
), connection
)+"'";
3406 qs
+= "'"+MSW::escapeString(NLMISC::toString(_ReservedSlots
), connection
)+"'";
3408 qs
+= _EstimatedDuration
.isValid()
3409 ? "'"+_EstimatedDuration
.toString()+"'"
3410 : "DEFAULT(estimated_duration)";
3412 qs
+= "'"+MSW::escapeString(NLMISC::toString(_FinalDuration
), connection
)+"'";
3414 qs
+= "'"+MSW::escapeString(NLMISC::toString(_FolderId
), connection
)+"'";
3416 qs
+= "'"+MSW::escapeString(NLMISC::toString(_Lang
), connection
)+"'";
3418 qs
+= "'"+MSW::escapeString(NLMISC::toString(_Icone
), connection
)+"'";
3420 qs
+= _AnimMode
.isValid()
3421 ? "'"+_AnimMode
.toString()+"'"
3422 : "DEFAULT(anim_mode)";
3424 qs
+= "'"+_RaceFilter
.toString()+"'";
3426 qs
+= "'"+_ReligionFilter
.toString()+"'";
3428 qs
+= _GuildFilter
.isValid()
3429 ? "'"+_GuildFilter
.toString()+"'"
3430 : "DEFAULT(guild_filter)";
3432 qs
+= "'"+_ShardFilter
.toString()+"'";
3434 qs
+= "'"+_LevelFilter
.toString()+"'";
3436 qs
+= "'"+MSW::escapeString(NLMISC::toString(_SubscriptionClosed
), connection
)+"'";
3438 qs
+= "'"+MSW::escapeString(NLMISC::toString(_Newcomer
), connection
)+"'";
3442 if (connection
.query(qs
))
3444 uint32 _id_
= connection
.getLastGeneratedId();
3448 setPersistentState(NOPE::os_clean
);
3450 // update the parent class instance in cache if any
3454 // need to update the parent class child list if it is in the cache
3455 CCharacter
*parent
= CCharacter::loadFromCache(_OwnerId
, false);
3456 if (parent
&& parent
->_Sessions
!= NULL
)
3459 nlassert(std::find(parent
->_Sessions
->begin(), parent
->_Sessions
->end(), CSessionPtr(this, __FILE__
, __LINE__
)) == parent
->_Sessions
->end());
3460 parent
->_Sessions
->push_back(CSessionPtr(this, __FILE__
, __LINE__
));
3467 // need to update the parent class child list if it is in the cache
3468 CFolder
*parent
= CFolder::loadFromCache(_FolderId
, false);
3469 if (parent
&& parent
->_Sessions
!= NULL
)
3472 nlassert(std::find(parent
->_Sessions
->begin(), parent
->_Sessions
->end(), CSessionPtr(this, __FILE__
, __LINE__
)) == parent
->_Sessions
->end());
3473 parent
->_Sessions
->push_back(CSessionPtr(this, __FILE__
, __LINE__
));
3484 bool CSession::update(MSW::CConnection
&connection
)
3486 nlassert(getPersistentState() == NOPE::os_dirty
|| getPersistentState() == NOPE::os_clean
);
3488 if (getPersistentState() == NOPE::os_clean
)
3489 // the object is clean, just ignore the save
3493 qs
= "UPDATE sessions SET ";
3495 qs
+= "session_type = '"+_SessionType
.toString()+"'";
3497 qs
+= "title = '"+MSW::escapeString(NLMISC::toString(_Title
), connection
)+"'";
3499 qs
+= "owner = '"+MSW::escapeString(NLMISC::toString(_OwnerId
), connection
)+"'";
3501 qs
+= "plan_date = '"+MSW::encodeDate(_PlanDate
)+"'";
3503 qs
+= "start_date = '"+MSW::encodeDate(_StartDate
)+"'";
3505 qs
+= "description = '"+MSW::escapeString(NLMISC::toString(_Description
), connection
)+"'";
3507 qs
+= "orientation = " + (_Orientation
.isValid()
3508 ? "'"+_Orientation
.toString()+"'"
3509 : "DEFAULT(orientation)");
3511 qs
+= "level = " + (_Level
.isValid()
3512 ? "'"+_Level
.toString()+"'"
3513 : "DEFAULT(level)");
3515 qs
+= "rule_type = " + (_RuleType
.isValid()
3516 ? "'"+_RuleType
.toString()+"'"
3517 : "DEFAULT(rule_type)");
3519 qs
+= "access_type = " + (_AccessType
.isValid()
3520 ? "'"+_AccessType
.toString()+"'"
3521 : "DEFAULT(access_type)");
3523 qs
+= "state = " + (_State
.isValid()
3524 ? "'"+_State
.toString()+"'"
3525 : "DEFAULT(state)");
3527 qs
+= "host_shard_id = '"+MSW::escapeString(NLMISC::toString(_HostShardId
), connection
)+"'";
3529 qs
+= "subscription_slots = '"+MSW::escapeString(NLMISC::toString(_SubscriptionSlots
), connection
)+"'";
3531 qs
+= "reserved_slots = '"+MSW::escapeString(NLMISC::toString(_ReservedSlots
), connection
)+"'";
3533 qs
+= "estimated_duration = " + (_EstimatedDuration
.isValid()
3534 ? "'"+_EstimatedDuration
.toString()+"'"
3535 : "DEFAULT(estimated_duration)");
3537 qs
+= "final_duration = '"+MSW::escapeString(NLMISC::toString(_FinalDuration
), connection
)+"'";
3539 qs
+= "folder_id = '"+MSW::escapeString(NLMISC::toString(_FolderId
), connection
)+"'";
3541 qs
+= "lang = '"+MSW::escapeString(NLMISC::toString(_Lang
), connection
)+"'";
3543 qs
+= "icone = '"+MSW::escapeString(NLMISC::toString(_Icone
), connection
)+"'";
3545 qs
+= "anim_mode = " + (_AnimMode
.isValid()
3546 ? "'"+_AnimMode
.toString()+"'"
3547 : "DEFAULT(anim_mode)");
3549 qs
+= "race_filter = '"+_RaceFilter
.toString()+"'";
3551 qs
+= "religion_filter = '"+_ReligionFilter
.toString()+"'";
3553 qs
+= "guild_filter = " + (_GuildFilter
.isValid()
3554 ? "'"+_GuildFilter
.toString()+"'"
3555 : "DEFAULT(guild_filter)");
3557 qs
+= "shard_filter = '"+_ShardFilter
.toString()+"'";
3559 qs
+= "level_filter = '"+_LevelFilter
.toString()+"'";
3561 qs
+= "subscription_closed = '"+MSW::escapeString(NLMISC::toString(_SubscriptionClosed
), connection
)+"'";
3563 qs
+= "newcomer = '"+MSW::escapeString(NLMISC::toString(_Newcomer
), connection
)+"'";
3565 qs
+= " WHERE session_id = '"+NLMISC::toString(_SessionId
)+"'";
3568 if (connection
.query(qs
))
3570 if (connection
.getAffectedRows() == 1)
3572 setPersistentState(NOPE::os_clean
);
3580 bool CSession::remove(MSW::CConnection
&connection
)
3582 nlassert(getPersistentState() == NOPE::os_dirty
|| getPersistentState() == NOPE::os_clean
);
3585 qs
= "DELETE FROM sessions ";
3587 qs
+= " WHERE session_id = '"+NLMISC::toString(_SessionId
)+"'";
3590 if (connection
.query(qs
))
3592 if (connection
.getAffectedRows() == 1)
3596 // cascading deletion for vector child SessionParticipants
3597 if (loadSessionParticipants(connection
, __FILE__
, __LINE__
))
3599 const std::vector
< CSessionParticipantPtr
> & childs
= getSessionParticipants();
3601 while (!childs
.empty())
3603 getSessionParticipantsByIndex((uint32
)childs
.size()-1)->remove(connection
);
3610 // cascading deletion for vector child GuildInvites
3611 if (loadGuildInvites(connection
, __FILE__
, __LINE__
))
3613 const std::vector
< CGuildInvitePtr
> & childs
= getGuildInvites();
3615 while (!childs
.empty())
3617 getGuildInvitesByIndex((uint32
)childs
.size()-1)->remove(connection
);
3624 // cascading deletion for vector child JournalEntries
3625 if (loadJournalEntries(connection
, __FILE__
, __LINE__
))
3627 const std::vector
< CJournalEntryPtr
> & childs
= getJournalEntries();
3629 while (!childs
.empty())
3631 getJournalEntriesByIndex((uint32
)childs
.size()-1)->remove(connection
);
3638 // change the persistant state to 'removed'.
3639 setPersistentState(NOPE::os_removed
);
3641 // need to remove ref from parent class container (if any)
3644 CCharacterPtr
parent(CCharacter::loadFromCache(_OwnerId
, true), __FILE__
, __LINE__
);
3645 if (parent
!= NULL
&& parent
->_Sessions
!= NULL
)
3648 std::vector
< CSessionPtr
>::iterator it
= std::find(parent
->_Sessions
->begin(), parent
->_Sessions
->end(), this);
3649 if (it
!= parent
->_Sessions
->end())
3651 parent
->_Sessions
->erase(it
);
3658 CFolderPtr
parent(CFolder::loadFromCache(_FolderId
, true), __FILE__
, __LINE__
);
3659 if (parent
!= NULL
&& parent
->_Sessions
!= NULL
)
3662 std::vector
< CSessionPtr
>::iterator it
= std::find(parent
->_Sessions
->begin(), parent
->_Sessions
->end(), this);
3663 if (it
!= parent
->_Sessions
->end())
3665 parent
->_Sessions
->erase(it
);
3671 // need to remove ref from parent (if any)
3680 bool CSession::removeById(MSW::CConnection
&connection
, uint32 id
)
3682 CSession
*object
= loadFromCache(id
, true);
3685 return object
->remove(connection
);
3687 // not in cache, run a SQL query
3689 qs
= "DELETE FROM sessions ";
3691 qs
+= " WHERE session_id = '"+NLMISC::toString(id
)+"'";
3694 if (connection
.query(qs
))
3696 if (connection
.getAffectedRows() == 1)
3698 // ok, the row is removed
3707 // Try to load the specified object from the memory cache, return NULL if the object is not in the cache
3708 CSession
*CSession::loadFromCache(uint32 objectId
, bool unrelease
)
3710 // look in the cache
3711 TObjectCache::iterator
it(_ObjectCache
.find(objectId
));
3712 if (it
== _ObjectCache
.end())
3714 // not found, return null
3719 CSession
*object
= it
->second
;
3721 if (object
->_ObjectState
== NOPE::os_released
)
3725 // we need to remove this object from the released object set.
3726 object
->removeFromReleased();
3727 object
->_ObjectState
= NOPE::os_clean
;
3734 // Receive and execute command from the cache manager.
3735 uint32
CSession::cacheCmd(NOPE::TCacheCmd cmd
)
3737 if (cmd
== NOPE::cc_update
)
3741 else if (cmd
== NOPE::cc_clear
)
3745 else if (cmd
== NOPE::cc_dump
)
3749 else if (cmd
== NOPE::cc_instance_count
)
3751 return (uint32
)_ObjectCache
.size();
3754 // default return value
3758 void CSession::dump()
3760 nlinfo(" Cache info for class CSession :");
3761 nlinfo(" There are %u object instances in cache", _ObjectCache
.size());
3763 // count the number of object in the released object set
3764 uint32 nbReleased
= 0;
3766 TReleasedObject::iterator
first(_ReleasedObject
.begin()), last(_ReleasedObject
.end());
3767 for (; first
!= last
; ++first
)
3769 nbReleased
+= (uint32
)first
->second
.size();
3772 nlinfo(" There are %u object instances in cache not referenced (waiting deletion or re-use))", nbReleased
);
3775 void CSession::updateCache()
3777 if (_ReleasedObject
.empty())
3780 // 30 s hold in cache
3781 const time_t MAX_CACHE_OLD_TIME
= 30;
3783 time_t now
= NLMISC::CTime::getSecondsSince1970();
3785 // look for object set older than MAX_CACHE_OLD_TIME and delete them
3786 while (!_ReleasedObject
.empty() && _ReleasedObject
.begin()->first
< now
-MAX_CACHE_OLD_TIME
)
3788 TObjectSet
&delSet
= _ReleasedObject
.begin()->second
;
3789 // unload this objects
3790 while (!delSet
.empty())
3792 CSession
*object
= *delSet
.begin();
3796 _ReleasedObject
.erase(_ReleasedObject
.begin());
3800 void CSession::clearCache()
3802 // remove any unreferenced object from the cache
3803 while (!_ReleasedObject
.empty())
3805 TObjectSet
&delSet
= _ReleasedObject
.begin()->second
;
3806 // unload this objects
3807 while (!delSet
.empty())
3809 CSession
*object
= *delSet
.begin();
3813 _ReleasedObject
.erase(_ReleasedObject
.begin());
3817 void CSession::registerUpdatable()
3819 static bool registered
= false;
3822 NOPE::CPersistentCache::getInstance().registerCache(&CSession::cacheCmd
);
3828 // set the pointer on the first pointer of the pointer list (set to null when there is no more pointer)
3829 void CSession::setFirstPtr(CSessionPtr
*ptr
)
3835 // this is the last pointer !
3836 if (_ObjectState
== NOPE::os_transient
3837 || _ObjectState
== NOPE::os_removed
)
3839 // not a persistent object, or removed object, just delet it
3842 else if (_ObjectState
!= NOPE::os_removed
)
3844 setPersistentState(NOPE::os_released
);
3849 // Set the persistent state of the object and do some house keeping
3850 void CSession::setPersistentState(NOPE::TObjectState state
)
3852 nlassert(NOPE::AllowedTransition
[_ObjectState
][state
] == true);
3854 if(_ObjectState
== NOPE::os_released
&& state
== NOPE::os_removed
)
3856 // a release object gets removed (e.g. by remove by id)
3858 // delete the object
3865 if (_ObjectState
== NOPE::os_transient
&& state
!= NOPE::os_transient
)
3867 nldebug("NOPE: inserting CSession @%p in cache with id %u", this, static_cast<uint32
>(_SessionId
));
3868 nlverify(_ObjectCache
.insert(std::make_pair(_SessionId
, this)).second
);
3871 if (_ObjectState
!= NOPE::os_transient
)
3872 nlassert(_ObjectCache
.find(_SessionId
) != _ObjectCache
.end());
3874 _ObjectState
= state
;
3876 if (state
== NOPE::os_released
)
3878 _ReleaseDate
= NLMISC::CTime::getSecondsSince1970();
3879 nlverify(_ReleasedObject
[_ReleaseDate
].insert(this).second
);
3881 else if (state
== NOPE::os_removed
)
3883 nldebug("NOPE: erasing CSession @%p in cache with id %u", this, static_cast<uint32
>(_SessionId
));
3884 nlverify(_ObjectCache
.erase(_SessionId
) == 1);
3889 CSessionPtr
CSession::load(MSW::CConnection
&connection
, uint32 id
, const char *filename
, uint32 lineNum
)
3891 CSession
*inCache
= loadFromCache(id
, true);
3892 if (inCache
!= NULL
)
3894 return CSessionPtr(inCache
, filename
, lineNum
);
3900 qs
+= "session_id, session_type, title, owner, plan_date, start_date, description, orientation, level, rule_type, access_type, state, host_shard_id, subscription_slots, reserved_slots, estimated_duration, final_duration, folder_id, lang, icone, anim_mode, race_filter, religion_filter, guild_filter, shard_filter, level_filter, subscription_closed, newcomer";
3902 qs
+= " FROM sessions";
3904 qs
+= " WHERE session_id = '"+NLMISC::toString(id
)+"'";
3906 if (!connection
.query(qs
))
3911 MSW::CStoreResult
*result
= connection
.storeResult().release();
3913 nlassert(result
->getNumRows() <= 1);
3914 if (result
->getNumRows() == 1)
3916 ret
.assign(new CSession
, filename
, lineNum
);
3917 // ok, we have an object
3920 result
->getField(0, ret
->_SessionId
);
3923 result
->getField(1, s
);
3924 ret
->_SessionType
= TSessionType(s
);
3926 result
->getField(2, ret
->_Title
);
3927 result
->getField(3, ret
->_OwnerId
);
3928 result
->getDateField(4, ret
->_PlanDate
);
3929 result
->getDateField(5, ret
->_StartDate
);
3930 result
->getField(6, ret
->_Description
);
3933 result
->getField(7, s
);
3934 ret
->_Orientation
= TSessionOrientation(s
);
3938 result
->getField(8, s
);
3939 ret
->_Level
= R2::TSessionLevel(s
);
3943 result
->getField(9, s
);
3944 ret
->_RuleType
= TRuleType(s
);
3948 result
->getField(10, s
);
3949 ret
->_AccessType
= TAccessType(s
);
3953 result
->getField(11, s
);
3954 ret
->_State
= TSessionState(s
);
3956 result
->getField(12, ret
->_HostShardId
);
3957 result
->getField(13, ret
->_SubscriptionSlots
);
3958 result
->getField(14, ret
->_ReservedSlots
);
3961 result
->getField(15, s
);
3962 ret
->_EstimatedDuration
= TEstimatedDuration(s
);
3964 result
->getField(16, ret
->_FinalDuration
);
3965 result
->getField(17, ret
->_FolderId
);
3966 result
->getField(18, ret
->_Lang
);
3967 result
->getField(19, ret
->_Icone
);
3970 result
->getField(20, s
);
3971 ret
->_AnimMode
= TAnimMode(s
);
3975 result
->getField(21, s
);
3976 ret
->_RaceFilter
= TRaceFilter(s
);
3980 result
->getField(22, s
);
3981 ret
->_ReligionFilter
= TReligionFilter(s
);
3985 result
->getField(23, s
);
3986 ret
->_GuildFilter
= TGuildFilter(s
);
3990 result
->getField(24, s
);
3991 ret
->_ShardFilter
= TShardFilter(s
);
3995 result
->getField(25, s
);
3996 ret
->_LevelFilter
= TLevelFilter(s
);
3998 result
->getField(26, ret
->_SubscriptionClosed
);
3999 result
->getField(27, ret
->_Newcomer
);
4002 ret
->setPersistentState(NOPE::os_clean
);
4011 bool CSession::loadChildrenOfCCharacter(MSW::CConnection
&connection
, uint32 parentId
, std::vector
< CSessionPtr
> & container
, const char *filename
, uint32 lineNum
)
4017 qs
+= "session_id, session_type, title, owner, plan_date, start_date, description, orientation, level, rule_type, access_type, state, host_shard_id, subscription_slots, reserved_slots, estimated_duration, final_duration, folder_id, lang, icone, anim_mode, race_filter, religion_filter, guild_filter, shard_filter, level_filter, subscription_closed, newcomer";
4019 qs
+= " FROM sessions";
4020 qs
+= " WHERE owner = '"+NLMISC::toString(parentId
)+"'";
4022 if (!connection
.query(qs
))
4027 CUniquePtr
<MSW::CStoreResult
> result
= connection
.storeResult();
4029 for (uint i
=0; i
<result
->getNumRows(); ++i
)
4031 CSession
*ret
= new CSession();
4032 // ok, we have an object
4035 result
->getField(0, ret
->_SessionId
);
4039 result
->getField(1, s
);
4040 ret
->_SessionType
= TSessionType(s
);
4043 result
->getField(2, ret
->_Title
);
4045 result
->getField(3, ret
->_OwnerId
);
4047 result
->getDateField(4, ret
->_PlanDate
);
4049 result
->getDateField(5, ret
->_StartDate
);
4051 result
->getField(6, ret
->_Description
);
4055 result
->getField(7, s
);
4056 ret
->_Orientation
= TSessionOrientation(s
);
4061 result
->getField(8, s
);
4062 ret
->_Level
= R2::TSessionLevel(s
);
4067 result
->getField(9, s
);
4068 ret
->_RuleType
= TRuleType(s
);
4073 result
->getField(10, s
);
4074 ret
->_AccessType
= TAccessType(s
);
4079 result
->getField(11, s
);
4080 ret
->_State
= TSessionState(s
);
4083 result
->getField(12, ret
->_HostShardId
);
4085 result
->getField(13, ret
->_SubscriptionSlots
);
4087 result
->getField(14, ret
->_ReservedSlots
);
4091 result
->getField(15, s
);
4092 ret
->_EstimatedDuration
= TEstimatedDuration(s
);
4095 result
->getField(16, ret
->_FinalDuration
);
4097 result
->getField(17, ret
->_FolderId
);
4099 result
->getField(18, ret
->_Lang
);
4101 result
->getField(19, ret
->_Icone
);
4105 result
->getField(20, s
);
4106 ret
->_AnimMode
= TAnimMode(s
);
4111 result
->getField(21, s
);
4112 ret
->_RaceFilter
= TRaceFilter(s
);
4117 result
->getField(22, s
);
4118 ret
->_ReligionFilter
= TReligionFilter(s
);
4123 result
->getField(23, s
);
4124 ret
->_GuildFilter
= TGuildFilter(s
);
4129 result
->getField(24, s
);
4130 ret
->_ShardFilter
= TShardFilter(s
);
4135 result
->getField(25, s
);
4136 ret
->_LevelFilter
= TLevelFilter(s
);
4139 result
->getField(26, ret
->_SubscriptionClosed
);
4141 result
->getField(27, ret
->_Newcomer
);
4142 CSession
*inCache
= loadFromCache(ret
->_SessionId
, true);
4143 if (inCache
!= NULL
)
4146 container
.push_back(CSessionPtr(inCache
, filename
, lineNum
));
4153 ret
->setPersistentState(NOPE::os_clean
);
4155 container
.push_back(CSessionPtr(ret
, filename
, lineNum
));
4163 bool CSession::loadChildrenOfCFolder(MSW::CConnection
&connection
, uint32 parentId
, std::vector
< CSessionPtr
> & container
, const char *filename
, uint32 lineNum
)
4169 qs
+= "session_id, session_type, title, owner, plan_date, start_date, description, orientation, level, rule_type, access_type, state, host_shard_id, subscription_slots, reserved_slots, estimated_duration, final_duration, folder_id, lang, icone, anim_mode, race_filter, religion_filter, guild_filter, shard_filter, level_filter, subscription_closed, newcomer";
4171 qs
+= " FROM sessions";
4172 qs
+= " WHERE folder_id = '"+NLMISC::toString(parentId
)+"'";
4174 if (!connection
.query(qs
))
4179 CUniquePtr
<MSW::CStoreResult
> result
= connection
.storeResult();
4181 for (uint i
=0; i
<result
->getNumRows(); ++i
)
4183 CSession
*ret
= new CSession();
4184 // ok, we have an object
4187 result
->getField(0, ret
->_SessionId
);
4191 result
->getField(1, s
);
4192 ret
->_SessionType
= TSessionType(s
);
4195 result
->getField(2, ret
->_Title
);
4197 result
->getField(3, ret
->_OwnerId
);
4199 result
->getDateField(4, ret
->_PlanDate
);
4201 result
->getDateField(5, ret
->_StartDate
);
4203 result
->getField(6, ret
->_Description
);
4207 result
->getField(7, s
);
4208 ret
->_Orientation
= TSessionOrientation(s
);
4213 result
->getField(8, s
);
4214 ret
->_Level
= R2::TSessionLevel(s
);
4219 result
->getField(9, s
);
4220 ret
->_RuleType
= TRuleType(s
);
4225 result
->getField(10, s
);
4226 ret
->_AccessType
= TAccessType(s
);
4231 result
->getField(11, s
);
4232 ret
->_State
= TSessionState(s
);
4235 result
->getField(12, ret
->_HostShardId
);
4237 result
->getField(13, ret
->_SubscriptionSlots
);
4239 result
->getField(14, ret
->_ReservedSlots
);
4243 result
->getField(15, s
);
4244 ret
->_EstimatedDuration
= TEstimatedDuration(s
);
4247 result
->getField(16, ret
->_FinalDuration
);
4249 result
->getField(17, ret
->_FolderId
);
4251 result
->getField(18, ret
->_Lang
);
4253 result
->getField(19, ret
->_Icone
);
4257 result
->getField(20, s
);
4258 ret
->_AnimMode
= TAnimMode(s
);
4263 result
->getField(21, s
);
4264 ret
->_RaceFilter
= TRaceFilter(s
);
4269 result
->getField(22, s
);
4270 ret
->_ReligionFilter
= TReligionFilter(s
);
4275 result
->getField(23, s
);
4276 ret
->_GuildFilter
= TGuildFilter(s
);
4281 result
->getField(24, s
);
4282 ret
->_ShardFilter
= TShardFilter(s
);
4287 result
->getField(25, s
);
4288 ret
->_LevelFilter
= TLevelFilter(s
);
4291 result
->getField(26, ret
->_SubscriptionClosed
);
4293 result
->getField(27, ret
->_Newcomer
);
4294 CSession
*inCache
= loadFromCache(ret
->_SessionId
, true);
4295 if (inCache
!= NULL
)
4298 container
.push_back(CSessionPtr(inCache
, filename
, lineNum
));
4305 ret
->setPersistentState(NOPE::os_clean
);
4307 container
.push_back(CSessionPtr(ret
, filename
, lineNum
));
4315 bool CSession::loadSessionParticipants(MSW::CConnection
&connection
, const char *filename
, uint32 lineNum
)
4318 if (_SessionParticipants
!= NULL
)
4320 // the children are already loaded, just return true
4324 // allocate the container
4325 _SessionParticipants
= new std::vector
< CSessionParticipantPtr
>;
4328 ret
&= CSessionParticipant::loadChildrenOfCSession(connection
, getObjectId(), *_SessionParticipants
, filename
, lineNum
);
4333 const std::vector
<CSessionParticipantPtr
> &CSession::getSessionParticipants() const
4335 nlassert(_SessionParticipants
!= NULL
);
4336 return *_SessionParticipants
;
4339 CSessionParticipantPtr
&CSession::getSessionParticipantsByIndex(uint32 index
) const
4341 nlassert(_SessionParticipants
!= NULL
);
4342 nlassert(index
< _SessionParticipants
->size());
4343 return const_cast< CSessionParticipantPtr
& >(_SessionParticipants
->operator[](index
));
4346 CSessionParticipantPtr
&CSession::getSessionParticipantsById(uint32 id
) const
4348 nlassert(_SessionParticipants
!= NULL
);
4349 std::vector
<CSessionParticipantPtr
>::const_iterator
first(_SessionParticipants
->begin()), last(_SessionParticipants
->end());
4350 for (; first
!= last
; ++first
)
4352 const CSessionParticipantPtr
&child
= *first
;
4353 if (child
->getObjectId() == id
)
4355 return const_cast< CSessionParticipantPtr
& >(child
);
4359 // no object with this id, return a null pointer
4360 static CSessionParticipantPtr nilPtr
;
4366 bool CSession::loadGuildInvites(MSW::CConnection
&connection
, const char *filename
, uint32 lineNum
)
4369 if (_GuildInvites
!= NULL
)
4371 // the children are already loaded, just return true
4375 // allocate the container
4376 _GuildInvites
= new std::vector
< CGuildInvitePtr
>;
4379 ret
&= CGuildInvite::loadChildrenOfCSession(connection
, getObjectId(), *_GuildInvites
, filename
, lineNum
);
4384 const std::vector
<CGuildInvitePtr
> &CSession::getGuildInvites() const
4386 nlassert(_GuildInvites
!= NULL
);
4387 return *_GuildInvites
;
4390 CGuildInvitePtr
&CSession::getGuildInvitesByIndex(uint32 index
) const
4392 nlassert(_GuildInvites
!= NULL
);
4393 nlassert(index
< _GuildInvites
->size());
4394 return const_cast< CGuildInvitePtr
& >(_GuildInvites
->operator[](index
));
4397 CGuildInvitePtr
&CSession::getGuildInvitesById(uint32 id
) const
4399 nlassert(_GuildInvites
!= NULL
);
4400 std::vector
<CGuildInvitePtr
>::const_iterator
first(_GuildInvites
->begin()), last(_GuildInvites
->end());
4401 for (; first
!= last
; ++first
)
4403 const CGuildInvitePtr
&child
= *first
;
4404 if (child
->getObjectId() == id
)
4406 return const_cast< CGuildInvitePtr
& >(child
);
4410 // no object with this id, return a null pointer
4411 static CGuildInvitePtr nilPtr
;
4417 bool CSession::loadJournalEntries(MSW::CConnection
&connection
, const char *filename
, uint32 lineNum
)
4420 if (_JournalEntries
!= NULL
)
4422 // the children are already loaded, just return true
4426 // allocate the container
4427 _JournalEntries
= new std::vector
< CJournalEntryPtr
>;
4430 ret
&= CJournalEntry::loadChildrenOfCSession(connection
, getObjectId(), *_JournalEntries
, filename
, lineNum
);
4435 const std::vector
<CJournalEntryPtr
> &CSession::getJournalEntries() const
4437 nlassert(_JournalEntries
!= NULL
);
4438 return *_JournalEntries
;
4441 CJournalEntryPtr
&CSession::getJournalEntriesByIndex(uint32 index
) const
4443 nlassert(_JournalEntries
!= NULL
);
4444 nlassert(index
< _JournalEntries
->size());
4445 return const_cast< CJournalEntryPtr
& >(_JournalEntries
->operator[](index
));
4448 CJournalEntryPtr
&CSession::getJournalEntriesById(uint32 id
) const
4450 nlassert(_JournalEntries
!= NULL
);
4451 std::vector
<CJournalEntryPtr
>::const_iterator
first(_JournalEntries
->begin()), last(_JournalEntries
->end());
4452 for (; first
!= last
; ++first
)
4454 const CJournalEntryPtr
&child
= *first
;
4455 if (child
->getObjectId() == id
)
4457 return const_cast< CJournalEntryPtr
& >(child
);
4461 // no object with this id, return a null pointer
4462 static CJournalEntryPtr nilPtr
;
4468 void CShardPtr::linkPtr()
4470 nlassert(_NextPtr
== NULL
);
4471 nlassert(_PrevPtr
== NULL
);
4474 _NextPtr
= _Ptr
->getFirstPtr();
4475 if (_NextPtr
!= NULL
)
4477 _PrevPtr
= _NextPtr
->_PrevPtr
;
4478 _PrevPtr
->_NextPtr
= this;
4479 _NextPtr
->_PrevPtr
= this;
4485 _Ptr
->setFirstPtr(this);
4490 void CShardPtr::unlinkPtr()
4492 if (_NextPtr
== NULL
)
4494 nlassert(_PrevPtr
== NULL
);
4500 if (_NextPtr
== this)
4502 nlassert(_PrevPtr
== this);
4504 _Ptr
->setFirstPtr(NULL
);
4508 if (_Ptr
->getFirstPtr() == this)
4510 // the first ptr is the current one, we need to switch to next one
4511 _Ptr
->setFirstPtr(_NextPtr
);
4516 if (_NextPtr
!= this)
4518 nlassert(_PrevPtr
!= this);
4520 _NextPtr
->_PrevPtr
= _PrevPtr
;
4521 _PrevPtr
->_NextPtr
= _NextPtr
;
4528 CShard::TObjectCache
CShard::_ObjectCache
;
4529 CShard::TReleasedObject
CShard::_ReleasedObject
;
4532 // Destructor, delete any children
4535 // release childs reference
4536 if (_Guilds
!= NULL
)
4540 if (_PtrList
!= NULL
)
4542 nlwarning("ERROR : someone try to delete this object, but there are still ptr on it !");
4543 CShardPtr
*ptr
= _PtrList
;
4546 nlwarning(" Pointer created from '%s', line %u", ptr
->_FileName
, ptr
->_LineNum
);
4547 ptr
= _PtrList
->getNextPtr();
4548 } while(ptr
!= _PtrList
);
4551 // remove object from cache map
4552 if (_ShardId
!= NOPE::INVALID_OBJECT_ID
4553 && _ObjectState
!= NOPE::os_removed
4554 && _ObjectState
!= NOPE::os_transient
)
4556 nldebug("NOPE: clearing CShard @%p from cache with id %u", this, static_cast<uint32
>(_ShardId
));
4557 nlverify(_ObjectCache
.erase(_ShardId
) == 1);
4559 else if (_ObjectState
!= NOPE::os_transient
)
4561 nlassert(_ObjectCache
.find(_ShardId
) == _ObjectCache
.end());
4563 if (_ObjectState
== NOPE::os_released
)
4565 removeFromReleased();
4569 TReleasedObject::iterator
it(_ReleasedObject
.find(_ReleaseDate
));
4570 if (it
!= _ReleasedObject
.end())
4572 nlassert(it
->second
.find(this) == it
->second
.end());
4577 void CShard::removeFromReleased()
4579 TReleasedObject::iterator
it(_ReleasedObject
.find(_ReleaseDate
));
4580 nlassert(it
!= _ReleasedObject
.end());
4581 TObjectSet
&os
= it
->second
;
4583 nlverify(os
.erase(this) == 1);
4585 // nb : _ReleasedObject time entry are removed by the cache update
4588 bool CShard::create(MSW::CConnection
&connection
)
4590 nlassert(getPersistentState() == NOPE::os_transient
);
4592 nlassert(_ShardId
!= 0);
4594 qs
= "INSERT INTO shard (";
4596 qs
+= "shard_id, WSOnline, RequiredState, MOTD";
4599 qs
+= "'"+MSW::escapeString(NLMISC::toString(_ShardId
), connection
)+"'";
4601 qs
+= "'"+MSW::escapeString(NLMISC::toString(_WSOnline
), connection
)+"'";
4603 qs
+= _RequiredState
.isValid()
4604 ? "'"+_RequiredState
.toString()+"'"
4605 : "DEFAULT(RequiredState)";
4607 qs
+= "'"+MSW::escapeString(NLMISC::toString(_MOTD
), connection
)+"'";
4611 if (connection
.query(qs
))
4615 setPersistentState(NOPE::os_clean
);
4617 // update the parent class instance in cache if any
4625 bool CShard::update(MSW::CConnection
&connection
)
4627 nlassert(getPersistentState() == NOPE::os_dirty
|| getPersistentState() == NOPE::os_clean
);
4629 if (getPersistentState() == NOPE::os_clean
)
4630 // the object is clean, just ignore the save
4634 qs
= "UPDATE shard SET ";
4636 qs
+= "shard_id = '"+MSW::escapeString(NLMISC::toString(_ShardId
), connection
)+"'";
4638 qs
+= "WSOnline = '"+MSW::escapeString(NLMISC::toString(_WSOnline
), connection
)+"'";
4640 qs
+= "RequiredState = " + (_RequiredState
.isValid()
4641 ? "'"+_RequiredState
.toString()+"'"
4642 : "DEFAULT(RequiredState)");
4644 qs
+= "MOTD = '"+MSW::escapeString(NLMISC::toString(_MOTD
), connection
)+"'";
4646 qs
+= " WHERE shard_id = '"+NLMISC::toString(_ShardId
)+"'";
4649 if (connection
.query(qs
))
4651 if (connection
.getAffectedRows() == 1)
4653 setPersistentState(NOPE::os_clean
);
4661 bool CShard::remove(MSW::CConnection
&connection
)
4663 nlassert(getPersistentState() == NOPE::os_dirty
|| getPersistentState() == NOPE::os_clean
);
4666 qs
= "DELETE FROM shard ";
4668 qs
+= " WHERE shard_id = '"+NLMISC::toString(_ShardId
)+"'";
4671 if (connection
.query(qs
))
4673 if (connection
.getAffectedRows() == 1)
4677 // change the persistant state to 'removed'.
4678 setPersistentState(NOPE::os_removed
);
4680 // need to remove ref from parent class container (if any)
4682 // need to remove ref from parent (if any)
4691 bool CShard::removeById(MSW::CConnection
&connection
, uint32 id
)
4693 CShard
*object
= loadFromCache(id
, true);
4696 return object
->remove(connection
);
4698 // not in cache, run a SQL query
4700 qs
= "DELETE FROM shard ";
4702 qs
+= " WHERE shard_id = '"+NLMISC::toString(id
)+"'";
4705 if (connection
.query(qs
))
4707 if (connection
.getAffectedRows() == 1)
4709 // ok, the row is removed
4718 // Try to load the specified object from the memory cache, return NULL if the object is not in the cache
4719 CShard
*CShard::loadFromCache(uint32 objectId
, bool unrelease
)
4721 // look in the cache
4722 TObjectCache::iterator
it(_ObjectCache
.find(objectId
));
4723 if (it
== _ObjectCache
.end())
4725 // not found, return null
4730 CShard
*object
= it
->second
;
4732 if (object
->_ObjectState
== NOPE::os_released
)
4736 // we need to remove this object from the released object set.
4737 object
->removeFromReleased();
4738 object
->_ObjectState
= NOPE::os_clean
;
4745 // Receive and execute command from the cache manager.
4746 uint32
CShard::cacheCmd(NOPE::TCacheCmd cmd
)
4748 if (cmd
== NOPE::cc_update
)
4752 else if (cmd
== NOPE::cc_clear
)
4756 else if (cmd
== NOPE::cc_dump
)
4760 else if (cmd
== NOPE::cc_instance_count
)
4762 return (uint32
)_ObjectCache
.size();
4765 // default return value
4771 nlinfo(" Cache info for class CShard :");
4772 nlinfo(" There are %u object instances in cache", _ObjectCache
.size());
4774 // count the number of object in the released object set
4775 uint32 nbReleased
= 0;
4777 TReleasedObject::iterator
first(_ReleasedObject
.begin()), last(_ReleasedObject
.end());
4778 for (; first
!= last
; ++first
)
4780 nbReleased
+= (uint32
)first
->second
.size();
4783 nlinfo(" There are %u object instances in cache not referenced (waiting deletion or re-use))", nbReleased
);
4786 void CShard::updateCache()
4788 if (_ReleasedObject
.empty())
4791 // 30 s hold in cache
4792 const time_t MAX_CACHE_OLD_TIME
= 30;
4794 time_t now
= NLMISC::CTime::getSecondsSince1970();
4796 // look for object set older than MAX_CACHE_OLD_TIME and delete them
4797 while (!_ReleasedObject
.empty() && _ReleasedObject
.begin()->first
< now
-MAX_CACHE_OLD_TIME
)
4799 TObjectSet
&delSet
= _ReleasedObject
.begin()->second
;
4800 // unload this objects
4801 while (!delSet
.empty())
4803 CShard
*object
= *delSet
.begin();
4807 _ReleasedObject
.erase(_ReleasedObject
.begin());
4811 void CShard::clearCache()
4813 // remove any unreferenced object from the cache
4814 while (!_ReleasedObject
.empty())
4816 TObjectSet
&delSet
= _ReleasedObject
.begin()->second
;
4817 // unload this objects
4818 while (!delSet
.empty())
4820 CShard
*object
= *delSet
.begin();
4824 _ReleasedObject
.erase(_ReleasedObject
.begin());
4828 void CShard::registerUpdatable()
4830 static bool registered
= false;
4833 NOPE::CPersistentCache::getInstance().registerCache(&CShard::cacheCmd
);
4839 // set the pointer on the first pointer of the pointer list (set to null when there is no more pointer)
4840 void CShard::setFirstPtr(CShardPtr
*ptr
)
4846 // this is the last pointer !
4847 if (_ObjectState
== NOPE::os_transient
4848 || _ObjectState
== NOPE::os_removed
)
4850 // not a persistent object, or removed object, just delet it
4853 else if (_ObjectState
!= NOPE::os_removed
)
4855 setPersistentState(NOPE::os_released
);
4860 // Set the persistent state of the object and do some house keeping
4861 void CShard::setPersistentState(NOPE::TObjectState state
)
4863 nlassert(NOPE::AllowedTransition
[_ObjectState
][state
] == true);
4865 if(_ObjectState
== NOPE::os_released
&& state
== NOPE::os_removed
)
4867 // a release object gets removed (e.g. by remove by id)
4869 // delete the object
4876 if (_ObjectState
== NOPE::os_transient
&& state
!= NOPE::os_transient
)
4878 nldebug("NOPE: inserting CShard @%p in cache with id %u", this, static_cast<uint32
>(_ShardId
));
4879 nlverify(_ObjectCache
.insert(std::make_pair(_ShardId
, this)).second
);
4882 if (_ObjectState
!= NOPE::os_transient
)
4883 nlassert(_ObjectCache
.find(_ShardId
) != _ObjectCache
.end());
4885 _ObjectState
= state
;
4887 if (state
== NOPE::os_released
)
4889 _ReleaseDate
= NLMISC::CTime::getSecondsSince1970();
4890 nlverify(_ReleasedObject
[_ReleaseDate
].insert(this).second
);
4892 else if (state
== NOPE::os_removed
)
4894 nldebug("NOPE: erasing CShard @%p in cache with id %u", this, static_cast<uint32
>(_ShardId
));
4895 nlverify(_ObjectCache
.erase(_ShardId
) == 1);
4900 CShardPtr
CShard::load(MSW::CConnection
&connection
, uint32 id
, const char *filename
, uint32 lineNum
)
4902 CShard
*inCache
= loadFromCache(id
, true);
4903 if (inCache
!= NULL
)
4905 return CShardPtr(inCache
, filename
, lineNum
);
4911 qs
+= "shard_id, WSOnline, RequiredState, MOTD";
4913 qs
+= " FROM shard";
4915 qs
+= " WHERE shard_id = '"+NLMISC::toString(id
)+"'";
4917 if (!connection
.query(qs
))
4922 MSW::CStoreResult
*result
= connection
.storeResult().release();
4924 nlassert(result
->getNumRows() <= 1);
4925 if (result
->getNumRows() == 1)
4927 ret
.assign(new CShard
, filename
, lineNum
);
4928 // ok, we have an object
4931 result
->getField(0, ret
->_ShardId
);
4932 result
->getField(1, ret
->_WSOnline
);
4935 result
->getField(2, s
);
4936 ret
->_RequiredState
= TAccessLevel(s
);
4938 result
->getField(3, ret
->_MOTD
);
4941 ret
->setPersistentState(NOPE::os_clean
);
4950 bool CShard::loadGuilds(MSW::CConnection
&connection
, const char *filename
, uint32 lineNum
)
4953 if (_Guilds
!= NULL
)
4955 // the children are already loaded, just return true
4959 // allocate the container
4960 _Guilds
= new std::map
< uint32
, CGuildPtr
>;
4963 ret
&= CGuild::loadChildrenOfCShard(connection
, getObjectId(), *_Guilds
, filename
, lineNum
);
4968 const std::map
<uint32
, CGuildPtr
> &CShard::getGuilds() const
4970 nlassert(_Guilds
!= NULL
);
4974 CGuildPtr
&CShard::getGuildsById(uint32 id
) const
4976 nlassert(_Guilds
!= NULL
);
4977 std::map
<uint32
, CGuildPtr
>::const_iterator
it(_Guilds
->find(id
));
4979 if (it
== _Guilds
->end())
4981 // no object with this id, return a null pointer
4982 static CGuildPtr nilPtr
;
4986 return const_cast< CGuildPtr
& >(it
->second
);
4990 void CGuildPtr::linkPtr()
4992 nlassert(_NextPtr
== NULL
);
4993 nlassert(_PrevPtr
== NULL
);
4996 _NextPtr
= _Ptr
->getFirstPtr();
4997 if (_NextPtr
!= NULL
)
4999 _PrevPtr
= _NextPtr
->_PrevPtr
;
5000 _PrevPtr
->_NextPtr
= this;
5001 _NextPtr
->_PrevPtr
= this;
5007 _Ptr
->setFirstPtr(this);
5012 void CGuildPtr::unlinkPtr()
5014 if (_NextPtr
== NULL
)
5016 nlassert(_PrevPtr
== NULL
);
5022 if (_NextPtr
== this)
5024 nlassert(_PrevPtr
== this);
5026 _Ptr
->setFirstPtr(NULL
);
5030 if (_Ptr
->getFirstPtr() == this)
5032 // the first ptr is the current one, we need to switch to next one
5033 _Ptr
->setFirstPtr(_NextPtr
);
5038 if (_NextPtr
!= this)
5040 nlassert(_PrevPtr
!= this);
5042 _NextPtr
->_PrevPtr
= _PrevPtr
;
5043 _PrevPtr
->_NextPtr
= _NextPtr
;
5050 CGuild::TObjectCache
CGuild::_ObjectCache
;
5051 CGuild::TReleasedObject
CGuild::_ReleasedObject
;
5054 // Destructor, delete any children
5057 // release childs reference
5058 if (_Characters
!= NULL
)
5060 if (_Invites
!= NULL
)
5064 if (_PtrList
!= NULL
)
5066 nlwarning("ERROR : someone try to delete this object, but there are still ptr on it !");
5067 CGuildPtr
*ptr
= _PtrList
;
5070 nlwarning(" Pointer created from '%s', line %u", ptr
->_FileName
, ptr
->_LineNum
);
5071 ptr
= _PtrList
->getNextPtr();
5072 } while(ptr
!= _PtrList
);
5075 // remove object from cache map
5076 if (_GuildId
!= NOPE::INVALID_OBJECT_ID
5077 && _ObjectState
!= NOPE::os_removed
5078 && _ObjectState
!= NOPE::os_transient
)
5080 nldebug("NOPE: clearing CGuild @%p from cache with id %u", this, static_cast<uint32
>(_GuildId
));
5081 nlverify(_ObjectCache
.erase(_GuildId
) == 1);
5083 else if (_ObjectState
!= NOPE::os_transient
)
5085 nlassert(_ObjectCache
.find(_GuildId
) == _ObjectCache
.end());
5087 if (_ObjectState
== NOPE::os_released
)
5089 removeFromReleased();
5093 TReleasedObject::iterator
it(_ReleasedObject
.find(_ReleaseDate
));
5094 if (it
!= _ReleasedObject
.end())
5096 nlassert(it
->second
.find(this) == it
->second
.end());
5101 void CGuild::removeFromReleased()
5103 TReleasedObject::iterator
it(_ReleasedObject
.find(_ReleaseDate
));
5104 nlassert(it
!= _ReleasedObject
.end());
5105 TObjectSet
&os
= it
->second
;
5107 nlverify(os
.erase(this) == 1);
5109 // nb : _ReleasedObject time entry are removed by the cache update
5112 bool CGuild::create(MSW::CConnection
&connection
)
5114 nlassert(getPersistentState() == NOPE::os_transient
);
5116 nlassert(_GuildId
!= 0);
5118 qs
= "INSERT INTO guilds (";
5120 qs
+= "guild_id, guild_name, shard_id";
5123 qs
+= "'"+MSW::escapeString(NLMISC::toString(_GuildId
), connection
)+"'";
5125 qs
+= "'"+MSW::escapeString(NLMISC::toString(_GuildName
), connection
)+"'";
5127 qs
+= "'"+MSW::escapeString(NLMISC::toString(_ShardId
), connection
)+"'";
5131 if (connection
.query(qs
))
5135 setPersistentState(NOPE::os_clean
);
5137 // update the parent class instance in cache if any
5141 // need to update the parent class child list if it is in the cache
5142 CShard
*parent
= CShard::loadFromCache(_ShardId
, false);
5143 if (parent
&& parent
->_Guilds
!= NULL
)
5146 nlverify(parent
->_Guilds
->insert(std::make_pair(getObjectId(), CGuildPtr(this, __FILE__
, __LINE__
))).second
);
5157 bool CGuild::update(MSW::CConnection
&connection
)
5159 nlassert(getPersistentState() == NOPE::os_dirty
|| getPersistentState() == NOPE::os_clean
);
5161 if (getPersistentState() == NOPE::os_clean
)
5162 // the object is clean, just ignore the save
5166 qs
= "UPDATE guilds SET ";
5168 qs
+= "guild_id = '"+MSW::escapeString(NLMISC::toString(_GuildId
), connection
)+"'";
5170 qs
+= "guild_name = '"+MSW::escapeString(NLMISC::toString(_GuildName
), connection
)+"'";
5172 qs
+= "shard_id = '"+MSW::escapeString(NLMISC::toString(_ShardId
), connection
)+"'";
5174 qs
+= " WHERE guild_id = '"+NLMISC::toString(_GuildId
)+"'";
5177 if (connection
.query(qs
))
5179 if (connection
.getAffectedRows() == 1)
5181 setPersistentState(NOPE::os_clean
);
5189 bool CGuild::remove(MSW::CConnection
&connection
)
5191 nlassert(getPersistentState() == NOPE::os_dirty
|| getPersistentState() == NOPE::os_clean
);
5194 qs
= "DELETE FROM guilds ";
5196 qs
+= " WHERE guild_id = '"+NLMISC::toString(_GuildId
)+"'";
5199 if (connection
.query(qs
))
5201 if (connection
.getAffectedRows() == 1)
5205 // cascading deletion for vector child Invites
5206 if (loadInvites(connection
, __FILE__
, __LINE__
))
5208 const std::vector
< CGuildInvitePtr
> & childs
= getInvites();
5210 while (!childs
.empty())
5212 getInvitesByIndex((uint32
)childs
.size()-1)->remove(connection
);
5219 // unreference (and update) for vector child Characters
5220 if (loadCharacters(connection
, __FILE__
, __LINE__
))
5222 const std::vector
< CCharacterPtr
> & childs
= getCharacters();
5224 for (uint i
=0; i
< childs
.size(); ++i
)
5227 getCharactersByIndex(i
)->setGuildId(0);
5228 getCharactersByIndex(i
)->update(connection
);
5234 // change the persistant state to 'removed'.
5235 setPersistentState(NOPE::os_removed
);
5237 // need to remove ref from parent class container (if any)
5240 CShardPtr
parent(CShard::loadFromCache(_ShardId
, true), __FILE__
, __LINE__
);
5241 if (parent
!= NULL
&& parent
->_Guilds
!= NULL
)
5244 parent
->_Guilds
->erase(getObjectId());
5249 // need to remove ref from parent (if any)
5258 bool CGuild::removeById(MSW::CConnection
&connection
, uint32 id
)
5260 CGuild
*object
= loadFromCache(id
, true);
5263 return object
->remove(connection
);
5265 // not in cache, run a SQL query
5267 qs
= "DELETE FROM guilds ";
5269 qs
+= " WHERE guild_id = '"+NLMISC::toString(id
)+"'";
5272 if (connection
.query(qs
))
5274 if (connection
.getAffectedRows() == 1)
5276 // ok, the row is removed
5285 // Try to load the specified object from the memory cache, return NULL if the object is not in the cache
5286 CGuild
*CGuild::loadFromCache(uint32 objectId
, bool unrelease
)
5288 // look in the cache
5289 TObjectCache::iterator
it(_ObjectCache
.find(objectId
));
5290 if (it
== _ObjectCache
.end())
5292 // not found, return null
5297 CGuild
*object
= it
->second
;
5299 if (object
->_ObjectState
== NOPE::os_released
)
5303 // we need to remove this object from the released object set.
5304 object
->removeFromReleased();
5305 object
->_ObjectState
= NOPE::os_clean
;
5312 // Receive and execute command from the cache manager.
5313 uint32
CGuild::cacheCmd(NOPE::TCacheCmd cmd
)
5315 if (cmd
== NOPE::cc_update
)
5319 else if (cmd
== NOPE::cc_clear
)
5323 else if (cmd
== NOPE::cc_dump
)
5327 else if (cmd
== NOPE::cc_instance_count
)
5329 return (uint32
)_ObjectCache
.size();
5332 // default return value
5338 nlinfo(" Cache info for class CGuild :");
5339 nlinfo(" There are %u object instances in cache", _ObjectCache
.size());
5341 // count the number of object in the released object set
5342 uint32 nbReleased
= 0;
5344 TReleasedObject::iterator
first(_ReleasedObject
.begin()), last(_ReleasedObject
.end());
5345 for (; first
!= last
; ++first
)
5347 nbReleased
+= (uint32
)first
->second
.size();
5350 nlinfo(" There are %u object instances in cache not referenced (waiting deletion or re-use))", nbReleased
);
5353 void CGuild::updateCache()
5355 if (_ReleasedObject
.empty())
5358 // 30 s hold in cache
5359 const time_t MAX_CACHE_OLD_TIME
= 30;
5361 time_t now
= NLMISC::CTime::getSecondsSince1970();
5363 // look for object set older than MAX_CACHE_OLD_TIME and delete them
5364 while (!_ReleasedObject
.empty() && _ReleasedObject
.begin()->first
< now
-MAX_CACHE_OLD_TIME
)
5366 TObjectSet
&delSet
= _ReleasedObject
.begin()->second
;
5367 // unload this objects
5368 while (!delSet
.empty())
5370 CGuild
*object
= *delSet
.begin();
5374 _ReleasedObject
.erase(_ReleasedObject
.begin());
5378 void CGuild::clearCache()
5380 // remove any unreferenced object from the cache
5381 while (!_ReleasedObject
.empty())
5383 TObjectSet
&delSet
= _ReleasedObject
.begin()->second
;
5384 // unload this objects
5385 while (!delSet
.empty())
5387 CGuild
*object
= *delSet
.begin();
5391 _ReleasedObject
.erase(_ReleasedObject
.begin());
5395 void CGuild::registerUpdatable()
5397 static bool registered
= false;
5400 NOPE::CPersistentCache::getInstance().registerCache(&CGuild::cacheCmd
);
5406 // set the pointer on the first pointer of the pointer list (set to null when there is no more pointer)
5407 void CGuild::setFirstPtr(CGuildPtr
*ptr
)
5413 // this is the last pointer !
5414 if (_ObjectState
== NOPE::os_transient
5415 || _ObjectState
== NOPE::os_removed
)
5417 // not a persistent object, or removed object, just delet it
5420 else if (_ObjectState
!= NOPE::os_removed
)
5422 setPersistentState(NOPE::os_released
);
5427 // Set the persistent state of the object and do some house keeping
5428 void CGuild::setPersistentState(NOPE::TObjectState state
)
5430 nlassert(NOPE::AllowedTransition
[_ObjectState
][state
] == true);
5432 if(_ObjectState
== NOPE::os_released
&& state
== NOPE::os_removed
)
5434 // a release object gets removed (e.g. by remove by id)
5436 // delete the object
5443 if (_ObjectState
== NOPE::os_transient
&& state
!= NOPE::os_transient
)
5445 nldebug("NOPE: inserting CGuild @%p in cache with id %u", this, static_cast<uint32
>(_GuildId
));
5446 nlverify(_ObjectCache
.insert(std::make_pair(_GuildId
, this)).second
);
5449 if (_ObjectState
!= NOPE::os_transient
)
5450 nlassert(_ObjectCache
.find(_GuildId
) != _ObjectCache
.end());
5452 _ObjectState
= state
;
5454 if (state
== NOPE::os_released
)
5456 _ReleaseDate
= NLMISC::CTime::getSecondsSince1970();
5457 nlverify(_ReleasedObject
[_ReleaseDate
].insert(this).second
);
5459 else if (state
== NOPE::os_removed
)
5461 nldebug("NOPE: erasing CGuild @%p in cache with id %u", this, static_cast<uint32
>(_GuildId
));
5462 nlverify(_ObjectCache
.erase(_GuildId
) == 1);
5467 CGuildPtr
CGuild::load(MSW::CConnection
&connection
, uint32 id
, const char *filename
, uint32 lineNum
)
5469 CGuild
*inCache
= loadFromCache(id
, true);
5470 if (inCache
!= NULL
)
5472 return CGuildPtr(inCache
, filename
, lineNum
);
5478 qs
+= "guild_id, guild_name, shard_id";
5480 qs
+= " FROM guilds";
5482 qs
+= " WHERE guild_id = '"+NLMISC::toString(id
)+"'";
5484 if (!connection
.query(qs
))
5489 MSW::CStoreResult
*result
= connection
.storeResult().release();
5491 nlassert(result
->getNumRows() <= 1);
5492 if (result
->getNumRows() == 1)
5494 ret
.assign(new CGuild
, filename
, lineNum
);
5495 // ok, we have an object
5498 result
->getField(0, ret
->_GuildId
);
5499 result
->getField(1, ret
->_GuildName
);
5500 result
->getField(2, ret
->_ShardId
);
5503 ret
->setPersistentState(NOPE::os_clean
);
5512 bool CGuild::loadChildrenOfCShard(MSW::CConnection
&connection
, uint32 parentId
, std::map
< uint32
, CGuildPtr
> & container
, const char *filename
, uint32 lineNum
)
5518 qs
+= "guild_id, guild_name, shard_id";
5520 qs
+= " FROM guilds";
5521 qs
+= " WHERE shard_id = '"+NLMISC::toString(parentId
)+"'";
5523 if (!connection
.query(qs
))
5528 CUniquePtr
<MSW::CStoreResult
> result
= connection
.storeResult();
5530 for (uint i
=0; i
<result
->getNumRows(); ++i
)
5532 CGuild
*ret
= new CGuild();
5533 // ok, we have an object
5536 result
->getField(0, ret
->_GuildId
);
5538 result
->getField(1, ret
->_GuildName
);
5540 result
->getField(2, ret
->_ShardId
);
5541 CGuild
*inCache
= loadFromCache(ret
->_GuildId
, true);
5542 if (inCache
!= NULL
)
5545 container
.insert(std::make_pair(inCache
->getObjectId(), CGuildPtr(inCache
, filename
, lineNum
)));
5552 ret
->setPersistentState(NOPE::os_clean
);
5554 container
.insert(std::make_pair(ret
->getObjectId(), CGuildPtr(ret
, filename
, lineNum
)));
5562 bool CGuild::loadCharacters(MSW::CConnection
&connection
, const char *filename
, uint32 lineNum
)
5565 if (_Characters
!= NULL
)
5567 // the children are already loaded, just return true
5571 // allocate the container
5572 _Characters
= new std::vector
< CCharacterPtr
>;
5575 ret
&= CCharacter::loadChildrenOfCGuild(connection
, getObjectId(), *_Characters
, filename
, lineNum
);
5580 const std::vector
<CCharacterPtr
> &CGuild::getCharacters() const
5582 nlassert(_Characters
!= NULL
);
5583 return *_Characters
;
5586 CCharacterPtr
&CGuild::getCharactersByIndex(uint32 index
) const
5588 nlassert(_Characters
!= NULL
);
5589 nlassert(index
< _Characters
->size());
5590 return const_cast< CCharacterPtr
& >(_Characters
->operator[](index
));
5593 CCharacterPtr
&CGuild::getCharactersById(uint32 id
) const
5595 nlassert(_Characters
!= NULL
);
5596 std::vector
<CCharacterPtr
>::const_iterator
first(_Characters
->begin()), last(_Characters
->end());
5597 for (; first
!= last
; ++first
)
5599 const CCharacterPtr
&child
= *first
;
5600 if (child
->getObjectId() == id
)
5602 return const_cast< CCharacterPtr
& >(child
);
5606 // no object with this id, return a null pointer
5607 static CCharacterPtr nilPtr
;
5613 bool CGuild::loadInvites(MSW::CConnection
&connection
, const char *filename
, uint32 lineNum
)
5616 if (_Invites
!= NULL
)
5618 // the children are already loaded, just return true
5622 // allocate the container
5623 _Invites
= new std::vector
< CGuildInvitePtr
>;
5626 ret
&= CGuildInvite::loadChildrenOfCGuild(connection
, getObjectId(), *_Invites
, filename
, lineNum
);
5631 const std::vector
<CGuildInvitePtr
> &CGuild::getInvites() const
5633 nlassert(_Invites
!= NULL
);
5637 CGuildInvitePtr
&CGuild::getInvitesByIndex(uint32 index
) const
5639 nlassert(_Invites
!= NULL
);
5640 nlassert(index
< _Invites
->size());
5641 return const_cast< CGuildInvitePtr
& >(_Invites
->operator[](index
));
5644 CGuildInvitePtr
&CGuild::getInvitesById(uint32 id
) const
5646 nlassert(_Invites
!= NULL
);
5647 std::vector
<CGuildInvitePtr
>::const_iterator
first(_Invites
->begin()), last(_Invites
->end());
5648 for (; first
!= last
; ++first
)
5650 const CGuildInvitePtr
&child
= *first
;
5651 if (child
->getObjectId() == id
)
5653 return const_cast< CGuildInvitePtr
& >(child
);
5657 // no object with this id, return a null pointer
5658 static CGuildInvitePtr nilPtr
;
5664 void CGuildInvitePtr::linkPtr()
5666 nlassert(_NextPtr
== NULL
);
5667 nlassert(_PrevPtr
== NULL
);
5670 _NextPtr
= _Ptr
->getFirstPtr();
5671 if (_NextPtr
!= NULL
)
5673 _PrevPtr
= _NextPtr
->_PrevPtr
;
5674 _PrevPtr
->_NextPtr
= this;
5675 _NextPtr
->_PrevPtr
= this;
5681 _Ptr
->setFirstPtr(this);
5686 void CGuildInvitePtr::unlinkPtr()
5688 if (_NextPtr
== NULL
)
5690 nlassert(_PrevPtr
== NULL
);
5696 if (_NextPtr
== this)
5698 nlassert(_PrevPtr
== this);
5700 _Ptr
->setFirstPtr(NULL
);
5704 if (_Ptr
->getFirstPtr() == this)
5706 // the first ptr is the current one, we need to switch to next one
5707 _Ptr
->setFirstPtr(_NextPtr
);
5712 if (_NextPtr
!= this)
5714 nlassert(_PrevPtr
!= this);
5716 _NextPtr
->_PrevPtr
= _PrevPtr
;
5717 _PrevPtr
->_NextPtr
= _NextPtr
;
5724 CGuildInvite::TObjectCache
CGuildInvite::_ObjectCache
;
5725 CGuildInvite::TReleasedObject
CGuildInvite::_ReleasedObject
;
5728 // Destructor, delete any children
5729 CGuildInvite::~CGuildInvite()
5731 // release childs reference
5734 if (_PtrList
!= NULL
)
5736 nlwarning("ERROR : someone try to delete this object, but there are still ptr on it !");
5737 CGuildInvitePtr
*ptr
= _PtrList
;
5740 nlwarning(" Pointer created from '%s', line %u", ptr
->_FileName
, ptr
->_LineNum
);
5741 ptr
= _PtrList
->getNextPtr();
5742 } while(ptr
!= _PtrList
);
5745 // remove object from cache map
5746 if (_Id
!= NOPE::INVALID_OBJECT_ID
5747 && _ObjectState
!= NOPE::os_removed
5748 && _ObjectState
!= NOPE::os_transient
)
5750 nldebug("NOPE: clearing CGuildInvite @%p from cache with id %u", this, static_cast<uint32
>(_Id
));
5751 nlverify(_ObjectCache
.erase(_Id
) == 1);
5753 else if (_ObjectState
!= NOPE::os_transient
)
5755 nlassert(_ObjectCache
.find(_Id
) == _ObjectCache
.end());
5757 if (_ObjectState
== NOPE::os_released
)
5759 removeFromReleased();
5763 TReleasedObject::iterator
it(_ReleasedObject
.find(_ReleaseDate
));
5764 if (it
!= _ReleasedObject
.end())
5766 nlassert(it
->second
.find(this) == it
->second
.end());
5771 void CGuildInvite::removeFromReleased()
5773 TReleasedObject::iterator
it(_ReleasedObject
.find(_ReleaseDate
));
5774 nlassert(it
!= _ReleasedObject
.end());
5775 TObjectSet
&os
= it
->second
;
5777 nlverify(os
.erase(this) == 1);
5779 // nb : _ReleasedObject time entry are removed by the cache update
5782 bool CGuildInvite::create(MSW::CConnection
&connection
)
5784 nlassert(getPersistentState() == NOPE::os_transient
);
5787 qs
= "INSERT INTO guild_invites (";
5789 qs
+= "guild_id, session_id";
5792 qs
+= "'"+MSW::escapeString(NLMISC::toString(_GuildId
), connection
)+"'";
5794 qs
+= "'"+MSW::escapeString(NLMISC::toString(_SessionId
), connection
)+"'";
5798 if (connection
.query(qs
))
5800 uint32 _id_
= connection
.getLastGeneratedId();
5804 setPersistentState(NOPE::os_clean
);
5806 // update the parent class instance in cache if any
5810 // need to update the parent class child list if it is in the cache
5811 CGuild
*parent
= CGuild::loadFromCache(_GuildId
, false);
5812 if (parent
&& parent
->_Invites
!= NULL
)
5815 nlassert(std::find(parent
->_Invites
->begin(), parent
->_Invites
->end(), CGuildInvitePtr(this, __FILE__
, __LINE__
)) == parent
->_Invites
->end());
5816 parent
->_Invites
->push_back(CGuildInvitePtr(this, __FILE__
, __LINE__
));
5821 if (_SessionId
!= 0)
5823 // need to update the parent class child list if it is in the cache
5824 CSession
*parent
= CSession::loadFromCache(_SessionId
, false);
5825 if (parent
&& parent
->_GuildInvites
!= NULL
)
5828 nlassert(std::find(parent
->_GuildInvites
->begin(), parent
->_GuildInvites
->end(), CGuildInvitePtr(this, __FILE__
, __LINE__
)) == parent
->_GuildInvites
->end());
5829 parent
->_GuildInvites
->push_back(CGuildInvitePtr(this, __FILE__
, __LINE__
));
5840 bool CGuildInvite::update(MSW::CConnection
&connection
)
5842 nlassert(getPersistentState() == NOPE::os_dirty
|| getPersistentState() == NOPE::os_clean
);
5844 if (getPersistentState() == NOPE::os_clean
)
5845 // the object is clean, just ignore the save
5849 qs
= "UPDATE guild_invites SET ";
5851 qs
+= "guild_id = '"+MSW::escapeString(NLMISC::toString(_GuildId
), connection
)+"'";
5853 qs
+= "session_id = '"+MSW::escapeString(NLMISC::toString(_SessionId
), connection
)+"'";
5855 qs
+= " WHERE Id = '"+NLMISC::toString(_Id
)+"'";
5858 if (connection
.query(qs
))
5860 if (connection
.getAffectedRows() == 1)
5862 setPersistentState(NOPE::os_clean
);
5870 bool CGuildInvite::remove(MSW::CConnection
&connection
)
5872 nlassert(getPersistentState() == NOPE::os_dirty
|| getPersistentState() == NOPE::os_clean
);
5875 qs
= "DELETE FROM guild_invites ";
5877 qs
+= " WHERE Id = '"+NLMISC::toString(_Id
)+"'";
5880 if (connection
.query(qs
))
5882 if (connection
.getAffectedRows() == 1)
5886 // change the persistant state to 'removed'.
5887 setPersistentState(NOPE::os_removed
);
5889 // need to remove ref from parent class container (if any)
5892 CGuildPtr
parent(CGuild::loadFromCache(_GuildId
, true), __FILE__
, __LINE__
);
5893 if (parent
!= NULL
&& parent
->_Invites
!= NULL
)
5896 std::vector
< CGuildInvitePtr
>::iterator it
= std::find(parent
->_Invites
->begin(), parent
->_Invites
->end(), this);
5897 if (it
!= parent
->_Invites
->end())
5899 parent
->_Invites
->erase(it
);
5906 CSessionPtr
parent(CSession::loadFromCache(_SessionId
, true), __FILE__
, __LINE__
);
5907 if (parent
!= NULL
&& parent
->_GuildInvites
!= NULL
)
5910 std::vector
< CGuildInvitePtr
>::iterator it
= std::find(parent
->_GuildInvites
->begin(), parent
->_GuildInvites
->end(), this);
5911 if (it
!= parent
->_GuildInvites
->end())
5913 parent
->_GuildInvites
->erase(it
);
5919 // need to remove ref from parent (if any)
5928 bool CGuildInvite::removeById(MSW::CConnection
&connection
, uint32 id
)
5930 CGuildInvite
*object
= loadFromCache(id
, true);
5933 return object
->remove(connection
);
5935 // not in cache, run a SQL query
5937 qs
= "DELETE FROM guild_invites ";
5939 qs
+= " WHERE Id = '"+NLMISC::toString(id
)+"'";
5942 if (connection
.query(qs
))
5944 if (connection
.getAffectedRows() == 1)
5946 // ok, the row is removed
5955 // Try to load the specified object from the memory cache, return NULL if the object is not in the cache
5956 CGuildInvite
*CGuildInvite::loadFromCache(uint32 objectId
, bool unrelease
)
5958 // look in the cache
5959 TObjectCache::iterator
it(_ObjectCache
.find(objectId
));
5960 if (it
== _ObjectCache
.end())
5962 // not found, return null
5967 CGuildInvite
*object
= it
->second
;
5969 if (object
->_ObjectState
== NOPE::os_released
)
5973 // we need to remove this object from the released object set.
5974 object
->removeFromReleased();
5975 object
->_ObjectState
= NOPE::os_clean
;
5982 // Receive and execute command from the cache manager.
5983 uint32
CGuildInvite::cacheCmd(NOPE::TCacheCmd cmd
)
5985 if (cmd
== NOPE::cc_update
)
5989 else if (cmd
== NOPE::cc_clear
)
5993 else if (cmd
== NOPE::cc_dump
)
5997 else if (cmd
== NOPE::cc_instance_count
)
5999 return (uint32
)_ObjectCache
.size();
6002 // default return value
6006 void CGuildInvite::dump()
6008 nlinfo(" Cache info for class CGuildInvite :");
6009 nlinfo(" There are %u object instances in cache", _ObjectCache
.size());
6011 // count the number of object in the released object set
6012 uint32 nbReleased
= 0;
6014 TReleasedObject::iterator
first(_ReleasedObject
.begin()), last(_ReleasedObject
.end());
6015 for (; first
!= last
; ++first
)
6017 nbReleased
+= (uint32
)first
->second
.size();
6020 nlinfo(" There are %u object instances in cache not referenced (waiting deletion or re-use))", nbReleased
);
6023 void CGuildInvite::updateCache()
6025 if (_ReleasedObject
.empty())
6028 // 30 s hold in cache
6029 const time_t MAX_CACHE_OLD_TIME
= 30;
6031 time_t now
= NLMISC::CTime::getSecondsSince1970();
6033 // look for object set older than MAX_CACHE_OLD_TIME and delete them
6034 while (!_ReleasedObject
.empty() && _ReleasedObject
.begin()->first
< now
-MAX_CACHE_OLD_TIME
)
6036 TObjectSet
&delSet
= _ReleasedObject
.begin()->second
;
6037 // unload this objects
6038 while (!delSet
.empty())
6040 CGuildInvite
*object
= *delSet
.begin();
6044 _ReleasedObject
.erase(_ReleasedObject
.begin());
6048 void CGuildInvite::clearCache()
6050 // remove any unreferenced object from the cache
6051 while (!_ReleasedObject
.empty())
6053 TObjectSet
&delSet
= _ReleasedObject
.begin()->second
;
6054 // unload this objects
6055 while (!delSet
.empty())
6057 CGuildInvite
*object
= *delSet
.begin();
6061 _ReleasedObject
.erase(_ReleasedObject
.begin());
6065 void CGuildInvite::registerUpdatable()
6067 static bool registered
= false;
6070 NOPE::CPersistentCache::getInstance().registerCache(&CGuildInvite::cacheCmd
);
6076 // set the pointer on the first pointer of the pointer list (set to null when there is no more pointer)
6077 void CGuildInvite::setFirstPtr(CGuildInvitePtr
*ptr
)
6083 // this is the last pointer !
6084 if (_ObjectState
== NOPE::os_transient
6085 || _ObjectState
== NOPE::os_removed
)
6087 // not a persistent object, or removed object, just delet it
6090 else if (_ObjectState
!= NOPE::os_removed
)
6092 setPersistentState(NOPE::os_released
);
6097 // Set the persistent state of the object and do some house keeping
6098 void CGuildInvite::setPersistentState(NOPE::TObjectState state
)
6100 nlassert(NOPE::AllowedTransition
[_ObjectState
][state
] == true);
6102 if(_ObjectState
== NOPE::os_released
&& state
== NOPE::os_removed
)
6104 // a release object gets removed (e.g. by remove by id)
6106 // delete the object
6113 if (_ObjectState
== NOPE::os_transient
&& state
!= NOPE::os_transient
)
6115 nldebug("NOPE: inserting CGuildInvite @%p in cache with id %u", this, static_cast<uint32
>(_Id
));
6116 nlverify(_ObjectCache
.insert(std::make_pair(_Id
, this)).second
);
6119 if (_ObjectState
!= NOPE::os_transient
)
6120 nlassert(_ObjectCache
.find(_Id
) != _ObjectCache
.end());
6122 _ObjectState
= state
;
6124 if (state
== NOPE::os_released
)
6126 _ReleaseDate
= NLMISC::CTime::getSecondsSince1970();
6127 nlverify(_ReleasedObject
[_ReleaseDate
].insert(this).second
);
6129 else if (state
== NOPE::os_removed
)
6131 nldebug("NOPE: erasing CGuildInvite @%p in cache with id %u", this, static_cast<uint32
>(_Id
));
6132 nlverify(_ObjectCache
.erase(_Id
) == 1);
6137 CGuildInvitePtr
CGuildInvite::load(MSW::CConnection
&connection
, uint32 id
, const char *filename
, uint32 lineNum
)
6139 CGuildInvite
*inCache
= loadFromCache(id
, true);
6140 if (inCache
!= NULL
)
6142 return CGuildInvitePtr(inCache
, filename
, lineNum
);
6148 qs
+= "Id, guild_id, session_id";
6150 qs
+= " FROM guild_invites";
6152 qs
+= " WHERE Id = '"+NLMISC::toString(id
)+"'";
6153 CGuildInvitePtr ret
;
6154 if (!connection
.query(qs
))
6159 MSW::CStoreResult
*result
= connection
.storeResult().release();
6161 nlassert(result
->getNumRows() <= 1);
6162 if (result
->getNumRows() == 1)
6164 ret
.assign(new CGuildInvite
, filename
, lineNum
);
6165 // ok, we have an object
6168 result
->getField(0, ret
->_Id
);
6169 result
->getField(1, ret
->_GuildId
);
6170 result
->getField(2, ret
->_SessionId
);
6173 ret
->setPersistentState(NOPE::os_clean
);
6182 bool CGuildInvite::loadChildrenOfCGuild(MSW::CConnection
&connection
, uint32 parentId
, std::vector
< CGuildInvitePtr
> & container
, const char *filename
, uint32 lineNum
)
6188 qs
+= "Id, guild_id, session_id";
6190 qs
+= " FROM guild_invites";
6191 qs
+= " WHERE guild_id = '"+NLMISC::toString(parentId
)+"'";
6193 if (!connection
.query(qs
))
6198 CUniquePtr
<MSW::CStoreResult
> result
= connection
.storeResult();
6200 for (uint i
=0; i
<result
->getNumRows(); ++i
)
6202 CGuildInvite
*ret
= new CGuildInvite();
6203 // ok, we have an object
6206 result
->getField(0, ret
->_Id
);
6208 result
->getField(1, ret
->_GuildId
);
6210 result
->getField(2, ret
->_SessionId
);
6211 CGuildInvite
*inCache
= loadFromCache(ret
->_Id
, true);
6212 if (inCache
!= NULL
)
6215 container
.push_back(CGuildInvitePtr(inCache
, filename
, lineNum
));
6222 ret
->setPersistentState(NOPE::os_clean
);
6224 container
.push_back(CGuildInvitePtr(ret
, filename
, lineNum
));
6232 bool CGuildInvite::loadChildrenOfCSession(MSW::CConnection
&connection
, uint32 parentId
, std::vector
< CGuildInvitePtr
> & container
, const char *filename
, uint32 lineNum
)
6238 qs
+= "Id, guild_id, session_id";
6240 qs
+= " FROM guild_invites";
6241 qs
+= " WHERE session_id = '"+NLMISC::toString(parentId
)+"'";
6243 if (!connection
.query(qs
))
6248 CUniquePtr
<MSW::CStoreResult
> result
= connection
.storeResult();
6250 for (uint i
=0; i
<result
->getNumRows(); ++i
)
6252 CGuildInvite
*ret
= new CGuildInvite();
6253 // ok, we have an object
6256 result
->getField(0, ret
->_Id
);
6258 result
->getField(1, ret
->_GuildId
);
6260 result
->getField(2, ret
->_SessionId
);
6261 CGuildInvite
*inCache
= loadFromCache(ret
->_Id
, true);
6262 if (inCache
!= NULL
)
6265 container
.push_back(CGuildInvitePtr(inCache
, filename
, lineNum
));
6272 ret
->setPersistentState(NOPE::os_clean
);
6274 container
.push_back(CGuildInvitePtr(ret
, filename
, lineNum
));
6282 void CPlayerRatingPtr::linkPtr()
6284 nlassert(_NextPtr
== NULL
);
6285 nlassert(_PrevPtr
== NULL
);
6288 _NextPtr
= _Ptr
->getFirstPtr();
6289 if (_NextPtr
!= NULL
)
6291 _PrevPtr
= _NextPtr
->_PrevPtr
;
6292 _PrevPtr
->_NextPtr
= this;
6293 _NextPtr
->_PrevPtr
= this;
6299 _Ptr
->setFirstPtr(this);
6304 void CPlayerRatingPtr::unlinkPtr()
6306 if (_NextPtr
== NULL
)
6308 nlassert(_PrevPtr
== NULL
);
6314 if (_NextPtr
== this)
6316 nlassert(_PrevPtr
== this);
6318 _Ptr
->setFirstPtr(NULL
);
6322 if (_Ptr
->getFirstPtr() == this)
6324 // the first ptr is the current one, we need to switch to next one
6325 _Ptr
->setFirstPtr(_NextPtr
);
6330 if (_NextPtr
!= this)
6332 nlassert(_PrevPtr
!= this);
6334 _NextPtr
->_PrevPtr
= _PrevPtr
;
6335 _PrevPtr
->_NextPtr
= _NextPtr
;
6342 CPlayerRating::TObjectCache
CPlayerRating::_ObjectCache
;
6343 CPlayerRating::TReleasedObject
CPlayerRating::_ReleasedObject
;
6346 // Destructor, delete any children
6347 CPlayerRating::~CPlayerRating()
6349 // release childs reference
6352 if (_PtrList
!= NULL
)
6354 nlwarning("ERROR : someone try to delete this object, but there are still ptr on it !");
6355 CPlayerRatingPtr
*ptr
= _PtrList
;
6358 nlwarning(" Pointer created from '%s', line %u", ptr
->_FileName
, ptr
->_LineNum
);
6359 ptr
= _PtrList
->getNextPtr();
6360 } while(ptr
!= _PtrList
);
6363 // remove object from cache map
6364 if (_Id
!= NOPE::INVALID_OBJECT_ID
6365 && _ObjectState
!= NOPE::os_removed
6366 && _ObjectState
!= NOPE::os_transient
)
6368 nldebug("NOPE: clearing CPlayerRating @%p from cache with id %u", this, static_cast<uint32
>(_Id
));
6369 nlverify(_ObjectCache
.erase(_Id
) == 1);
6371 else if (_ObjectState
!= NOPE::os_transient
)
6373 nlassert(_ObjectCache
.find(_Id
) == _ObjectCache
.end());
6375 if (_ObjectState
== NOPE::os_released
)
6377 removeFromReleased();
6381 TReleasedObject::iterator
it(_ReleasedObject
.find(_ReleaseDate
));
6382 if (it
!= _ReleasedObject
.end())
6384 nlassert(it
->second
.find(this) == it
->second
.end());
6389 void CPlayerRating::removeFromReleased()
6391 TReleasedObject::iterator
it(_ReleasedObject
.find(_ReleaseDate
));
6392 nlassert(it
!= _ReleasedObject
.end());
6393 TObjectSet
&os
= it
->second
;
6395 nlverify(os
.erase(this) == 1);
6397 // nb : _ReleasedObject time entry are removed by the cache update
6400 bool CPlayerRating::create(MSW::CConnection
&connection
)
6402 nlassert(getPersistentState() == NOPE::os_transient
);
6405 qs
= "INSERT INTO player_rating (";
6407 qs
+= "scenario_id, author, rate_fun, rate_difficulty, rate_accessibility, rate_originality, rate_direction";
6410 qs
+= "'"+MSW::escapeString(NLMISC::toString(_ScenarioId
), connection
)+"'";
6412 qs
+= "'"+MSW::escapeString(NLMISC::toString(_Author
), connection
)+"'";
6414 qs
+= "'"+MSW::escapeString(NLMISC::toString(_RateFun
), connection
)+"'";
6416 qs
+= "'"+MSW::escapeString(NLMISC::toString(_RateDifficulty
), connection
)+"'";
6418 qs
+= "'"+MSW::escapeString(NLMISC::toString(_RateAccessibility
), connection
)+"'";
6420 qs
+= "'"+MSW::escapeString(NLMISC::toString(_RateOriginality
), connection
)+"'";
6422 qs
+= "'"+MSW::escapeString(NLMISC::toString(_RateDirection
), connection
)+"'";
6426 if (connection
.query(qs
))
6428 uint32 _id_
= connection
.getLastGeneratedId();
6432 setPersistentState(NOPE::os_clean
);
6434 // update the parent class instance in cache if any
6436 if (_ScenarioId
!= 0)
6438 // need to update the parent class child list if it is in the cache
6439 CScenario
*parent
= CScenario::loadFromCache(_ScenarioId
, false);
6440 if (parent
&& parent
->_PlayerRatings
!= NULL
)
6443 nlassert(std::find(parent
->_PlayerRatings
->begin(), parent
->_PlayerRatings
->end(), CPlayerRatingPtr(this, __FILE__
, __LINE__
)) == parent
->_PlayerRatings
->end());
6444 parent
->_PlayerRatings
->push_back(CPlayerRatingPtr(this, __FILE__
, __LINE__
));
6451 // need to update the parent class child list if it is in the cache
6452 CCharacter
*parent
= CCharacter::loadFromCache(_Author
, false);
6453 if (parent
&& parent
->_PlayerRatings
!= NULL
)
6456 nlassert(std::find(parent
->_PlayerRatings
->begin(), parent
->_PlayerRatings
->end(), CPlayerRatingPtr(this, __FILE__
, __LINE__
)) == parent
->_PlayerRatings
->end());
6457 parent
->_PlayerRatings
->push_back(CPlayerRatingPtr(this, __FILE__
, __LINE__
));
6468 bool CPlayerRating::update(MSW::CConnection
&connection
)
6470 nlassert(getPersistentState() == NOPE::os_dirty
|| getPersistentState() == NOPE::os_clean
);
6472 if (getPersistentState() == NOPE::os_clean
)
6473 // the object is clean, just ignore the save
6477 qs
= "UPDATE player_rating SET ";
6479 qs
+= "scenario_id = '"+MSW::escapeString(NLMISC::toString(_ScenarioId
), connection
)+"'";
6481 qs
+= "author = '"+MSW::escapeString(NLMISC::toString(_Author
), connection
)+"'";
6483 qs
+= "rate_fun = '"+MSW::escapeString(NLMISC::toString(_RateFun
), connection
)+"'";
6485 qs
+= "rate_difficulty = '"+MSW::escapeString(NLMISC::toString(_RateDifficulty
), connection
)+"'";
6487 qs
+= "rate_accessibility = '"+MSW::escapeString(NLMISC::toString(_RateAccessibility
), connection
)+"'";
6489 qs
+= "rate_originality = '"+MSW::escapeString(NLMISC::toString(_RateOriginality
), connection
)+"'";
6491 qs
+= "rate_direction = '"+MSW::escapeString(NLMISC::toString(_RateDirection
), connection
)+"'";
6493 qs
+= " WHERE Id = '"+NLMISC::toString(_Id
)+"'";
6496 if (connection
.query(qs
))
6498 if (connection
.getAffectedRows() == 1)
6500 setPersistentState(NOPE::os_clean
);
6508 bool CPlayerRating::remove(MSW::CConnection
&connection
)
6510 nlassert(getPersistentState() == NOPE::os_dirty
|| getPersistentState() == NOPE::os_clean
);
6513 qs
= "DELETE FROM player_rating ";
6515 qs
+= " WHERE Id = '"+NLMISC::toString(_Id
)+"'";
6518 if (connection
.query(qs
))
6520 if (connection
.getAffectedRows() == 1)
6524 // change the persistant state to 'removed'.
6525 setPersistentState(NOPE::os_removed
);
6527 // need to remove ref from parent class container (if any)
6530 CScenarioPtr
parent(CScenario::loadFromCache(_ScenarioId
, true), __FILE__
, __LINE__
);
6531 if (parent
!= NULL
&& parent
->_PlayerRatings
!= NULL
)
6534 std::vector
< CPlayerRatingPtr
>::iterator it
= std::find(parent
->_PlayerRatings
->begin(), parent
->_PlayerRatings
->end(), this);
6535 if (it
!= parent
->_PlayerRatings
->end())
6537 parent
->_PlayerRatings
->erase(it
);
6544 CCharacterPtr
parent(CCharacter::loadFromCache(_Author
, true), __FILE__
, __LINE__
);
6545 if (parent
!= NULL
&& parent
->_PlayerRatings
!= NULL
)
6548 std::vector
< CPlayerRatingPtr
>::iterator it
= std::find(parent
->_PlayerRatings
->begin(), parent
->_PlayerRatings
->end(), this);
6549 if (it
!= parent
->_PlayerRatings
->end())
6551 parent
->_PlayerRatings
->erase(it
);
6557 // need to remove ref from parent (if any)
6566 bool CPlayerRating::removeById(MSW::CConnection
&connection
, uint32 id
)
6568 CPlayerRating
*object
= loadFromCache(id
, true);
6571 return object
->remove(connection
);
6573 // not in cache, run a SQL query
6575 qs
= "DELETE FROM player_rating ";
6577 qs
+= " WHERE Id = '"+NLMISC::toString(id
)+"'";
6580 if (connection
.query(qs
))
6582 if (connection
.getAffectedRows() == 1)
6584 // ok, the row is removed
6593 // Try to load the specified object from the memory cache, return NULL if the object is not in the cache
6594 CPlayerRating
*CPlayerRating::loadFromCache(uint32 objectId
, bool unrelease
)
6596 // look in the cache
6597 TObjectCache::iterator
it(_ObjectCache
.find(objectId
));
6598 if (it
== _ObjectCache
.end())
6600 // not found, return null
6605 CPlayerRating
*object
= it
->second
;
6607 if (object
->_ObjectState
== NOPE::os_released
)
6611 // we need to remove this object from the released object set.
6612 object
->removeFromReleased();
6613 object
->_ObjectState
= NOPE::os_clean
;
6620 // Receive and execute command from the cache manager.
6621 uint32
CPlayerRating::cacheCmd(NOPE::TCacheCmd cmd
)
6623 if (cmd
== NOPE::cc_update
)
6627 else if (cmd
== NOPE::cc_clear
)
6631 else if (cmd
== NOPE::cc_dump
)
6635 else if (cmd
== NOPE::cc_instance_count
)
6637 return (uint32
)_ObjectCache
.size();
6640 // default return value
6644 void CPlayerRating::dump()
6646 nlinfo(" Cache info for class CPlayerRating :");
6647 nlinfo(" There are %u object instances in cache", _ObjectCache
.size());
6649 // count the number of object in the released object set
6650 uint32 nbReleased
= 0;
6652 TReleasedObject::iterator
first(_ReleasedObject
.begin()), last(_ReleasedObject
.end());
6653 for (; first
!= last
; ++first
)
6655 nbReleased
+= (uint32
)first
->second
.size();
6658 nlinfo(" There are %u object instances in cache not referenced (waiting deletion or re-use))", nbReleased
);
6661 void CPlayerRating::updateCache()
6663 if (_ReleasedObject
.empty())
6666 // 30 s hold in cache
6667 const time_t MAX_CACHE_OLD_TIME
= 30;
6669 time_t now
= NLMISC::CTime::getSecondsSince1970();
6671 // look for object set older than MAX_CACHE_OLD_TIME and delete them
6672 while (!_ReleasedObject
.empty() && _ReleasedObject
.begin()->first
< now
-MAX_CACHE_OLD_TIME
)
6674 TObjectSet
&delSet
= _ReleasedObject
.begin()->second
;
6675 // unload this objects
6676 while (!delSet
.empty())
6678 CPlayerRating
*object
= *delSet
.begin();
6682 _ReleasedObject
.erase(_ReleasedObject
.begin());
6686 void CPlayerRating::clearCache()
6688 // remove any unreferenced object from the cache
6689 while (!_ReleasedObject
.empty())
6691 TObjectSet
&delSet
= _ReleasedObject
.begin()->second
;
6692 // unload this objects
6693 while (!delSet
.empty())
6695 CPlayerRating
*object
= *delSet
.begin();
6699 _ReleasedObject
.erase(_ReleasedObject
.begin());
6703 void CPlayerRating::registerUpdatable()
6705 static bool registered
= false;
6708 NOPE::CPersistentCache::getInstance().registerCache(&CPlayerRating::cacheCmd
);
6714 // set the pointer on the first pointer of the pointer list (set to null when there is no more pointer)
6715 void CPlayerRating::setFirstPtr(CPlayerRatingPtr
*ptr
)
6721 // this is the last pointer !
6722 if (_ObjectState
== NOPE::os_transient
6723 || _ObjectState
== NOPE::os_removed
)
6725 // not a persistent object, or removed object, just delet it
6728 else if (_ObjectState
!= NOPE::os_removed
)
6730 setPersistentState(NOPE::os_released
);
6735 // Set the persistent state of the object and do some house keeping
6736 void CPlayerRating::setPersistentState(NOPE::TObjectState state
)
6738 nlassert(NOPE::AllowedTransition
[_ObjectState
][state
] == true);
6740 if(_ObjectState
== NOPE::os_released
&& state
== NOPE::os_removed
)
6742 // a release object gets removed (e.g. by remove by id)
6744 // delete the object
6751 if (_ObjectState
== NOPE::os_transient
&& state
!= NOPE::os_transient
)
6753 nldebug("NOPE: inserting CPlayerRating @%p in cache with id %u", this, static_cast<uint32
>(_Id
));
6754 nlverify(_ObjectCache
.insert(std::make_pair(_Id
, this)).second
);
6757 if (_ObjectState
!= NOPE::os_transient
)
6758 nlassert(_ObjectCache
.find(_Id
) != _ObjectCache
.end());
6760 _ObjectState
= state
;
6762 if (state
== NOPE::os_released
)
6764 _ReleaseDate
= NLMISC::CTime::getSecondsSince1970();
6765 nlverify(_ReleasedObject
[_ReleaseDate
].insert(this).second
);
6767 else if (state
== NOPE::os_removed
)
6769 nldebug("NOPE: erasing CPlayerRating @%p in cache with id %u", this, static_cast<uint32
>(_Id
));
6770 nlverify(_ObjectCache
.erase(_Id
) == 1);
6775 CPlayerRatingPtr
CPlayerRating::load(MSW::CConnection
&connection
, uint32 id
, const char *filename
, uint32 lineNum
)
6777 CPlayerRating
*inCache
= loadFromCache(id
, true);
6778 if (inCache
!= NULL
)
6780 return CPlayerRatingPtr(inCache
, filename
, lineNum
);
6786 qs
+= "Id, scenario_id, author, rate_fun, rate_difficulty, rate_accessibility, rate_originality, rate_direction";
6788 qs
+= " FROM player_rating";
6790 qs
+= " WHERE Id = '"+NLMISC::toString(id
)+"'";
6791 CPlayerRatingPtr ret
;
6792 if (!connection
.query(qs
))
6797 MSW::CStoreResult
*result
= connection
.storeResult().release();
6799 nlassert(result
->getNumRows() <= 1);
6800 if (result
->getNumRows() == 1)
6802 ret
.assign(new CPlayerRating
, filename
, lineNum
);
6803 // ok, we have an object
6806 result
->getField(0, ret
->_Id
);
6807 result
->getField(1, ret
->_ScenarioId
);
6808 result
->getField(2, ret
->_Author
);
6809 result
->getField(3, ret
->_RateFun
);
6810 result
->getField(4, ret
->_RateDifficulty
);
6811 result
->getField(5, ret
->_RateAccessibility
);
6812 result
->getField(6, ret
->_RateOriginality
);
6813 result
->getField(7, ret
->_RateDirection
);
6816 ret
->setPersistentState(NOPE::os_clean
);
6825 bool CPlayerRating::loadChildrenOfCScenario(MSW::CConnection
&connection
, uint32 parentId
, std::vector
< CPlayerRatingPtr
> & container
, const char *filename
, uint32 lineNum
)
6831 qs
+= "Id, scenario_id, author, rate_fun, rate_difficulty, rate_accessibility, rate_originality, rate_direction";
6833 qs
+= " FROM player_rating";
6834 qs
+= " WHERE scenario_id = '"+NLMISC::toString(parentId
)+"'";
6836 if (!connection
.query(qs
))
6841 CUniquePtr
<MSW::CStoreResult
> result
= connection
.storeResult();
6843 for (uint i
=0; i
<result
->getNumRows(); ++i
)
6845 CPlayerRating
*ret
= new CPlayerRating();
6846 // ok, we have an object
6849 result
->getField(0, ret
->_Id
);
6851 result
->getField(1, ret
->_ScenarioId
);
6853 result
->getField(2, ret
->_Author
);
6855 result
->getField(3, ret
->_RateFun
);
6857 result
->getField(4, ret
->_RateDifficulty
);
6859 result
->getField(5, ret
->_RateAccessibility
);
6861 result
->getField(6, ret
->_RateOriginality
);
6863 result
->getField(7, ret
->_RateDirection
);
6864 CPlayerRating
*inCache
= loadFromCache(ret
->_Id
, true);
6865 if (inCache
!= NULL
)
6868 container
.push_back(CPlayerRatingPtr(inCache
, filename
, lineNum
));
6875 ret
->setPersistentState(NOPE::os_clean
);
6877 container
.push_back(CPlayerRatingPtr(ret
, filename
, lineNum
));
6885 bool CPlayerRating::loadChildrenOfCCharacter(MSW::CConnection
&connection
, uint32 parentId
, std::vector
< CPlayerRatingPtr
> & container
, const char *filename
, uint32 lineNum
)
6891 qs
+= "Id, scenario_id, author, rate_fun, rate_difficulty, rate_accessibility, rate_originality, rate_direction";
6893 qs
+= " FROM player_rating";
6894 qs
+= " WHERE author = '"+NLMISC::toString(parentId
)+"'";
6896 if (!connection
.query(qs
))
6901 CUniquePtr
<MSW::CStoreResult
> result
= connection
.storeResult();
6903 for (uint i
=0; i
<result
->getNumRows(); ++i
)
6905 CPlayerRating
*ret
= new CPlayerRating();
6906 // ok, we have an object
6909 result
->getField(0, ret
->_Id
);
6911 result
->getField(1, ret
->_ScenarioId
);
6913 result
->getField(2, ret
->_Author
);
6915 result
->getField(3, ret
->_RateFun
);
6917 result
->getField(4, ret
->_RateDifficulty
);
6919 result
->getField(5, ret
->_RateAccessibility
);
6921 result
->getField(6, ret
->_RateOriginality
);
6923 result
->getField(7, ret
->_RateDirection
);
6924 CPlayerRating
*inCache
= loadFromCache(ret
->_Id
, true);
6925 if (inCache
!= NULL
)
6928 container
.push_back(CPlayerRatingPtr(inCache
, filename
, lineNum
));
6935 ret
->setPersistentState(NOPE::os_clean
);
6937 container
.push_back(CPlayerRatingPtr(ret
, filename
, lineNum
));
6945 void CJournalEntryPtr::linkPtr()
6947 nlassert(_NextPtr
== NULL
);
6948 nlassert(_PrevPtr
== NULL
);
6951 _NextPtr
= _Ptr
->getFirstPtr();
6952 if (_NextPtr
!= NULL
)
6954 _PrevPtr
= _NextPtr
->_PrevPtr
;
6955 _PrevPtr
->_NextPtr
= this;
6956 _NextPtr
->_PrevPtr
= this;
6962 _Ptr
->setFirstPtr(this);
6967 void CJournalEntryPtr::unlinkPtr()
6969 if (_NextPtr
== NULL
)
6971 nlassert(_PrevPtr
== NULL
);
6977 if (_NextPtr
== this)
6979 nlassert(_PrevPtr
== this);
6981 _Ptr
->setFirstPtr(NULL
);
6985 if (_Ptr
->getFirstPtr() == this)
6987 // the first ptr is the current one, we need to switch to next one
6988 _Ptr
->setFirstPtr(_NextPtr
);
6993 if (_NextPtr
!= this)
6995 nlassert(_PrevPtr
!= this);
6997 _NextPtr
->_PrevPtr
= _PrevPtr
;
6998 _PrevPtr
->_NextPtr
= _NextPtr
;
7005 CJournalEntry::TObjectCache
CJournalEntry::_ObjectCache
;
7006 CJournalEntry::TReleasedObject
CJournalEntry::_ReleasedObject
;
7009 // Destructor, delete any children
7010 CJournalEntry::~CJournalEntry()
7012 // release childs reference
7015 if (_PtrList
!= NULL
)
7017 nlwarning("ERROR : someone try to delete this object, but there are still ptr on it !");
7018 CJournalEntryPtr
*ptr
= _PtrList
;
7021 nlwarning(" Pointer created from '%s', line %u", ptr
->_FileName
, ptr
->_LineNum
);
7022 ptr
= _PtrList
->getNextPtr();
7023 } while(ptr
!= _PtrList
);
7026 // remove object from cache map
7027 if (_Id
!= NOPE::INVALID_OBJECT_ID
7028 && _ObjectState
!= NOPE::os_removed
7029 && _ObjectState
!= NOPE::os_transient
)
7031 nldebug("NOPE: clearing CJournalEntry @%p from cache with id %u", this, static_cast<uint32
>(_Id
));
7032 nlverify(_ObjectCache
.erase(_Id
) == 1);
7034 else if (_ObjectState
!= NOPE::os_transient
)
7036 nlassert(_ObjectCache
.find(_Id
) == _ObjectCache
.end());
7038 if (_ObjectState
== NOPE::os_released
)
7040 removeFromReleased();
7044 TReleasedObject::iterator
it(_ReleasedObject
.find(_ReleaseDate
));
7045 if (it
!= _ReleasedObject
.end())
7047 nlassert(it
->second
.find(this) == it
->second
.end());
7052 void CJournalEntry::removeFromReleased()
7054 TReleasedObject::iterator
it(_ReleasedObject
.find(_ReleaseDate
));
7055 nlassert(it
!= _ReleasedObject
.end());
7056 TObjectSet
&os
= it
->second
;
7058 nlverify(os
.erase(this) == 1);
7060 // nb : _ReleasedObject time entry are removed by the cache update
7063 bool CJournalEntry::create(MSW::CConnection
&connection
)
7065 nlassert(getPersistentState() == NOPE::os_transient
);
7068 qs
= "INSERT INTO journal_entry (";
7070 qs
+= "session_id, author, type, text, time_stamp";
7073 qs
+= "'"+MSW::escapeString(NLMISC::toString(_SessionId
), connection
)+"'";
7075 qs
+= "'"+MSW::escapeString(NLMISC::toString(_Author
), connection
)+"'";
7077 qs
+= _Type
.isValid()
7078 ? "'"+_Type
.toString()+"'"
7081 qs
+= "'"+MSW::escapeString(NLMISC::toString(_Text
), connection
)+"'";
7083 qs
+= "'"+MSW::encodeDate(_TimeStamp
)+"'";
7087 if (connection
.query(qs
))
7089 uint32 _id_
= connection
.getLastGeneratedId();
7093 setPersistentState(NOPE::os_clean
);
7095 // update the parent class instance in cache if any
7097 if (_SessionId
!= 0)
7099 // need to update the parent class child list if it is in the cache
7100 CSession
*parent
= CSession::loadFromCache(_SessionId
, false);
7101 if (parent
&& parent
->_JournalEntries
!= NULL
)
7104 nlassert(std::find(parent
->_JournalEntries
->begin(), parent
->_JournalEntries
->end(), CJournalEntryPtr(this, __FILE__
, __LINE__
)) == parent
->_JournalEntries
->end());
7105 parent
->_JournalEntries
->push_back(CJournalEntryPtr(this, __FILE__
, __LINE__
));
7116 bool CJournalEntry::update(MSW::CConnection
&connection
)
7118 nlassert(getPersistentState() == NOPE::os_dirty
|| getPersistentState() == NOPE::os_clean
);
7120 if (getPersistentState() == NOPE::os_clean
)
7121 // the object is clean, just ignore the save
7125 qs
= "UPDATE journal_entry SET ";
7127 qs
+= "session_id = '"+MSW::escapeString(NLMISC::toString(_SessionId
), connection
)+"'";
7129 qs
+= "author = '"+MSW::escapeString(NLMISC::toString(_Author
), connection
)+"'";
7131 qs
+= "type = " + (_Type
.isValid()
7132 ? "'"+_Type
.toString()+"'"
7135 qs
+= "text = '"+MSW::escapeString(NLMISC::toString(_Text
), connection
)+"'";
7137 qs
+= "time_stamp = '"+MSW::encodeDate(_TimeStamp
)+"'";
7139 qs
+= " WHERE Id = '"+NLMISC::toString(_Id
)+"'";
7142 if (connection
.query(qs
))
7144 if (connection
.getAffectedRows() == 1)
7146 setPersistentState(NOPE::os_clean
);
7154 bool CJournalEntry::remove(MSW::CConnection
&connection
)
7156 nlassert(getPersistentState() == NOPE::os_dirty
|| getPersistentState() == NOPE::os_clean
);
7159 qs
= "DELETE FROM journal_entry ";
7161 qs
+= " WHERE Id = '"+NLMISC::toString(_Id
)+"'";
7164 if (connection
.query(qs
))
7166 if (connection
.getAffectedRows() == 1)
7170 // change the persistant state to 'removed'.
7171 setPersistentState(NOPE::os_removed
);
7173 // need to remove ref from parent class container (if any)
7176 CSessionPtr
parent(CSession::loadFromCache(_SessionId
, true), __FILE__
, __LINE__
);
7177 if (parent
!= NULL
&& parent
->_JournalEntries
!= NULL
)
7180 std::vector
< CJournalEntryPtr
>::iterator it
= std::find(parent
->_JournalEntries
->begin(), parent
->_JournalEntries
->end(), this);
7181 if (it
!= parent
->_JournalEntries
->end())
7183 parent
->_JournalEntries
->erase(it
);
7189 // need to remove ref from parent (if any)
7198 bool CJournalEntry::removeById(MSW::CConnection
&connection
, uint32 id
)
7200 CJournalEntry
*object
= loadFromCache(id
, true);
7203 return object
->remove(connection
);
7205 // not in cache, run a SQL query
7207 qs
= "DELETE FROM journal_entry ";
7209 qs
+= " WHERE Id = '"+NLMISC::toString(id
)+"'";
7212 if (connection
.query(qs
))
7214 if (connection
.getAffectedRows() == 1)
7216 // ok, the row is removed
7225 // Try to load the specified object from the memory cache, return NULL if the object is not in the cache
7226 CJournalEntry
*CJournalEntry::loadFromCache(uint32 objectId
, bool unrelease
)
7228 // look in the cache
7229 TObjectCache::iterator
it(_ObjectCache
.find(objectId
));
7230 if (it
== _ObjectCache
.end())
7232 // not found, return null
7237 CJournalEntry
*object
= it
->second
;
7239 if (object
->_ObjectState
== NOPE::os_released
)
7243 // we need to remove this object from the released object set.
7244 object
->removeFromReleased();
7245 object
->_ObjectState
= NOPE::os_clean
;
7252 // Receive and execute command from the cache manager.
7253 uint32
CJournalEntry::cacheCmd(NOPE::TCacheCmd cmd
)
7255 if (cmd
== NOPE::cc_update
)
7259 else if (cmd
== NOPE::cc_clear
)
7263 else if (cmd
== NOPE::cc_dump
)
7267 else if (cmd
== NOPE::cc_instance_count
)
7269 return (uint32
)_ObjectCache
.size();
7272 // default return value
7276 void CJournalEntry::dump()
7278 nlinfo(" Cache info for class CJournalEntry :");
7279 nlinfo(" There are %u object instances in cache", _ObjectCache
.size());
7281 // count the number of object in the released object set
7282 uint32 nbReleased
= 0;
7284 TReleasedObject::iterator
first(_ReleasedObject
.begin()), last(_ReleasedObject
.end());
7285 for (; first
!= last
; ++first
)
7287 nbReleased
+= (uint32
)first
->second
.size();
7290 nlinfo(" There are %u object instances in cache not referenced (waiting deletion or re-use))", nbReleased
);
7293 void CJournalEntry::updateCache()
7295 if (_ReleasedObject
.empty())
7298 // 30 s hold in cache
7299 const time_t MAX_CACHE_OLD_TIME
= 30;
7301 time_t now
= NLMISC::CTime::getSecondsSince1970();
7303 // look for object set older than MAX_CACHE_OLD_TIME and delete them
7304 while (!_ReleasedObject
.empty() && _ReleasedObject
.begin()->first
< now
-MAX_CACHE_OLD_TIME
)
7306 TObjectSet
&delSet
= _ReleasedObject
.begin()->second
;
7307 // unload this objects
7308 while (!delSet
.empty())
7310 CJournalEntry
*object
= *delSet
.begin();
7314 _ReleasedObject
.erase(_ReleasedObject
.begin());
7318 void CJournalEntry::clearCache()
7320 // remove any unreferenced object from the cache
7321 while (!_ReleasedObject
.empty())
7323 TObjectSet
&delSet
= _ReleasedObject
.begin()->second
;
7324 // unload this objects
7325 while (!delSet
.empty())
7327 CJournalEntry
*object
= *delSet
.begin();
7331 _ReleasedObject
.erase(_ReleasedObject
.begin());
7335 void CJournalEntry::registerUpdatable()
7337 static bool registered
= false;
7340 NOPE::CPersistentCache::getInstance().registerCache(&CJournalEntry::cacheCmd
);
7346 // set the pointer on the first pointer of the pointer list (set to null when there is no more pointer)
7347 void CJournalEntry::setFirstPtr(CJournalEntryPtr
*ptr
)
7353 // this is the last pointer !
7354 if (_ObjectState
== NOPE::os_transient
7355 || _ObjectState
== NOPE::os_removed
)
7357 // not a persistent object, or removed object, just delet it
7360 else if (_ObjectState
!= NOPE::os_removed
)
7362 setPersistentState(NOPE::os_released
);
7367 // Set the persistent state of the object and do some house keeping
7368 void CJournalEntry::setPersistentState(NOPE::TObjectState state
)
7370 nlassert(NOPE::AllowedTransition
[_ObjectState
][state
] == true);
7372 if(_ObjectState
== NOPE::os_released
&& state
== NOPE::os_removed
)
7374 // a release object gets removed (e.g. by remove by id)
7376 // delete the object
7383 if (_ObjectState
== NOPE::os_transient
&& state
!= NOPE::os_transient
)
7385 nldebug("NOPE: inserting CJournalEntry @%p in cache with id %u", this, static_cast<uint32
>(_Id
));
7386 nlverify(_ObjectCache
.insert(std::make_pair(_Id
, this)).second
);
7389 if (_ObjectState
!= NOPE::os_transient
)
7390 nlassert(_ObjectCache
.find(_Id
) != _ObjectCache
.end());
7392 _ObjectState
= state
;
7394 if (state
== NOPE::os_released
)
7396 _ReleaseDate
= NLMISC::CTime::getSecondsSince1970();
7397 nlverify(_ReleasedObject
[_ReleaseDate
].insert(this).second
);
7399 else if (state
== NOPE::os_removed
)
7401 nldebug("NOPE: erasing CJournalEntry @%p in cache with id %u", this, static_cast<uint32
>(_Id
));
7402 nlverify(_ObjectCache
.erase(_Id
) == 1);
7407 CJournalEntryPtr
CJournalEntry::load(MSW::CConnection
&connection
, uint32 id
, const char *filename
, uint32 lineNum
)
7409 CJournalEntry
*inCache
= loadFromCache(id
, true);
7410 if (inCache
!= NULL
)
7412 return CJournalEntryPtr(inCache
, filename
, lineNum
);
7418 qs
+= "Id, session_id, author, type, text, time_stamp";
7420 qs
+= " FROM journal_entry";
7422 qs
+= " WHERE Id = '"+NLMISC::toString(id
)+"'";
7423 CJournalEntryPtr ret
;
7424 if (!connection
.query(qs
))
7429 MSW::CStoreResult
*result
= connection
.storeResult().release();
7431 nlassert(result
->getNumRows() <= 1);
7432 if (result
->getNumRows() == 1)
7434 ret
.assign(new CJournalEntry
, filename
, lineNum
);
7435 // ok, we have an object
7438 result
->getField(0, ret
->_Id
);
7439 result
->getField(1, ret
->_SessionId
);
7440 result
->getField(2, ret
->_Author
);
7443 result
->getField(3, s
);
7444 ret
->_Type
= TJournalEntryType(s
);
7446 result
->getField(4, ret
->_Text
);
7447 result
->getDateField(5, ret
->_TimeStamp
);
7450 ret
->setPersistentState(NOPE::os_clean
);
7459 bool CJournalEntry::loadChildrenOfCSession(MSW::CConnection
&connection
, uint32 parentId
, std::vector
< CJournalEntryPtr
> & container
, const char *filename
, uint32 lineNum
)
7465 qs
+= "Id, session_id, author, type, text, time_stamp";
7467 qs
+= " FROM journal_entry";
7468 qs
+= " WHERE session_id = '"+NLMISC::toString(parentId
)+"'";
7470 if (!connection
.query(qs
))
7475 CUniquePtr
<MSW::CStoreResult
> result
= connection
.storeResult();
7477 for (uint i
=0; i
<result
->getNumRows(); ++i
)
7479 CJournalEntry
*ret
= new CJournalEntry();
7480 // ok, we have an object
7483 result
->getField(0, ret
->_Id
);
7485 result
->getField(1, ret
->_SessionId
);
7487 result
->getField(2, ret
->_Author
);
7491 result
->getField(3, s
);
7492 ret
->_Type
= TJournalEntryType(s
);
7495 result
->getField(4, ret
->_Text
);
7497 result
->getDateField(5, ret
->_TimeStamp
);
7498 CJournalEntry
*inCache
= loadFromCache(ret
->_Id
, true);
7499 if (inCache
!= NULL
)
7502 container
.push_back(CJournalEntryPtr(inCache
, filename
, lineNum
));
7509 ret
->setPersistentState(NOPE::os_clean
);
7511 container
.push_back(CJournalEntryPtr(ret
, filename
, lineNum
));
7519 void CFolderPtr::linkPtr()
7521 nlassert(_NextPtr
== NULL
);
7522 nlassert(_PrevPtr
== NULL
);
7525 _NextPtr
= _Ptr
->getFirstPtr();
7526 if (_NextPtr
!= NULL
)
7528 _PrevPtr
= _NextPtr
->_PrevPtr
;
7529 _PrevPtr
->_NextPtr
= this;
7530 _NextPtr
->_PrevPtr
= this;
7536 _Ptr
->setFirstPtr(this);
7541 void CFolderPtr::unlinkPtr()
7543 if (_NextPtr
== NULL
)
7545 nlassert(_PrevPtr
== NULL
);
7551 if (_NextPtr
== this)
7553 nlassert(_PrevPtr
== this);
7555 _Ptr
->setFirstPtr(NULL
);
7559 if (_Ptr
->getFirstPtr() == this)
7561 // the first ptr is the current one, we need to switch to next one
7562 _Ptr
->setFirstPtr(_NextPtr
);
7567 if (_NextPtr
!= this)
7569 nlassert(_PrevPtr
!= this);
7571 _NextPtr
->_PrevPtr
= _PrevPtr
;
7572 _PrevPtr
->_NextPtr
= _NextPtr
;
7579 CFolder::TObjectCache
CFolder::_ObjectCache
;
7580 CFolder::TReleasedObject
CFolder::_ReleasedObject
;
7583 // Destructor, delete any children
7586 // release childs reference
7587 if (_FolderAccess
!= NULL
)
7588 delete _FolderAccess
;
7589 if (_Sessions
!= NULL
)
7593 if (_PtrList
!= NULL
)
7595 nlwarning("ERROR : someone try to delete this object, but there are still ptr on it !");
7596 CFolderPtr
*ptr
= _PtrList
;
7599 nlwarning(" Pointer created from '%s', line %u", ptr
->_FileName
, ptr
->_LineNum
);
7600 ptr
= _PtrList
->getNextPtr();
7601 } while(ptr
!= _PtrList
);
7604 // remove object from cache map
7605 if (_Id
!= NOPE::INVALID_OBJECT_ID
7606 && _ObjectState
!= NOPE::os_removed
7607 && _ObjectState
!= NOPE::os_transient
)
7609 nldebug("NOPE: clearing CFolder @%p from cache with id %u", this, static_cast<uint32
>(_Id
));
7610 nlverify(_ObjectCache
.erase(_Id
) == 1);
7612 else if (_ObjectState
!= NOPE::os_transient
)
7614 nlassert(_ObjectCache
.find(_Id
) == _ObjectCache
.end());
7616 if (_ObjectState
== NOPE::os_released
)
7618 removeFromReleased();
7622 TReleasedObject::iterator
it(_ReleasedObject
.find(_ReleaseDate
));
7623 if (it
!= _ReleasedObject
.end())
7625 nlassert(it
->second
.find(this) == it
->second
.end());
7630 void CFolder::removeFromReleased()
7632 TReleasedObject::iterator
it(_ReleasedObject
.find(_ReleaseDate
));
7633 nlassert(it
!= _ReleasedObject
.end());
7634 TObjectSet
&os
= it
->second
;
7636 nlverify(os
.erase(this) == 1);
7638 // nb : _ReleasedObject time entry are removed by the cache update
7641 bool CFolder::create(MSW::CConnection
&connection
)
7643 nlassert(getPersistentState() == NOPE::os_transient
);
7646 qs
= "INSERT INTO folder (";
7648 qs
+= "author, title, comments";
7651 qs
+= "'"+MSW::escapeString(NLMISC::toString(_Author
), connection
)+"'";
7653 qs
+= "'"+MSW::escapeString(NLMISC::toString(_Title
), connection
)+"'";
7655 qs
+= "'"+MSW::escapeString(NLMISC::toString(_Comments
), connection
)+"'";
7659 if (connection
.query(qs
))
7661 uint32 _id_
= connection
.getLastGeneratedId();
7665 setPersistentState(NOPE::os_clean
);
7667 // update the parent class instance in cache if any
7671 // need to update the parent class child list if it is in the cache
7672 CRingUser
*parent
= CRingUser::loadFromCache(_Author
, false);
7673 if (parent
&& parent
->_Folders
!= NULL
)
7676 nlassert(std::find(parent
->_Folders
->begin(), parent
->_Folders
->end(), CFolderPtr(this, __FILE__
, __LINE__
)) == parent
->_Folders
->end());
7677 parent
->_Folders
->push_back(CFolderPtr(this, __FILE__
, __LINE__
));
7688 bool CFolder::update(MSW::CConnection
&connection
)
7690 nlassert(getPersistentState() == NOPE::os_dirty
|| getPersistentState() == NOPE::os_clean
);
7692 if (getPersistentState() == NOPE::os_clean
)
7693 // the object is clean, just ignore the save
7697 qs
= "UPDATE folder SET ";
7699 qs
+= "author = '"+MSW::escapeString(NLMISC::toString(_Author
), connection
)+"'";
7701 qs
+= "title = '"+MSW::escapeString(NLMISC::toString(_Title
), connection
)+"'";
7703 qs
+= "comments = '"+MSW::escapeString(NLMISC::toString(_Comments
), connection
)+"'";
7705 qs
+= " WHERE Id = '"+NLMISC::toString(_Id
)+"'";
7708 if (connection
.query(qs
))
7710 if (connection
.getAffectedRows() == 1)
7712 setPersistentState(NOPE::os_clean
);
7720 bool CFolder::remove(MSW::CConnection
&connection
)
7722 nlassert(getPersistentState() == NOPE::os_dirty
|| getPersistentState() == NOPE::os_clean
);
7725 qs
= "DELETE FROM folder ";
7727 qs
+= " WHERE Id = '"+NLMISC::toString(_Id
)+"'";
7730 if (connection
.query(qs
))
7732 if (connection
.getAffectedRows() == 1)
7736 // cascading deletion for vector child FolderAccess
7737 if (loadFolderAccess(connection
, __FILE__
, __LINE__
))
7739 const std::vector
< CFolderAccessPtr
> & childs
= getFolderAccess();
7741 while (!childs
.empty())
7743 getFolderAccessByIndex((uint32
)childs
.size()-1)->remove(connection
);
7750 // unreference (and update) for vector child Sessions
7751 if (loadSessions(connection
, __FILE__
, __LINE__
))
7753 const std::vector
< CSessionPtr
> & childs
= getSessions();
7755 for (uint i
=0; i
< childs
.size(); ++i
)
7758 getSessionsByIndex(i
)->setFolderId(0);
7759 getSessionsByIndex(i
)->update(connection
);
7765 // change the persistant state to 'removed'.
7766 setPersistentState(NOPE::os_removed
);
7768 // need to remove ref from parent class container (if any)
7771 CRingUserPtr
parent(CRingUser::loadFromCache(_Author
, true), __FILE__
, __LINE__
);
7772 if (parent
!= NULL
&& parent
->_Folders
!= NULL
)
7775 std::vector
< CFolderPtr
>::iterator it
= std::find(parent
->_Folders
->begin(), parent
->_Folders
->end(), this);
7776 if (it
!= parent
->_Folders
->end())
7778 parent
->_Folders
->erase(it
);
7784 // need to remove ref from parent (if any)
7793 bool CFolder::removeById(MSW::CConnection
&connection
, uint32 id
)
7795 CFolder
*object
= loadFromCache(id
, true);
7798 return object
->remove(connection
);
7800 // not in cache, run a SQL query
7802 qs
= "DELETE FROM folder ";
7804 qs
+= " WHERE Id = '"+NLMISC::toString(id
)+"'";
7807 if (connection
.query(qs
))
7809 if (connection
.getAffectedRows() == 1)
7811 // ok, the row is removed
7820 // Try to load the specified object from the memory cache, return NULL if the object is not in the cache
7821 CFolder
*CFolder::loadFromCache(uint32 objectId
, bool unrelease
)
7823 // look in the cache
7824 TObjectCache::iterator
it(_ObjectCache
.find(objectId
));
7825 if (it
== _ObjectCache
.end())
7827 // not found, return null
7832 CFolder
*object
= it
->second
;
7834 if (object
->_ObjectState
== NOPE::os_released
)
7838 // we need to remove this object from the released object set.
7839 object
->removeFromReleased();
7840 object
->_ObjectState
= NOPE::os_clean
;
7847 // Receive and execute command from the cache manager.
7848 uint32
CFolder::cacheCmd(NOPE::TCacheCmd cmd
)
7850 if (cmd
== NOPE::cc_update
)
7854 else if (cmd
== NOPE::cc_clear
)
7858 else if (cmd
== NOPE::cc_dump
)
7862 else if (cmd
== NOPE::cc_instance_count
)
7864 return (uint32
)_ObjectCache
.size();
7867 // default return value
7871 void CFolder::dump()
7873 nlinfo(" Cache info for class CFolder :");
7874 nlinfo(" There are %u object instances in cache", _ObjectCache
.size());
7876 // count the number of object in the released object set
7877 uint32 nbReleased
= 0;
7879 TReleasedObject::iterator
first(_ReleasedObject
.begin()), last(_ReleasedObject
.end());
7880 for (; first
!= last
; ++first
)
7882 nbReleased
+= (uint32
)first
->second
.size();
7885 nlinfo(" There are %u object instances in cache not referenced (waiting deletion or re-use))", nbReleased
);
7888 void CFolder::updateCache()
7890 if (_ReleasedObject
.empty())
7893 // 30 s hold in cache
7894 const time_t MAX_CACHE_OLD_TIME
= 30;
7896 time_t now
= NLMISC::CTime::getSecondsSince1970();
7898 // look for object set older than MAX_CACHE_OLD_TIME and delete them
7899 while (!_ReleasedObject
.empty() && _ReleasedObject
.begin()->first
< now
-MAX_CACHE_OLD_TIME
)
7901 TObjectSet
&delSet
= _ReleasedObject
.begin()->second
;
7902 // unload this objects
7903 while (!delSet
.empty())
7905 CFolder
*object
= *delSet
.begin();
7909 _ReleasedObject
.erase(_ReleasedObject
.begin());
7913 void CFolder::clearCache()
7915 // remove any unreferenced object from the cache
7916 while (!_ReleasedObject
.empty())
7918 TObjectSet
&delSet
= _ReleasedObject
.begin()->second
;
7919 // unload this objects
7920 while (!delSet
.empty())
7922 CFolder
*object
= *delSet
.begin();
7926 _ReleasedObject
.erase(_ReleasedObject
.begin());
7930 void CFolder::registerUpdatable()
7932 static bool registered
= false;
7935 NOPE::CPersistentCache::getInstance().registerCache(&CFolder::cacheCmd
);
7941 // set the pointer on the first pointer of the pointer list (set to null when there is no more pointer)
7942 void CFolder::setFirstPtr(CFolderPtr
*ptr
)
7948 // this is the last pointer !
7949 if (_ObjectState
== NOPE::os_transient
7950 || _ObjectState
== NOPE::os_removed
)
7952 // not a persistent object, or removed object, just delet it
7955 else if (_ObjectState
!= NOPE::os_removed
)
7957 setPersistentState(NOPE::os_released
);
7962 // Set the persistent state of the object and do some house keeping
7963 void CFolder::setPersistentState(NOPE::TObjectState state
)
7965 nlassert(NOPE::AllowedTransition
[_ObjectState
][state
] == true);
7967 if(_ObjectState
== NOPE::os_released
&& state
== NOPE::os_removed
)
7969 // a release object gets removed (e.g. by remove by id)
7971 // delete the object
7978 if (_ObjectState
== NOPE::os_transient
&& state
!= NOPE::os_transient
)
7980 nldebug("NOPE: inserting CFolder @%p in cache with id %u", this, static_cast<uint32
>(_Id
));
7981 nlverify(_ObjectCache
.insert(std::make_pair(_Id
, this)).second
);
7984 if (_ObjectState
!= NOPE::os_transient
)
7985 nlassert(_ObjectCache
.find(_Id
) != _ObjectCache
.end());
7987 _ObjectState
= state
;
7989 if (state
== NOPE::os_released
)
7991 _ReleaseDate
= NLMISC::CTime::getSecondsSince1970();
7992 nlverify(_ReleasedObject
[_ReleaseDate
].insert(this).second
);
7994 else if (state
== NOPE::os_removed
)
7996 nldebug("NOPE: erasing CFolder @%p in cache with id %u", this, static_cast<uint32
>(_Id
));
7997 nlverify(_ObjectCache
.erase(_Id
) == 1);
8002 CFolderPtr
CFolder::load(MSW::CConnection
&connection
, uint32 id
, const char *filename
, uint32 lineNum
)
8004 CFolder
*inCache
= loadFromCache(id
, true);
8005 if (inCache
!= NULL
)
8007 return CFolderPtr(inCache
, filename
, lineNum
);
8013 qs
+= "Id, author, title, comments";
8015 qs
+= " FROM folder";
8017 qs
+= " WHERE Id = '"+NLMISC::toString(id
)+"'";
8019 if (!connection
.query(qs
))
8024 MSW::CStoreResult
*result
= connection
.storeResult().release();
8026 nlassert(result
->getNumRows() <= 1);
8027 if (result
->getNumRows() == 1)
8029 ret
.assign(new CFolder
, filename
, lineNum
);
8030 // ok, we have an object
8033 result
->getField(0, ret
->_Id
);
8034 result
->getField(1, ret
->_Author
);
8035 result
->getField(2, ret
->_Title
);
8036 result
->getField(3, ret
->_Comments
);
8039 ret
->setPersistentState(NOPE::os_clean
);
8048 bool CFolder::loadChildrenOfCRingUser(MSW::CConnection
&connection
, uint32 parentId
, std::vector
< CFolderPtr
> & container
, const char *filename
, uint32 lineNum
)
8054 qs
+= "Id, author, title, comments";
8056 qs
+= " FROM folder";
8057 qs
+= " WHERE author = '"+NLMISC::toString(parentId
)+"'";
8059 if (!connection
.query(qs
))
8064 CUniquePtr
<MSW::CStoreResult
> result
= connection
.storeResult();
8066 for (uint i
=0; i
<result
->getNumRows(); ++i
)
8068 CFolder
*ret
= new CFolder();
8069 // ok, we have an object
8072 result
->getField(0, ret
->_Id
);
8074 result
->getField(1, ret
->_Author
);
8076 result
->getField(2, ret
->_Title
);
8078 result
->getField(3, ret
->_Comments
);
8079 CFolder
*inCache
= loadFromCache(ret
->_Id
, true);
8080 if (inCache
!= NULL
)
8083 container
.push_back(CFolderPtr(inCache
, filename
, lineNum
));
8090 ret
->setPersistentState(NOPE::os_clean
);
8092 container
.push_back(CFolderPtr(ret
, filename
, lineNum
));
8100 bool CFolder::loadFolderAccess(MSW::CConnection
&connection
, const char *filename
, uint32 lineNum
)
8103 if (_FolderAccess
!= NULL
)
8105 // the children are already loaded, just return true
8109 // allocate the container
8110 _FolderAccess
= new std::vector
< CFolderAccessPtr
>;
8113 ret
&= CFolderAccess::loadChildrenOfCFolder(connection
, getObjectId(), *_FolderAccess
, filename
, lineNum
);
8118 const std::vector
<CFolderAccessPtr
> &CFolder::getFolderAccess() const
8120 nlassert(_FolderAccess
!= NULL
);
8121 return *_FolderAccess
;
8124 CFolderAccessPtr
&CFolder::getFolderAccessByIndex(uint32 index
) const
8126 nlassert(_FolderAccess
!= NULL
);
8127 nlassert(index
< _FolderAccess
->size());
8128 return const_cast< CFolderAccessPtr
& >(_FolderAccess
->operator[](index
));
8131 CFolderAccessPtr
&CFolder::getFolderAccessById(uint32 id
) const
8133 nlassert(_FolderAccess
!= NULL
);
8134 std::vector
<CFolderAccessPtr
>::const_iterator
first(_FolderAccess
->begin()), last(_FolderAccess
->end());
8135 for (; first
!= last
; ++first
)
8137 const CFolderAccessPtr
&child
= *first
;
8138 if (child
->getObjectId() == id
)
8140 return const_cast< CFolderAccessPtr
& >(child
);
8144 // no object with this id, return a null pointer
8145 static CFolderAccessPtr nilPtr
;
8151 bool CFolder::loadSessions(MSW::CConnection
&connection
, const char *filename
, uint32 lineNum
)
8154 if (_Sessions
!= NULL
)
8156 // the children are already loaded, just return true
8160 // allocate the container
8161 _Sessions
= new std::vector
< CSessionPtr
>;
8164 ret
&= CSession::loadChildrenOfCFolder(connection
, getObjectId(), *_Sessions
, filename
, lineNum
);
8169 const std::vector
<CSessionPtr
> &CFolder::getSessions() const
8171 nlassert(_Sessions
!= NULL
);
8175 CSessionPtr
&CFolder::getSessionsByIndex(uint32 index
) const
8177 nlassert(_Sessions
!= NULL
);
8178 nlassert(index
< _Sessions
->size());
8179 return const_cast< CSessionPtr
& >(_Sessions
->operator[](index
));
8182 CSessionPtr
&CFolder::getSessionsById(uint32 id
) const
8184 nlassert(_Sessions
!= NULL
);
8185 std::vector
<CSessionPtr
>::const_iterator
first(_Sessions
->begin()), last(_Sessions
->end());
8186 for (; first
!= last
; ++first
)
8188 const CSessionPtr
&child
= *first
;
8189 if (child
->getObjectId() == id
)
8191 return const_cast< CSessionPtr
& >(child
);
8195 // no object with this id, return a null pointer
8196 static CSessionPtr nilPtr
;
8202 void CFolderAccessPtr::linkPtr()
8204 nlassert(_NextPtr
== NULL
);
8205 nlassert(_PrevPtr
== NULL
);
8208 _NextPtr
= _Ptr
->getFirstPtr();
8209 if (_NextPtr
!= NULL
)
8211 _PrevPtr
= _NextPtr
->_PrevPtr
;
8212 _PrevPtr
->_NextPtr
= this;
8213 _NextPtr
->_PrevPtr
= this;
8219 _Ptr
->setFirstPtr(this);
8224 void CFolderAccessPtr::unlinkPtr()
8226 if (_NextPtr
== NULL
)
8228 nlassert(_PrevPtr
== NULL
);
8234 if (_NextPtr
== this)
8236 nlassert(_PrevPtr
== this);
8238 _Ptr
->setFirstPtr(NULL
);
8242 if (_Ptr
->getFirstPtr() == this)
8244 // the first ptr is the current one, we need to switch to next one
8245 _Ptr
->setFirstPtr(_NextPtr
);
8250 if (_NextPtr
!= this)
8252 nlassert(_PrevPtr
!= this);
8254 _NextPtr
->_PrevPtr
= _PrevPtr
;
8255 _PrevPtr
->_NextPtr
= _NextPtr
;
8262 CFolderAccess::TObjectCache
CFolderAccess::_ObjectCache
;
8263 CFolderAccess::TReleasedObject
CFolderAccess::_ReleasedObject
;
8266 // Destructor, delete any children
8267 CFolderAccess::~CFolderAccess()
8269 // release childs reference
8272 if (_PtrList
!= NULL
)
8274 nlwarning("ERROR : someone try to delete this object, but there are still ptr on it !");
8275 CFolderAccessPtr
*ptr
= _PtrList
;
8278 nlwarning(" Pointer created from '%s', line %u", ptr
->_FileName
, ptr
->_LineNum
);
8279 ptr
= _PtrList
->getNextPtr();
8280 } while(ptr
!= _PtrList
);
8283 // remove object from cache map
8284 if (_Id
!= NOPE::INVALID_OBJECT_ID
8285 && _ObjectState
!= NOPE::os_removed
8286 && _ObjectState
!= NOPE::os_transient
)
8288 nldebug("NOPE: clearing CFolderAccess @%p from cache with id %u", this, static_cast<uint32
>(_Id
));
8289 nlverify(_ObjectCache
.erase(_Id
) == 1);
8291 else if (_ObjectState
!= NOPE::os_transient
)
8293 nlassert(_ObjectCache
.find(_Id
) == _ObjectCache
.end());
8295 if (_ObjectState
== NOPE::os_released
)
8297 removeFromReleased();
8301 TReleasedObject::iterator
it(_ReleasedObject
.find(_ReleaseDate
));
8302 if (it
!= _ReleasedObject
.end())
8304 nlassert(it
->second
.find(this) == it
->second
.end());
8309 void CFolderAccess::removeFromReleased()
8311 TReleasedObject::iterator
it(_ReleasedObject
.find(_ReleaseDate
));
8312 nlassert(it
!= _ReleasedObject
.end());
8313 TObjectSet
&os
= it
->second
;
8315 nlverify(os
.erase(this) == 1);
8317 // nb : _ReleasedObject time entry are removed by the cache update
8320 bool CFolderAccess::create(MSW::CConnection
&connection
)
8322 nlassert(getPersistentState() == NOPE::os_transient
);
8325 qs
= "INSERT INTO folder_access (";
8327 qs
+= "folder_id, user_id";
8330 qs
+= "'"+MSW::escapeString(NLMISC::toString(_FolderId
), connection
)+"'";
8332 qs
+= "'"+MSW::escapeString(NLMISC::toString(_UserId
), connection
)+"'";
8336 if (connection
.query(qs
))
8338 uint32 _id_
= connection
.getLastGeneratedId();
8342 setPersistentState(NOPE::os_clean
);
8344 // update the parent class instance in cache if any
8348 // need to update the parent class child list if it is in the cache
8349 CRingUser
*parent
= CRingUser::loadFromCache(_UserId
, false);
8350 if (parent
&& parent
->_FolderAccess
!= NULL
)
8353 nlassert(std::find(parent
->_FolderAccess
->begin(), parent
->_FolderAccess
->end(), CFolderAccessPtr(this, __FILE__
, __LINE__
)) == parent
->_FolderAccess
->end());
8354 parent
->_FolderAccess
->push_back(CFolderAccessPtr(this, __FILE__
, __LINE__
));
8361 // need to update the parent class child list if it is in the cache
8362 CFolder
*parent
= CFolder::loadFromCache(_FolderId
, false);
8363 if (parent
&& parent
->_FolderAccess
!= NULL
)
8366 nlassert(std::find(parent
->_FolderAccess
->begin(), parent
->_FolderAccess
->end(), CFolderAccessPtr(this, __FILE__
, __LINE__
)) == parent
->_FolderAccess
->end());
8367 parent
->_FolderAccess
->push_back(CFolderAccessPtr(this, __FILE__
, __LINE__
));
8378 bool CFolderAccess::update(MSW::CConnection
&connection
)
8380 nlassert(getPersistentState() == NOPE::os_dirty
|| getPersistentState() == NOPE::os_clean
);
8382 if (getPersistentState() == NOPE::os_clean
)
8383 // the object is clean, just ignore the save
8387 qs
= "UPDATE folder_access SET ";
8389 qs
+= "folder_id = '"+MSW::escapeString(NLMISC::toString(_FolderId
), connection
)+"'";
8391 qs
+= "user_id = '"+MSW::escapeString(NLMISC::toString(_UserId
), connection
)+"'";
8393 qs
+= " WHERE Id = '"+NLMISC::toString(_Id
)+"'";
8396 if (connection
.query(qs
))
8398 if (connection
.getAffectedRows() == 1)
8400 setPersistentState(NOPE::os_clean
);
8408 bool CFolderAccess::remove(MSW::CConnection
&connection
)
8410 nlassert(getPersistentState() == NOPE::os_dirty
|| getPersistentState() == NOPE::os_clean
);
8413 qs
= "DELETE FROM folder_access ";
8415 qs
+= " WHERE Id = '"+NLMISC::toString(_Id
)+"'";
8418 if (connection
.query(qs
))
8420 if (connection
.getAffectedRows() == 1)
8424 // change the persistant state to 'removed'.
8425 setPersistentState(NOPE::os_removed
);
8427 // need to remove ref from parent class container (if any)
8430 CRingUserPtr
parent(CRingUser::loadFromCache(_UserId
, true), __FILE__
, __LINE__
);
8431 if (parent
!= NULL
&& parent
->_FolderAccess
!= NULL
)
8434 std::vector
< CFolderAccessPtr
>::iterator it
= std::find(parent
->_FolderAccess
->begin(), parent
->_FolderAccess
->end(), this);
8435 if (it
!= parent
->_FolderAccess
->end())
8437 parent
->_FolderAccess
->erase(it
);
8444 CFolderPtr
parent(CFolder::loadFromCache(_FolderId
, true), __FILE__
, __LINE__
);
8445 if (parent
!= NULL
&& parent
->_FolderAccess
!= NULL
)
8448 std::vector
< CFolderAccessPtr
>::iterator it
= std::find(parent
->_FolderAccess
->begin(), parent
->_FolderAccess
->end(), this);
8449 if (it
!= parent
->_FolderAccess
->end())
8451 parent
->_FolderAccess
->erase(it
);
8457 // need to remove ref from parent (if any)
8466 bool CFolderAccess::removeById(MSW::CConnection
&connection
, uint32 id
)
8468 CFolderAccess
*object
= loadFromCache(id
, true);
8471 return object
->remove(connection
);
8473 // not in cache, run a SQL query
8475 qs
= "DELETE FROM folder_access ";
8477 qs
+= " WHERE Id = '"+NLMISC::toString(id
)+"'";
8480 if (connection
.query(qs
))
8482 if (connection
.getAffectedRows() == 1)
8484 // ok, the row is removed
8493 // Try to load the specified object from the memory cache, return NULL if the object is not in the cache
8494 CFolderAccess
*CFolderAccess::loadFromCache(uint32 objectId
, bool unrelease
)
8496 // look in the cache
8497 TObjectCache::iterator
it(_ObjectCache
.find(objectId
));
8498 if (it
== _ObjectCache
.end())
8500 // not found, return null
8505 CFolderAccess
*object
= it
->second
;
8507 if (object
->_ObjectState
== NOPE::os_released
)
8511 // we need to remove this object from the released object set.
8512 object
->removeFromReleased();
8513 object
->_ObjectState
= NOPE::os_clean
;
8520 // Receive and execute command from the cache manager.
8521 uint32
CFolderAccess::cacheCmd(NOPE::TCacheCmd cmd
)
8523 if (cmd
== NOPE::cc_update
)
8527 else if (cmd
== NOPE::cc_clear
)
8531 else if (cmd
== NOPE::cc_dump
)
8535 else if (cmd
== NOPE::cc_instance_count
)
8537 return (uint32
)_ObjectCache
.size();
8540 // default return value
8544 void CFolderAccess::dump()
8546 nlinfo(" Cache info for class CFolderAccess :");
8547 nlinfo(" There are %u object instances in cache", _ObjectCache
.size());
8549 // count the number of object in the released object set
8550 uint32 nbReleased
= 0;
8552 TReleasedObject::iterator
first(_ReleasedObject
.begin()), last(_ReleasedObject
.end());
8553 for (; first
!= last
; ++first
)
8555 nbReleased
+= (uint32
)first
->second
.size();
8558 nlinfo(" There are %u object instances in cache not referenced (waiting deletion or re-use))", nbReleased
);
8561 void CFolderAccess::updateCache()
8563 if (_ReleasedObject
.empty())
8566 // 30 s hold in cache
8567 const time_t MAX_CACHE_OLD_TIME
= 30;
8569 time_t now
= NLMISC::CTime::getSecondsSince1970();
8571 // look for object set older than MAX_CACHE_OLD_TIME and delete them
8572 while (!_ReleasedObject
.empty() && _ReleasedObject
.begin()->first
< now
-MAX_CACHE_OLD_TIME
)
8574 TObjectSet
&delSet
= _ReleasedObject
.begin()->second
;
8575 // unload this objects
8576 while (!delSet
.empty())
8578 CFolderAccess
*object
= *delSet
.begin();
8582 _ReleasedObject
.erase(_ReleasedObject
.begin());
8586 void CFolderAccess::clearCache()
8588 // remove any unreferenced object from the cache
8589 while (!_ReleasedObject
.empty())
8591 TObjectSet
&delSet
= _ReleasedObject
.begin()->second
;
8592 // unload this objects
8593 while (!delSet
.empty())
8595 CFolderAccess
*object
= *delSet
.begin();
8599 _ReleasedObject
.erase(_ReleasedObject
.begin());
8603 void CFolderAccess::registerUpdatable()
8605 static bool registered
= false;
8608 NOPE::CPersistentCache::getInstance().registerCache(&CFolderAccess::cacheCmd
);
8614 // set the pointer on the first pointer of the pointer list (set to null when there is no more pointer)
8615 void CFolderAccess::setFirstPtr(CFolderAccessPtr
*ptr
)
8621 // this is the last pointer !
8622 if (_ObjectState
== NOPE::os_transient
8623 || _ObjectState
== NOPE::os_removed
)
8625 // not a persistent object, or removed object, just delet it
8628 else if (_ObjectState
!= NOPE::os_removed
)
8630 setPersistentState(NOPE::os_released
);
8635 // Set the persistent state of the object and do some house keeping
8636 void CFolderAccess::setPersistentState(NOPE::TObjectState state
)
8638 nlassert(NOPE::AllowedTransition
[_ObjectState
][state
] == true);
8640 if(_ObjectState
== NOPE::os_released
&& state
== NOPE::os_removed
)
8642 // a release object gets removed (e.g. by remove by id)
8644 // delete the object
8651 if (_ObjectState
== NOPE::os_transient
&& state
!= NOPE::os_transient
)
8653 nldebug("NOPE: inserting CFolderAccess @%p in cache with id %u", this, static_cast<uint32
>(_Id
));
8654 nlverify(_ObjectCache
.insert(std::make_pair(_Id
, this)).second
);
8657 if (_ObjectState
!= NOPE::os_transient
)
8658 nlassert(_ObjectCache
.find(_Id
) != _ObjectCache
.end());
8660 _ObjectState
= state
;
8662 if (state
== NOPE::os_released
)
8664 _ReleaseDate
= NLMISC::CTime::getSecondsSince1970();
8665 nlverify(_ReleasedObject
[_ReleaseDate
].insert(this).second
);
8667 else if (state
== NOPE::os_removed
)
8669 nldebug("NOPE: erasing CFolderAccess @%p in cache with id %u", this, static_cast<uint32
>(_Id
));
8670 nlverify(_ObjectCache
.erase(_Id
) == 1);
8675 CFolderAccessPtr
CFolderAccess::load(MSW::CConnection
&connection
, uint32 id
, const char *filename
, uint32 lineNum
)
8677 CFolderAccess
*inCache
= loadFromCache(id
, true);
8678 if (inCache
!= NULL
)
8680 return CFolderAccessPtr(inCache
, filename
, lineNum
);
8686 qs
+= "Id, folder_id, user_id";
8688 qs
+= " FROM folder_access";
8690 qs
+= " WHERE Id = '"+NLMISC::toString(id
)+"'";
8691 CFolderAccessPtr ret
;
8692 if (!connection
.query(qs
))
8697 MSW::CStoreResult
*result
= connection
.storeResult().release();
8699 nlassert(result
->getNumRows() <= 1);
8700 if (result
->getNumRows() == 1)
8702 ret
.assign(new CFolderAccess
, filename
, lineNum
);
8703 // ok, we have an object
8706 result
->getField(0, ret
->_Id
);
8707 result
->getField(1, ret
->_FolderId
);
8708 result
->getField(2, ret
->_UserId
);
8711 ret
->setPersistentState(NOPE::os_clean
);
8720 bool CFolderAccess::loadChildrenOfCRingUser(MSW::CConnection
&connection
, uint32 parentId
, std::vector
< CFolderAccessPtr
> & container
, const char *filename
, uint32 lineNum
)
8726 qs
+= "Id, folder_id, user_id";
8728 qs
+= " FROM folder_access";
8729 qs
+= " WHERE user_id = '"+NLMISC::toString(parentId
)+"'";
8731 if (!connection
.query(qs
))
8736 CUniquePtr
<MSW::CStoreResult
> result
= connection
.storeResult();
8738 for (uint i
=0; i
<result
->getNumRows(); ++i
)
8740 CFolderAccess
*ret
= new CFolderAccess();
8741 // ok, we have an object
8744 result
->getField(0, ret
->_Id
);
8746 result
->getField(1, ret
->_FolderId
);
8748 result
->getField(2, ret
->_UserId
);
8749 CFolderAccess
*inCache
= loadFromCache(ret
->_Id
, true);
8750 if (inCache
!= NULL
)
8753 container
.push_back(CFolderAccessPtr(inCache
, filename
, lineNum
));
8760 ret
->setPersistentState(NOPE::os_clean
);
8762 container
.push_back(CFolderAccessPtr(ret
, filename
, lineNum
));
8770 bool CFolderAccess::loadChildrenOfCFolder(MSW::CConnection
&connection
, uint32 parentId
, std::vector
< CFolderAccessPtr
> & container
, const char *filename
, uint32 lineNum
)
8776 qs
+= "Id, folder_id, user_id";
8778 qs
+= " FROM folder_access";
8779 qs
+= " WHERE folder_id = '"+NLMISC::toString(parentId
)+"'";
8781 if (!connection
.query(qs
))
8786 CUniquePtr
<MSW::CStoreResult
> result
= connection
.storeResult();
8788 for (uint i
=0; i
<result
->getNumRows(); ++i
)
8790 CFolderAccess
*ret
= new CFolderAccess();
8791 // ok, we have an object
8794 result
->getField(0, ret
->_Id
);
8796 result
->getField(1, ret
->_FolderId
);
8798 result
->getField(2, ret
->_UserId
);
8799 CFolderAccess
*inCache
= loadFromCache(ret
->_Id
, true);
8800 if (inCache
!= NULL
)
8803 container
.push_back(CFolderAccessPtr(inCache
, filename
, lineNum
));
8810 ret
->setPersistentState(NOPE::os_clean
);
8812 container
.push_back(CFolderAccessPtr(ret
, filename
, lineNum
));
8820 void CScenarioPtr::linkPtr()
8822 nlassert(_NextPtr
== NULL
);
8823 nlassert(_PrevPtr
== NULL
);
8826 _NextPtr
= _Ptr
->getFirstPtr();
8827 if (_NextPtr
!= NULL
)
8829 _PrevPtr
= _NextPtr
->_PrevPtr
;
8830 _PrevPtr
->_NextPtr
= this;
8831 _NextPtr
->_PrevPtr
= this;
8837 _Ptr
->setFirstPtr(this);
8842 void CScenarioPtr::unlinkPtr()
8844 if (_NextPtr
== NULL
)
8846 nlassert(_PrevPtr
== NULL
);
8852 if (_NextPtr
== this)
8854 nlassert(_PrevPtr
== this);
8856 _Ptr
->setFirstPtr(NULL
);
8860 if (_Ptr
->getFirstPtr() == this)
8862 // the first ptr is the current one, we need to switch to next one
8863 _Ptr
->setFirstPtr(_NextPtr
);
8868 if (_NextPtr
!= this)
8870 nlassert(_PrevPtr
!= this);
8872 _NextPtr
->_PrevPtr
= _PrevPtr
;
8873 _PrevPtr
->_NextPtr
= _NextPtr
;
8880 CScenario::TObjectCache
CScenario::_ObjectCache
;
8881 CScenario::TReleasedObject
CScenario::_ReleasedObject
;
8884 // Destructor, delete any children
8885 CScenario::~CScenario()
8887 // release childs reference
8888 if (_SessionLogs
!= NULL
)
8889 delete _SessionLogs
;
8890 if (_PlayerRatings
!= NULL
)
8891 delete _PlayerRatings
;
8894 if (_PtrList
!= NULL
)
8896 nlwarning("ERROR : someone try to delete this object, but there are still ptr on it !");
8897 CScenarioPtr
*ptr
= _PtrList
;
8900 nlwarning(" Pointer created from '%s', line %u", ptr
->_FileName
, ptr
->_LineNum
);
8901 ptr
= _PtrList
->getNextPtr();
8902 } while(ptr
!= _PtrList
);
8905 // remove object from cache map
8906 if (_Id
!= NOPE::INVALID_OBJECT_ID
8907 && _ObjectState
!= NOPE::os_removed
8908 && _ObjectState
!= NOPE::os_transient
)
8910 nldebug("NOPE: clearing CScenario @%p from cache with id %u", this, static_cast<uint32
>(_Id
));
8911 nlverify(_ObjectCache
.erase(_Id
) == 1);
8913 else if (_ObjectState
!= NOPE::os_transient
)
8915 nlassert(_ObjectCache
.find(_Id
) == _ObjectCache
.end());
8917 if (_ObjectState
== NOPE::os_released
)
8919 removeFromReleased();
8923 TReleasedObject::iterator
it(_ReleasedObject
.find(_ReleaseDate
));
8924 if (it
!= _ReleasedObject
.end())
8926 nlassert(it
->second
.find(this) == it
->second
.end());
8931 void CScenario::removeFromReleased()
8933 TReleasedObject::iterator
it(_ReleasedObject
.find(_ReleaseDate
));
8934 nlassert(it
!= _ReleasedObject
.end());
8935 TObjectSet
&os
= it
->second
;
8937 nlverify(os
.erase(this) == 1);
8939 // nb : _ReleasedObject time entry are removed by the cache update
8942 bool CScenario::create(MSW::CConnection
&connection
)
8944 nlassert(getPersistentState() == NOPE::os_transient
);
8947 qs
= "INSERT INTO scenario (";
8949 qs
+= "md5, title, description, author, rrp_total, anim_mode, language, orientation, level, allow_free_trial";
8952 qs
+= "'"+MSW::escapeString(_MD5
.toString(), connection
)+"'";
8954 qs
+= "'"+MSW::escapeString(NLMISC::toString(_Title
), connection
)+"'";
8956 qs
+= "'"+MSW::escapeString(NLMISC::toString(_Description
), connection
)+"'";
8958 qs
+= "'"+MSW::escapeString(NLMISC::toString(_Author
), connection
)+"'";
8960 qs
+= "'"+MSW::escapeString(NLMISC::toString(_RRPTotal
), connection
)+"'";
8962 qs
+= _AnimMode
.isValid()
8963 ? "'"+_AnimMode
.toString()+"'"
8964 : "DEFAULT(anim_mode)";
8966 qs
+= "'"+MSW::escapeString(NLMISC::toString(_Language
), connection
)+"'";
8968 qs
+= _Orientation
.isValid()
8969 ? "'"+_Orientation
.toString()+"'"
8970 : "DEFAULT(orientation)";
8972 qs
+= _Level
.isValid()
8973 ? "'"+_Level
.toString()+"'"
8976 qs
+= "'"+MSW::escapeString(NLMISC::toString(_AllowFreeTrial
), connection
)+"'";
8980 if (connection
.query(qs
))
8982 uint32 _id_
= connection
.getLastGeneratedId();
8986 setPersistentState(NOPE::os_clean
);
8988 // update the parent class instance in cache if any
8996 bool CScenario::update(MSW::CConnection
&connection
)
8998 nlassert(getPersistentState() == NOPE::os_dirty
|| getPersistentState() == NOPE::os_clean
);
9000 if (getPersistentState() == NOPE::os_clean
)
9001 // the object is clean, just ignore the save
9005 qs
= "UPDATE scenario SET ";
9007 qs
+= "md5 = '"+MSW::escapeString(_MD5
.toString(), connection
)+"'";
9009 qs
+= "title = '"+MSW::escapeString(NLMISC::toString(_Title
), connection
)+"'";
9011 qs
+= "description = '"+MSW::escapeString(NLMISC::toString(_Description
), connection
)+"'";
9013 qs
+= "author = '"+MSW::escapeString(NLMISC::toString(_Author
), connection
)+"'";
9015 qs
+= "rrp_total = '"+MSW::escapeString(NLMISC::toString(_RRPTotal
), connection
)+"'";
9017 qs
+= "anim_mode = " + (_AnimMode
.isValid()
9018 ? "'"+_AnimMode
.toString()+"'"
9019 : "DEFAULT(anim_mode)");
9021 qs
+= "language = '"+MSW::escapeString(NLMISC::toString(_Language
), connection
)+"'";
9023 qs
+= "orientation = " + (_Orientation
.isValid()
9024 ? "'"+_Orientation
.toString()+"'"
9025 : "DEFAULT(orientation)");
9027 qs
+= "level = " + (_Level
.isValid()
9028 ? "'"+_Level
.toString()+"'"
9029 : "DEFAULT(level)");
9031 qs
+= "allow_free_trial = '"+MSW::escapeString(NLMISC::toString(_AllowFreeTrial
), connection
)+"'";
9033 qs
+= " WHERE id = '"+NLMISC::toString(_Id
)+"'";
9036 if (connection
.query(qs
))
9038 if (connection
.getAffectedRows() == 1)
9040 setPersistentState(NOPE::os_clean
);
9048 bool CScenario::remove(MSW::CConnection
&connection
)
9050 nlassert(getPersistentState() == NOPE::os_dirty
|| getPersistentState() == NOPE::os_clean
);
9053 qs
= "DELETE FROM scenario ";
9055 qs
+= " WHERE id = '"+NLMISC::toString(_Id
)+"'";
9058 if (connection
.query(qs
))
9060 if (connection
.getAffectedRows() == 1)
9064 // cascading deletion for vector child SessionLogs
9065 if (loadSessionLogs(connection
, __FILE__
, __LINE__
))
9067 const std::vector
< CSessionLogPtr
> & childs
= getSessionLogs();
9069 while (!childs
.empty())
9071 getSessionLogsByIndex((uint32
)childs
.size()-1)->remove(connection
);
9078 // cascading deletion for vector child PlayerRatings
9079 if (loadPlayerRatings(connection
, __FILE__
, __LINE__
))
9081 const std::vector
< CPlayerRatingPtr
> & childs
= getPlayerRatings();
9083 while (!childs
.empty())
9085 getPlayerRatingsByIndex((uint32
)childs
.size()-1)->remove(connection
);
9092 // change the persistant state to 'removed'.
9093 setPersistentState(NOPE::os_removed
);
9095 // need to remove ref from parent class container (if any)
9097 // need to remove ref from parent (if any)
9106 bool CScenario::removeById(MSW::CConnection
&connection
, uint32 id
)
9108 CScenario
*object
= loadFromCache(id
, true);
9111 return object
->remove(connection
);
9113 // not in cache, run a SQL query
9115 qs
= "DELETE FROM scenario ";
9117 qs
+= " WHERE id = '"+NLMISC::toString(id
)+"'";
9120 if (connection
.query(qs
))
9122 if (connection
.getAffectedRows() == 1)
9124 // ok, the row is removed
9133 // Try to load the specified object from the memory cache, return NULL if the object is not in the cache
9134 CScenario
*CScenario::loadFromCache(uint32 objectId
, bool unrelease
)
9136 // look in the cache
9137 TObjectCache::iterator
it(_ObjectCache
.find(objectId
));
9138 if (it
== _ObjectCache
.end())
9140 // not found, return null
9145 CScenario
*object
= it
->second
;
9147 if (object
->_ObjectState
== NOPE::os_released
)
9151 // we need to remove this object from the released object set.
9152 object
->removeFromReleased();
9153 object
->_ObjectState
= NOPE::os_clean
;
9160 // Receive and execute command from the cache manager.
9161 uint32
CScenario::cacheCmd(NOPE::TCacheCmd cmd
)
9163 if (cmd
== NOPE::cc_update
)
9167 else if (cmd
== NOPE::cc_clear
)
9171 else if (cmd
== NOPE::cc_dump
)
9175 else if (cmd
== NOPE::cc_instance_count
)
9177 return (uint32
)_ObjectCache
.size();
9180 // default return value
9184 void CScenario::dump()
9186 nlinfo(" Cache info for class CScenario :");
9187 nlinfo(" There are %u object instances in cache", _ObjectCache
.size());
9189 // count the number of object in the released object set
9190 uint32 nbReleased
= 0;
9192 TReleasedObject::iterator
first(_ReleasedObject
.begin()), last(_ReleasedObject
.end());
9193 for (; first
!= last
; ++first
)
9195 nbReleased
+= (uint32
)first
->second
.size();
9198 nlinfo(" There are %u object instances in cache not referenced (waiting deletion or re-use))", nbReleased
);
9201 void CScenario::updateCache()
9203 if (_ReleasedObject
.empty())
9206 // 30 s hold in cache
9207 const time_t MAX_CACHE_OLD_TIME
= 30;
9209 time_t now
= NLMISC::CTime::getSecondsSince1970();
9211 // look for object set older than MAX_CACHE_OLD_TIME and delete them
9212 while (!_ReleasedObject
.empty() && _ReleasedObject
.begin()->first
< now
-MAX_CACHE_OLD_TIME
)
9214 TObjectSet
&delSet
= _ReleasedObject
.begin()->second
;
9215 // unload this objects
9216 while (!delSet
.empty())
9218 CScenario
*object
= *delSet
.begin();
9222 _ReleasedObject
.erase(_ReleasedObject
.begin());
9226 void CScenario::clearCache()
9228 // remove any unreferenced object from the cache
9229 while (!_ReleasedObject
.empty())
9231 TObjectSet
&delSet
= _ReleasedObject
.begin()->second
;
9232 // unload this objects
9233 while (!delSet
.empty())
9235 CScenario
*object
= *delSet
.begin();
9239 _ReleasedObject
.erase(_ReleasedObject
.begin());
9243 void CScenario::registerUpdatable()
9245 static bool registered
= false;
9248 NOPE::CPersistentCache::getInstance().registerCache(&CScenario::cacheCmd
);
9254 // set the pointer on the first pointer of the pointer list (set to null when there is no more pointer)
9255 void CScenario::setFirstPtr(CScenarioPtr
*ptr
)
9261 // this is the last pointer !
9262 if (_ObjectState
== NOPE::os_transient
9263 || _ObjectState
== NOPE::os_removed
)
9265 // not a persistent object, or removed object, just delet it
9268 else if (_ObjectState
!= NOPE::os_removed
)
9270 setPersistentState(NOPE::os_released
);
9275 // Set the persistent state of the object and do some house keeping
9276 void CScenario::setPersistentState(NOPE::TObjectState state
)
9278 nlassert(NOPE::AllowedTransition
[_ObjectState
][state
] == true);
9280 if(_ObjectState
== NOPE::os_released
&& state
== NOPE::os_removed
)
9282 // a release object gets removed (e.g. by remove by id)
9284 // delete the object
9291 if (_ObjectState
== NOPE::os_transient
&& state
!= NOPE::os_transient
)
9293 nldebug("NOPE: inserting CScenario @%p in cache with id %u", this, static_cast<uint32
>(_Id
));
9294 nlverify(_ObjectCache
.insert(std::make_pair(_Id
, this)).second
);
9297 if (_ObjectState
!= NOPE::os_transient
)
9298 nlassert(_ObjectCache
.find(_Id
) != _ObjectCache
.end());
9300 _ObjectState
= state
;
9302 if (state
== NOPE::os_released
)
9304 _ReleaseDate
= NLMISC::CTime::getSecondsSince1970();
9305 nlverify(_ReleasedObject
[_ReleaseDate
].insert(this).second
);
9307 else if (state
== NOPE::os_removed
)
9309 nldebug("NOPE: erasing CScenario @%p in cache with id %u", this, static_cast<uint32
>(_Id
));
9310 nlverify(_ObjectCache
.erase(_Id
) == 1);
9315 CScenarioPtr
CScenario::load(MSW::CConnection
&connection
, uint32 id
, const char *filename
, uint32 lineNum
)
9317 CScenario
*inCache
= loadFromCache(id
, true);
9318 if (inCache
!= NULL
)
9320 return CScenarioPtr(inCache
, filename
, lineNum
);
9326 qs
+= "id, md5, title, description, author, rrp_total, anim_mode, language, orientation, level, allow_free_trial";
9328 qs
+= " FROM scenario";
9330 qs
+= " WHERE id = '"+NLMISC::toString(id
)+"'";
9332 if (!connection
.query(qs
))
9337 MSW::CStoreResult
*result
= connection
.storeResult().release();
9339 nlassert(result
->getNumRows() <= 1);
9340 if (result
->getNumRows() == 1)
9342 ret
.assign(new CScenario
, filename
, lineNum
);
9343 // ok, we have an object
9346 result
->getField(0, ret
->_Id
);
9347 result
->getMD5Field(1, ret
->_MD5
);
9348 result
->getField(2, ret
->_Title
);
9349 result
->getField(3, ret
->_Description
);
9350 result
->getField(4, ret
->_Author
);
9351 result
->getField(5, ret
->_RRPTotal
);
9354 result
->getField(6, s
);
9355 ret
->_AnimMode
= TAnimMode(s
);
9357 result
->getField(7, ret
->_Language
);
9360 result
->getField(8, s
);
9361 ret
->_Orientation
= TSessionOrientation(s
);
9365 result
->getField(9, s
);
9366 ret
->_Level
= R2::TSessionLevel(s
);
9368 result
->getField(10, ret
->_AllowFreeTrial
);
9371 ret
->setPersistentState(NOPE::os_clean
);
9380 bool CScenario::loadSessionLogs(MSW::CConnection
&connection
, const char *filename
, uint32 lineNum
)
9383 if (_SessionLogs
!= NULL
)
9385 // the children are already loaded, just return true
9389 // allocate the container
9390 _SessionLogs
= new std::vector
< CSessionLogPtr
>;
9393 ret
&= CSessionLog::loadChildrenOfCScenario(connection
, getObjectId(), *_SessionLogs
, filename
, lineNum
);
9398 const std::vector
<CSessionLogPtr
> &CScenario::getSessionLogs() const
9400 nlassert(_SessionLogs
!= NULL
);
9401 return *_SessionLogs
;
9404 CSessionLogPtr
&CScenario::getSessionLogsByIndex(uint32 index
) const
9406 nlassert(_SessionLogs
!= NULL
);
9407 nlassert(index
< _SessionLogs
->size());
9408 return const_cast< CSessionLogPtr
& >(_SessionLogs
->operator[](index
));
9411 CSessionLogPtr
&CScenario::getSessionLogsById(uint32 id
) const
9413 nlassert(_SessionLogs
!= NULL
);
9414 std::vector
<CSessionLogPtr
>::const_iterator
first(_SessionLogs
->begin()), last(_SessionLogs
->end());
9415 for (; first
!= last
; ++first
)
9417 const CSessionLogPtr
&child
= *first
;
9418 if (child
->getObjectId() == id
)
9420 return const_cast< CSessionLogPtr
& >(child
);
9424 // no object with this id, return a null pointer
9425 static CSessionLogPtr nilPtr
;
9431 bool CScenario::loadPlayerRatings(MSW::CConnection
&connection
, const char *filename
, uint32 lineNum
)
9434 if (_PlayerRatings
!= NULL
)
9436 // the children are already loaded, just return true
9440 // allocate the container
9441 _PlayerRatings
= new std::vector
< CPlayerRatingPtr
>;
9444 ret
&= CPlayerRating::loadChildrenOfCScenario(connection
, getObjectId(), *_PlayerRatings
, filename
, lineNum
);
9449 const std::vector
<CPlayerRatingPtr
> &CScenario::getPlayerRatings() const
9451 nlassert(_PlayerRatings
!= NULL
);
9452 return *_PlayerRatings
;
9455 CPlayerRatingPtr
&CScenario::getPlayerRatingsByIndex(uint32 index
) const
9457 nlassert(_PlayerRatings
!= NULL
);
9458 nlassert(index
< _PlayerRatings
->size());
9459 return const_cast< CPlayerRatingPtr
& >(_PlayerRatings
->operator[](index
));
9462 CPlayerRatingPtr
&CScenario::getPlayerRatingsById(uint32 id
) const
9464 nlassert(_PlayerRatings
!= NULL
);
9465 std::vector
<CPlayerRatingPtr
>::const_iterator
first(_PlayerRatings
->begin()), last(_PlayerRatings
->end());
9466 for (; first
!= last
; ++first
)
9468 const CPlayerRatingPtr
&child
= *first
;
9469 if (child
->getObjectId() == id
)
9471 return const_cast< CPlayerRatingPtr
& >(child
);
9475 // no object with this id, return a null pointer
9476 static CPlayerRatingPtr nilPtr
;
9482 void CSessionLogPtr::linkPtr()
9484 nlassert(_NextPtr
== NULL
);
9485 nlassert(_PrevPtr
== NULL
);
9488 _NextPtr
= _Ptr
->getFirstPtr();
9489 if (_NextPtr
!= NULL
)
9491 _PrevPtr
= _NextPtr
->_PrevPtr
;
9492 _PrevPtr
->_NextPtr
= this;
9493 _NextPtr
->_PrevPtr
= this;
9499 _Ptr
->setFirstPtr(this);
9504 void CSessionLogPtr::unlinkPtr()
9506 if (_NextPtr
== NULL
)
9508 nlassert(_PrevPtr
== NULL
);
9514 if (_NextPtr
== this)
9516 nlassert(_PrevPtr
== this);
9518 _Ptr
->setFirstPtr(NULL
);
9522 if (_Ptr
->getFirstPtr() == this)
9524 // the first ptr is the current one, we need to switch to next one
9525 _Ptr
->setFirstPtr(_NextPtr
);
9530 if (_NextPtr
!= this)
9532 nlassert(_PrevPtr
!= this);
9534 _NextPtr
->_PrevPtr
= _PrevPtr
;
9535 _PrevPtr
->_NextPtr
= _NextPtr
;
9542 CSessionLog::TObjectCache
CSessionLog::_ObjectCache
;
9543 CSessionLog::TReleasedObject
CSessionLog::_ReleasedObject
;
9546 // Destructor, delete any children
9547 CSessionLog::~CSessionLog()
9549 // release childs reference
9552 if (_PtrList
!= NULL
)
9554 nlwarning("ERROR : someone try to delete this object, but there are still ptr on it !");
9555 CSessionLogPtr
*ptr
= _PtrList
;
9558 nlwarning(" Pointer created from '%s', line %u", ptr
->_FileName
, ptr
->_LineNum
);
9559 ptr
= _PtrList
->getNextPtr();
9560 } while(ptr
!= _PtrList
);
9563 // remove object from cache map
9564 if (_Id
!= NOPE::INVALID_OBJECT_ID
9565 && _ObjectState
!= NOPE::os_removed
9566 && _ObjectState
!= NOPE::os_transient
)
9568 nldebug("NOPE: clearing CSessionLog @%p from cache with id %u", this, static_cast<uint32
>(_Id
));
9569 nlverify(_ObjectCache
.erase(_Id
) == 1);
9571 else if (_ObjectState
!= NOPE::os_transient
)
9573 nlassert(_ObjectCache
.find(_Id
) == _ObjectCache
.end());
9575 if (_ObjectState
== NOPE::os_released
)
9577 removeFromReleased();
9581 TReleasedObject::iterator
it(_ReleasedObject
.find(_ReleaseDate
));
9582 if (it
!= _ReleasedObject
.end())
9584 nlassert(it
->second
.find(this) == it
->second
.end());
9589 void CSessionLog::removeFromReleased()
9591 TReleasedObject::iterator
it(_ReleasedObject
.find(_ReleaseDate
));
9592 nlassert(it
!= _ReleasedObject
.end());
9593 TObjectSet
&os
= it
->second
;
9595 nlverify(os
.erase(this) == 1);
9597 // nb : _ReleasedObject time entry are removed by the cache update
9600 bool CSessionLog::create(MSW::CConnection
&connection
)
9602 nlassert(getPersistentState() == NOPE::os_transient
);
9606 qs
= "INSERT INTO session_log (";
9608 qs
+= "id, scenario_id, rrp_scored, scenario_point_scored, time_taken, participants, launch_date, owner, guild_name";
9611 qs
+= "'"+MSW::escapeString(NLMISC::toString(_Id
), connection
)+"'";
9613 qs
+= "'"+MSW::escapeString(NLMISC::toString(_ScenarioId
), connection
)+"'";
9615 qs
+= "'"+MSW::escapeString(NLMISC::toString(_RRPScored
), connection
)+"'";
9617 qs
+= "'"+MSW::escapeString(NLMISC::toString(_ScenarioPointScored
), connection
)+"'";
9619 qs
+= "'"+MSW::escapeString(NLMISC::toString(_TimeTaken
), connection
)+"'";
9621 qs
+= "'"+MSW::escapeString(NLMISC::toString(_Participants
), connection
)+"'";
9623 qs
+= "'"+MSW::encodeDate(_LaunchDate
)+"'";
9625 qs
+= "'"+MSW::escapeString(NLMISC::toString(_Owner
), connection
)+"'";
9627 qs
+= "'"+MSW::escapeString(NLMISC::toString(_GuildName
), connection
)+"'";
9631 if (connection
.query(qs
))
9635 setPersistentState(NOPE::os_clean
);
9637 // update the parent class instance in cache if any
9639 if (_ScenarioId
!= 0)
9641 // need to update the parent class child list if it is in the cache
9642 CScenario
*parent
= CScenario::loadFromCache(_ScenarioId
, false);
9643 if (parent
&& parent
->_SessionLogs
!= NULL
)
9646 nlassert(std::find(parent
->_SessionLogs
->begin(), parent
->_SessionLogs
->end(), CSessionLogPtr(this, __FILE__
, __LINE__
)) == parent
->_SessionLogs
->end());
9647 parent
->_SessionLogs
->push_back(CSessionLogPtr(this, __FILE__
, __LINE__
));
9658 bool CSessionLog::update(MSW::CConnection
&connection
)
9660 nlassert(getPersistentState() == NOPE::os_dirty
|| getPersistentState() == NOPE::os_clean
);
9662 if (getPersistentState() == NOPE::os_clean
)
9663 // the object is clean, just ignore the save
9667 qs
= "UPDATE session_log SET ";
9669 qs
+= "id = '"+MSW::escapeString(NLMISC::toString(_Id
), connection
)+"'";
9671 qs
+= "scenario_id = '"+MSW::escapeString(NLMISC::toString(_ScenarioId
), connection
)+"'";
9673 qs
+= "rrp_scored = '"+MSW::escapeString(NLMISC::toString(_RRPScored
), connection
)+"'";
9675 qs
+= "scenario_point_scored = '"+MSW::escapeString(NLMISC::toString(_ScenarioPointScored
), connection
)+"'";
9677 qs
+= "time_taken = '"+MSW::escapeString(NLMISC::toString(_TimeTaken
), connection
)+"'";
9679 qs
+= "participants = '"+MSW::escapeString(NLMISC::toString(_Participants
), connection
)+"'";
9681 qs
+= "launch_date = '"+MSW::encodeDate(_LaunchDate
)+"'";
9683 qs
+= "owner = '"+MSW::escapeString(NLMISC::toString(_Owner
), connection
)+"'";
9685 qs
+= "guild_name = '"+MSW::escapeString(NLMISC::toString(_GuildName
), connection
)+"'";
9687 qs
+= " WHERE id = '"+NLMISC::toString(_Id
)+"'";
9690 if (connection
.query(qs
))
9692 if (connection
.getAffectedRows() == 1)
9694 setPersistentState(NOPE::os_clean
);
9702 bool CSessionLog::remove(MSW::CConnection
&connection
)
9704 nlassert(getPersistentState() == NOPE::os_dirty
|| getPersistentState() == NOPE::os_clean
);
9707 qs
= "DELETE FROM session_log ";
9709 qs
+= " WHERE id = '"+NLMISC::toString(_Id
)+"'";
9712 if (connection
.query(qs
))
9714 if (connection
.getAffectedRows() == 1)
9718 // change the persistant state to 'removed'.
9719 setPersistentState(NOPE::os_removed
);
9721 // need to remove ref from parent class container (if any)
9724 CScenarioPtr
parent(CScenario::loadFromCache(_ScenarioId
, true), __FILE__
, __LINE__
);
9725 if (parent
!= NULL
&& parent
->_SessionLogs
!= NULL
)
9728 std::vector
< CSessionLogPtr
>::iterator it
= std::find(parent
->_SessionLogs
->begin(), parent
->_SessionLogs
->end(), this);
9729 if (it
!= parent
->_SessionLogs
->end())
9731 parent
->_SessionLogs
->erase(it
);
9737 // need to remove ref from parent (if any)
9746 bool CSessionLog::removeById(MSW::CConnection
&connection
, uint32 id
)
9748 CSessionLog
*object
= loadFromCache(id
, true);
9751 return object
->remove(connection
);
9753 // not in cache, run a SQL query
9755 qs
= "DELETE FROM session_log ";
9757 qs
+= " WHERE id = '"+NLMISC::toString(id
)+"'";
9760 if (connection
.query(qs
))
9762 if (connection
.getAffectedRows() == 1)
9764 // ok, the row is removed
9773 // Try to load the specified object from the memory cache, return NULL if the object is not in the cache
9774 CSessionLog
*CSessionLog::loadFromCache(uint32 objectId
, bool unrelease
)
9776 // look in the cache
9777 TObjectCache::iterator
it(_ObjectCache
.find(objectId
));
9778 if (it
== _ObjectCache
.end())
9780 // not found, return null
9785 CSessionLog
*object
= it
->second
;
9787 if (object
->_ObjectState
== NOPE::os_released
)
9791 // we need to remove this object from the released object set.
9792 object
->removeFromReleased();
9793 object
->_ObjectState
= NOPE::os_clean
;
9800 // Receive and execute command from the cache manager.
9801 uint32
CSessionLog::cacheCmd(NOPE::TCacheCmd cmd
)
9803 if (cmd
== NOPE::cc_update
)
9807 else if (cmd
== NOPE::cc_clear
)
9811 else if (cmd
== NOPE::cc_dump
)
9815 else if (cmd
== NOPE::cc_instance_count
)
9817 return (uint32
)_ObjectCache
.size();
9820 // default return value
9824 void CSessionLog::dump()
9826 nlinfo(" Cache info for class CSessionLog :");
9827 nlinfo(" There are %u object instances in cache", _ObjectCache
.size());
9829 // count the number of object in the released object set
9830 uint32 nbReleased
= 0;
9832 TReleasedObject::iterator
first(_ReleasedObject
.begin()), last(_ReleasedObject
.end());
9833 for (; first
!= last
; ++first
)
9835 nbReleased
+= (uint32
)first
->second
.size();
9838 nlinfo(" There are %u object instances in cache not referenced (waiting deletion or re-use))", nbReleased
);
9841 void CSessionLog::updateCache()
9843 if (_ReleasedObject
.empty())
9846 // 30 s hold in cache
9847 const time_t MAX_CACHE_OLD_TIME
= 30;
9849 time_t now
= NLMISC::CTime::getSecondsSince1970();
9851 // look for object set older than MAX_CACHE_OLD_TIME and delete them
9852 while (!_ReleasedObject
.empty() && _ReleasedObject
.begin()->first
< now
-MAX_CACHE_OLD_TIME
)
9854 TObjectSet
&delSet
= _ReleasedObject
.begin()->second
;
9855 // unload this objects
9856 while (!delSet
.empty())
9858 CSessionLog
*object
= *delSet
.begin();
9862 _ReleasedObject
.erase(_ReleasedObject
.begin());
9866 void CSessionLog::clearCache()
9868 // remove any unreferenced object from the cache
9869 while (!_ReleasedObject
.empty())
9871 TObjectSet
&delSet
= _ReleasedObject
.begin()->second
;
9872 // unload this objects
9873 while (!delSet
.empty())
9875 CSessionLog
*object
= *delSet
.begin();
9879 _ReleasedObject
.erase(_ReleasedObject
.begin());
9883 void CSessionLog::registerUpdatable()
9885 static bool registered
= false;
9888 NOPE::CPersistentCache::getInstance().registerCache(&CSessionLog::cacheCmd
);
9894 // set the pointer on the first pointer of the pointer list (set to null when there is no more pointer)
9895 void CSessionLog::setFirstPtr(CSessionLogPtr
*ptr
)
9901 // this is the last pointer !
9902 if (_ObjectState
== NOPE::os_transient
9903 || _ObjectState
== NOPE::os_removed
)
9905 // not a persistent object, or removed object, just delet it
9908 else if (_ObjectState
!= NOPE::os_removed
)
9910 setPersistentState(NOPE::os_released
);
9915 // Set the persistent state of the object and do some house keeping
9916 void CSessionLog::setPersistentState(NOPE::TObjectState state
)
9918 nlassert(NOPE::AllowedTransition
[_ObjectState
][state
] == true);
9920 if(_ObjectState
== NOPE::os_released
&& state
== NOPE::os_removed
)
9922 // a release object gets removed (e.g. by remove by id)
9924 // delete the object
9931 if (_ObjectState
== NOPE::os_transient
&& state
!= NOPE::os_transient
)
9933 nldebug("NOPE: inserting CSessionLog @%p in cache with id %u", this, static_cast<uint32
>(_Id
));
9934 nlverify(_ObjectCache
.insert(std::make_pair(_Id
, this)).second
);
9937 if (_ObjectState
!= NOPE::os_transient
)
9938 nlassert(_ObjectCache
.find(_Id
) != _ObjectCache
.end());
9940 _ObjectState
= state
;
9942 if (state
== NOPE::os_released
)
9944 _ReleaseDate
= NLMISC::CTime::getSecondsSince1970();
9945 nlverify(_ReleasedObject
[_ReleaseDate
].insert(this).second
);
9947 else if (state
== NOPE::os_removed
)
9949 nldebug("NOPE: erasing CSessionLog @%p in cache with id %u", this, static_cast<uint32
>(_Id
));
9950 nlverify(_ObjectCache
.erase(_Id
) == 1);
9955 CSessionLogPtr
CSessionLog::load(MSW::CConnection
&connection
, uint32 id
, const char *filename
, uint32 lineNum
)
9957 CSessionLog
*inCache
= loadFromCache(id
, true);
9958 if (inCache
!= NULL
)
9960 return CSessionLogPtr(inCache
, filename
, lineNum
);
9966 qs
+= "id, scenario_id, rrp_scored, scenario_point_scored, time_taken, participants, launch_date, owner, guild_name";
9968 qs
+= " FROM session_log";
9970 qs
+= " WHERE id = '"+NLMISC::toString(id
)+"'";
9972 if (!connection
.query(qs
))
9977 MSW::CStoreResult
*result
= connection
.storeResult().release();
9979 nlassert(result
->getNumRows() <= 1);
9980 if (result
->getNumRows() == 1)
9982 ret
.assign(new CSessionLog
, filename
, lineNum
);
9983 // ok, we have an object
9986 result
->getField(0, ret
->_Id
);
9987 result
->getField(1, ret
->_ScenarioId
);
9988 result
->getField(2, ret
->_RRPScored
);
9989 result
->getField(3, ret
->_ScenarioPointScored
);
9990 result
->getField(4, ret
->_TimeTaken
);
9991 result
->getField(5, ret
->_Participants
);
9992 result
->getDateField(6, ret
->_LaunchDate
);
9993 result
->getField(7, ret
->_Owner
);
9994 result
->getField(8, ret
->_GuildName
);
9997 ret
->setPersistentState(NOPE::os_clean
);
10006 bool CSessionLog::loadChildrenOfCScenario(MSW::CConnection
&connection
, uint32 parentId
, std::vector
< CSessionLogPtr
> & container
, const char *filename
, uint32 lineNum
)
10012 qs
+= "id, scenario_id, rrp_scored, scenario_point_scored, time_taken, participants, launch_date, owner, guild_name";
10014 qs
+= " FROM session_log";
10015 qs
+= " WHERE scenario_id = '"+NLMISC::toString(parentId
)+"'";
10017 if (!connection
.query(qs
))
10022 CUniquePtr
<MSW::CStoreResult
> result
= connection
.storeResult();
10024 for (uint i
=0; i
<result
->getNumRows(); ++i
)
10026 CSessionLog
*ret
= new CSessionLog();
10027 // ok, we have an object
10028 result
->fetchRow();
10030 result
->getField(0, ret
->_Id
);
10032 result
->getField(1, ret
->_ScenarioId
);
10034 result
->getField(2, ret
->_RRPScored
);
10036 result
->getField(3, ret
->_ScenarioPointScored
);
10038 result
->getField(4, ret
->_TimeTaken
);
10040 result
->getField(5, ret
->_Participants
);
10042 result
->getDateField(6, ret
->_LaunchDate
);
10044 result
->getField(7, ret
->_Owner
);
10046 result
->getField(8, ret
->_GuildName
);
10047 CSessionLog
*inCache
= loadFromCache(ret
->_Id
, true);
10048 if (inCache
!= NULL
)
10051 container
.push_back(CSessionLogPtr(inCache
, filename
, lineNum
));
10058 ret
->setPersistentState(NOPE::os_clean
);
10060 container
.push_back(CSessionLogPtr(ret
, filename
, lineNum
));
10068 void CGmStatusPtr::linkPtr()
10070 nlassert(_NextPtr
== NULL
);
10071 nlassert(_PrevPtr
== NULL
);
10074 _NextPtr
= _Ptr
->getFirstPtr();
10075 if (_NextPtr
!= NULL
)
10077 _PrevPtr
= _NextPtr
->_PrevPtr
;
10078 _PrevPtr
->_NextPtr
= this;
10079 _NextPtr
->_PrevPtr
= this;
10085 _Ptr
->setFirstPtr(this);
10090 void CGmStatusPtr::unlinkPtr()
10092 if (_NextPtr
== NULL
)
10094 nlassert(_PrevPtr
== NULL
);
10100 if (_NextPtr
== this)
10102 nlassert(_PrevPtr
== this);
10104 _Ptr
->setFirstPtr(NULL
);
10108 if (_Ptr
->getFirstPtr() == this)
10110 // the first ptr is the current one, we need to switch to next one
10111 _Ptr
->setFirstPtr(_NextPtr
);
10116 if (_NextPtr
!= this)
10118 nlassert(_PrevPtr
!= this);
10120 _NextPtr
->_PrevPtr
= _PrevPtr
;
10121 _PrevPtr
->_NextPtr
= _NextPtr
;
10128 CGmStatus::TObjectCache
CGmStatus::_ObjectCache
;
10129 CGmStatus::TReleasedObject
CGmStatus::_ReleasedObject
;
10132 // Destructor, delete any children
10133 CGmStatus::~CGmStatus()
10135 // release childs reference
10138 if (_PtrList
!= NULL
)
10140 nlwarning("ERROR : someone try to delete this object, but there are still ptr on it !");
10141 CGmStatusPtr
*ptr
= _PtrList
;
10144 nlwarning(" Pointer created from '%s', line %u", ptr
->_FileName
, ptr
->_LineNum
);
10145 ptr
= _PtrList
->getNextPtr();
10146 } while(ptr
!= _PtrList
);
10149 // remove object from cache map
10150 if (_UserId
!= NOPE::INVALID_OBJECT_ID
10151 && _ObjectState
!= NOPE::os_removed
10152 && _ObjectState
!= NOPE::os_transient
)
10154 nldebug("NOPE: clearing CGmStatus @%p from cache with id %u", this, static_cast<uint32
>(_UserId
));
10155 nlverify(_ObjectCache
.erase(_UserId
) == 1);
10157 else if (_ObjectState
!= NOPE::os_transient
)
10159 nlassert(_ObjectCache
.find(_UserId
) == _ObjectCache
.end());
10161 if (_ObjectState
== NOPE::os_released
)
10163 removeFromReleased();
10167 TReleasedObject::iterator
it(_ReleasedObject
.find(_ReleaseDate
));
10168 if (it
!= _ReleasedObject
.end())
10170 nlassert(it
->second
.find(this) == it
->second
.end());
10175 void CGmStatus::removeFromReleased()
10177 TReleasedObject::iterator
it(_ReleasedObject
.find(_ReleaseDate
));
10178 nlassert(it
!= _ReleasedObject
.end());
10179 TObjectSet
&os
= it
->second
;
10181 nlverify(os
.erase(this) == 1);
10183 // nb : _ReleasedObject time entry are removed by the cache update
10186 bool CGmStatus::create(MSW::CConnection
&connection
)
10188 nlassert(getPersistentState() == NOPE::os_transient
);
10190 nlassert(_UserId
!= 0);
10192 qs
= "INSERT INTO gm_status (";
10194 qs
+= "user_id, available";
10195 qs
+= ") VALUES (";
10197 qs
+= "'"+MSW::escapeString(NLMISC::toString(_UserId
), connection
)+"'";
10199 qs
+= "'"+MSW::escapeString(NLMISC::toString(_Available
), connection
)+"'";
10203 if (connection
.query(qs
))
10207 setPersistentState(NOPE::os_clean
);
10209 // update the parent class instance in cache if any
10213 // need to update the parent class child if it is in the cache
10214 CRingUser
*parent
= CRingUser::loadFromCache(_UserId
, false);
10215 if (parent
&& parent
->_GMStatusLoaded
)
10217 nlassert(parent
->_GMStatus
== NULL
);
10218 parent
->_GMStatus
= CGmStatusPtr(this, __FILE__
, __LINE__
);
10228 bool CGmStatus::update(MSW::CConnection
&connection
)
10230 nlassert(getPersistentState() == NOPE::os_dirty
|| getPersistentState() == NOPE::os_clean
);
10232 if (getPersistentState() == NOPE::os_clean
)
10233 // the object is clean, just ignore the save
10237 qs
= "UPDATE gm_status SET ";
10239 qs
+= "user_id = '"+MSW::escapeString(NLMISC::toString(_UserId
), connection
)+"'";
10241 qs
+= "available = '"+MSW::escapeString(NLMISC::toString(_Available
), connection
)+"'";
10243 qs
+= " WHERE user_id = '"+NLMISC::toString(_UserId
)+"'";
10246 if (connection
.query(qs
))
10248 if (connection
.getAffectedRows() == 1)
10250 setPersistentState(NOPE::os_clean
);
10258 bool CGmStatus::remove(MSW::CConnection
&connection
)
10260 nlassert(getPersistentState() == NOPE::os_dirty
|| getPersistentState() == NOPE::os_clean
);
10263 qs
= "DELETE FROM gm_status ";
10265 qs
+= " WHERE user_id = '"+NLMISC::toString(_UserId
)+"'";
10268 if (connection
.query(qs
))
10270 if (connection
.getAffectedRows() == 1)
10274 // change the persistant state to 'removed'.
10275 setPersistentState(NOPE::os_removed
);
10277 // need to remove ref from parent class container (if any)
10279 // need to remove ref from parent (if any)
10282 CRingUserPtr
parent(CRingUser::loadFromCache(_UserId
, true), __FILE__
, __LINE__
);
10283 if (parent
!= NULL
&& parent
->_GMStatusLoaded
)
10285 // assign a new NULL pointer
10286 parent
->_GMStatus
.assign(CGmStatusPtr(), __FILE__
, __LINE__
);
10297 bool CGmStatus::removeById(MSW::CConnection
&connection
, uint32 id
)
10299 CGmStatus
*object
= loadFromCache(id
, true);
10300 if (object
!= NULL
)
10302 return object
->remove(connection
);
10304 // not in cache, run a SQL query
10306 qs
= "DELETE FROM gm_status ";
10308 qs
+= " WHERE user_id = '"+NLMISC::toString(id
)+"'";
10311 if (connection
.query(qs
))
10313 if (connection
.getAffectedRows() == 1)
10315 // ok, the row is removed
10324 // Try to load the specified object from the memory cache, return NULL if the object is not in the cache
10325 CGmStatus
*CGmStatus::loadFromCache(uint32 objectId
, bool unrelease
)
10327 // look in the cache
10328 TObjectCache::iterator
it(_ObjectCache
.find(objectId
));
10329 if (it
== _ObjectCache
.end())
10331 // not found, return null
10336 CGmStatus
*object
= it
->second
;
10338 if (object
->_ObjectState
== NOPE::os_released
)
10342 // we need to remove this object from the released object set.
10343 object
->removeFromReleased();
10344 object
->_ObjectState
= NOPE::os_clean
;
10351 // Receive and execute command from the cache manager.
10352 uint32
CGmStatus::cacheCmd(NOPE::TCacheCmd cmd
)
10354 if (cmd
== NOPE::cc_update
)
10358 else if (cmd
== NOPE::cc_clear
)
10362 else if (cmd
== NOPE::cc_dump
)
10366 else if (cmd
== NOPE::cc_instance_count
)
10368 return (uint32
)_ObjectCache
.size();
10371 // default return value
10375 void CGmStatus::dump()
10377 nlinfo(" Cache info for class CGmStatus :");
10378 nlinfo(" There are %u object instances in cache", _ObjectCache
.size());
10380 // count the number of object in the released object set
10381 uint32 nbReleased
= 0;
10383 TReleasedObject::iterator
first(_ReleasedObject
.begin()), last(_ReleasedObject
.end());
10384 for (; first
!= last
; ++first
)
10386 nbReleased
+= (uint32
)first
->second
.size();
10389 nlinfo(" There are %u object instances in cache not referenced (waiting deletion or re-use))", nbReleased
);
10392 void CGmStatus::updateCache()
10394 if (_ReleasedObject
.empty())
10397 // 30 s hold in cache
10398 const time_t MAX_CACHE_OLD_TIME
= 30;
10400 time_t now
= NLMISC::CTime::getSecondsSince1970();
10402 // look for object set older than MAX_CACHE_OLD_TIME and delete them
10403 while (!_ReleasedObject
.empty() && _ReleasedObject
.begin()->first
< now
-MAX_CACHE_OLD_TIME
)
10405 TObjectSet
&delSet
= _ReleasedObject
.begin()->second
;
10406 // unload this objects
10407 while (!delSet
.empty())
10409 CGmStatus
*object
= *delSet
.begin();
10413 _ReleasedObject
.erase(_ReleasedObject
.begin());
10417 void CGmStatus::clearCache()
10419 // remove any unreferenced object from the cache
10420 while (!_ReleasedObject
.empty())
10422 TObjectSet
&delSet
= _ReleasedObject
.begin()->second
;
10423 // unload this objects
10424 while (!delSet
.empty())
10426 CGmStatus
*object
= *delSet
.begin();
10430 _ReleasedObject
.erase(_ReleasedObject
.begin());
10434 void CGmStatus::registerUpdatable()
10436 static bool registered
= false;
10439 NOPE::CPersistentCache::getInstance().registerCache(&CGmStatus::cacheCmd
);
10445 // set the pointer on the first pointer of the pointer list (set to null when there is no more pointer)
10446 void CGmStatus::setFirstPtr(CGmStatusPtr
*ptr
)
10452 // this is the last pointer !
10453 if (_ObjectState
== NOPE::os_transient
10454 || _ObjectState
== NOPE::os_removed
)
10456 // not a persistent object, or removed object, just delet it
10459 else if (_ObjectState
!= NOPE::os_removed
)
10461 setPersistentState(NOPE::os_released
);
10466 // Set the persistent state of the object and do some house keeping
10467 void CGmStatus::setPersistentState(NOPE::TObjectState state
)
10469 nlassert(NOPE::AllowedTransition
[_ObjectState
][state
] == true);
10471 if(_ObjectState
== NOPE::os_released
&& state
== NOPE::os_removed
)
10473 // a release object gets removed (e.g. by remove by id)
10475 // delete the object
10482 if (_ObjectState
== NOPE::os_transient
&& state
!= NOPE::os_transient
)
10484 nldebug("NOPE: inserting CGmStatus @%p in cache with id %u", this, static_cast<uint32
>(_UserId
));
10485 nlverify(_ObjectCache
.insert(std::make_pair(_UserId
, this)).second
);
10488 if (_ObjectState
!= NOPE::os_transient
)
10489 nlassert(_ObjectCache
.find(_UserId
) != _ObjectCache
.end());
10491 _ObjectState
= state
;
10493 if (state
== NOPE::os_released
)
10495 _ReleaseDate
= NLMISC::CTime::getSecondsSince1970();
10496 nlverify(_ReleasedObject
[_ReleaseDate
].insert(this).second
);
10498 else if (state
== NOPE::os_removed
)
10500 nldebug("NOPE: erasing CGmStatus @%p in cache with id %u", this, static_cast<uint32
>(_UserId
));
10501 nlverify(_ObjectCache
.erase(_UserId
) == 1);
10506 CGmStatusPtr
CGmStatus::load(MSW::CConnection
&connection
, uint32 id
, const char *filename
, uint32 lineNum
)
10508 CGmStatus
*inCache
= loadFromCache(id
, true);
10509 if (inCache
!= NULL
)
10511 return CGmStatusPtr(inCache
, filename
, lineNum
);
10517 qs
+= "user_id, available";
10519 qs
+= " FROM gm_status";
10521 qs
+= " WHERE user_id = '"+NLMISC::toString(id
)+"'";
10523 if (!connection
.query(qs
))
10528 MSW::CStoreResult
*result
= connection
.storeResult().release();
10530 nlassert(result
->getNumRows() <= 1);
10531 if (result
->getNumRows() == 1)
10533 ret
.assign(new CGmStatus
, filename
, lineNum
);
10534 // ok, we have an object
10535 result
->fetchRow();
10537 result
->getField(0, ret
->_UserId
);
10538 result
->getField(1, ret
->_Available
);
10541 ret
->setPersistentState(NOPE::os_clean
);
10549 bool CGmStatus::loadChildOfCRingUser(MSW::CConnection
&connection
, uint32 parentId
, CGmStatusPtr
&childPtr
, const char *filename
, uint32 lineNum
)
10554 qs
+= "user_id, available";
10556 qs
+= " FROM gm_status";
10557 qs
+= " WHERE user_id = '"+NLMISC::toString(parentId
)+"'";
10560 if (!connection
.query(qs
))
10562 childPtr
= CGmStatusPtr();
10566 CUniquePtr
<MSW::CStoreResult
> result
= connection
.storeResult();
10568 // check that the data description is consistent with database content
10569 nlassert(result
->getNumRows() <= 1);
10571 if (result
->getNumRows() == 1)
10573 CGmStatus
*object
= new CGmStatus
;
10574 // ok, we have an object
10575 result
->fetchRow();
10577 result
->getField(0, object
->_UserId
);
10579 result
->getField(1, object
->_Available
);
10580 CGmStatus
*inCache
= loadFromCache(object
->_UserId
, true);
10581 if (inCache
!= NULL
)
10583 ret
.assign(inCache
, filename
, lineNum
);
10589 object
->setPersistentState(NOPE::os_clean
);
10590 ret
.assign(object
, filename
, lineNum
);
10597 // no result, but no error
10598 childPtr
= CGmStatusPtr();