/* dbx_tree: tree database driver for Miranda IM Copyright 2007-2010 Michael "Protogenes" Kunz, This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #pragma once #include "Interface.h" #include "BTree.h" #include "FileBTree.h" #include "BlockManager.h" #include "IterationHeap.h" #include "Entities.h" #include "Settings.h" #include "Hash.h" #include "EncryptionManager.h" #include "sigslot.h" #ifdef _MSC_VER #include #include #else #include #include #endif #include #include #include #pragma pack(push, 1) // push current alignment to stack, set alignment to 1 byte boundary /** \brief Key Type of the EventsBTree The Key consists of a timestamp, seconds elapsed since 1.1.1970 and an Index, which makes it possible to store multiple events with the same timestamp **/ typedef struct TEventKey { uint32_t TimeStamp; /// timestamp at which the event occoured TDBTEventHandle Event; bool operator < (const TEventKey & Other) const { if (TimeStamp != Other.TimeStamp) return TimeStamp < Other.TimeStamp; if (Event != Other.Event) return Event < Other.Event; return false; } //bool operator <= (const TEventKey & Other); bool operator == (const TEventKey & Other) const { return (TimeStamp == Other.TimeStamp) && (Event == Other.Event); } //bool operator >= (const TEventKey & Other); bool operator > (const TEventKey & Other) const { if (TimeStamp != Other.TimeStamp) return TimeStamp > Other.TimeStamp; if (Event != Other.Event) return Event > Other.Event; return false; } } TEventKey; /** \brief The data of an Event A event's data is variable length. The data is a TDBTEvent-structure followed by varaible length data. - fixed data - blob data (mostly UTF8 message body) **/ typedef struct TEvent { uint32_t Flags; /// Flags uint32_t TimeStamp; /// Timestamp of the event (seconds elapsed since 1.1.1970) used as key element uint32_t Type; /// Eventtype TDBTEntityHandle Entity; /// hEntity which owns this event uint32_t DataLength; /// Length of the stored data in bytes uint8_t Reserved[8]; /// reserved storage } TEvent; #pragma pack(pop) static const uint32_t cEventSignature = 0x365A7E92; static const uint16_t cEventNodeSignature = 0x195C; /** \brief Manages the Events Index in the Database **/ class CEventsTree : public CFileBTree { private: TDBTEntityHandle m_Entity; public: CEventsTree(CBlockManager & BlockManager, TNodeRef RootNode, TDBTEntityHandle Entity) : CFileBTree::CFileBTree(BlockManager, RootNode, cEventNodeSignature), m_Entity(Entity) { }; ~CEventsTree() { }; TDBTEntityHandle Entity() { return m_Entity; }; void Entity(TDBTEntityHandle NewEntity) { m_Entity = NewEntity; }; }; /** \brief Manages the Virtual Events Index Sorry for duplicating code... **/ class CVirtualEventsTree : public CBTree { private: TDBTEntityHandle m_Entity; public: CVirtualEventsTree(TDBTEntityHandle Entity) : CBTree::CBTree(0), m_Entity(Entity) { }; ~CVirtualEventsTree() { }; TDBTEntityHandle Entity() { return m_Entity; }; void Entity(TDBTEntityHandle NewEntity) { m_Entity = NewEntity; }; }; class CEventsTypeManager { public: CEventsTypeManager(CEntities & Entities, CSettings & Settings); ~CEventsTypeManager(); uint32_t MakeGlobalID(char* Module, uint32_t EventType); bool GetType(uint32_t GlobalID, char * & Module, uint32_t & EventType); uint32_t EnsureIDExists(char* Module, uint32_t EventType); private: typedef struct TEventType { char * ModuleName; uint32_t EventType; } TEventType, *PEventType; #ifdef _MSC_VER typedef stdext::hash_map TTypeMap; #else typedef __gnu_cxx::hash_map TTypeMap; #endif CEntities & m_Entities; CSettings & m_Settings; TTypeMap m_Map; }; class CEvents : public sigslot::has_slots<> { public: CEvents( CBlockManager & BlockManager, CEncryptionManager & EncryptionManager, CEntities & Entities, CSettings & Settings ); ~CEvents(); //compatibility TDBTEventHandle compFirstEvent(TDBTEntityHandle hEntity); TDBTEventHandle compFirstUnreadEvent(TDBTEntityHandle hEntity); TDBTEventHandle compLastEvent(TDBTEntityHandle hEntity); TDBTEventHandle compNextEvent(TDBTEventHandle hEvent); TDBTEventHandle compPrevEvent(TDBTEventHandle hEvent); //services unsigned int GetBlobSize(TDBTEventHandle hEvent); unsigned int Get(TDBTEventHandle hEvent, TDBTEvent & Event); unsigned int GetCount(TDBTEntityHandle hEntity); unsigned int Delete(TDBTEventHandle hEvent); TDBTEventHandle Add(TDBTEntityHandle hEntity, TDBTEvent & Event); unsigned int MarkRead(TDBTEventHandle hEvent); unsigned int WriteToDisk(TDBTEventHandle hEvent); TDBTEntityHandle getEntity(TDBTEventHandle hEvent); TDBTEventIterationHandle IterationInit(TDBTEventIterFilter & Filter); TDBTEventHandle IterationNext(TDBTEventIterationHandle Iteration); unsigned int IterationClose(TDBTEventIterationHandle Iteration); private: typedef CBTree TEventBase; typedef struct { CEventsTree * RealTree; CVirtualEventsTree * VirtualTree; uint32_t VirtualCount; TEventKey FirstVirtualUnread; } TEntityEventsRecord, *PEntityEventsRecord; #ifdef _MSC_VER typedef stdext::hash_map TEntityEventsMap; #else typedef __gnu_cxx::hash_map TEntityEventsMap; #endif typedef CIterationHeap TEventsHeap; CBlockManager & m_BlockManager; CEncryptionManager & m_EncryptionManager; CEntities & m_Entities; CEventsTypeManager m_Types; TEntityEventsMap m_EntityEventsMap; typedef struct TEventIteration { TDBTEventIterFilter Filter; TEventsHeap * Heap; TDBTEventHandle LastEvent; } TEventIteration, *PEventIteration; void onRootChanged(void* EventsTree, CEventsTree::TNodeRef NewRoot); void onDeleteEventCallback(void * Tree, const TEventKey & Key, uint32_t Param); void onDeleteVirtualEventCallback(void * Tree, const TEventKey & Key, uint32_t Param); void onDeleteEvents(CEntities * Entities, TDBTEntityHandle hEntity); void onTransferEvents(CEntities * Entities, TDBTEntityHandle Source, TDBTEntityHandle Dest); PEntityEventsRecord getEntityRecord(TDBTEntityHandle hEntity); uint32_t adjustVirtualEventCount(PEntityEventsRecord Record, int32_t Adjust); bool MarkEventsTree(TEventBase::iterator Iterator, TDBTEventHandle FirstUnread); void FindNextUnreadEvent(TEventBase::iterator & Iterator); };