author | zecke <zecke> | 2002-10-10 17:08:58 (UTC) |
---|---|---|
committer | zecke <zecke> | 2002-10-10 17:08:58 (UTC) |
commit | 1dcc1b1fc9fd35d959255452c8b5be1269ca4f44 (patch) (side-by-side diff) | |
tree | 469d239dec74f5751f3aced43c4bae1f0f3a42e3 | |
parent | aa38f642a07810515dcc18ea38bf520e26d7f88e (diff) | |
download | opie-1dcc1b1fc9fd35d959255452c8b5be1269ca4f44.zip opie-1dcc1b1fc9fd35d959255452c8b5be1269ca4f44.tar.gz opie-1dcc1b1fc9fd35d959255452c8b5be1269ca4f44.tar.bz2 |
The Cache is finally in place
I tested it with my todolist and it 'works' for 10.000 todos the hits are awesome ;)
The read ahead functionality does not make sense for XMLs backends because most of the stuff is already in memory. While using readahead on SQL makes things a lot faster....
I still have to fully implement read ahead
This change is bic but sc
-rw-r--r-- | libopie/pim/obackendfactory.h | 20 | ||||
-rw-r--r-- | libopie/pim/opimaccessbackend.h | 40 | ||||
-rw-r--r-- | libopie/pim/opimaccesstemplate.h | 57 | ||||
-rw-r--r-- | libopie/pim/opimcache.h | 117 | ||||
-rw-r--r-- | libopie/pim/orecordlist.h | 20 | ||||
-rw-r--r-- | libopie/pim/otemplatebase.h | 11 | ||||
-rw-r--r-- | libopie2/opiepim/backend/obackendfactory.h | 20 | ||||
-rw-r--r-- | libopie2/opiepim/backend/opimaccessbackend.h | 40 | ||||
-rw-r--r-- | libopie2/opiepim/core/opimaccesstemplate.h | 57 | ||||
-rw-r--r-- | libopie2/opiepim/core/opimcache.h | 117 | ||||
-rw-r--r-- | libopie2/opiepim/core/otemplatebase.h | 11 | ||||
-rw-r--r-- | libopie2/opiepim/orecordlist.h | 20 |
12 files changed, 496 insertions, 34 deletions
diff --git a/libopie/pim/obackendfactory.h b/libopie/pim/obackendfactory.h index f11f029..89b8c58 100644 --- a/libopie/pim/obackendfactory.h +++ b/libopie/pim/obackendfactory.h @@ -7,49 +7,57 @@ * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; * either version 2 of the License, or (at your option) any later * version. * ===================================================================== * ToDo: Use plugins * ===================================================================== * Version: $Id$ * ===================================================================== * History: * $Log$ + * Revision 1.3 2002/10/10 17:08:58 zecke + * The Cache is finally in place + * I tested it with my todolist and it 'works' for 10.000 todos the hits are awesome ;) + * The read ahead functionality does not make sense for XMLs backends because most of the stuff is already in memory. While using readahead on SQL makes things a lot faster.... + * I still have to fully implement read ahead + * This change is bic but sc + * * Revision 1.2 2002/10/08 09:27:36 eilers * Fixed libopie.pro to include the new pim-API. * The SQL-Stuff is currently deactivated. Otherwise everyone who wants to * compile itself would need to install libsqlite, libopiesql... * Therefore, the backend currently uses XML only.. * * Revision 1.1 2002/10/07 17:35:01 eilers * added OBackendFactory for advanced backend access * * * ===================================================================== */ -#ifndef __OPIE_BACKENDFACTORY_H_ -#define __OPIE_BACKENDFACTORY_H_ +#ifndef OPIE_BACKENDFACTORY_H_ +#define OPIE_BACKENDFACTORY_H_ #include <qstring.h> #include <qasciidict.h> #include <qpe/config.h> #include "otodoaccessxml.h" #include "ocontactaccessbackend_xml.h" -#ifdef __USE_SQL +/*#ifdef __USE_SQL #include "otodoaccesssql.h" #endif +*/ template<class T> class OBackendFactory { public: OBackendFactory() {}; enum BACKENDS { TODO, CONTACT, DATE }; @@ -63,31 +71,31 @@ class OBackendFactory QAsciiDict<int> dict ( 3 ); dict.setAutoDelete ( TRUE ); dict.insert( "todo", new int (TODO) ); dict.insert( "contact", new int (CONTACT) ); qWarning ("TODO is: %d", TODO); qWarning ("CONTACT is: %d", CONTACT); switch ( *dict.take( backendName ) ){ case TODO: -#ifdef __USE_SQL +/*#ifdef __USE_SQL if ( backend == "sql" ) return (T*) new OTodoAccessBackendSQL(""); -#else +#else*/ if ( backend == "sql" ) qWarning ("OBackendFactory:: sql Backend not implemented! Using XML instead!"); -#endif +//#endif return (T*) new OTodoAccessXML( appName ); case CONTACT: if ( backend == "sql" ) qWarning ("OBackendFactory:: sql Backend not implemented! Using XML instead!"); return (T*) new OContactAccessBackend_XML( appName ); case DATE: qWarning ("OBackendFactory:: DATE-Backend not implemented!"); return NULL; default: return NULL; diff --git a/libopie/pim/opimaccessbackend.h b/libopie/pim/opimaccessbackend.h index c27acbb..27d3cb8 100644 --- a/libopie/pim/opimaccessbackend.h +++ b/libopie/pim/opimaccessbackend.h @@ -1,31 +1,33 @@ #ifndef OPIE_PIM_ACCESS_BACKEND #define OPIE_PIM_ACCESS_BACKEND #include <qarray.h> +#include <opie/otemplatebase.h> #include <opie/opimrecord.h> /** * OPimAccessBackend is the base class * for all private backends * it operates on OPimRecord as the base class * and it's responsible for fast manipulating * the resource the implementation takes care * of */ template <class T = OPimRecord> class OPimAccessBackend { public: + typedef OTemplateBase<T> Frontend; OPimAccessBackend(); virtual ~OPimAccessBackend(); /** * load the resource */ virtual bool load() = 0; /** * reload the resource */ virtual bool reload() = 0; @@ -45,45 +47,81 @@ public: /** * queryByExample for T with the SortOrder * sort */ virtual QArray<int> queryByExample( const T& t, int sort ) = 0; /** * find the OPimRecord with uid @param uid * returns T and T.isEmpty() if nothing was found */ virtual T find(int uid )const = 0; + virtual T find(int uid, const QArray<int>& items, + uint current, Frontend::CacheDirection )const ; /** * clear the back end */ virtual void clear() = 0; /** * add T */ virtual bool add( const T& t ) = 0; /** * remove */ virtual bool remove( int uid ) = 0; /** * replace a record with T.uid() */ virtual bool replace( const T& t ) = 0; + /* + * setTheFrontEnd!!! + */ + void setFrontend( Frontend* front ); + +protected: + void cache( const T& t )const; + + /** + * use a prime number here! + */ + void setSaneCacheSize( int ); + +private: + Frontend* m_front; }; template <class T> OPimAccessBackend<T>::OPimAccessBackend() { - + m_front = 0l; } template <class T> OPimAccessBackend<T>::~OPimAccessBackend() { } +template <class T> +void OPimAccessBackend<T>::setFrontend( Frontend* fr ) { + m_front = fr; +} +template <class T> +void OPimAccessBackend<T>::cache( const T& t )const { + if (m_front ) + m_front->cache( t ); +} +template <class T> +void OPimAccessBackend<T>::setSaneCacheSize( int size) { + if (m_front ) + m_front->setSaneCacheSize( size ); +} +template <class T> +T OPimAccessBackend<T>::find( int uid, const QArray<int>&, + uint, Frontend::CacheDirection )const { + return find( uid ); +} #endif diff --git a/libopie/pim/opimaccesstemplate.h b/libopie/pim/opimaccesstemplate.h index 31ab516..92d7192 100644 --- a/libopie/pim/opimaccesstemplate.h +++ b/libopie/pim/opimaccesstemplate.h @@ -1,37 +1,39 @@ #ifndef OPIE_PIM_ACCESS_TEMPLATE_H #define OPIE_PIM_ACCESS_TEMPLATE_H #include <qarray.h> #include <opie/opimrecord.h> #include <opie/opimaccessbackend.h> #include <opie/orecordlist.h> +#include "opimcache.h" #include "otemplatebase.h" /** * Thats the frontend to our OPIE PIM * Library. Either you want to use it's * interface or you want to implement * your own Access lib * Just create a OPimRecord and inherit from * the plugins */ template <class T = OPimRecord > class OPimAccessTemplate : public OTemplateBase<T> { public: typedef ORecordList<T> List; typedef OPimAccessBackend<T> BackEnd; + typedef OPimCache<T> Cache; /** * our sort order * should be safe explaining */ enum SortOrder { WildCards = 0, IgnoreCase = 1, RegExp = 2, ExactMatch = 4 }; /** * c'tor BackEnd */ OPimAccessTemplate( BackEnd* end); @@ -64,24 +66,30 @@ public: virtual List allRecords()const; /** * queryByExample */ virtual List queryByExample( const T& t, int sortOrder ); /** * find the OPimRecord uid */ virtual T find( int uid )const; + /** + * read ahead cache find method ;) + */ + virtual T find( int uid, const QArray<int>&, + uint current, CacheDirection dir = Forward )const; + /* invalidate cache here */ /** * clears the backend and invalidates the backend */ virtual void clear() ; /** * add T to the backend */ virtual bool add( const T& t ) ; /* only the uid matters */ @@ -90,52 +98,61 @@ public: */ virtual bool remove( const T& t ); /** * remove the OPimRecord with uid */ virtual bool remove( int uid ); /** * replace T from backend */ virtual bool replace( const T& t) ; + + /** + * @internal + */ + void cache( const T& )const; + void setSaneCacheSize( int ); protected: /** * invalidate the cache */ void invalidateCache(); void setBackEnd( BackEnd* end ); /** * returns the backend */ BackEnd* backEnd(); BackEnd* m_backEnd; + Cache m_cache; }; template <class T> OPimAccessTemplate<T>::OPimAccessTemplate( BackEnd* end ) : OTemplateBase<T>(), m_backEnd( end ) { - + if (end ) + end->setFrontend( this ); } template <class T> OPimAccessTemplate<T>::~OPimAccessTemplate() { qWarning("~OPimAccessTemplate<T>"); delete m_backEnd; } template <class T> bool OPimAccessTemplate<T>::load() { + invalidateCache(); return m_backEnd->load(); } template <class T> bool OPimAccessTemplate<T>::reload() { return m_backEnd->reload(); } template <class T> bool OPimAccessTemplate<T>::save() { return m_backEnd->save(); } template <class T> OPimAccessTemplate<T>::List OPimAccessTemplate<T>::allRecords()const { @@ -145,52 +162,86 @@ OPimAccessTemplate<T>::List OPimAccessTemplate<T>::allRecords()const { } template <class T> OPimAccessTemplate<T>::List OPimAccessTemplate<T>::queryByExample( const T& t, int sortOrder ) { QArray<int> ints = m_backEnd->queryByExample( t, sortOrder ); List lis(ints, this ); return lis; } template <class T> T OPimAccessTemplate<T>::find( int uid ) const{ T t = m_backEnd->find( uid ); + cache( t ); + return t; +} +template <class T> +T OPimAccessTemplate<T>::find( int uid, const QArray<int>& ar, + uint current, CacheDirection dir )const { + /* + * better do T.isEmpty() + * after a find this way we would + * avoid two finds in QCache... + */ + // qWarning("find it now %d", uid ); + if (m_cache.contains( uid ) ) { + qWarning("m cache contains %d", uid); + return m_cache.find( uid ); + } + + T t = m_backEnd->find( uid, ar, current, dir ); + qWarning("found it and cache it now %d", uid); + cache( t ); return t; } template <class T> void OPimAccessTemplate<T>::clear() { invalidateCache(); m_backEnd->clear(); } template <class T> bool OPimAccessTemplate<T>::add( const T& t ) { + cache( t ); return m_backEnd->add( t ); } template <class T> bool OPimAccessTemplate<T>::remove( const T& t ) { - return m_backEnd->remove( t.uid() ); + return remove( t.uid() ); } template <class T> bool OPimAccessTemplate<T>::remove( int uid ) { + m_cache.remove( uid ); return m_backEnd->remove( uid ); } template <class T> bool OPimAccessTemplate<T>::replace( const T& t ) { + m_cache.replace( t ); return m_backEnd->replace( t ); } template <class T> void OPimAccessTemplate<T>::invalidateCache() { - + m_cache.invalidate(); } template <class T> OPimAccessTemplate<T>::BackEnd* OPimAccessTemplate<T>::backEnd() { return m_backEnd; } template <class T> bool OPimAccessTemplate<T>::wasChangedExternally()const { return false; } template <class T> void OPimAccessTemplate<T>::setBackEnd( BackEnd* end ) { m_backEnd = end; + if (m_backEnd ) + m_backEnd->setFrontend( this ); +} +template <class T> +void OPimAccessTemplate<T>::cache( const T& t ) const{ + /* hacky we need to work around the const*/ + ((OPimAccessTemplate<T>*)this)->m_cache.add( t ); +} +template <class T> +void OPimAccessTemplate<T>::setSaneCacheSize( int size ) { + m_cache.setSize( size ); } #endif diff --git a/libopie/pim/opimcache.h b/libopie/pim/opimcache.h new file mode 100644 index 0000000..067f6e7 --- a/dev/null +++ b/libopie/pim/opimcache.h @@ -0,0 +1,117 @@ +#ifndef OPIE_PIM_CACHE_H +#define OPIE_PIM_CACHE_H + +#include <qintcache.h> + +#include "opimrecord.h" + +template <class T = OPimRecord> +class OPimCacheItem { +public: + OPimCacheItem( const T& t = T() ); + ~OPimCacheItem(); + + T record()const; + void setRecord( const T& ); +private: + T m_t; +}; + +/** + * OPimCache for caching the items + * We support adding, removing + * and finding + */ +template <class T = OPimRecord> +class OPimCache { +public: + typedef OPimCacheItem<T> Item; + OPimCache(); + ~OPimCache(); + + bool contains(int uid)const; + void invalidate(); + void setSize( int size ); + + T find(int uid )const; + void add( const T& ); + void remove( int uid ); + void replace( const T& ); + +private: + QIntCache<Item> m_cache; +}; + +// Implementation +template <class T> +OPimCacheItem<T>::OPimCacheItem( const T& t ) + : m_t(t) { +} +template <class T> +OPimCacheItem<T>::~OPimCacheItem() { + +} +template <class T> +T OPimCacheItem<T>::record()const { + return m_t; +} +template <class T> +void OPimCacheItem<T>::setRecord( const T& t ) { + m_t = t; +} +// Cache +template <class T> +OPimCache<T>::OPimCache() { + m_cache.setAutoDelete( TRUE ); +} +template <class T> +OPimCache<T>::~OPimCache() { + +} +template <class T> +bool OPimCache<T>::contains(int uid )const { + Item* it = m_cache.find( uid, FALSE ); + if (!it) + return false; + return true; +} +template <class T> +void OPimCache<T>::invalidate() { + m_cache.clear(); +} +template <class T> +void OPimCache<T>::setSize( int size ) { + m_cache.setMaxCost( size ); +} +template <class T> +T OPimCache<T>::find(int uid )const { + Item *it = m_cache.find( uid ); + if (it) + return it->record(); + return T(); +} +template <class T> +void OPimCache<T>::add( const T& t ) { + Item* it = 0l; + it = m_cache.find(t.uid(), FALSE ); + + if (it ) + it->setRecord( t ); + + it = new Item( t ); + if (!m_cache.insert( t.uid(), it ) ) + delete it; +} +template <class T> +void OPimCache<T>::remove( int uid ) { + m_cache.remove( uid ); +} +template <class T> +void OPimCache<T>::replace( const T& t) { + Item *it = m_cache.find( t.uid() ); + if ( it ) { + it->setRecord( t ); + } +} + +#endif diff --git a/libopie/pim/orecordlist.h b/libopie/pim/orecordlist.h index b6fa7fa..08f5c85 100644 --- a/libopie/pim/orecordlist.h +++ b/libopie/pim/orecordlist.h @@ -59,24 +59,25 @@ public: /** * sets the current item */ void setCurrent( uint cur ); private: QArray<int> m_uids; uint m_current; const Base* m_temp; bool m_end : 1; T m_record; + bool m_direction :1; /* d pointer for future versions */ class IteratorPrivate; IteratorPrivate *d; }; /** * The recordlist used as a return type * from OPimAccessTemplate */ template <class T = OPimRecord > class ORecordList { public: @@ -116,78 +117,81 @@ public: private: QArray<int> m_ids; const Base* m_acc; }; /* ok now implement it */ template <class T> ORecordListIterator<T>::ORecordListIterator() { m_current = 0; m_temp = 0l; m_end = true; m_record = T(); + /* forward */ + m_direction = TRUE; } template <class T> ORecordListIterator<T>::~ORecordListIterator() { /* nothing to delete */ } template <class T> ORecordListIterator<T>::ORecordListIterator( const ORecordListIterator<T>& it) { // qWarning("ORecordListIterator copy c'tor"); m_uids = it.m_uids; m_current = it.m_current; m_temp = it.m_temp; m_end = it.m_end; m_record = it.m_record; + m_direction = it.m_direction; } template <class T> ORecordListIterator<T> &ORecordListIterator<T>::operator=( const ORecordListIterator<T>& it) { m_uids = it.m_uids; m_current = it.m_current; m_temp = it.m_temp; m_end = it.m_end; m_record = it.m_record; return *this; } template <class T> T ORecordListIterator<T>::operator*() { qWarning("operator* %d %d", m_current, m_uids[m_current] ); if (!m_end ) - /* FIXME - * until the cache is in place - * we do the uid match uid check - */ - m_record = m_temp->find( m_uids[m_current] ); + m_record = m_temp->find( m_uids[m_current], m_uids, m_current, + m_direction ? Base::Forward : + Base::Reverse ); else m_record = T(); return m_record; } template <class T> ORecordListIterator<T> &ORecordListIterator<T>::operator++() { + m_direction = true; if (m_current < m_uids.count() ) { m_end = false; ++m_current; }else m_end = true; return *this; } template <class T> ORecordListIterator<T> &ORecordListIterator<T>::operator--() { + m_direction = false; if ( m_current > 0 ) { --m_current; m_end = false; } else m_end = true; return *this; } template <class T> bool ORecordListIterator<T>::operator==( const ORecordListIterator<T>& it ) { @@ -198,25 +202,26 @@ bool ORecordListIterator<T>::operator==( const ORecordListIterator<T>& it ) { if ( m_current != it.m_current ) return false; if ( m_temp != it.m_temp ) return false; return true; } template <class T> bool ORecordListIterator<T>::operator!=( const ORecordListIterator<T>& it ) { return !(*this == it ); } template <class T> ORecordListIterator<T>::ORecordListIterator( const QArray<int> uids, const Base* t ) - : m_uids( uids ), m_current( 0 ), m_temp( t ), m_end( false ) + : m_uids( uids ), m_current( 0 ), m_temp( t ), m_end( false ), + m_direction( false ) { } template <class T> uint ORecordListIterator<T>::current()const { return m_current; } template <class T> void ORecordListIterator<T>::setCurrent( uint cur ) { if( cur < m_uids.count() ) { m_end = false; m_current= cur; } @@ -245,15 +250,16 @@ ORecordList<T>::Iterator ORecordList<T>::end() { Iterator it( m_ids, m_acc ); it.m_end = true; it.m_current = m_ids.count(); return it; } template <class T> uint ORecordList<T>::count()const { return m_ids.count(); } template <class T> T ORecordList<T>::operator[]( uint i ) { - return m_acc->find( m_ids[i] ); + /* forward */ + return m_acc->find( m_ids[i], m_ids, i ); } #endif diff --git a/libopie/pim/otemplatebase.h b/libopie/pim/otemplatebase.h index f71417b..b855919 100644 --- a/libopie/pim/otemplatebase.h +++ b/libopie/pim/otemplatebase.h @@ -1,21 +1,32 @@ #ifndef OPIE_TEMPLATE_BASE_H #define OPIE_TEMPLATE_BASE_H +#include <qarray.h> + #include "opimrecord.h" /** * internal template base */ template <class T = OPimRecord> class OTemplateBase { public: + enum CacheDirection { Forward=0, Reverse }; OTemplateBase() { }; virtual ~OTemplateBase() { } virtual T find( int uid )const = 0; + /** + * read ahead find + */ + virtual T find( int uid, const QArray<int>& items, + uint current, CacheDirection dir = Forward )const = 0; + virtual void cache( const T& )const = 0; + virtual void setSaneCacheSize( int ) = 0; + }; #endif diff --git a/libopie2/opiepim/backend/obackendfactory.h b/libopie2/opiepim/backend/obackendfactory.h index f11f029..89b8c58 100644 --- a/libopie2/opiepim/backend/obackendfactory.h +++ b/libopie2/opiepim/backend/obackendfactory.h @@ -7,49 +7,57 @@ * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; * either version 2 of the License, or (at your option) any later * version. * ===================================================================== * ToDo: Use plugins * ===================================================================== * Version: $Id$ * ===================================================================== * History: * $Log$ + * Revision 1.3 2002/10/10 17:08:58 zecke + * The Cache is finally in place + * I tested it with my todolist and it 'works' for 10.000 todos the hits are awesome ;) + * The read ahead functionality does not make sense for XMLs backends because most of the stuff is already in memory. While using readahead on SQL makes things a lot faster.... + * I still have to fully implement read ahead + * This change is bic but sc + * * Revision 1.2 2002/10/08 09:27:36 eilers * Fixed libopie.pro to include the new pim-API. * The SQL-Stuff is currently deactivated. Otherwise everyone who wants to * compile itself would need to install libsqlite, libopiesql... * Therefore, the backend currently uses XML only.. * * Revision 1.1 2002/10/07 17:35:01 eilers * added OBackendFactory for advanced backend access * * * ===================================================================== */ -#ifndef __OPIE_BACKENDFACTORY_H_ -#define __OPIE_BACKENDFACTORY_H_ +#ifndef OPIE_BACKENDFACTORY_H_ +#define OPIE_BACKENDFACTORY_H_ #include <qstring.h> #include <qasciidict.h> #include <qpe/config.h> #include "otodoaccessxml.h" #include "ocontactaccessbackend_xml.h" -#ifdef __USE_SQL +/*#ifdef __USE_SQL #include "otodoaccesssql.h" #endif +*/ template<class T> class OBackendFactory { public: OBackendFactory() {}; enum BACKENDS { TODO, CONTACT, DATE }; @@ -63,31 +71,31 @@ class OBackendFactory QAsciiDict<int> dict ( 3 ); dict.setAutoDelete ( TRUE ); dict.insert( "todo", new int (TODO) ); dict.insert( "contact", new int (CONTACT) ); qWarning ("TODO is: %d", TODO); qWarning ("CONTACT is: %d", CONTACT); switch ( *dict.take( backendName ) ){ case TODO: -#ifdef __USE_SQL +/*#ifdef __USE_SQL if ( backend == "sql" ) return (T*) new OTodoAccessBackendSQL(""); -#else +#else*/ if ( backend == "sql" ) qWarning ("OBackendFactory:: sql Backend not implemented! Using XML instead!"); -#endif +//#endif return (T*) new OTodoAccessXML( appName ); case CONTACT: if ( backend == "sql" ) qWarning ("OBackendFactory:: sql Backend not implemented! Using XML instead!"); return (T*) new OContactAccessBackend_XML( appName ); case DATE: qWarning ("OBackendFactory:: DATE-Backend not implemented!"); return NULL; default: return NULL; diff --git a/libopie2/opiepim/backend/opimaccessbackend.h b/libopie2/opiepim/backend/opimaccessbackend.h index c27acbb..27d3cb8 100644 --- a/libopie2/opiepim/backend/opimaccessbackend.h +++ b/libopie2/opiepim/backend/opimaccessbackend.h @@ -1,31 +1,33 @@ #ifndef OPIE_PIM_ACCESS_BACKEND #define OPIE_PIM_ACCESS_BACKEND #include <qarray.h> +#include <opie/otemplatebase.h> #include <opie/opimrecord.h> /** * OPimAccessBackend is the base class * for all private backends * it operates on OPimRecord as the base class * and it's responsible for fast manipulating * the resource the implementation takes care * of */ template <class T = OPimRecord> class OPimAccessBackend { public: + typedef OTemplateBase<T> Frontend; OPimAccessBackend(); virtual ~OPimAccessBackend(); /** * load the resource */ virtual bool load() = 0; /** * reload the resource */ virtual bool reload() = 0; @@ -45,45 +47,81 @@ public: /** * queryByExample for T with the SortOrder * sort */ virtual QArray<int> queryByExample( const T& t, int sort ) = 0; /** * find the OPimRecord with uid @param uid * returns T and T.isEmpty() if nothing was found */ virtual T find(int uid )const = 0; + virtual T find(int uid, const QArray<int>& items, + uint current, Frontend::CacheDirection )const ; /** * clear the back end */ virtual void clear() = 0; /** * add T */ virtual bool add( const T& t ) = 0; /** * remove */ virtual bool remove( int uid ) = 0; /** * replace a record with T.uid() */ virtual bool replace( const T& t ) = 0; + /* + * setTheFrontEnd!!! + */ + void setFrontend( Frontend* front ); + +protected: + void cache( const T& t )const; + + /** + * use a prime number here! + */ + void setSaneCacheSize( int ); + +private: + Frontend* m_front; }; template <class T> OPimAccessBackend<T>::OPimAccessBackend() { - + m_front = 0l; } template <class T> OPimAccessBackend<T>::~OPimAccessBackend() { } +template <class T> +void OPimAccessBackend<T>::setFrontend( Frontend* fr ) { + m_front = fr; +} +template <class T> +void OPimAccessBackend<T>::cache( const T& t )const { + if (m_front ) + m_front->cache( t ); +} +template <class T> +void OPimAccessBackend<T>::setSaneCacheSize( int size) { + if (m_front ) + m_front->setSaneCacheSize( size ); +} +template <class T> +T OPimAccessBackend<T>::find( int uid, const QArray<int>&, + uint, Frontend::CacheDirection )const { + return find( uid ); +} #endif diff --git a/libopie2/opiepim/core/opimaccesstemplate.h b/libopie2/opiepim/core/opimaccesstemplate.h index 31ab516..92d7192 100644 --- a/libopie2/opiepim/core/opimaccesstemplate.h +++ b/libopie2/opiepim/core/opimaccesstemplate.h @@ -1,37 +1,39 @@ #ifndef OPIE_PIM_ACCESS_TEMPLATE_H #define OPIE_PIM_ACCESS_TEMPLATE_H #include <qarray.h> #include <opie/opimrecord.h> #include <opie/opimaccessbackend.h> #include <opie/orecordlist.h> +#include "opimcache.h" #include "otemplatebase.h" /** * Thats the frontend to our OPIE PIM * Library. Either you want to use it's * interface or you want to implement * your own Access lib * Just create a OPimRecord and inherit from * the plugins */ template <class T = OPimRecord > class OPimAccessTemplate : public OTemplateBase<T> { public: typedef ORecordList<T> List; typedef OPimAccessBackend<T> BackEnd; + typedef OPimCache<T> Cache; /** * our sort order * should be safe explaining */ enum SortOrder { WildCards = 0, IgnoreCase = 1, RegExp = 2, ExactMatch = 4 }; /** * c'tor BackEnd */ OPimAccessTemplate( BackEnd* end); @@ -64,24 +66,30 @@ public: virtual List allRecords()const; /** * queryByExample */ virtual List queryByExample( const T& t, int sortOrder ); /** * find the OPimRecord uid */ virtual T find( int uid )const; + /** + * read ahead cache find method ;) + */ + virtual T find( int uid, const QArray<int>&, + uint current, CacheDirection dir = Forward )const; + /* invalidate cache here */ /** * clears the backend and invalidates the backend */ virtual void clear() ; /** * add T to the backend */ virtual bool add( const T& t ) ; /* only the uid matters */ @@ -90,52 +98,61 @@ public: */ virtual bool remove( const T& t ); /** * remove the OPimRecord with uid */ virtual bool remove( int uid ); /** * replace T from backend */ virtual bool replace( const T& t) ; + + /** + * @internal + */ + void cache( const T& )const; + void setSaneCacheSize( int ); protected: /** * invalidate the cache */ void invalidateCache(); void setBackEnd( BackEnd* end ); /** * returns the backend */ BackEnd* backEnd(); BackEnd* m_backEnd; + Cache m_cache; }; template <class T> OPimAccessTemplate<T>::OPimAccessTemplate( BackEnd* end ) : OTemplateBase<T>(), m_backEnd( end ) { - + if (end ) + end->setFrontend( this ); } template <class T> OPimAccessTemplate<T>::~OPimAccessTemplate() { qWarning("~OPimAccessTemplate<T>"); delete m_backEnd; } template <class T> bool OPimAccessTemplate<T>::load() { + invalidateCache(); return m_backEnd->load(); } template <class T> bool OPimAccessTemplate<T>::reload() { return m_backEnd->reload(); } template <class T> bool OPimAccessTemplate<T>::save() { return m_backEnd->save(); } template <class T> OPimAccessTemplate<T>::List OPimAccessTemplate<T>::allRecords()const { @@ -145,52 +162,86 @@ OPimAccessTemplate<T>::List OPimAccessTemplate<T>::allRecords()const { } template <class T> OPimAccessTemplate<T>::List OPimAccessTemplate<T>::queryByExample( const T& t, int sortOrder ) { QArray<int> ints = m_backEnd->queryByExample( t, sortOrder ); List lis(ints, this ); return lis; } template <class T> T OPimAccessTemplate<T>::find( int uid ) const{ T t = m_backEnd->find( uid ); + cache( t ); + return t; +} +template <class T> +T OPimAccessTemplate<T>::find( int uid, const QArray<int>& ar, + uint current, CacheDirection dir )const { + /* + * better do T.isEmpty() + * after a find this way we would + * avoid two finds in QCache... + */ + // qWarning("find it now %d", uid ); + if (m_cache.contains( uid ) ) { + qWarning("m cache contains %d", uid); + return m_cache.find( uid ); + } + + T t = m_backEnd->find( uid, ar, current, dir ); + qWarning("found it and cache it now %d", uid); + cache( t ); return t; } template <class T> void OPimAccessTemplate<T>::clear() { invalidateCache(); m_backEnd->clear(); } template <class T> bool OPimAccessTemplate<T>::add( const T& t ) { + cache( t ); return m_backEnd->add( t ); } template <class T> bool OPimAccessTemplate<T>::remove( const T& t ) { - return m_backEnd->remove( t.uid() ); + return remove( t.uid() ); } template <class T> bool OPimAccessTemplate<T>::remove( int uid ) { + m_cache.remove( uid ); return m_backEnd->remove( uid ); } template <class T> bool OPimAccessTemplate<T>::replace( const T& t ) { + m_cache.replace( t ); return m_backEnd->replace( t ); } template <class T> void OPimAccessTemplate<T>::invalidateCache() { - + m_cache.invalidate(); } template <class T> OPimAccessTemplate<T>::BackEnd* OPimAccessTemplate<T>::backEnd() { return m_backEnd; } template <class T> bool OPimAccessTemplate<T>::wasChangedExternally()const { return false; } template <class T> void OPimAccessTemplate<T>::setBackEnd( BackEnd* end ) { m_backEnd = end; + if (m_backEnd ) + m_backEnd->setFrontend( this ); +} +template <class T> +void OPimAccessTemplate<T>::cache( const T& t ) const{ + /* hacky we need to work around the const*/ + ((OPimAccessTemplate<T>*)this)->m_cache.add( t ); +} +template <class T> +void OPimAccessTemplate<T>::setSaneCacheSize( int size ) { + m_cache.setSize( size ); } #endif diff --git a/libopie2/opiepim/core/opimcache.h b/libopie2/opiepim/core/opimcache.h new file mode 100644 index 0000000..067f6e7 --- a/dev/null +++ b/libopie2/opiepim/core/opimcache.h @@ -0,0 +1,117 @@ +#ifndef OPIE_PIM_CACHE_H +#define OPIE_PIM_CACHE_H + +#include <qintcache.h> + +#include "opimrecord.h" + +template <class T = OPimRecord> +class OPimCacheItem { +public: + OPimCacheItem( const T& t = T() ); + ~OPimCacheItem(); + + T record()const; + void setRecord( const T& ); +private: + T m_t; +}; + +/** + * OPimCache for caching the items + * We support adding, removing + * and finding + */ +template <class T = OPimRecord> +class OPimCache { +public: + typedef OPimCacheItem<T> Item; + OPimCache(); + ~OPimCache(); + + bool contains(int uid)const; + void invalidate(); + void setSize( int size ); + + T find(int uid )const; + void add( const T& ); + void remove( int uid ); + void replace( const T& ); + +private: + QIntCache<Item> m_cache; +}; + +// Implementation +template <class T> +OPimCacheItem<T>::OPimCacheItem( const T& t ) + : m_t(t) { +} +template <class T> +OPimCacheItem<T>::~OPimCacheItem() { + +} +template <class T> +T OPimCacheItem<T>::record()const { + return m_t; +} +template <class T> +void OPimCacheItem<T>::setRecord( const T& t ) { + m_t = t; +} +// Cache +template <class T> +OPimCache<T>::OPimCache() { + m_cache.setAutoDelete( TRUE ); +} +template <class T> +OPimCache<T>::~OPimCache() { + +} +template <class T> +bool OPimCache<T>::contains(int uid )const { + Item* it = m_cache.find( uid, FALSE ); + if (!it) + return false; + return true; +} +template <class T> +void OPimCache<T>::invalidate() { + m_cache.clear(); +} +template <class T> +void OPimCache<T>::setSize( int size ) { + m_cache.setMaxCost( size ); +} +template <class T> +T OPimCache<T>::find(int uid )const { + Item *it = m_cache.find( uid ); + if (it) + return it->record(); + return T(); +} +template <class T> +void OPimCache<T>::add( const T& t ) { + Item* it = 0l; + it = m_cache.find(t.uid(), FALSE ); + + if (it ) + it->setRecord( t ); + + it = new Item( t ); + if (!m_cache.insert( t.uid(), it ) ) + delete it; +} +template <class T> +void OPimCache<T>::remove( int uid ) { + m_cache.remove( uid ); +} +template <class T> +void OPimCache<T>::replace( const T& t) { + Item *it = m_cache.find( t.uid() ); + if ( it ) { + it->setRecord( t ); + } +} + +#endif diff --git a/libopie2/opiepim/core/otemplatebase.h b/libopie2/opiepim/core/otemplatebase.h index f71417b..b855919 100644 --- a/libopie2/opiepim/core/otemplatebase.h +++ b/libopie2/opiepim/core/otemplatebase.h @@ -1,21 +1,32 @@ #ifndef OPIE_TEMPLATE_BASE_H #define OPIE_TEMPLATE_BASE_H +#include <qarray.h> + #include "opimrecord.h" /** * internal template base */ template <class T = OPimRecord> class OTemplateBase { public: + enum CacheDirection { Forward=0, Reverse }; OTemplateBase() { }; virtual ~OTemplateBase() { } virtual T find( int uid )const = 0; + /** + * read ahead find + */ + virtual T find( int uid, const QArray<int>& items, + uint current, CacheDirection dir = Forward )const = 0; + virtual void cache( const T& )const = 0; + virtual void setSaneCacheSize( int ) = 0; + }; #endif diff --git a/libopie2/opiepim/orecordlist.h b/libopie2/opiepim/orecordlist.h index b6fa7fa..08f5c85 100644 --- a/libopie2/opiepim/orecordlist.h +++ b/libopie2/opiepim/orecordlist.h @@ -59,24 +59,25 @@ public: /** * sets the current item */ void setCurrent( uint cur ); private: QArray<int> m_uids; uint m_current; const Base* m_temp; bool m_end : 1; T m_record; + bool m_direction :1; /* d pointer for future versions */ class IteratorPrivate; IteratorPrivate *d; }; /** * The recordlist used as a return type * from OPimAccessTemplate */ template <class T = OPimRecord > class ORecordList { public: @@ -116,78 +117,81 @@ public: private: QArray<int> m_ids; const Base* m_acc; }; /* ok now implement it */ template <class T> ORecordListIterator<T>::ORecordListIterator() { m_current = 0; m_temp = 0l; m_end = true; m_record = T(); + /* forward */ + m_direction = TRUE; } template <class T> ORecordListIterator<T>::~ORecordListIterator() { /* nothing to delete */ } template <class T> ORecordListIterator<T>::ORecordListIterator( const ORecordListIterator<T>& it) { // qWarning("ORecordListIterator copy c'tor"); m_uids = it.m_uids; m_current = it.m_current; m_temp = it.m_temp; m_end = it.m_end; m_record = it.m_record; + m_direction = it.m_direction; } template <class T> ORecordListIterator<T> &ORecordListIterator<T>::operator=( const ORecordListIterator<T>& it) { m_uids = it.m_uids; m_current = it.m_current; m_temp = it.m_temp; m_end = it.m_end; m_record = it.m_record; return *this; } template <class T> T ORecordListIterator<T>::operator*() { qWarning("operator* %d %d", m_current, m_uids[m_current] ); if (!m_end ) - /* FIXME - * until the cache is in place - * we do the uid match uid check - */ - m_record = m_temp->find( m_uids[m_current] ); + m_record = m_temp->find( m_uids[m_current], m_uids, m_current, + m_direction ? Base::Forward : + Base::Reverse ); else m_record = T(); return m_record; } template <class T> ORecordListIterator<T> &ORecordListIterator<T>::operator++() { + m_direction = true; if (m_current < m_uids.count() ) { m_end = false; ++m_current; }else m_end = true; return *this; } template <class T> ORecordListIterator<T> &ORecordListIterator<T>::operator--() { + m_direction = false; if ( m_current > 0 ) { --m_current; m_end = false; } else m_end = true; return *this; } template <class T> bool ORecordListIterator<T>::operator==( const ORecordListIterator<T>& it ) { @@ -198,25 +202,26 @@ bool ORecordListIterator<T>::operator==( const ORecordListIterator<T>& it ) { if ( m_current != it.m_current ) return false; if ( m_temp != it.m_temp ) return false; return true; } template <class T> bool ORecordListIterator<T>::operator!=( const ORecordListIterator<T>& it ) { return !(*this == it ); } template <class T> ORecordListIterator<T>::ORecordListIterator( const QArray<int> uids, const Base* t ) - : m_uids( uids ), m_current( 0 ), m_temp( t ), m_end( false ) + : m_uids( uids ), m_current( 0 ), m_temp( t ), m_end( false ), + m_direction( false ) { } template <class T> uint ORecordListIterator<T>::current()const { return m_current; } template <class T> void ORecordListIterator<T>::setCurrent( uint cur ) { if( cur < m_uids.count() ) { m_end = false; m_current= cur; } @@ -245,15 +250,16 @@ ORecordList<T>::Iterator ORecordList<T>::end() { Iterator it( m_ids, m_acc ); it.m_end = true; it.m_current = m_ids.count(); return it; } template <class T> uint ORecordList<T>::count()const { return m_ids.count(); } template <class T> T ORecordList<T>::operator[]( uint i ) { - return m_acc->find( m_ids[i] ); + /* forward */ + return m_acc->find( m_ids[i], m_ids, i ); } #endif |