Rex Dieter adf30a
From 215b188d891d5236fe94131d176d7ddc3ae02d5d Mon Sep 17 00:00:00 2001
Rex Dieter adf30a
From: =?UTF-8?q?Dan=20Vr=C3=A1til?= <dvratil@redhat.com>
Rex Dieter adf30a
Date: Fri, 5 Dec 2014 17:12:28 +0100
Rex Dieter adf30a
Subject: [PATCH 20/30] Avoid ridiculous amount of SQL queries by caching
Rex Dieter adf30a
 PartTypes
Rex Dieter adf30a
Rex Dieter adf30a
PartTypes are identified by their FQ name, which is in form NAMESPACE:NAME,
Rex Dieter adf30a
where namespace and name are stored in individual columns. For this reason
Rex Dieter adf30a
the standard ::retrieveByName() and name cache generated from entities.xslt
Rex Dieter adf30a
does not work. This patch adds special handling for PartType table, so that
Rex Dieter adf30a
a special PartType::retrieveByFQName() method as well as PartType name cache
Rex Dieter adf30a
handling are generated during the XSL Transformation, allowing us to cache
Rex Dieter adf30a
all the PartTypes.
Rex Dieter adf30a
Rex Dieter adf30a
This reduces the amount of SQL queries by at least two for each single AKAPPEND,
Rex Dieter adf30a
MERGE, STORE and FETCH command, providing a nice performance boost during
Rex Dieter adf30a
sync.
Rex Dieter adf30a
---
Rex Dieter adf30a
 server/src/handler/append.cpp          |  4 ++--
Rex Dieter adf30a
 server/src/storage/datastore.cpp       |  4 +++-
Rex Dieter adf30a
 server/src/storage/entities-header.xsl |  7 ++++++-
Rex Dieter adf30a
 server/src/storage/entities-source.xsl | 31 ++++++++++++++++++++++++++++++-
Rex Dieter adf30a
 server/src/storage/entities.xsl        |  7 ++++++-
Rex Dieter adf30a
 server/src/storage/parttypehelper.cpp  | 29 +----------------------------
Rex Dieter adf30a
 server/src/storage/parttypehelper.h    | 13 -------------
Rex Dieter adf30a
 7 files changed, 48 insertions(+), 47 deletions(-)
Rex Dieter adf30a
Rex Dieter adf30a
diff --git a/server/src/handler/append.cpp b/server/src/handler/append.cpp
Rex Dieter adf30a
index c503216..b594e27 100644
Rex Dieter adf30a
--- a/server/src/handler/append.cpp
Rex Dieter adf30a
+++ b/server/src/handler/append.cpp
Rex Dieter adf30a
@@ -134,7 +134,7 @@ bool Append::commit()
Rex Dieter adf30a
 
Rex Dieter adf30a
     // wrap data into a part
Rex Dieter adf30a
     Part part;
Rex Dieter adf30a
-    part.setPartType( PartTypeHelper::fromName( "PLD", "RFC822" ) );
Rex Dieter adf30a
+    part.setPartType( PartType::retrieveByFQName( QLatin1String("PLD"), QLatin1String("RFC822") ) );
Rex Dieter adf30a
     part.setData( m_data );
Rex Dieter adf30a
     part.setPimItemId( item.id() );
Rex Dieter adf30a
     part.setDatasize( dataSize );
Rex Dieter adf30a
@@ -148,7 +148,7 @@ bool Append::commit()
Rex Dieter adf30a
     //akDebug() << "Append handler: doPreprocessing is" << doPreprocessing;
Rex Dieter adf30a
     if ( doPreprocessing ) {
Rex Dieter adf30a
       Part hiddenAttribute;
Rex Dieter adf30a
-      hiddenAttribute.setPartType( PartTypeHelper::fromName( "ATR", "HIDDEN" ) );
Rex Dieter adf30a
+      hiddenAttribute.setPartType( PartType::retrieveByFQName( QLatin1String("ATR"), QLatin1String("HIDDEN") ) );
Rex Dieter adf30a
       hiddenAttribute.setData( QByteArray() );
Rex Dieter adf30a
       hiddenAttribute.setPimItemId( item.id() );
Rex Dieter adf30a
       hiddenAttribute.setDatasize( 0 );
Rex Dieter adf30a
diff --git a/server/src/storage/datastore.cpp b/server/src/storage/datastore.cpp
Rex Dieter adf30a
index ae78bab..304f0e8 100644
Rex Dieter adf30a
--- a/server/src/storage/datastore.cpp
Rex Dieter adf30a
+++ b/server/src/storage/datastore.cpp
Rex Dieter adf30a
@@ -183,6 +183,7 @@ bool DataStore::init()
Rex Dieter adf30a
   Flag::enableCache( true );
Rex Dieter adf30a
   Resource::enableCache( true );
Rex Dieter adf30a
   Collection::enableCache( true );
Rex Dieter adf30a
+  PartType::enableCache( true );
Rex Dieter adf30a
 
Rex Dieter adf30a
   return true;
Rex Dieter adf30a
 }
Rex Dieter adf30a
@@ -1025,7 +1026,8 @@ bool DataStore::unhideAllPimItems()
Rex Dieter adf30a
   akDebug() << "DataStore::unhideAllPimItems()";
Rex Dieter adf30a
 
Rex Dieter adf30a
   try {
Rex Dieter adf30a
-    return PartHelper::remove( Part::partTypeIdFullColumnName(), PartTypeHelper::fromName( "ATR", "HIDDEN" ).id() );
Rex Dieter adf30a
+    return PartHelper::remove( Part::partTypeIdFullColumnName(),
Rex Dieter adf30a
+                               PartType::retrieveByFQName( QLatin1String("ATR"), QLatin1String("HIDDEN") ).id() );
Rex Dieter adf30a
   } catch ( ... ) {} // we can live with this failing
Rex Dieter adf30a
 
Rex Dieter adf30a
   return false;
Rex Dieter adf30a
diff --git a/server/src/storage/entities-header.xsl b/server/src/storage/entities-header.xsl
Rex Dieter adf30a
index 4966966..d515fd3 100644
Rex Dieter adf30a
--- a/server/src/storage/entities-header.xsl
Rex Dieter adf30a
+++ b/server/src/storage/entities-header.xsl
Rex Dieter adf30a
@@ -133,11 +133,16 @@ class <xsl:value-of select="$className"/> : private Entity
Rex Dieter adf30a
     <xsl:text>static </xsl:text><xsl:value-of select="$className"/> retrieveById( qint64 id );
Rex Dieter adf30a
     </xsl:if>
Rex Dieter adf30a
 
Rex Dieter adf30a
-    <xsl:if test="column[@name = 'name']">
Rex Dieter adf30a
+    <xsl:if test="column[@name = 'name'] and $className != 'PartType'">
Rex Dieter adf30a
     /** Returns the record with name @p name. */
Rex Dieter adf30a
     <xsl:text>static </xsl:text><xsl:value-of select="$className"/> retrieveByName( const <xsl:value-of select="column[@name = 'name']/@type"/> &name );
Rex Dieter adf30a
     </xsl:if>
Rex Dieter adf30a
 
Rex Dieter adf30a
+    <xsl:if test="column[@name = 'name'] and $className = 'PartType'">
Rex Dieter adf30a
+    
Rex Dieter adf30a
+    <xsl:text>static PartType retrieveByFQName( const QString &ns, const QString &name );</xsl:text>
Rex Dieter adf30a
+    </xsl:if>
Rex Dieter adf30a
+
Rex Dieter adf30a
     /** Retrieve all records from this table. */
Rex Dieter adf30a
     static <xsl:value-of select="$className"/>::List retrieveAll();
Rex Dieter adf30a
     /** Retrieve all records with value @p value in column @p key. */
Rex Dieter adf30a
diff --git a/server/src/storage/entities-source.xsl b/server/src/storage/entities-source.xsl
Rex Dieter adf30a
index e398da5..46ef3a6 100644
Rex Dieter adf30a
--- a/server/src/storage/entities-source.xsl
Rex Dieter adf30a
+++ b/server/src/storage/entities-source.xsl
Rex Dieter adf30a
@@ -130,7 +130,15 @@ void <xsl:value-of select="$className"/>::Private::addToCache( const 
Rex Dieter adf30a
   idCache.insert( entry.id(), entry );
Rex Dieter adf30a
   </xsl:if>
Rex Dieter adf30a
   <xsl:if test="column[@name = 'name']">
Rex Dieter adf30a
+    <xsl:choose>
Rex Dieter adf30a
+     <xsl:when test="$className = 'PartType'">
Rex Dieter adf30a
+      
Rex Dieter adf30a
+  nameCache.insert( entry.ns() + QLatin1Char(':') + entry.name(), entry );
Rex Dieter adf30a
+      </xsl:when>
Rex Dieter adf30a
+      <xsl:otherwise>
Rex Dieter adf30a
   nameCache.insert( entry.name(), entry );
Rex Dieter adf30a
+      </xsl:otherwise>
Rex Dieter adf30a
+    </xsl:choose>
Rex Dieter adf30a
   </xsl:if>
Rex Dieter adf30a
 }
Rex Dieter adf30a
 
Rex Dieter adf30a
@@ -323,7 +331,7 @@ QVector< <xsl:value-of select="$className"/> > 
Rex Dieter adf30a
 }
Rex Dieter adf30a
 
Rex Dieter adf30a
 </xsl:if>
Rex Dieter adf30a
-<xsl:if test="column[@name = 'name']">
Rex Dieter adf30a
+<xsl:if test="column[@name = 'name'] and $className != 'PartType'">
Rex Dieter adf30a
 <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 )
Rex Dieter adf30a
 {
Rex Dieter adf30a
   <xsl:call-template name="data-retrieval">
Rex Dieter adf30a
@@ -333,6 +341,19 @@ QVector< <xsl:value-of select="$className"/> > 
Rex Dieter adf30a
 }
Rex Dieter adf30a
 </xsl:if>
Rex Dieter adf30a
 
Rex Dieter adf30a
+<xsl:if test="column[@name = 'name'] and $className = 'PartType'">
Rex Dieter adf30a
+<xsl:text>PartType PartType::retrieveByFQName( const QString & ns, const QString & name )</xsl:text>
Rex Dieter adf30a
+{
Rex Dieter adf30a
+  const QString fqname = ns + QLatin1Char(':') + name;
Rex Dieter adf30a
+  <xsl:call-template name="data-retrieval">
Rex Dieter adf30a
+  <xsl:with-param name="key">ns</xsl:with-param>
Rex Dieter adf30a
+  <xsl:with-param name="key2">name</xsl:with-param>
Rex Dieter adf30a
+  <xsl:with-param name="lookupKey">fqname</xsl:with-param>
Rex Dieter adf30a
+  <xsl:with-param name="cache">nameCache</xsl:with-param>
Rex Dieter adf30a
+  </xsl:call-template>
Rex Dieter adf30a
+}
Rex Dieter adf30a
+</xsl:if>
Rex Dieter adf30a
+
Rex Dieter adf30a
 QVector<<xsl:value-of select="$className"/>> <xsl:value-of select="$className"/>::retrieveAll()
Rex Dieter adf30a
 {
Rex Dieter adf30a
   QSqlDatabase db = DataStore::self()->database();
Rex Dieter adf30a
@@ -588,7 +609,15 @@ void <xsl:value-of select="$className"/>::invalidateCache() const
Rex Dieter adf30a
     Private::idCache.remove( id() );
Rex Dieter adf30a
     </xsl:if>
Rex Dieter adf30a
     <xsl:if test="column[@name = 'name']">
Rex Dieter adf30a
+      <xsl:choose>
Rex Dieter adf30a
+        <xsl:when test="$className = 'PartType'">
Rex Dieter adf30a
+        
Rex Dieter adf30a
+    Private::nameCache.remove( ns() + QLatin1Char(':') + name() );
Rex Dieter adf30a
+        </xsl:when>
Rex Dieter adf30a
+        <xsl:otherwise>
Rex Dieter adf30a
     Private::nameCache.remove( name() );
Rex Dieter adf30a
+        </xsl:otherwise>
Rex Dieter adf30a
+      </xsl:choose>
Rex Dieter adf30a
     </xsl:if>
Rex Dieter adf30a
   }
