]>
Commit | Line | Data |
---|---|---|
8a8f9fb3 AM |
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 | |
5 | PartTypes | |
6 | ||
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 | |
13 | all the PartTypes. | |
14 | ||
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 | |
17 | sync. | |
18 | --- | |
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(-) | |
27 | ||
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() | |
33 | ||
34 | // wrap data into a part | |
35 | Part 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 ) { | |
44 | Part hiddenAttribute; | |
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 ); | |
59 | ||
60 | return true; | |
61 | } | |
62 | @@ -1025,7 +1026,8 @@ bool DataStore::unhideAllPimItems() | |
63 | akDebug() << "DataStore::unhideAllPimItems()"; | |
64 | ||
65 | try { | |
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 | |
70 | ||
71 | return false; | |
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 ); | |
78 | </xsl:if> | |
79 | ||
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 ); | |
84 | </xsl:if> | |
85 | ||
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> | |
89 | + </xsl:if> | |
90 | + | |
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 ); | |
100 | </xsl:if> | |
101 | <xsl:if test="column[@name = 'name']"> | |
102 | + <xsl:choose> | |
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 ); | |
106 | + </xsl:when> | |
107 | + <xsl:otherwise> | |
108 | nameCache.insert( entry.name(), entry ); | |
109 | + </xsl:otherwise> | |
110 | + </xsl:choose> | |
111 | </xsl:if> | |
112 | } | |
113 | ||
114 | @@ -323,7 +331,7 @@ QVector< <xsl:value-of select="$className"/> > <xsl:value-of select="$clas | |
115 | } | |
116 | ||
117 | </xsl:if> | |
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 ) | |
121 | { | |
122 | <xsl:call-template name="data-retrieval"> | |
123 | @@ -333,6 +341,19 @@ QVector< <xsl:value-of select="$className"/> > <xsl:value-of select="$clas | |
124 | } | |
125 | </xsl:if> | |
126 | ||
127 | +<xsl:if test="column[@name = 'name'] and $className = 'PartType'"> | |
128 | +<xsl:text>PartType PartType::retrieveByFQName( const QString & ns, const QString & name )</xsl:text> | |
129 | +{ | |
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> | |
137 | +} | |
138 | +</xsl:if> | |
139 | + | |
140 | QVector<<xsl:value-of select="$className"/>> <xsl:value-of select="$className"/>::retrieveAll() | |
141 | { | |
142 | QSqlDatabase db = DataStore::self()->database(); | |
143 | @@ -588,7 +609,15 @@ void <xsl:value-of select="$className"/>::invalidateCache() const | |
144 | Private::idCache.remove( id() ); | |
145 | </xsl:if> | |
146 | <xsl:if test="column[@name = 'name']"> | |
147 | + <xsl:choose> | |
148 | + <xsl:when test="$className = 'PartType'"> | |
149 | + <!-- Special handling for PartType, which is identified as "NS:NAME" --> | |
150 | + Private::nameCache.remove( ns() + QLatin1Char(':') + name() ); | |
151 | + </xsl:when> | |
152 | + <xsl:otherwise> | |
153 | Private::nameCache.remove( name() ); | |
154 | + </xsl:otherwise> | |
155 | + </xsl:choose> | |
156 | </xsl:if> | |
157 | } | |
158 | } | |
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() ) { | |
177 | return it.value(); | |
178 | } | |
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"/> ); | |
185 | + </xsl:if> | |
186 | if ( !qb.exec() ) { | |
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) | |
195 | { | |
196 | const QPair<QString, QString> p = parseFqName( fqName ); | |
197 | - return fromName( p.first, p.second ); | |
198 | + return PartType::retrieveByFQName(p.first, p.second); | |
199 | } | |
200 | ||
201 | PartType PartTypeHelper::fromFqName(const QByteArray& fqName) | |
202 | @@ -45,33 +45,6 @@ PartType PartTypeHelper::fromFqName(const QByteArray& fqName) | |
203 | return fromFqName( QLatin1String(fqName) ); | |
204 | } | |
205 | ||
206 | -PartType PartTypeHelper::fromName(const QString& ns, const QString& typeName) | |
207 | -{ | |
208 | - SelectQueryBuilder<PartType> qb; | |
209 | - qb.addValueCondition( PartType::nsColumn(), Query::Equals, ns ); | |
210 | - qb.addValueCondition( PartType::nameColumn(), Query::Equals, typeName ); | |
211 | - if ( !qb.exec() ) | |
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." ); | |
218 | - | |
219 | - // doesn't exist yet, so let's create a new one | |
220 | - PartType type; | |
221 | - type.setName( typeName ); | |
222 | - type.setNs( ns ); | |
223 | - if ( !type.insert() ) | |
224 | - throw PartTypeException( "Creating a new part type failed." ); | |
225 | - return type; | |
226 | -} | |
227 | - | |
228 | -PartType PartTypeHelper::fromName(const char* ns, const char* typeName) | |
229 | -{ | |
230 | - return fromName( QLatin1String(ns), QLatin1String(typeName) ); | |
231 | -} | |
232 | - | |
233 | Query::Condition PartTypeHelper::conditionFromFqName(const QString& fqName) | |
234 | { | |
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 ); | |
242 | ||
243 | /** | |
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 | |
248 | - */ | |
249 | - PartType fromName( const QString &ns, const QString &typeName ); | |
250 | - | |
251 | - /** | |
252 | - * Convenience overload of the above. | |
253 | - */ | |
254 | - PartType fromName( const char *ns, const char *typeName ); | |
255 | - | |
256 | - /** | |
257 | * Returns a query condition that matches the given part. | |
258 | * @param fqName fully-qualified part type name | |
259 | * @throws PartTypeException | |
260 | -- | |
261 | 2.1.0 | |
262 |