Commit 3b177918 authored by Dmitry Smirnov's avatar Dmitry Smirnov

Bunch of optimisation patches from upstream 1.13 branch.

parent da22484e
......@@ -8,3 +8,10 @@ upstream-prevent-QTimer-negative-interval.patch
upstream-use-QAtomicInt.patch
upstream_dont_call_insert_from_Q_ASSERT.patch
upstream_dont_leak_old_external_payload_files.patch
upstream_opt-0001-skip-value-condition-on-invalid-flags.patch
upstream_opt-0002-intern-entity-strings.patch
upstream_opt-0003-QMutexLocker.patch
upstream_opt-0004-one-hash-lookup.patch
upstream_opt-0005-optimize-queries.patch
upstream_opt-0006-cache-PartTypes.patch
upstream_opt-0007-avoid-recursive-listing-in-SearchHelper.patch
From 7cbff48f5782d1f7f844678e6b785aeb419b0c47 Mon Sep 17 00:00:00 2001
From: Milian Wolff <mail@milianw.de>
Date: Mon, 1 Dec 2014 11:59:12 +0100
Subject: [PATCH] Optimize: Skip value condition on invalid flags.
HandlerHelper::itemWithFlagsCount gets called quite often apparently
and I noticed that it was relatively slow from the Query Debugger
in Akonadi Console. EXPLAIN'ing the query showed that it was using
a slow-path for the WHERE FOO AND (BAR OR ASDF) condition. Here,
ASDF was always id = -1, the id of the $IGNORED flag, which
I apparently don't have. Getting rid of that condition simplifies
the query to WHERE FOO AND BAR, which is apparently much better
optimizable. Before, the query often showed a runtime of ~15ms.
Now it is down to ~9ms.
REVIEW: 121306
---
server/src/handlerhelper.cpp | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/server/src/handlerhelper.cpp b/server/src/handlerhelper.cpp
index 634a26c..82347b4 100644
--- a/server/src/handlerhelper.cpp
+++ b/server/src/handlerhelper.cpp
@@ -123,6 +123,10 @@ int HandlerHelper::itemWithFlagsCount( const Collection &col, const QStringList
// it hits an in-memory cache.
Q_FOREACH ( const QString &flag, flags ) {
const Flag f = Flag::retrieveByName( flag );
+ if (!f.isValid()) {
+ // since we OR this condition, we can skip invalid flags to speed up the query
+ continue;
+ }
cond.addValueCondition( PimItemFlagRelation::rightFullColumnName(), Query::Equals, f.id() );
}
qb.addCondition( cond );
--
2.1.4
From a04809a44c235bed854adc3bd49ca75b9673bf1f Mon Sep 17 00:00:00 2001
From: Milian Wolff <mail@milianw.de>
Date: Wed, 26 Nov 2014 13:20:05 +0100
Subject: [PATCH] Intern entity strings for table and column names.
This should drastically cut down on the amount of allocations done
by the AkonadiServer. Currently, the getters will do the conversion
from QLatin1String to QString on every call. By reusing the data
via a function-local static const QString object, we can eliminate
all of these allocations and increase the cache locality as well.
REVIEW: 121255
---
server/src/storage/entities-source.xsl | 56 +++++++++++++++++++++-------------
server/src/storage/entities.xsl | 4 +--
2 files changed, 36 insertions(+), 24 deletions(-)
diff --git a/server/src/storage/entities-source.xsl b/server/src/storage/entities-source.xsl
index 174cf4f..7090c31 100644
--- a/server/src/storage/entities-source.xsl
+++ b/server/src/storage/entities-source.xsl
@@ -214,36 +214,41 @@ void <xsl:value-of select="$className"/>::<xsl:call-template name="setter-signat
// SQL table information
<xsl:text>QString </xsl:text><xsl:value-of select="$className"/>::tableName()
{
- return QLatin1String( "<xsl:value-of select="$tableName"/>" );
+ static const QString tableName = QLatin1String( "<xsl:value-of select="$tableName"/>" );
+ return tableName;
}
QStringList <xsl:value-of select="$className"/>::columnNames()
{
- QStringList rv;
+ static const QStringList columns = QStringList()
<xsl:for-each select="column">
- rv.append( QLatin1String( "<xsl:value-of select="@name"/>" ) );
+ &lt;&lt; <xsl:value-of select="@name"/>Column()
</xsl:for-each>
- return rv;
+ ;
+ return columns;
}
QStringList <xsl:value-of select="$className"/>::fullColumnNames()
{
- QStringList rv;
+ static const QStringList columns = QStringList()
<xsl:for-each select="column">
- rv.append( QLatin1String( "<xsl:value-of select="$tableName"/>.<xsl:value-of select="@name"/>" ) );
+ &lt;&lt; <xsl:value-of select="@name"/>FullColumnName()
</xsl:for-each>
- return rv;
+ ;
+ return columns;
}
<xsl:for-each select="column">
QString <xsl:value-of select="$className"/>::<xsl:value-of select="@name"/>Column()
{
- return QLatin1String( "<xsl:value-of select="@name"/>" );
+ static const QString column = QLatin1String( "<xsl:value-of select="@name"/>" );
+ return column;
}
QString <xsl:value-of select="$className"/>::<xsl:value-of select="@name"/>FullColumnName()
{
- return tableName() + QLatin1String( ".<xsl:value-of select="@name"/>" );
+ static const QString column = QLatin1String( "<xsl:value-of select="$tableName"/>.<xsl:value-of select="@name"/>" );
+ return column;
}
</xsl:for-each>
@@ -399,7 +404,6 @@ QVector&lt;<xsl:value-of select="@table"/>&gt; <xsl:value-of select="$className"
<xsl:variable name="relationName"><xsl:value-of select="@table1"/><xsl:value-of select="@table2"/>Relation</xsl:variable>
<xsl:variable name="rightSideClass"><xsl:value-of select="@table2"/></xsl:variable>
<xsl:variable name="rightSideEntity"><xsl:value-of select="@table2"/></xsl:variable>
-<xsl:variable name="rightSideTable"><xsl:value-of select="@table2"/>Table</xsl:variable>
// data retrieval for n:m relations
QVector&lt;<xsl:value-of select="$rightSideClass"/>&gt; <xsl:value-of select="$className"/>::<xsl:value-of select="concat(translate(substring(@table2,1,1),'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz'), substring(@table2,2))"/>s() const
@@ -408,14 +412,17 @@ QVector&lt;<xsl:value-of select="$rightSideClass"/>&gt; <xsl:value-of select="$c
if ( !db.isOpen() )
return QVector&lt;<xsl:value-of select="$rightSideClass"/>&gt;();
- QueryBuilder qb( QLatin1String("<xsl:value-of select="$rightSideTable"/>"), QueryBuilder::Select );
+ QueryBuilder qb( <xsl:value-of select="$rightSideClass"/>::tableName(), QueryBuilder::Select );
+ static const QStringList columns = QStringList()
<xsl:for-each select="/database/table[@name = $rightSideEntity]/column">
- qb.addColumn( QLatin1String("<xsl:value-of select="$rightSideTable"/>.<xsl:value-of select="@name"/>" ) );
+ &lt;&lt; <xsl:value-of select="$rightSideClass"/>::<xsl:value-of select="@name"/>FullColumnName()
</xsl:for-each>
- qb.addJoin( QueryBuilder::InnerJoin, QLatin1String("<xsl:value-of select="$relationName"/>"),
- QLatin1String("<xsl:value-of select="$relationName"/>.<xsl:value-of select="@table2"/>_<xsl:value-of select="@column2"/>"),
- QLatin1String("<xsl:value-of select="$rightSideTable"/>.<xsl:value-of select="@column2"/>") );
- qb.addValueCondition( QLatin1String("<xsl:value-of select="$relationName"/>.<xsl:value-of select="@table1"/>_<xsl:value-of select="@column1"/>"), Query::Equals, id() );
+ ;
+ qb.addColumns(columns);
+ qb.addJoin( QueryBuilder::InnerJoin, <xsl:value-of select="$relationName"/>::tableName(),
+ <xsl:value-of select="$relationName"/>::rightFullColumnName(),
+ <xsl:value-of select="$rightSideClass"/>::<xsl:value-of select="@column2"/>FullColumnName() );
+ qb.addValueCondition( <xsl:value-of select="$relationName"/>::leftFullColumnName(), Query::Equals, id() );
if ( !qb.exec() ) {
akDebug() &lt;&lt; "Error during selection of records from table <xsl:value-of select="@table1"/><xsl:value-of select="@table2"/>Relation"
@@ -546,7 +553,7 @@ bool <xsl:value-of select="$className"/>::update()
</xsl:for-each>
<xsl:if test="column[@name = 'id']">
- qb.addValueCondition( QLatin1String("id"), Query::Equals, id() );
+ qb.addValueCondition( idColumn(), Query::Equals, id() );
</xsl:if>
if ( !qb.exec() ) {
@@ -622,27 +629,32 @@ void <xsl:value-of select="$className"/>::enableCache( bool enable )
// SQL table information
QString <xsl:value-of select="$className"/>::tableName()
{
- return QLatin1String( "<xsl:value-of select="$tableName"/>" );
+ static const QString table = QLatin1String( "<xsl:value-of select="$tableName"/>" );
+ return table;
}
QString <xsl:value-of select="$className"/>::leftColumn()
{
- return QLatin1String( "<xsl:value-of select="@table1"/>_<xsl:value-of select="@column1"/>" );
+ static const QString column = QLatin1String( "<xsl:value-of select="@table1"/>_<xsl:value-of select="@column1"/>" );
+ return column;
}
QString <xsl:value-of select="$className"/>::leftFullColumnName()
{
- return tableName() + QLatin1String( "." ) + leftColumn();
+ static const QString column = QLatin1String( "<xsl:value-of select="$tableName"/>.<xsl:value-of select="@table1"/>_<xsl:value-of select="@column1"/>" );
+ return column;
}
QString <xsl:value-of select="$className"/>::rightColumn()
{
- return QLatin1String( "<xsl:value-of select="@table2"/>_<xsl:value-of select="@column2"/>" );
+ static const QString column = QLatin1String( "<xsl:value-of select="@table2"/>_<xsl:value-of select="@column2"/>" );
+ return column;
}
QString <xsl:value-of select="$className"/>::rightFullColumnName()
{
- return tableName() + QLatin1String( "." ) + rightColumn();
+ static const QString column = QLatin1String( "<xsl:value-of select="$tableName"/>.<xsl:value-of select="@table2"/>_<xsl:value-of select="@column2"/>" );
+ return column;
}
</xsl:template>
diff --git a/server/src/storage/entities.xsl b/server/src/storage/entities.xsl
index 033e292..8b0ed03 100644
--- a/server/src/storage/entities.xsl
+++ b/server/src/storage/entities.xsl
@@ -114,7 +114,7 @@ using namespace Akonadi::Server;
QVector&lt;QString&gt; Akonadi::Server::allDatabaseTables()
{
- static QVector&lt;QString&gt; allTables = QVector&lt;QString&gt;()
+ static const QVector&lt;QString&gt; allTables = QVector&lt;QString&gt;()
<xsl:for-each select="database/table">
&lt;&lt; QLatin1String( "<xsl:value-of select="@name"/>Table" )
</xsl:for-each>
@@ -182,7 +182,7 @@ set<xsl:value-of select="$methodName"/>( <xsl:call-template name="argument"/> )
QueryBuilder qb( tableName(), QueryBuilder::Select );
qb.addColumns( columnNames() );
- qb.addValueCondition( QLatin1String("<xsl:value-of select="$key"/>"), Query::Equals, <xsl:value-of select="$key"/> );
+ qb.addValueCondition( <xsl:value-of select="$key"/>Column(), Query::Equals, <xsl:value-of select="$key"/> );
if ( !qb.exec() ) {
akDebug() &lt;&lt; "Error during selection of record with <xsl:value-of select="$key"/>"
&lt;&lt; <xsl:value-of select="$key"/> &lt;&lt; "from table" &lt;&lt; tableName()
--
2.1.4
From f5a0e3f1f4787b6a48880e42463ae38dce336a8f Mon Sep 17 00:00:00 2001
From: Milian Wolff <mail@milianw.de>
Date: Mon, 1 Dec 2014 11:36:31 +0100
Subject: [PATCH] Use QMutexLocker instead of manual lock/unlock calls.
Just a minor cleanup patch, no change of behavior.
---
server/src/storage/entities-source.xsl | 17 +++++------------
server/src/storage/entities.xsl | 4 +---
2 files changed, 6 insertions(+), 15 deletions(-)
diff --git a/server/src/storage/entities-source.xsl b/server/src/storage/entities-source.xsl
index 7090c31..05a8cb1 100644
--- a/server/src/storage/entities-source.xsl
+++ b/server/src/storage/entities-source.xsl
@@ -125,14 +125,13 @@ void <xsl:value-of select="$className"/>::Private::addToCache( const <xsl:value-
{
Q_ASSERT( cacheEnabled );
Q_UNUSED( entry ); <!-- in case the table has neither an id nor name column -->
- cacheMutex.lock();
+ QMutexLocker lock(&amp;cacheMutex);
<xsl:if test="column[@name = 'id']">
idCache.insert( entry.id(), entry );
</xsl:if>
<xsl:if test="column[@name = 'name']">
nameCache.insert( entry.name(), entry );
</xsl:if>
- cacheMutex.unlock();
}
@@ -264,12 +263,10 @@ int <xsl:value-of select="$className"/>::count( const QString &amp;column, const
bool <xsl:value-of select="$className"/>::exists( qint64 id )
{
if ( Private::cacheEnabled ) {
- Private::cacheMutex.lock();
+ QMutexLocker lock(&amp;Private::cacheMutex);
if ( Private::idCache.contains( id ) ) {
- Private::cacheMutex.unlock();
return true;
}
- Private::cacheMutex.unlock();
}
return count( idColumn(), id ) > 0;
}
@@ -278,12 +275,10 @@ bool <xsl:value-of select="$className"/>::exists( qint64 id )
bool <xsl:value-of select="$className"/>::exists( const <xsl:value-of select="column[@name = 'name']/@type"/> &amp;name )
{
if ( Private::cacheEnabled ) {
- Private::cacheMutex.lock();
+ QMutexLocker lock(&amp;Private::cacheMutex);
if ( Private::nameCache.contains( name ) ) {
- Private::cacheMutex.unlock();
return true;
}
- Private::cacheMutex.unlock();
}
return count( nameColumn(), name ) > 0;
}
@@ -588,28 +583,26 @@ bool <xsl:value-of select="$className"/>::remove( qint64 id )
void <xsl:value-of select="$className"/>::invalidateCache() const
{
if ( Private::cacheEnabled ) {
- Private::cacheMutex.lock();
+ QMutexLocker lock(&amp;Private::cacheMutex);
<xsl:if test="column[@name = 'id']">
Private::idCache.remove( id() );
</xsl:if>
<xsl:if test="column[@name = 'name']">
Private::nameCache.remove( name() );
</xsl:if>
- Private::cacheMutex.unlock();
}
}
void <xsl:value-of select="$className"/>::invalidateCompleteCache()
{
if ( Private::cacheEnabled ) {
- Private::cacheMutex.lock();
+ QMutexLocker lock(&amp;Private::cacheMutex);
<xsl:if test="column[@name = 'id']">
Private::idCache.clear();
</xsl:if>
<xsl:if test="column[@name = 'name']">
Private::nameCache.clear();
</xsl:if>
- Private::cacheMutex.unlock();
}
}
diff --git a/server/src/storage/entities.xsl b/server/src/storage/entities.xsl
index 8b0ed03..a397544 100644
--- a/server/src/storage/entities.xsl
+++ b/server/src/storage/entities.xsl
@@ -167,13 +167,11 @@ set<xsl:value-of select="$methodName"/>( <xsl:call-template name="argument"/> )
<xsl:variable name="className"><xsl:value-of select="@name"/></xsl:variable>
<xsl:if test="$cache != ''">
if ( Private::cacheEnabled ) {
- Private::cacheMutex.lock();
+ QMutexLocker lock(&amp;Private::cacheMutex);
if ( Private::<xsl:value-of select="$cache"/>.contains( <xsl:value-of select="$key"/> ) ) {
const <xsl:value-of select="$className"/> tmp = Private::<xsl:value-of select="$cache"/>.value( <xsl:value-of select="$key"/> );
- Private::cacheMutex.unlock();
return tmp;
}
- Private::cacheMutex.unlock();
}
</xsl:if>
QSqlDatabase db = DataStore::self()->database();
--
2.1.4
From 202ffa522668087cc133026febf21a7de8963218 Mon Sep 17 00:00:00 2001
From: Milian Wolff <mail@milianw.de>
Date: Mon, 1 Dec 2014 11:51:04 +0100
Subject: [PATCH] Optimize: Only do one hash lookup to retrieve value from
cache.
Compilers do not merge the call to contains() and the successive
value() lookup. Using iterators thus saves us one QHash lookup.
---
server/src/storage/entities.xsl | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/server/src/storage/entities.xsl b/server/src/storage/entities.xsl
index a397544..9471293 100644
--- a/server/src/storage/entities.xsl
+++ b/server/src/storage/entities.xsl
@@ -168,9 +168,9 @@ set<xsl:value-of select="$methodName"/>( <xsl:call-template name="argument"/> )
<xsl:if test="$cache != ''">
if ( Private::cacheEnabled ) {
QMutexLocker lock(&amp;Private::cacheMutex);
- if ( Private::<xsl:value-of select="$cache"/>.contains( <xsl:value-of select="$key"/> ) ) {
- const <xsl:value-of select="$className"/> tmp = Private::<xsl:value-of select="$cache"/>.value( <xsl:value-of select="$key"/> );
- return tmp;
+ QHash&lt;<xsl:value-of select="column[@name = $key]/@type"/>, <xsl:value-of select="$className"/>&gt;::const_iterator it = Private::<xsl:value-of select="$cache"/>.constFind(<xsl:value-of select="$key"/>);
+ if ( it != Private::<xsl:value-of select="$cache"/>.constEnd() ) {
+ return it.value();
}
}
</xsl:if>
--
2.1.4
From e52b57b7a9f0303c0c710e60870d0ec265d32541 Mon Sep 17 00:00:00 2001
From: Milian Wolff <mail@milianw.de>
Date: Mon, 1 Dec 2014 14:11:19 +0100
Subject: [PATCH] Optimize queries: Do not retrieve known key used in the
condition.
There is no point in doing a select like:
SELECT foo, bar FROM table WHERE foo = needle;
That can be rewritten to say
SELECT bar FROM table WHERE foo = needle;
This reduces the data traffic with the mysql server. Additionally, it
work-arounds some issues in Qt SQL, which lead to bad performance:
QSqlResult::value incurs multiple temporary allocations, and string
conversions, even to read a simple integer ID for example. Finally,
by reusing an externally provided QString name e.g., we can leverage
Qt's implicit sharing, instead of duplicating the string in a separate
QString instance, with the contents read from SQL server.
REVIEW: 121310
---
server/src/storage/entities.xsl | 50 +++++++++++++++++++++++++++++------------
1 file changed, 36 insertions(+), 14 deletions(-)
diff --git a/server/src/storage/entities.xsl b/server/src/storage/entities.xsl
index 9471293..c8fb1fd 100644
--- a/server/src/storage/entities.xsl
+++ b/server/src/storage/entities.xsl
@@ -104,6 +104,12 @@ Q_DECLARE_TYPEINFO( Akonadi::Server::<xsl:value-of select="@name"/>, Q_MOVABLE_T
using namespace Akonadi::Server;
+static QStringList removeEntry(QStringList list, const QString&amp; entry)
+{
+ list.removeOne(entry);
+ return list;
+}
+
<xsl:for-each select="database/table">
<xsl:call-template name="table-source"/>
</xsl:for-each>
@@ -179,7 +185,8 @@ set<xsl:value-of select="$methodName"/>( <xsl:call-template name="argument"/> )
return <xsl:value-of select="$className"/>();
QueryBuilder qb( tableName(), QueryBuilder::Select );
- qb.addColumns( columnNames() );
+ static const QStringList columns = removeEntry(columnNames(), <xsl:value-of select="$key"/>Column());
+ qb.addColumns( columns );
qb.addValueCondition( <xsl:value-of select="$key"/>Column(), Query::Equals, <xsl:value-of select="$key"/> );
if ( !qb.exec() ) {
akDebug() &lt;&lt; "Error during selection of record with <xsl:value-of select="$key"/>"
@@ -191,21 +198,36 @@ set<xsl:value-of select="$methodName"/>( <xsl:call-template name="argument"/> )
return <xsl:value-of select="$className"/>();
}
+ <!-- this indirection is required to prevent off-by-one access now that we skip the key column -->
+ int valueIndex = 0;
+ <xsl:for-each select="column">
+ const <xsl:value-of select="@type"/> value<xsl:value-of select="position()"/> =
+ <xsl:choose>
+ <xsl:when test="@name=$key">
+ <xsl:value-of select="$key"/>;
+ </xsl:when>
+ <xsl:otherwise>
+ (qb.query().isNull(valueIndex)) ?
+ <xsl:value-of select="@type"/>() :
+ <xsl:choose>
+ <xsl:when test="starts-with(@type,'QString')">
+ Utils::variantToString( qb.query().value( valueIndex ) )
+ </xsl:when>
+ <xsl:when test="starts-with(@type, 'Tristate')">
+ static_cast&lt;Tristate&gt;(qb.query().value( valueIndex ).value&lt;int&gt;())
+ </xsl:when>
+ <xsl:otherwise>
+ qb.query().value( valueIndex ).value&lt;<xsl:value-of select="@type"/>&gt;()
+ </xsl:otherwise>
+ </xsl:choose>
+ ; ++valueIndex;
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:for-each>
+
<xsl:value-of select="$className"/> rv(
<xsl:for-each select="column">
- (qb.query().isNull(<xsl:value-of select="position() - 1"/>)) ?
- <xsl:value-of select="@type"/>() :
- <xsl:choose>
- <xsl:when test="starts-with(@type,'QString')">
- Utils::variantToString( qb.query().value( <xsl:value-of select="position() - 1"/> ) )
- </xsl:when>
- <xsl:when test="starts-with(@type, 'Tristate')">
- static_cast&lt;Tristate&gt;(qb.query().value( <xsl:value-of select="position() - 1"/> ).value&lt;int&gt;())
- </xsl:when>
- <xsl:otherwise>
- qb.query().value( <xsl:value-of select="position() - 1"/> ).value&lt;<xsl:value-of select="@type"/>&gt;()
- </xsl:otherwise>
- </xsl:choose>
+ value<xsl:value-of select="position()"/>
<xsl:if test="position() != last()">,</xsl:if>
</xsl:for-each>
);
--
2.1.4
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment