1 From 215b188d891d5236fe94131d176d7ddc3ae02d5d Mon Sep 17 00:00:00 2001
2 From: =?UTF-8?q?Dan=20Vr=C3=A1til?= <dvratil@redhat.com>
3 Date: Fri, 5 Dec 2014 17:12:28 +0100
4 Subject: [PATCH 20/30] Avoid ridiculous amount of SQL queries by caching
7 PartTypes are identified by their FQ name, which is in form NAMESPACE:NAME,
8 where namespace and name are stored in individual columns. For this reason
9 the standard ::retrieveByName() and name cache generated from entities.xslt
10 does not work. This patch adds special handling for PartType table, so that
11 a special PartType::retrieveByFQName() method as well as PartType name cache
12 handling are generated during the XSL Transformation, allowing us to cache
15 This reduces the amount of SQL queries by at least two for each single AKAPPEND,
16 MERGE, STORE and FETCH command, providing a nice performance boost during
19 server/src/handler/append.cpp | 4 ++--
20 server/src/storage/datastore.cpp | 4 +++-
21 server/src/storage/entities-header.xsl | 7 ++++++-
22 server/src/storage/entities-source.xsl | 31 ++++++++++++++++++++++++++++++-
23 server/src/storage/entities.xsl | 7 ++++++-
24 server/src/storage/parttypehelper.cpp | 29 +----------------------------
25 server/src/storage/parttypehelper.h | 13 -------------
26 7 files changed, 48 insertions(+), 47 deletions(-)
28 diff --git a/server/src/handler/append.cpp b/server/src/handler/append.cpp
29 index c503216..b594e27 100644
30 --- a/server/src/handler/append.cpp
31 +++ b/server/src/handler/append.cpp
32 @@ -134,7 +134,7 @@ bool Append::commit()
34 // wrap data into a part
36 - part.setPartType( PartTypeHelper::fromName( "PLD", "RFC822" ) );
37 + part.setPartType( PartType::retrieveByFQName( QLatin1String("PLD"), QLatin1String("RFC822") ) );
38 part.setData( m_data );
39 part.setPimItemId( item.id() );
40 part.setDatasize( dataSize );
41 @@ -148,7 +148,7 @@ bool Append::commit()
42 //akDebug() << "Append handler: doPreprocessing is" << doPreprocessing;
43 if ( doPreprocessing ) {
45 - hiddenAttribute.setPartType( PartTypeHelper::fromName( "ATR", "HIDDEN" ) );
46 + hiddenAttribute.setPartType( PartType::retrieveByFQName( QLatin1String("ATR"), QLatin1String("HIDDEN") ) );
47 hiddenAttribute.setData( QByteArray() );
48 hiddenAttribute.setPimItemId( item.id() );
49 hiddenAttribute.setDatasize( 0 );
50 diff --git a/server/src/storage/datastore.cpp b/server/src/storage/datastore.cpp
51 index ae78bab..304f0e8 100644
52 --- a/server/src/storage/datastore.cpp
53 +++ b/server/src/storage/datastore.cpp
54 @@ -183,6 +183,7 @@ bool DataStore::init()
55 Flag::enableCache( true );
56 Resource::enableCache( true );
57 Collection::enableCache( true );
58 + PartType::enableCache( true );
62 @@ -1025,7 +1026,8 @@ bool DataStore::unhideAllPimItems()
63 akDebug() << "DataStore::unhideAllPimItems()";
66 - return PartHelper::remove( Part::partTypeIdFullColumnName(), PartTypeHelper::fromName( "ATR", "HIDDEN" ).id() );
67 + return PartHelper::remove( Part::partTypeIdFullColumnName(),
68 + PartType::retrieveByFQName( QLatin1String("ATR"), QLatin1String("HIDDEN") ).id() );
69 } catch ( ... ) {} // we can live with this failing
72 diff --git a/server/src/storage/entities-header.xsl b/server/src/storage/entities-header.xsl
73 index 4966966..d515fd3 100644
74 --- a/server/src/storage/entities-header.xsl
75 +++ b/server/src/storage/entities-header.xsl
76 @@ -133,11 +133,16 @@ class <xsl:value-of select="$className"/> : private Entity
77 <xsl:text>static </xsl:text><xsl:value-of select="$className"/> retrieveById( qint64 id );
80 - <xsl:if test="column[@name = 'name']">
81 + <xsl:if test="column[@name = 'name'] and $className != 'PartType'">
82 /** Returns the record with name @p name. */
83 <xsl:text>static </xsl:text><xsl:value-of select="$className"/> retrieveByName( const <xsl:value-of select="column[@name = 'name']/@type"/> &name );
86 + <xsl:if test="column[@name = 'name'] and $className = 'PartType'">
87 + <!-- Special case for PartTypes, which are identified by "NS:NAME" -->
88 + <xsl:text>static PartType retrieveByFQName( const QString &ns, const QString &name );</xsl:text>
91 /** Retrieve all records from this table. */
92 static <xsl:value-of select="$className"/>::List retrieveAll();
93 /** Retrieve all records with value @p value in column @p key. */
94 diff --git a/server/src/storage/entities-source.xsl b/server/src/storage/entities-source.xsl
95 index e398da5..46ef3a6 100644
96 --- a/server/src/storage/entities-source.xsl
97 +++ b/server/src/storage/entities-source.xsl
98 @@ -130,7 +130,15 @@ void <xsl:value-of select="$className"/>::Private::addToCache( const <xsl:value-
99 idCache.insert( entry.id(), entry );
101 <xsl:if test="column[@name = 'name']">
103 + <xsl:when test="$className = 'PartType'">
104 + <!-- special case for PartType, which is identified as "NS:NAME" -->
105 + nameCache.insert( entry.ns() + QLatin1Char(':') + entry.name(), entry );
108 nameCache.insert( entry.name(), entry );
114 @@ -323,7 +331,7 @@ QVector< <xsl:value-of select="$className"/> > <xsl:value-of select="$clas
118 -<xsl:if test="column[@name = 'name']">
119 +<xsl:if test="column[@name = 'name'] and $className != 'PartType'">
120 <xsl:value-of select="$className"/><xsl:text> </xsl:text><xsl:value-of select="$className"/>::retrieveByName( const <xsl:value-of select="column[@name = 'name']/@type"/> &name )
122 <xsl:call-template name="data-retrieval">
123 @@ -333,6 +341,19 @@ QVector< <xsl:value-of select="$className"/> > <xsl:value-of select="$clas
127 +<xsl:if test="column[@name = 'name'] and $className = 'PartType'">
128 +<xsl:text>PartType PartType::retrieveByFQName( const QString & ns, const QString & name )</xsl:text>
130 + const QString fqname = ns + QLatin1Char(':') + name;
131 + <xsl:call-template name="data-retrieval">
132 + <xsl:with-param name="key">ns</xsl:with-param>
133 + <xsl:with-param name="key2">name</xsl:with-param>
134 + <xsl:with-param name="lookupKey">fqname</xsl:with-param>
135 + <xsl:with-param name="cache">nameCache</xsl:with-param>
136 + </xsl:call-template>
140 QVector<<xsl:value-of select="$className"/>> <xsl:value-of select="$className"/>::retrieveAll()
142 QSqlDatabase db = DataStore::self()->database();
143 @@ -588,7 +609,15 @@ void <xsl:value-of select="$className"/>::invalidateCache() const
144 Private::idCache.remove( id() );
146 <xsl:if test="column[@name = 'name']">
148 + <xsl:when test="$className = 'PartType'">
149 + <!-- Special handling for PartType, which is identified as "NS:NAME" -->
150 + Private::nameCache.remove( ns() + QLatin1Char(':') + name() );
153 Private::nameCache.remove( name() );
159 diff --git a/server/src/storage/entities.xsl b/server/src/storage/entities.xsl
160 index c8fb1fd..2cf96c4 100644
161 --- a/server/src/storage/entities.xsl
162 +++ b/server/src/storage/entities.xsl
163 @@ -169,12 +169,14 @@ set<xsl:value-of select="$methodName"/>( <xsl:call-template name="argument"/> )
164 <!-- data retrieval for a given key field -->
165 <xsl:template name="data-retrieval">
166 <xsl:param name="key"/>
167 +<xsl:param name="key2"/>
168 +<xsl:param name="lookupKey" select="$key"/>
169 <xsl:param name="cache"/>
170 <xsl:variable name="className"><xsl:value-of select="@name"/></xsl:variable>
171 <xsl:if test="$cache != ''">
172 if ( Private::cacheEnabled ) {
173 QMutexLocker lock(&Private::cacheMutex);
174 - QHash<<xsl:value-of select="column[@name = $key]/@type"/>, <xsl:value-of select="$className"/>>::const_iterator it = Private::<xsl:value-of select="$cache"/>.constFind(<xsl:value-of select="$key"/>);
175 + QHash<<xsl:value-of select="column[@name = $key]/@type"/>, <xsl:value-of select="$className"/>>::const_iterator it = Private::<xsl:value-of select="$cache"/>.constFind(<xsl:value-of select="$lookupKey"/>);
176 if ( it != Private::<xsl:value-of select="$cache"/>.constEnd() ) {
179 @@ -188,6 +190,9 @@ set<xsl:value-of select="$methodName"/>( <xsl:call-template name="argument"/> )
180 static const QStringList columns = removeEntry(columnNames(), <xsl:value-of select="$key"/>Column());
181 qb.addColumns( columns );
182 qb.addValueCondition( <xsl:value-of select="$key"/>Column(), Query::Equals, <xsl:value-of select="$key"/> );
183 + <xsl:if test="$key2 != ''">
184 + qb.addValueCondition( <xsl:value-of select="$key2"/>Column(), Query::Equals, <xsl:value-of select="$key2"/> );
187 akDebug() << "Error during selection of record with <xsl:value-of select="$key"/>"
188 << <xsl:value-of select="$key"/> << "from table" << tableName()
189 diff --git a/server/src/storage/parttypehelper.cpp b/server/src/storage/parttypehelper.cpp
190 index b73dcd5..7654108 100644
191 --- a/server/src/storage/parttypehelper.cpp
192 +++ b/server/src/storage/parttypehelper.cpp
193 @@ -37,7 +37,7 @@ QPair< QString, QString > PartTypeHelper::parseFqName(const QString& fqName)
194 PartType PartTypeHelper::fromFqName(const QString& fqName)
196 const QPair<QString, QString> p = parseFqName( fqName );
197 - return fromName( p.first, p.second );
198 + return PartType::retrieveByFQName(p.first, p.second);
201 PartType PartTypeHelper::fromFqName(const QByteArray& fqName)
202 @@ -45,33 +45,6 @@ PartType PartTypeHelper::fromFqName(const QByteArray& fqName)
203 return fromFqName( QLatin1String(fqName) );
206 -PartType PartTypeHelper::fromName(const QString& ns, const QString& typeName)
208 - SelectQueryBuilder<PartType> qb;
209 - qb.addValueCondition( PartType::nsColumn(), Query::Equals, ns );
210 - qb.addValueCondition( PartType::nameColumn(), Query::Equals, typeName );
212 - throw PartTypeException( "Unable to query part type table." );
213 - const PartType::List result = qb.result();
214 - if ( result.size() == 1 )
215 - return result.first();
216 - if ( result.size() > 1 )
217 - throw PartTypeException( "Part type uniqueness constraint violation." );
219 - // doesn't exist yet, so let's create a new one
221 - type.setName( typeName );
223 - if ( !type.insert() )
224 - throw PartTypeException( "Creating a new part type failed." );
228 -PartType PartTypeHelper::fromName(const char* ns, const char* typeName)
230 - return fromName( QLatin1String(ns), QLatin1String(typeName) );
233 Query::Condition PartTypeHelper::conditionFromFqName(const QString& fqName)
235 const QPair<QString, QString> p = parseFqName( fqName );
236 diff --git a/server/src/storage/parttypehelper.h b/server/src/storage/parttypehelper.h
237 index 38cb858..4c4f42f 100644
238 --- a/server/src/storage/parttypehelper.h
239 +++ b/server/src/storage/parttypehelper.h
240 @@ -48,19 +48,6 @@ namespace PartTypeHelper
241 PartType fromFqName( const QByteArray &fqName );
244 - * Retrieve (or create) PartType for the given namespace and type name.
245 - * @param ns Namespace
246 - * @param typeName Part type name.
247 - * @throws PartTypeException
249 - PartType fromName( const QString &ns, const QString &typeName );
252 - * Convenience overload of the above.
254 - PartType fromName( const char *ns, const char *typeName );
257 * Returns a query condition that matches the given part.
258 * @param fqName fully-qualified part type name
259 * @throws PartTypeException