Rex Dieter adf30a
 }
Rex Dieter adf30a
diff --git a/server/src/storage/entities.xsl b/server/src/storage/entities.xsl
Rex Dieter adf30a
index c8fb1fd..2cf96c4 100644
Rex Dieter adf30a
--- a/server/src/storage/entities.xsl
Rex Dieter adf30a
+++ b/server/src/storage/entities.xsl
Rex Dieter adf30a
@@ -169,12 +169,14 @@ set<xsl:value-of select="$methodName"/>( <xsl:call-template name="argument"/> )
Rex Dieter adf30a
 
Rex Dieter adf30a
 <xsl:template name="data-retrieval">
Rex Dieter adf30a
 <xsl:param name="key"/>
Rex Dieter adf30a
+<xsl:param name="key2"/>
Rex Dieter adf30a
+<xsl:param name="lookupKey" select="$key"/>
Rex Dieter adf30a
 <xsl:param name="cache"/>
Rex Dieter adf30a
 <xsl:variable name="className"><xsl:value-of select="@name"/></xsl:variable>
Rex Dieter adf30a
   <xsl:if test="$cache != ''">
Rex Dieter adf30a
   if ( Private::cacheEnabled ) {
Rex Dieter adf30a
     QMutexLocker lock(&Private::cacheMutex);
Rex Dieter adf30a
-    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"/>);
Rex Dieter adf30a
+    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"/>);
Rex Dieter adf30a
     if ( it != Private::<xsl:value-of select="$cache"/>.constEnd() ) {
Rex Dieter adf30a
       return it.value();
Rex Dieter adf30a
     }
Rex Dieter adf30a
@@ -188,6 +190,9 @@ set<xsl:value-of select="$methodName"/>( <xsl:call-template name="argument"/> )
Rex Dieter adf30a
   static const QStringList columns = removeEntry(columnNames(), <xsl:value-of select="$key"/>Column());
Rex Dieter adf30a
   qb.addColumns( columns );
Rex Dieter adf30a
   qb.addValueCondition( <xsl:value-of select="$key"/>Column(), Query::Equals, <xsl:value-of select="$key"/> );
Rex Dieter adf30a
+  <xsl:if test="$key2 != ''">
Rex Dieter adf30a
+  qb.addValueCondition( <xsl:value-of select="$key2"/>Column(), Query::Equals, <xsl:value-of select="$key2"/> );
Rex Dieter adf30a
+  </xsl:if>
Rex Dieter adf30a
   if ( !qb.exec() ) {
Rex Dieter adf30a
     akDebug() << "Error during selection of record with <xsl:value-of select="$key"/>"
Rex Dieter adf30a
       << <xsl:value-of select="$key"/> << "from table" << tableName()
Rex Dieter adf30a
diff --git a/server/src/storage/parttypehelper.cpp b/server/src/storage/parttypehelper.cpp
Rex Dieter adf30a
index b73dcd5..7654108 100644
Rex Dieter adf30a
--- a/server/src/storage/parttypehelper.cpp
Rex Dieter adf30a
+++ b/server/src/storage/parttypehelper.cpp
Rex Dieter adf30a
@@ -37,7 +37,7 @@ QPair< QString, QString > PartTypeHelper::parseFqName(const QString& fqName)
Rex Dieter adf30a
 PartType PartTypeHelper::fromFqName(const QString& fqName)
Rex Dieter adf30a
 {
Rex Dieter adf30a
   const QPair<QString, QString> p = parseFqName( fqName );
Rex Dieter adf30a
-  return fromName( p.first, p.second );
Rex Dieter adf30a
+  return PartType::retrieveByFQName(p.first, p.second);
Rex Dieter adf30a
 }
Rex Dieter adf30a
 
Rex Dieter adf30a
 PartType PartTypeHelper::fromFqName(const QByteArray& fqName)
Rex Dieter adf30a
@@ -45,33 +45,6 @@ PartType PartTypeHelper::fromFqName(const QByteArray& fqName)
Rex Dieter adf30a
   return fromFqName( QLatin1String(fqName) );
Rex Dieter adf30a
 }
Rex Dieter adf30a
 
Rex Dieter adf30a
-PartType PartTypeHelper::fromName(const QString& ns, const QString& typeName)
Rex Dieter adf30a
-{
Rex Dieter adf30a
-  SelectQueryBuilder<PartType> qb;
Rex Dieter adf30a
-  qb.addValueCondition( PartType::nsColumn(), Query::Equals, ns );
Rex Dieter adf30a
-  qb.addValueCondition( PartType::nameColumn(), Query::Equals, typeName );
Rex Dieter adf30a
-  if ( !qb.exec() )
Rex Dieter adf30a
-    throw PartTypeException( "Unable to query part type table." );
Rex Dieter adf30a
-  const PartType::List result = qb.result();
Rex Dieter adf30a
-  if ( result.size() == 1 )
Rex Dieter adf30a
-    return result.first();
Rex Dieter adf30a
-  if ( result.size() > 1 )
Rex Dieter adf30a
-    throw PartTypeException( "Part type uniqueness constraint violation." );
Rex Dieter adf30a
-
Rex Dieter adf30a
-  // doesn't exist yet, so let's create a new one
Rex Dieter adf30a
-  PartType type;
Rex Dieter adf30a
-  type.setName( typeName );
Rex Dieter adf30a
-  type.setNs( ns );
Rex Dieter adf30a
-  if ( !type.insert() )
Rex Dieter adf30a
-    throw PartTypeException( "Creating a new part type failed." );
Rex Dieter adf30a
-  return type;
Rex Dieter adf30a
-}
Rex Dieter adf30a
-
Rex Dieter adf30a
-PartType PartTypeHelper::fromName(const char* ns, const char* typeName)
Rex Dieter adf30a
-{
Rex Dieter adf30a
-  return fromName( QLatin1String(ns), QLatin1String(typeName) );
Rex Dieter adf30a
-}
Rex Dieter adf30a
-
Rex Dieter adf30a
 Query::Condition PartTypeHelper::conditionFromFqName(const QString& fqName)
Rex Dieter adf30a
 {
Rex Dieter adf30a
   const QPair<QString, QString> p = parseFqName( fqName );
Rex Dieter adf30a
diff --git a/server/src/storage/parttypehelper.h b/server/src/storage/parttypehelper.h
Rex Dieter adf30a
index 38cb858..4c4f42f 100644
Rex Dieter adf30a
--- a/server/src/storage/parttypehelper.h
Rex Dieter adf30a
+++ b/server/src/storage/parttypehelper.h
Rex Dieter adf30a
@@ -48,19 +48,6 @@ namespace PartTypeHelper
Rex Dieter adf30a
   PartType fromFqName( const QByteArray &fqName );
Rex Dieter adf30a
 
Rex Dieter adf30a
   /**
Rex Dieter adf30a
-   * Retrieve (or create) PartType for the given namespace and type name.
Rex Dieter adf30a
-   * @param ns Namespace
Rex Dieter adf30a
-   * @param typeName Part type name.
Rex Dieter adf30a
-   * @throws PartTypeException
Rex Dieter adf30a
-   */
Rex Dieter adf30a
-  PartType fromName( const QString &ns, const QString &typeName );
Rex Dieter adf30a
-
Rex Dieter adf30a
-  /**
Rex Dieter adf30a
-   * Convenience overload of the above.
Rex Dieter adf30a
-   */
Rex Dieter adf30a
-  PartType fromName( const char *ns, const char *typeName );
Rex Dieter adf30a
-
Rex Dieter adf30a
-  /**
Rex Dieter adf30a
    * Returns a query condition that matches the given part.
Rex Dieter adf30a
    * @param fqName fully-qualified part type name
Rex Dieter adf30a
    * @throws PartTypeException
Rex Dieter adf30a
-- 
Rex Dieter adf30a
2.1.0
Rex Dieter adf30a