|
Rex Dieter |
adf30a |
From c24329bb570ee16c033228588e6d22b0f6000f95 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 18:23:33 +0100
|
|
Rex Dieter |
adf30a |
Subject: [PATCH 22/30] Implement cache for CollectionStatistics to
|
|
Rex Dieter |
adf30a |
significantly reduce amount of SQL queries
|
|
Rex Dieter |
adf30a |
|
|
Rex Dieter |
adf30a |
Collection statistics are being requested extremely often (basically whenever
|
|
Rex Dieter |
adf30a |
a PimItem is changed, or when a Collection itself is changed), and it's always
|
|
Rex Dieter |
adf30a |
requested by at least 5 or so clients (including agents that listen to
|
|
Rex Dieter |
adf30a |
everything).
|
|
Rex Dieter |
adf30a |
|
|
Rex Dieter |
adf30a |
To decrease the load on database we now cache the Collection statistics and
|
|
Rex Dieter |
adf30a |
we only invalidate a cache entry when respective collection (or it's content)
|
|
Rex Dieter |
adf30a |
is changed. The invalidation is invoked from NotificationCollector, which is
|
|
Rex Dieter |
adf30a |
basically a hack, but performance-wise it's the best place to avoid additional
|
|
Rex Dieter |
adf30a |
expensive queries.
|
|
Rex Dieter |
adf30a |
|
|
Rex Dieter |
adf30a |
This patch also optimizes the SQL query needed to get up-to-date statistics.
|
|
Rex Dieter |
adf30a |
We now have only one query to get both full count and read items count, which
|
|
Rex Dieter |
adf30a |
a bit is faster as the database only has to deal with one large JOIN.
|
|
Rex Dieter |
adf30a |
|
|
Rex Dieter |
adf30a |
Thanks to the cache the number of SQL queries for Collection statistics have
|
|
Rex Dieter |
adf30a |
reduced by 70%-80%, and average query duration is now between 20 and 80ms
|
|
Rex Dieter |
adf30a |
depending on average collection size and database used.
|
|
Rex Dieter |
adf30a |
---
|
|
Rex Dieter |
adf30a |
server/CMakeLists.txt | 1 +
|
|
Rex Dieter |
adf30a |
server/src/handler/link.cpp | 2 +-
|
|
Rex Dieter |
adf30a |
server/src/handler/merge.cpp | 4 +-
|
|
Rex Dieter |
adf30a |
server/src/handler/select.cpp | 14 ++--
|
|
Rex Dieter |
adf30a |
server/src/handler/status.cpp | 20 ++---
|
|
Rex Dieter |
adf30a |
server/src/handlerhelper.cpp | 81 ++------------------
|
|
Rex Dieter |
adf30a |
server/src/handlerhelper.h | 22 ------
|
|
Rex Dieter |
adf30a |
server/src/storage/collectionstatistics.cpp | 108 +++++++++++++++++++++++++++
|
|
Rex Dieter |
adf30a |
server/src/storage/collectionstatistics.h | 70 +++++++++++++++++
|
|
Rex Dieter |
adf30a |
server/src/storage/datastore.cpp | 8 +-
|
|
Rex Dieter |
adf30a |
server/src/storage/datastore.h | 6 +-
|
|
Rex Dieter |
adf30a |
server/src/storage/notificationcollector.cpp | 8 ++
|
|
Rex Dieter |
adf30a |
server/tests/unittest/fakedatastore.cpp | 8 +-
|
|
Rex Dieter |
adf30a |
server/tests/unittest/fakedatastore.h | 2 +
|
|
Rex Dieter |
adf30a |
14 files changed, 224 insertions(+), 130 deletions(-)
|
|
Rex Dieter |
adf30a |
create mode 100644 server/src/storage/collectionstatistics.cpp
|
|
Rex Dieter |
adf30a |
create mode 100644 server/src/storage/collectionstatistics.h
|
|
Rex Dieter |
adf30a |
|
|
Rex Dieter |
adf30a |
diff --git a/server/CMakeLists.txt b/server/CMakeLists.txt
|
|
Rex Dieter |
adf30a |
index 275938d..f0e0093 100644
|
|
Rex Dieter |
adf30a |
--- a/server/CMakeLists.txt
|
|
Rex Dieter |
adf30a |
+++ b/server/CMakeLists.txt
|
|
Rex Dieter |
adf30a |
@@ -161,6 +161,7 @@ set(libakonadiprivate_SRCS
|
|
Rex Dieter |
adf30a |
src/search/searchmanager.cpp
|
|
Rex Dieter |
adf30a |
|
|
Rex Dieter |
adf30a |
src/storage/collectionqueryhelper.cpp
|
|
Rex Dieter |
adf30a |
+ src/storage/collectionstatistics.cpp
|
|
Rex Dieter |
adf30a |
src/storage/entity.cpp
|
|
Rex Dieter |
adf30a |
${CMAKE_CURRENT_BINARY_DIR}/entities.cpp
|
|
Rex Dieter |
adf30a |
${CMAKE_CURRENT_BINARY_DIR}/akonadischema.cpp
|
|
Rex Dieter |
adf30a |
diff --git a/server/src/handler/link.cpp b/server/src/handler/link.cpp
|
|
Rex Dieter |
adf30a |
index ce18e47..227de11 100644
|
|
Rex Dieter |
adf30a |
--- a/server/src/handler/link.cpp
|
|
Rex Dieter |
adf30a |
+++ b/server/src/handler/link.cpp
|
|
Rex Dieter |
adf30a |
@@ -25,10 +25,10 @@
|
|
Rex Dieter |
adf30a |
#include "storage/itemqueryhelper.h"
|
|
Rex Dieter |
adf30a |
#include "storage/transaction.h"
|
|
Rex Dieter |
adf30a |
#include "storage/selectquerybuilder.h"
|
|
Rex Dieter |
adf30a |
+#include "storage/collectionqueryhelper.h"
|
|
Rex Dieter |
adf30a |
#include "entities.h"
|
|
Rex Dieter |
adf30a |
|
|
Rex Dieter |
adf30a |
#include "imapstreamparser.h"
|
|
Rex Dieter |
adf30a |
-#include <storage/collectionqueryhelper.h>
|
|
Rex Dieter |
adf30a |
|
|
Rex Dieter |
adf30a |
using namespace Akonadi::Server;
|
|
Rex Dieter |
adf30a |
|
|
Rex Dieter |
adf30a |
diff --git a/server/src/handler/merge.cpp b/server/src/handler/merge.cpp
|
|
Rex Dieter |
adf30a |
index c26917d..5149916 100644
|
|
Rex Dieter |
adf30a |
--- a/server/src/handler/merge.cpp
|
|
Rex Dieter |
adf30a |
+++ b/server/src/handler/merge.cpp
|
|
Rex Dieter |
adf30a |
@@ -88,7 +88,7 @@ bool Merge::mergeItem( PimItem &newItem, PimItem ¤tItem,
|
|
Rex Dieter |
adf30a |
if ( !itemFlags.removed.isEmpty() ) {
|
|
Rex Dieter |
adf30a |
const Flag::List removedFlags = HandlerHelper::resolveFlags( itemFlags.removed );
|
|
Rex Dieter |
adf30a |
DataStore::self()->removeItemsFlags( PimItem::List() << currentItem, removedFlags,
|
|
Rex Dieter |
adf30a |
- &flagsRemoved, true );
|
|
Rex Dieter |
adf30a |
+ &flagsRemoved, col, true );
|
|
Rex Dieter |
adf30a |
}
|
|
Rex Dieter |
adf30a |
|
|
Rex Dieter |
adf30a |
if ( flagsAdded || flagsRemoved ) {
|
|
Rex Dieter |
adf30a |
@@ -98,7 +98,7 @@ bool Merge::mergeItem( PimItem &newItem, PimItem ¤tItem,
|
|
Rex Dieter |
adf30a |
bool flagsChanged = false;
|
|
Rex Dieter |
adf30a |
const Flag::List flags = HandlerHelper::resolveFlags( itemFlags.added );
|
|
Rex Dieter |
adf30a |
DataStore::self()->setItemsFlags( PimItem::List() << currentItem, flags,
|
|
Rex Dieter |
adf30a |
- &flagsChanged, true );
|
|
Rex Dieter |
adf30a |
+ &flagsChanged, col, true );
|
|
Rex Dieter |
adf30a |
if ( flagsChanged ) {
|
|
Rex Dieter |
adf30a |
mChangedParts << AKONADI_PARAM_FLAGS;
|
|
Rex Dieter |
adf30a |
}
|
|
Rex Dieter |
adf30a |
diff --git a/server/src/handler/select.cpp b/server/src/handler/select.cpp
|
|
Rex Dieter |
adf30a |
index 1c5dd8a..f1ecc44 100644
|
|
Rex Dieter |
adf30a |
--- a/server/src/handler/select.cpp
|
|
Rex Dieter |
adf30a |
+++ b/server/src/handler/select.cpp
|
|
Rex Dieter |
adf30a |
@@ -27,6 +27,7 @@
|
|
Rex Dieter |
adf30a |
#include "handlerhelper.h"
|
|
Rex Dieter |
adf30a |
#include "imapstreamparser.h"
|
|
Rex Dieter |
adf30a |
#include "storage/selectquerybuilder.h"
|
|
Rex Dieter |
adf30a |
+#include "storage/collectionstatistics.h"
|
|
Rex Dieter |
adf30a |
#include "commandcontext.h"
|
|
Rex Dieter |
adf30a |
|
|
Rex Dieter |
adf30a |
#include "response.h"
|
|
Rex Dieter |
adf30a |
@@ -96,19 +97,14 @@ bool Select::parseStream()
|
|
Rex Dieter |
adf30a |
response.setString( "FLAGS (" + Flag::joinByName( Flag::retrieveAll(), QLatin1String( " " ) ).toLatin1() + ")" );
|
|
Rex Dieter |
adf30a |
Q_EMIT responseAvailable( response );
|
|
Rex Dieter |
adf30a |
|
|
Rex Dieter |
adf30a |
- const int itemCount = HandlerHelper::itemCount( col );
|
|
Rex Dieter |
adf30a |
- if ( itemCount < 0 ) {
|
|
Rex Dieter |
adf30a |
+ const CollectionStatistics::Statistics stats = CollectionStatistics::instance()->statistics(col);
|
|
Rex Dieter |
adf30a |
+ if ( stats.count == -1 ) {
|
|
Rex Dieter |
adf30a |
return failureResponse( "Unable to determine item count" );
|
|
Rex Dieter |
adf30a |
}
|
|
Rex Dieter |
adf30a |
- response.setString( QByteArray::number( itemCount ) + " EXISTS" );
|
|
Rex Dieter |
adf30a |
+ response.setString( QByteArray::number( stats.count ) + " EXISTS" );
|
|
Rex Dieter |
adf30a |
Q_EMIT responseAvailable( response );
|
|
Rex Dieter |
adf30a |
|
|
Rex Dieter |
adf30a |
- int readCount = HandlerHelper::itemWithFlagsCount( col, QStringList() << QLatin1String( AKONADI_FLAG_SEEN )
|
|
Rex Dieter |
adf30a |
- << QLatin1String( AKONADI_FLAG_IGNORED ) );
|
|
Rex Dieter |
adf30a |
- if ( readCount < 0 || itemCount < readCount ) {
|
|
Rex Dieter |
adf30a |
- return failureResponse( "Unable to retrieve unseen count" );
|
|
Rex Dieter |
adf30a |
- }
|
|
Rex Dieter |
adf30a |
- response.setString( "OK [UNSEEN " + QByteArray::number( itemCount - readCount ) + "] Message 0 is first unseen" );
|
|
Rex Dieter |
adf30a |
+ response.setString( "OK [UNSEEN " + QByteArray::number( stats.count - stats.read ) + "] Message 0 is first unseen" );
|
|
Rex Dieter |
adf30a |
Q_EMIT responseAvailable( response );
|
|
Rex Dieter |
adf30a |
}
|
|
Rex Dieter |
adf30a |
|
|
Rex Dieter |
adf30a |
diff --git a/server/src/handler/status.cpp b/server/src/handler/status.cpp
|
|
Rex Dieter |
adf30a |
index 8c6823d..283532c 100644
|
|
Rex Dieter |
adf30a |
--- a/server/src/handler/status.cpp
|
|
Rex Dieter |
adf30a |
+++ b/server/src/handler/status.cpp
|
|
Rex Dieter |
adf30a |
@@ -25,6 +25,7 @@
|
|
Rex Dieter |
adf30a |
#include "storage/datastore.h"
|
|
Rex Dieter |
adf30a |
#include "storage/entity.h"
|
|
Rex Dieter |
adf30a |
#include "storage/countquerybuilder.h"
|
|
Rex Dieter |
adf30a |
+#include "storage/collectionstatistics.h"
|
|
Rex Dieter |
adf30a |
|
|
Rex Dieter |
adf30a |
#include "response.h"
|
|
Rex Dieter |
adf30a |
#include "handlerhelper.h"
|
|
Rex Dieter |
adf30a |
@@ -62,9 +63,9 @@ bool Status::parseStream()
|
|
Rex Dieter |
adf30a |
// Responses:
|
|
Rex Dieter |
adf30a |
// REQUIRED untagged responses: STATUS
|
|
Rex Dieter |
adf30a |
|
|
Rex Dieter |
adf30a |
- qint64 itemCount, itemSize;
|
|
Rex Dieter |
adf30a |
- if ( !HandlerHelper::itemStatistics( col, itemCount, itemSize ) ) {
|
|
Rex Dieter |
adf30a |
- return failureResponse( "Failed to query statistics." );
|
|
Rex Dieter |
adf30a |
+ const CollectionStatistics::Statistics &stats = CollectionStatistics::instance()->statistics(col);
|
|
Rex Dieter |
adf30a |
+ if (stats.count == -1) {
|
|
Rex Dieter |
adf30a |
+ return failureResponse( "Failed to query statistics." );
|
|
Rex Dieter |
adf30a |
}
|
|
Rex Dieter |
adf30a |
|
|
Rex Dieter |
adf30a |
// build STATUS response
|
|
Rex Dieter |
adf30a |
@@ -72,7 +73,7 @@ bool Status::parseStream()
|
|
Rex Dieter |
adf30a |
// MESSAGES - The number of messages in the mailbox
|
|
Rex Dieter |
adf30a |
if ( attributeList.contains( AKONADI_ATTRIBUTE_MESSAGES ) ) {
|
|
Rex Dieter |
adf30a |
statusResponse += AKONADI_ATTRIBUTE_MESSAGES " ";
|
|
Rex Dieter |
adf30a |
- statusResponse += QByteArray::number( itemCount );
|
|
Rex Dieter |
adf30a |
+ statusResponse += QByteArray::number( stats.count );
|
|
Rex Dieter |
adf30a |
}
|
|
Rex Dieter |
adf30a |
|
|
Rex Dieter |
adf30a |
if ( attributeList.contains( AKONADI_ATTRIBUTE_UNSEEN ) ) {
|
|
Rex Dieter |
adf30a |
@@ -80,21 +81,14 @@ bool Status::parseStream()
|
|
Rex Dieter |
adf30a |
statusResponse += " ";
|
|
Rex Dieter |
adf30a |
}
|
|
Rex Dieter |
adf30a |
statusResponse += AKONADI_ATTRIBUTE_UNSEEN " ";
|
|
Rex Dieter |
adf30a |
-
|
|
Rex Dieter |
adf30a |
- // itemWithFlagCount is twice as fast as itemWithoutFlagCount...
|
|
Rex Dieter |
adf30a |
- const int count = HandlerHelper::itemWithFlagsCount( col, QStringList() << QLatin1String( AKONADI_FLAG_SEEN )
|
|
Rex Dieter |
adf30a |
- << QLatin1String( AKONADI_FLAG_IGNORED ) );
|
|
Rex Dieter |
adf30a |
- if ( count < 0 ) {
|
|
Rex Dieter |
adf30a |
- return failureResponse( "Unable to retrieve unread count" );
|
|
Rex Dieter |
adf30a |
- }
|
|
Rex Dieter |
adf30a |
- statusResponse += QByteArray::number( itemCount - count );
|
|
Rex Dieter |
adf30a |
+ statusResponse += QByteArray::number( stats.count - stats.read );
|
|
Rex Dieter |
adf30a |
}
|
|
Rex Dieter |
adf30a |
if ( attributeList.contains( AKONADI_PARAM_SIZE ) ) {
|
|
Rex Dieter |
adf30a |
if ( !statusResponse.isEmpty() ) {
|
|
Rex Dieter |
adf30a |
statusResponse += " ";
|
|
Rex Dieter |
adf30a |
}
|
|
Rex Dieter |
adf30a |
statusResponse += AKONADI_PARAM_SIZE " ";
|
|
Rex Dieter |
adf30a |
- statusResponse += QByteArray::number( itemSize );
|
|
Rex Dieter |
adf30a |
+ statusResponse += QByteArray::number( stats.size );
|
|
Rex Dieter |
adf30a |
}
|
|
Rex Dieter |
adf30a |
|
|
Rex Dieter |
adf30a |
Response response;
|
|
Rex Dieter |
adf30a |
diff --git a/server/src/handlerhelper.cpp b/server/src/handlerhelper.cpp
|
|
Rex Dieter |
adf30a |
index 82347b4..39583ce 100644
|
|
Rex Dieter |
adf30a |
--- a/server/src/handlerhelper.cpp
|
|
Rex Dieter |
adf30a |
+++ b/server/src/handlerhelper.cpp
|
|
Rex Dieter |
adf30a |
@@ -22,6 +22,7 @@
|
|
Rex Dieter |
adf30a |
#include "storage/countquerybuilder.h"
|
|
Rex Dieter |
adf30a |
#include "storage/datastore.h"
|
|
Rex Dieter |
adf30a |
#include "storage/selectquerybuilder.h"
|
|
Rex Dieter |
adf30a |
+#include "storage/collectionstatistics.h"
|
|
Rex Dieter |
adf30a |
#include "storage/queryhelper.h"
|
|
Rex Dieter |
adf30a |
#include "libs/imapparser_p.h"
|
|
Rex Dieter |
adf30a |
#include "libs/protocol_p.h"
|
|
Rex Dieter |
adf30a |
@@ -78,74 +79,6 @@ QString HandlerHelper::pathForCollection( const Collection &col )
|
|
Rex Dieter |
adf30a |
return parts.join( QLatin1String( "/" ) );
|
|
Rex Dieter |
adf30a |
}
|
|
Rex Dieter |
adf30a |
|
|
Rex Dieter |
adf30a |
-bool HandlerHelper::itemStatistics( const Collection &col, qint64 &count, qint64 &size )
|
|
Rex Dieter |
adf30a |
-{
|
|
Rex Dieter |
adf30a |
- QueryBuilder qb( PimItem::tableName() );
|
|
Rex Dieter |
adf30a |
- qb.addAggregation( PimItem::idColumn(), QLatin1String( "count" ) );
|
|
Rex Dieter |
adf30a |
- qb.addAggregation( PimItem::sizeColumn(), QLatin1String( "sum" ) );
|
|
Rex Dieter |
adf30a |
-
|
|
Rex Dieter |
adf30a |
- if ( col.isVirtual() ) {
|
|
Rex Dieter |
adf30a |
- qb.addJoin( QueryBuilder::InnerJoin, CollectionPimItemRelation::tableName(),
|
|
Rex Dieter |
adf30a |
- CollectionPimItemRelation::rightFullColumnName(), PimItem::idFullColumnName() );
|
|
Rex Dieter |
adf30a |
- qb.addValueCondition( CollectionPimItemRelation::leftFullColumnName(), Query::Equals, col.id() );
|
|
Rex Dieter |
adf30a |
- } else {
|
|
Rex Dieter |
adf30a |
- qb.addValueCondition( PimItem::collectionIdColumn(), Query::Equals, col.id() );
|
|
Rex Dieter |
adf30a |
- }
|
|
Rex Dieter |
adf30a |
-
|
|
Rex Dieter |
adf30a |
- if ( !qb.exec() ) {
|
|
Rex Dieter |
adf30a |
- return false;
|
|
Rex Dieter |
adf30a |
- }
|
|
Rex Dieter |
adf30a |
- if ( !qb.query().next() ) {
|
|
Rex Dieter |
adf30a |
- akError() << "Error during retrieving result of statistics query:" << qb.query().lastError().text();
|
|
Rex Dieter |
adf30a |
- return false;
|
|
Rex Dieter |
adf30a |
- }
|
|
Rex Dieter |
adf30a |
- count = qb.query().value( 0 ).toLongLong();
|
|
Rex Dieter |
adf30a |
- size = qb.query().value( 1 ).toLongLong();
|
|
Rex Dieter |
adf30a |
- return true;
|
|
Rex Dieter |
adf30a |
-}
|
|
Rex Dieter |
adf30a |
-
|
|
Rex Dieter |
adf30a |
-int HandlerHelper::itemWithFlagsCount( const Collection &col, const QStringList &flags )
|
|
Rex Dieter |
adf30a |
-{
|
|
Rex Dieter |
adf30a |
- CountQueryBuilder qb( PimItem::tableName(), PimItem::idFullColumnName(), CountQueryBuilder::Distinct );
|
|
Rex Dieter |
adf30a |
- qb.addJoin( QueryBuilder::InnerJoin, PimItemFlagRelation::tableName(),
|
|
Rex Dieter |
adf30a |
- PimItem::idFullColumnName(), PimItemFlagRelation::leftFullColumnName() );
|
|
Rex Dieter |
adf30a |
- if ( col.isVirtual() ) {
|
|
Rex Dieter |
adf30a |
- qb.addJoin( QueryBuilder::InnerJoin, CollectionPimItemRelation::tableName(),
|
|
Rex Dieter |
adf30a |
- CollectionPimItemRelation::rightFullColumnName(), PimItem::idFullColumnName() );
|
|
Rex Dieter |
adf30a |
- qb.addValueCondition( CollectionPimItemRelation::leftFullColumnName(), Query::Equals, col.id() );
|
|
Rex Dieter |
adf30a |
- } else {
|
|
Rex Dieter |
adf30a |
- qb.addValueCondition( PimItem::collectionIdFullColumnName(), Query::Equals, col.id() );
|
|
Rex Dieter |
adf30a |
- }
|
|
Rex Dieter |
adf30a |
- Query::Condition cond( Query::Or );
|
|
Rex Dieter |
adf30a |
- // We use the below instead of an inner join in the query above because postgres seems
|
|
Rex Dieter |
adf30a |
- // to struggle to optimize the two inner joins, despite having indices that should
|
|
Rex Dieter |
adf30a |
- // facilitate that. This exploits the fact that the Flag::retrieveByName is fast because
|
|
Rex Dieter |
adf30a |
- // it hits an in-memory cache.
|
|
Rex Dieter |
adf30a |
- Q_FOREACH ( const QString &flag, flags ) {
|
|
Rex Dieter |
adf30a |
- const Flag f = Flag::retrieveByName( flag );
|
|
Rex Dieter |
adf30a |
- if (!f.isValid()) {
|
|
Rex Dieter |
adf30a |
- // since we OR this condition, we can skip invalid flags to speed up the query
|
|
Rex Dieter |
adf30a |
- continue;
|
|
Rex Dieter |
adf30a |
- }
|
|
Rex Dieter |
adf30a |
- cond.addValueCondition( PimItemFlagRelation::rightFullColumnName(), Query::Equals, f.id() );
|
|
Rex Dieter |
adf30a |
- }
|
|
Rex Dieter |
adf30a |
- qb.addCondition( cond );
|
|
Rex Dieter |
adf30a |
- if ( !qb.exec() ) {
|
|
Rex Dieter |
adf30a |
- return -1;
|
|
Rex Dieter |
adf30a |
- }
|
|
Rex Dieter |
adf30a |
- return qb.result();
|
|
Rex Dieter |
adf30a |
-}
|
|
Rex Dieter |
adf30a |
-
|
|
Rex Dieter |
adf30a |
-int HandlerHelper::itemCount( const Collection &col )
|
|
Rex Dieter |
adf30a |
-{
|
|
Rex Dieter |
adf30a |
- CountQueryBuilder qb( PimItem::tableName() );
|
|
Rex Dieter |
adf30a |
- qb.addValueCondition( PimItem::collectionIdColumn(), Query::Equals, col.id() );
|
|
Rex Dieter |
adf30a |
- if ( !qb.exec() ) {
|
|
Rex Dieter |
adf30a |
- return -1;
|
|
Rex Dieter |
adf30a |
- }
|
|
Rex Dieter |
adf30a |
- return qb.result();
|
|
Rex Dieter |
adf30a |
-}
|
|
Rex Dieter |
adf30a |
-
|
|
Rex Dieter |
adf30a |
int HandlerHelper::parseCachePolicy( const QByteArray &data, Collection &col, int start, bool *changed )
|
|
Rex Dieter |
adf30a |
{
|
|
Rex Dieter |
adf30a |
bool inheritChanged = false;
|
|
Rex Dieter |
adf30a |
@@ -233,14 +166,12 @@ QByteArray HandlerHelper::collectionToByteArray( const Collection &col, bool hid
|
|
Rex Dieter |
adf30a |
b += " " AKONADI_PARAM_VIRTUAL " " + QByteArray::number( col.isVirtual() ) + ' ';
|
|
Rex Dieter |
adf30a |
|
|
Rex Dieter |
adf30a |
if ( includeStatistics ) {
|
|
Rex Dieter |
adf30a |
- qint64 itemCount, itemSize;
|
|
Rex Dieter |
adf30a |
- if ( itemStatistics( col, itemCount, itemSize ) ) {
|
|
Rex Dieter |
adf30a |
- b += AKONADI_ATTRIBUTE_MESSAGES " " + QByteArray::number( itemCount ) + ' ';
|
|
Rex Dieter |
adf30a |
- // itemWithFlagCount is twice as fast as itemWithoutFlagCount, so emulated that...
|
|
Rex Dieter |
adf30a |
+ const CollectionStatistics::Statistics &stats = CollectionStatistics::instance()->statistics(col);
|
|
Rex Dieter |
adf30a |
+ if (stats.count > -1) {
|
|
Rex Dieter |
adf30a |
+ b += AKONADI_ATTRIBUTE_MESSAGES " " + QByteArray::number( stats.count ) + ' ';
|
|
Rex Dieter |
adf30a |
b += AKONADI_ATTRIBUTE_UNSEEN " ";
|
|
Rex Dieter |
adf30a |
- b += QByteArray::number( itemCount - itemWithFlagsCount( col, QStringList() << QLatin1String( AKONADI_FLAG_SEEN )
|
|
Rex Dieter |
adf30a |
- << QLatin1String( AKONADI_FLAG_IGNORED ) ) );
|
|
Rex Dieter |
adf30a |
- b += " " AKONADI_PARAM_SIZE " " + QByteArray::number( itemSize ) + ' ';
|
|
Rex Dieter |
adf30a |
+ b += QByteArray::number( stats.count - stats.read) ;
|
|
Rex Dieter |
adf30a |
+ b += " " AKONADI_PARAM_SIZE " " + QByteArray::number( stats.size ) + ' ';
|
|
Rex Dieter |
adf30a |
}
|
|
Rex Dieter |
adf30a |
}
|
|
Rex Dieter |
adf30a |
|
|
Rex Dieter |
adf30a |
diff --git a/server/src/handlerhelper.h b/server/src/handlerhelper.h
|
|
Rex Dieter |
adf30a |
index 22e6e1c..cf9ac22 100644
|
|
Rex Dieter |
adf30a |
--- a/server/src/handlerhelper.h
|
|
Rex Dieter |
adf30a |
+++ b/server/src/handlerhelper.h
|
|
Rex Dieter |
adf30a |
@@ -52,28 +52,6 @@ class HandlerHelper
|
|
Rex Dieter |
adf30a |
static QString pathForCollection( const Collection &col );
|
|
Rex Dieter |
adf30a |
|
|
Rex Dieter |
adf30a |
/**
|
|
Rex Dieter |
adf30a |
- Returns the amount of existing items in the given collection.
|
|
Rex Dieter |
adf30a |
- @return -1 on error
|
|
Rex Dieter |
adf30a |
- */
|
|
Rex Dieter |
adf30a |
- static int itemCount( const Collection &col );
|
|
Rex Dieter |
adf30a |
-
|
|
Rex Dieter |
adf30a |
- /**
|
|
Rex Dieter |
adf30a |
- * Queries for collection statistics.
|
|
Rex Dieter |
adf30a |
- * @param col The collection to query.
|
|
Rex Dieter |
adf30a |
- * @param count The total amount of items in this collection.
|
|
Rex Dieter |
adf30a |
- * @param size The size of all items in this collection.
|
|
Rex Dieter |
adf30a |
- * @return @c false on a query error, @c true otherwise
|
|
Rex Dieter |
adf30a |
- */
|
|
Rex Dieter |
adf30a |
- static bool itemStatistics( const Collection &col, qint64 &count, qint64 &size );
|
|
Rex Dieter |
adf30a |
-
|
|
Rex Dieter |
adf30a |
- /**
|
|
Rex Dieter |
adf30a |
- Returns the amount of existing items in the given collection
|
|
Rex Dieter |
adf30a |
- which have a given flag set.
|
|
Rex Dieter |
adf30a |
- @return -1 on error.
|
|
Rex Dieter |
adf30a |
- */
|
|
Rex Dieter |
adf30a |
- static int itemWithFlagsCount( const Collection &col, const QStringList &flags );
|
|
Rex Dieter |
adf30a |
-
|
|
Rex Dieter |
adf30a |
- /**
|
|
Rex Dieter |
adf30a |
Parse cache policy and update the given Collection object accoordingly.
|
|
Rex Dieter |
adf30a |
@param changed Indicates whether or not the cache policy already available in @p col
|
|
Rex Dieter |
adf30a |
has actually changed
|
|
Rex Dieter |
adf30a |
diff --git a/server/src/storage/collectionstatistics.cpp b/server/src/storage/collectionstatistics.cpp
|
|
Rex Dieter |
adf30a |
new file mode 100644
|
|
Rex Dieter |
adf30a |
index 0000000..85ee449
|
|
Rex Dieter |
adf30a |
--- /dev/null
|
|
Rex Dieter |
adf30a |
+++ b/server/src/storage/collectionstatistics.cpp
|
|
Rex Dieter |
adf30a |
@@ -0,0 +1,108 @@
|
|
Rex Dieter |
adf30a |
+/*
|
|
Rex Dieter |
adf30a |
+ * Copyright (C) 2014 Daniel Vrátil <dvratil@redhat.com>
|
|
Rex Dieter |
adf30a |
+ *
|
|
Rex Dieter |
adf30a |
+ * This library is free software; you can redistribute it and/or
|
|
Rex Dieter |
adf30a |
+ * modify it under the terms of the GNU Lesser General Public
|
|
Rex Dieter |
adf30a |
+ * License as published by the Free Software Foundation; either
|
|
Rex Dieter |
adf30a |
+ * version 2.1 of the License, or (at your option) any later version.
|
|
Rex Dieter |
adf30a |
+ *
|
|
Rex Dieter |
adf30a |
+ * This library is distributed in the hope that it will be useful,
|
|
Rex Dieter |
adf30a |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Rex Dieter |
adf30a |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Rex Dieter |
adf30a |
+ * Lesser General Public License for more details.
|
|
Rex Dieter |
adf30a |
+ *
|
|
Rex Dieter |
adf30a |
+ * You should have received a copy of the GNU Lesser General Public
|
|
Rex Dieter |
adf30a |
+ * License along with this library; if not, write to the Free Software
|
|
Rex Dieter |
adf30a |
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
Rex Dieter |
adf30a |
+ *
|
|
Rex Dieter |
adf30a |
+ */
|
|
Rex Dieter |
adf30a |
+
|
|
Rex Dieter |
adf30a |
+#include "collectionstatistics.h"
|
|
Rex Dieter |
adf30a |
+#include "querybuilder.h"
|
|
Rex Dieter |
adf30a |
+#include "countquerybuilder.h"
|
|
Rex Dieter |
adf30a |
+#include "akdebug.h"
|
|
Rex Dieter |
adf30a |
+#include "entities.h"
|
|
Rex Dieter |
adf30a |
+
|
|
Rex Dieter |
adf30a |
+#include <libs/protocol_p.h>
|
|
Rex Dieter |
adf30a |
+
|
|
Rex Dieter |
adf30a |
+#include <QDateTime>
|
|
Rex Dieter |
adf30a |
+
|
|
Rex Dieter |
adf30a |
+using namespace Akonadi::Server;
|
|
Rex Dieter |
adf30a |
+
|
|
Rex Dieter |
adf30a |
+CollectionStatistics *CollectionStatistics::sInstance = 0;
|
|
Rex Dieter |
adf30a |
+
|
|
Rex Dieter |
adf30a |
+CollectionStatistics* CollectionStatistics::instance()
|
|
Rex Dieter |
adf30a |
+{
|
|
Rex Dieter |
adf30a |
+ static QMutex lock;
|
|
Rex Dieter |
adf30a |
+ lock.lock();
|
|
Rex Dieter |
adf30a |
+ if (sInstance == 0) {
|
|
Rex Dieter |
adf30a |
+ sInstance = new CollectionStatistics();
|
|
Rex Dieter |
adf30a |
+ }
|
|
Rex Dieter |
adf30a |
+ lock.unlock();
|
|
Rex Dieter |
adf30a |
+ return sInstance;
|
|
Rex Dieter |
adf30a |
+}
|
|
Rex Dieter |
adf30a |
+
|
|
Rex Dieter |
adf30a |
+void CollectionStatistics::invalidateCollection(const Collection &col)
|
|
Rex Dieter |
adf30a |
+{
|
|
Rex Dieter |
adf30a |
+ QMutexLocker lock(&mCacheLock);
|
|
Rex Dieter |
adf30a |
+ mCache.remove(col.id());
|
|
Rex Dieter |
adf30a |
+}
|
|
Rex Dieter |
adf30a |
+
|
|
Rex Dieter |
adf30a |
+const CollectionStatistics::Statistics& CollectionStatistics::statistics(const Collection &col)
|
|
Rex Dieter |
adf30a |
+{
|
|
Rex Dieter |
adf30a |
+ QMutexLocker lock(&mCacheLock);
|
|
Rex Dieter |
adf30a |
+ auto it = mCache.find(col.id());
|
|
Rex Dieter |
adf30a |
+ if (it == mCache.constEnd()) {
|
|
Rex Dieter |
adf30a |
+ it = mCache.insert(col.id(), getCollectionStatistics(col));
|
|
Rex Dieter |
adf30a |
+ }
|
|
Rex Dieter |
adf30a |
+ return it.value();
|
|
Rex Dieter |
adf30a |
+}
|
|
Rex Dieter |
adf30a |
+
|
|
Rex Dieter |
adf30a |
+CollectionStatistics::Statistics CollectionStatistics::getCollectionStatistics(const Collection &col)
|
|
Rex Dieter |
adf30a |
+{
|
|
Rex Dieter |
adf30a |
+ QueryBuilder qb(PimItem::tableName());
|
|
Rex Dieter |
adf30a |
+ // COUNT(DISTINCT PimItemTable.id)
|
|
Rex Dieter |
adf30a |
+ qb.addAggregation(QString::fromLatin1("DISTINCT %1")
|
|
Rex Dieter |
adf30a |
+ .arg(PimItem::idFullColumnName()),
|
|
Rex Dieter |
adf30a |
+ QLatin1String("count"));
|
|
Rex Dieter |
adf30a |
+ // SUM(PimItemTable.size)
|
|
Rex Dieter |
adf30a |
+ qb.addAggregation(PimItem::sizeFullColumnName(), QLatin1String("sum"));
|
|
Rex Dieter |
adf30a |
+ // SUM(CASE WHEN FlagTable.name IN ('\SEEN', '$IGNORED') THEN 1 ELSE 0 END)
|
|
Rex Dieter |
adf30a |
+ // This allows us to get read messages count in a single query with the other
|
|
Rex Dieter |
adf30a |
+ // statistics. It is much than doing two queries, because the database
|
|
Rex Dieter |
adf30a |
+ // only has to calculate the JOINs once.
|
|
Rex Dieter |
adf30a |
+ //
|
|
Rex Dieter |
adf30a |
+ // Flag::retrieveByName() will hit the Entity cache, which allows us to avoid
|
|
Rex Dieter |
adf30a |
+ // a second JOIN with FlagTable, which PostgreSQL seems to struggle to optimize.
|
|
Rex Dieter |
adf30a |
+ Query::Condition cond(Query::Or);
|
|
Rex Dieter |
adf30a |
+ cond.addValueCondition(PimItemFlagRelation::rightFullColumnName(),
|
|
Rex Dieter |
adf30a |
+ Query::Equals,
|
|
Rex Dieter |
adf30a |
+ Flag::retrieveByName(QLatin1String(AKONADI_FLAG_SEEN)).id());
|
|
Rex Dieter |
adf30a |
+ cond.addValueCondition(PimItemFlagRelation::rightFullColumnName(),
|
|
Rex Dieter |
adf30a |
+ Query::Equals,
|
|
Rex Dieter |
adf30a |
+ Flag::retrieveByName(QLatin1String(AKONADI_FLAG_IGNORED)).id());
|
|
Rex Dieter |
adf30a |
+ Query::Case caseStmt(cond, QLatin1String("1"), QLatin1String("0"));
|
|
Rex Dieter |
adf30a |
+ qb.addAggregation(caseStmt, QLatin1String("sum"));
|
|
Rex Dieter |
adf30a |
+
|
|
Rex Dieter |
adf30a |
+ qb.addJoin(QueryBuilder::LeftJoin, PimItemFlagRelation::tableName(),
|
|
Rex Dieter |
adf30a |
+ PimItem::idFullColumnName(), PimItemFlagRelation::leftFullColumnName());
|
|
Rex Dieter |
adf30a |
+ if (col.isVirtual()) {
|
|
Rex Dieter |
adf30a |
+ qb.addJoin(QueryBuilder::InnerJoin, CollectionPimItemRelation::tableName(),
|
|
Rex Dieter |
adf30a |
+ CollectionPimItemRelation::rightFullColumnName(), PimItem::idFullColumnName());
|
|
Rex Dieter |
adf30a |
+ qb.addValueCondition(CollectionPimItemRelation::leftFullColumnName(), Query::Equals, col.id());
|
|
Rex Dieter |
adf30a |
+ } else {
|
|
Rex Dieter |
adf30a |
+ qb.addValueCondition(PimItem::collectionIdColumn(), Query::Equals, col.id());
|
|
Rex Dieter |
adf30a |
+ }
|
|
Rex Dieter |
adf30a |
+
|
|
Rex Dieter |
adf30a |
+ if (!qb.exec()) {
|
|
Rex Dieter |
adf30a |
+ return { -1, -1, -1 };
|
|
Rex Dieter |
adf30a |
+ }
|
|
Rex Dieter |
adf30a |
+ if (!qb.query().next()) {
|
|
Rex Dieter |
adf30a |
+ akError() << "Error during retrieving result of statistics query:" << qb.query().lastError().text();
|
|
Rex Dieter |
adf30a |
+ return { -1, -1, -1 };
|
|
Rex Dieter |
adf30a |
+ }
|
|
Rex Dieter |
adf30a |
+
|
|
Rex Dieter |
adf30a |
+ return { qb.query().value(0).toLongLong(),
|
|
Rex Dieter |
adf30a |
+ qb.query().value(1).toLongLong(),
|
|
Rex Dieter |
adf30a |
+ qb.query().value(2).toLongLong() };
|
|
Rex Dieter |
adf30a |
+}
|
|
Rex Dieter |
adf30a |
diff --git a/server/src/storage/collectionstatistics.h b/server/src/storage/collectionstatistics.h
|
|
Rex Dieter |
adf30a |
new file mode 100644
|
|
Rex Dieter |
adf30a |
index 0000000..2c0af6a
|
|
Rex Dieter |
adf30a |
--- /dev/null
|
|
Rex Dieter |
adf30a |
+++ b/server/src/storage/collectionstatistics.h
|
|
Rex Dieter |
adf30a |
@@ -0,0 +1,70 @@
|
|
Rex Dieter |
adf30a |
+/*
|
|
Rex Dieter |
adf30a |
+ * Copyright (C) 2014 Daniel Vrátil <dvratil@redhat.com>
|
|
Rex Dieter |
adf30a |
+ *
|
|
Rex Dieter |
adf30a |
+ * This library is free software; you can redistribute it and/or
|
|
Rex Dieter |
adf30a |
+ * modify it under the terms of the GNU Lesser General Public
|
|
Rex Dieter |
adf30a |
+ * License as published by the Free Software Foundation; either
|
|
Rex Dieter |
adf30a |
+ * version 2.1 of the License, or (at your option) any later version.
|
|
Rex Dieter |
adf30a |
+ *
|
|
Rex Dieter |
adf30a |
+ * This library is distributed in the hope that it will be useful,
|
|
Rex Dieter |
adf30a |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Rex Dieter |
adf30a |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Rex Dieter |
adf30a |
+ * Lesser General Public License for more details.
|
|
Rex Dieter |
adf30a |
+ *
|
|
Rex Dieter |
adf30a |
+ * You should have received a copy of the GNU Lesser General Public
|
|
Rex Dieter |
adf30a |
+ * License along with this library; if not, write to the Free Software
|
|
Rex Dieter |
adf30a |
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
Rex Dieter |
adf30a |
+ *
|
|
Rex Dieter |
adf30a |
+ */
|
|
Rex Dieter |
adf30a |
+
|
|
Rex Dieter |
adf30a |
+#ifndef AKONADI_SERVER_COLLECTIONSTATISTICS_H
|
|
Rex Dieter |
adf30a |
+#define AKONADI_SERVER_COLLECTIONSTATISTICS_H
|
|
Rex Dieter |
adf30a |
+
|
|
Rex Dieter |
adf30a |
+class QMutex;
|
|
Rex Dieter |
adf30a |
+
|
|
Rex Dieter |
adf30a |
+#include <QHash>
|
|
Rex Dieter |
adf30a |
+#include <QMutex>
|
|
Rex Dieter |
adf30a |
+
|
|
Rex Dieter |
adf30a |
+namespace Akonadi {
|
|
Rex Dieter |
adf30a |
+namespace Server {
|
|
Rex Dieter |
adf30a |
+
|
|
Rex Dieter |
adf30a |
+class Collection;
|
|
Rex Dieter |
adf30a |
+
|
|
Rex Dieter |
adf30a |
+/**
|
|
Rex Dieter |
adf30a |
+ * Provides cache for collection statistics
|
|
Rex Dieter |
adf30a |
+ *
|
|
Rex Dieter |
adf30a |
+ * Collection statistics are requested very often, so to take some load from the
|
|
Rex Dieter |
adf30a |
+ * database we cache the results until the statistics are invalidated (see
|
|
Rex Dieter |
adf30a |
+ * NotificationCollector, which takes care for invalidating the statistics).
|
|
Rex Dieter |
adf30a |
+ *
|
|
Rex Dieter |
adf30a |
+ * The cache (together with optimization of the actual SQL query) seems to
|
|
Rex Dieter |
adf30a |
+ * massively improve initial folder listing on system start (when IO and CPU loads
|
|
Rex Dieter |
adf30a |
+ * are very high).
|
|
Rex Dieter |
adf30a |
+ */
|
|
Rex Dieter |
adf30a |
+class CollectionStatistics
|
|
Rex Dieter |
adf30a |
+{
|
|
Rex Dieter |
adf30a |
+public:
|
|
Rex Dieter |
adf30a |
+ struct Statistics {
|
|
Rex Dieter |
adf30a |
+ qint64 count;
|
|
Rex Dieter |
adf30a |
+ qint64 size;
|
|
Rex Dieter |
adf30a |
+ qint64 read;
|
|
Rex Dieter |
adf30a |
+ };
|
|
Rex Dieter |
adf30a |
+
|
|
Rex Dieter |
adf30a |
+ static CollectionStatistics* instance();
|
|
Rex Dieter |
adf30a |
+
|
|
Rex Dieter |
adf30a |
+ const Statistics& statistics(const Collection &col);
|
|
Rex Dieter |
adf30a |
+ void invalidateCollection(const Collection &col);
|
|
Rex Dieter |
adf30a |
+
|
|
Rex Dieter |
adf30a |
+private:
|
|
Rex Dieter |
adf30a |
+ Statistics getCollectionStatistics(const Collection &col);
|
|
Rex Dieter |
adf30a |
+
|
|
Rex Dieter |
adf30a |
+ QMutex mCacheLock;
|
|
Rex Dieter |
adf30a |
+ QHash<qint64, Statistics> mCache;
|
|
Rex Dieter |
adf30a |
+
|
|
Rex Dieter |
adf30a |
+ static CollectionStatistics *sInstance;
|
|
Rex Dieter |
adf30a |
+};
|
|
Rex Dieter |
adf30a |
+
|
|
Rex Dieter |
adf30a |
+} // namespace Server
|
|
Rex Dieter |
adf30a |
+} // namespace Akonadi
|
|
Rex Dieter |
adf30a |
+
|
|
Rex Dieter |
adf30a |
+#endif // AKONADI_SERVER_COLLECTIONSTATISTICS_H
|
|
Rex Dieter |
adf30a |
diff --git a/server/src/storage/datastore.cpp b/server/src/storage/datastore.cpp
|
|
Rex Dieter |
adf30a |
index 304f0e8..0983d84 100644
|
|
Rex Dieter |
adf30a |
--- a/server/src/storage/datastore.cpp
|
|
Rex Dieter |
adf30a |
+++ b/server/src/storage/datastore.cpp
|
|
Rex Dieter |
adf30a |
@@ -209,7 +209,7 @@ DataStore *DataStore::self()
|
|
Rex Dieter |
adf30a |
/* --- ItemFlags ----------------------------------------------------- */
|
|
Rex Dieter |
adf30a |
|
|
Rex Dieter |
adf30a |
bool DataStore::setItemsFlags( const PimItem::List &items, const QVector<Flag> &flags,
|
|
Rex Dieter |
adf30a |
- bool *flagsChanged, bool silent )
|
|
Rex Dieter |
adf30a |
+ bool *flagsChanged, const Collection &col, bool silent )
|
|
Rex Dieter |
adf30a |
{
|
|
Rex Dieter |
adf30a |
QSet<QByteArray> removedFlags;
|
|
Rex Dieter |
adf30a |
QSet<QByteArray> addedFlags;
|
|
Rex Dieter |
adf30a |
@@ -258,7 +258,7 @@ bool DataStore::setItemsFlags( const PimItem::List &items, const QVector<Flag> &
|
|
Rex Dieter |
adf30a |
}
|
|
Rex Dieter |
adf30a |
|
|
Rex Dieter |
adf30a |
if ( !silent && ( !addedFlags.isEmpty() || !removedFlags.isEmpty() ) ) {
|
|
Rex Dieter |
adf30a |
- mNotificationCollector->itemsFlagsChanged( items, addedFlags, removedFlags );
|
|
Rex Dieter |
adf30a |
+ mNotificationCollector->itemsFlagsChanged( items, addedFlags, removedFlags, col );
|
|
Rex Dieter |
adf30a |
}
|
|
Rex Dieter |
adf30a |
|
|
Rex Dieter |
adf30a |
setBoolPtr( flagsChanged, ( addedFlags != removedFlags ) );
|
|
Rex Dieter |
adf30a |
@@ -361,7 +361,7 @@ bool DataStore::appendItemsFlags( const PimItem::List &items, const QVector
|
|
Rex Dieter |
adf30a |
}
|
|
Rex Dieter |
adf30a |
|
|
Rex Dieter |
adf30a |
bool DataStore::removeItemsFlags( const PimItem::List &items, const QVector<Flag> &flags,
|
|
Rex Dieter |
adf30a |
- bool *flagsChanged, bool silent )
|
|
Rex Dieter |
adf30a |
+ bool *flagsChanged, const Collection &col, bool silent )
|
|
Rex Dieter |
adf30a |
{
|
|
Rex Dieter |
adf30a |
QSet<QByteArray> removedFlags;
|
|
Rex Dieter |
adf30a |
QVariantList itemsIds;
|
|
Rex Dieter |
adf30a |
@@ -393,7 +393,7 @@ bool DataStore::removeItemsFlags( const PimItem::List &items, const QVector
|
|
Rex Dieter |
adf30a |
if ( qb.query().numRowsAffected() != 0 ) {
|
|
Rex Dieter |
adf30a |
setBoolPtr( flagsChanged, true );
|
|
Rex Dieter |
adf30a |
if ( !silent ) {
|
|
Rex Dieter |
adf30a |
- mNotificationCollector->itemsFlagsChanged( items, QSet<QByteArray>(), removedFlags );
|
|
Rex Dieter |
adf30a |
+ mNotificationCollector->itemsFlagsChanged( items, QSet<QByteArray>(), removedFlags, col );
|
|
Rex Dieter |
adf30a |
}
|
|
Rex Dieter |
adf30a |
}
|
|
Rex Dieter |
adf30a |
|
|
Rex Dieter |
adf30a |
diff --git a/server/src/storage/datastore.h b/server/src/storage/datastore.h
|
|
Rex Dieter |
adf30a |
index 395b227..a2d8a42 100644
|
|
Rex Dieter |
adf30a |
--- a/server/src/storage/datastore.h
|
|
Rex Dieter |
adf30a |
+++ b/server/src/storage/datastore.h
|
|
Rex Dieter |
adf30a |
@@ -119,10 +119,12 @@ class DataStore : public QObject
|
|
Rex Dieter |
adf30a |
static DataStore *self();
|
|
Rex Dieter |
adf30a |
|
|
Rex Dieter |
adf30a |
/* --- ItemFlags ----------------------------------------------------- */
|
|
Rex Dieter |
adf30a |
- virtual bool setItemsFlags( const PimItem::List &items, const QVector<Flag> &flags, bool *flagsChanged = 0, bool silent = false );
|
|
Rex Dieter |
adf30a |
+ virtual bool setItemsFlags( const PimItem::List &items, const QVector<Flag> &flags,
|
|
Rex Dieter |
adf30a |
+ bool *flagsChanged = 0, const Collection &col = Collection(), bool silent = false );
|
|
Rex Dieter |
adf30a |
virtual bool appendItemsFlags( const PimItem::List &items, const QVector<Flag> &flags, bool *flagsChanged = 0,
|
|
Rex Dieter |
adf30a |
bool checkIfExists = true, const Collection &col = Collection(), bool silent = false );
|
|
Rex Dieter |
adf30a |
- virtual bool removeItemsFlags( const PimItem::List &items, const QVector<Flag> &flags, bool *tagsChanged = 0, bool silent = false );
|
|
Rex Dieter |
adf30a |
+ virtual bool removeItemsFlags( const PimItem::List &items, const QVector<Flag> &flags, bool *tagsChanged = 0,
|
|
Rex Dieter |
adf30a |
+ const Collection &collection = Collection(), bool silent = false );
|
|
Rex Dieter |
adf30a |
|
|
Rex Dieter |
adf30a |
/* --- ItemTags ----------------------------------------------------- */
|
|
Rex Dieter |
adf30a |
virtual bool setItemsTags( const PimItem::List &items, const Tag::List &tags, bool *tagsChanged = 0, bool silent = false );
|
|
Rex Dieter |
adf30a |
diff --git a/server/src/storage/notificationcollector.cpp b/server/src/storage/notificationcollector.cpp
|
|
Rex Dieter |
adf30a |
index 67f57d1..dbc7883 100644
|
|
Rex Dieter |
adf30a |
--- a/server/src/storage/notificationcollector.cpp
|
|
Rex Dieter |
adf30a |
+++ b/server/src/storage/notificationcollector.cpp
|
|
Rex Dieter |
adf30a |
@@ -20,6 +20,7 @@
|
|
Rex Dieter |
adf30a |
#include "notificationcollector.h"
|
|
Rex Dieter |
adf30a |
#include "storage/datastore.h"
|
|
Rex Dieter |
adf30a |
#include "storage/entity.h"
|
|
Rex Dieter |
adf30a |
+#include "storage/collectionstatistics.h"
|
|
Rex Dieter |
adf30a |
#include "handlerhelper.h"
|
|
Rex Dieter |
adf30a |
#include "cachecleaner.h"
|
|
Rex Dieter |
adf30a |
#include "intervalcheck.h"
|
|
Rex Dieter |
adf30a |
@@ -133,6 +134,7 @@ void NotificationCollector::collectionChanged( const Collection &collection,
|
|
Rex Dieter |
adf30a |
if ( AkonadiServer::instance()->intervalChecker() ) {
|
|
Rex Dieter |
adf30a |
AkonadiServer::instance()->intervalChecker()->collectionAdded( collection.id() );
|
|
Rex Dieter |
adf30a |
}
|
|
Rex Dieter |
adf30a |
+ CollectionStatistics::instance()->invalidateCollection(collection);
|
|
Rex Dieter |
adf30a |
collectionNotification( NotificationMessageV2::Modify, collection, collection.parentId(), -1, resource, changes.toSet() );
|
|
Rex Dieter |
adf30a |
}
|
|
Rex Dieter |
adf30a |
|
|
Rex Dieter |
adf30a |
@@ -159,6 +161,8 @@ void NotificationCollector::collectionRemoved( const Collection &collection,
|
|
Rex Dieter |
adf30a |
if ( AkonadiServer::instance()->intervalChecker() ) {
|
|
Rex Dieter |
adf30a |
AkonadiServer::instance()->intervalChecker()->collectionRemoved( collection.id() );
|
|
Rex Dieter |
adf30a |
}
|
|
Rex Dieter |
adf30a |
+ CollectionStatistics::instance()->invalidateCollection(collection);
|
|
Rex Dieter |
adf30a |
+
|
|
Rex Dieter |
adf30a |
collectionNotification( NotificationMessageV2::Remove, collection, collection.parentId(), -1, resource );
|
|
Rex Dieter |
adf30a |
}
|
|
Rex Dieter |
adf30a |
|
|
Rex Dieter |
adf30a |
@@ -183,6 +187,8 @@ void NotificationCollector::collectionUnsubscribed( const Collection &collection
|
|
Rex Dieter |
adf30a |
if ( AkonadiServer::instance()->intervalChecker() ) {
|
|
Rex Dieter |
adf30a |
AkonadiServer::instance()->intervalChecker()->collectionRemoved( collection.id() );
|
|
Rex Dieter |
adf30a |
}
|
|
Rex Dieter |
adf30a |
+ CollectionStatistics::instance()->invalidateCollection(collection);
|
|
Rex Dieter |
adf30a |
+
|
|
Rex Dieter |
adf30a |
collectionNotification( NotificationMessageV2::Unsubscribe, collection, collection.parentId(), -1, resource, QSet<QByteArray>() );
|
|
Rex Dieter |
adf30a |
}
|
|
Rex Dieter |
adf30a |
|
|
Rex Dieter |
adf30a |
@@ -282,6 +288,7 @@ void NotificationCollector::itemNotification( NotificationMessageV2::Operation o
|
|
Rex Dieter |
adf30a |
copy.setParentCollection( iter.key() );
|
|
Rex Dieter |
adf30a |
copy.setResource( resource );
|
|
Rex Dieter |
adf30a |
|
|
Rex Dieter |
adf30a |
+ CollectionStatistics::instance()->invalidateCollection(Collection::retrieveById(iter.key()));
|
|
Rex Dieter |
adf30a |
dispatchNotification( copy );
|
|
Rex Dieter |
adf30a |
}
|
|
Rex Dieter |
adf30a |
|
|
Rex Dieter |
adf30a |
@@ -304,6 +311,7 @@ void NotificationCollector::itemNotification( NotificationMessageV2::Operation o
|
|
Rex Dieter |
adf30a |
}
|
|
Rex Dieter |
adf30a |
msg.setResource( res );
|
|
Rex Dieter |
adf30a |
|
|
Rex Dieter |
adf30a |
+ CollectionStatistics::instance()->invalidateCollection(col);
|
|
Rex Dieter |
adf30a |
dispatchNotification( msg );
|
|
Rex Dieter |
adf30a |
}
|
|
Rex Dieter |
adf30a |
|
|
Rex Dieter |
adf30a |
diff --git a/server/tests/unittest/fakedatastore.cpp b/server/tests/unittest/fakedatastore.cpp
|
|
Rex Dieter |
adf30a |
index 12214fa..43ef7e6 100644
|
|
Rex Dieter |
adf30a |
--- a/server/tests/unittest/fakedatastore.cpp
|
|
Rex Dieter |
adf30a |
+++ b/server/tests/unittest/fakedatastore.cpp
|
|
Rex Dieter |
adf30a |
@@ -91,13 +91,15 @@ bool FakeDataStore::init()
|
|
Rex Dieter |
adf30a |
bool FakeDataStore::setItemsFlags( const PimItem::List &items,
|
|
Rex Dieter |
adf30a |
const QVector<Flag> &flags,
|
|
Rex Dieter |
adf30a |
bool *flagsChanged,
|
|
Rex Dieter |
adf30a |
+ const Collection &col,
|
|
Rex Dieter |
adf30a |
bool silent )
|
|
Rex Dieter |
adf30a |
{
|
|
Rex Dieter |
adf30a |
mChanges.insert( QLatin1String( "setItemsFlags" ),
|
|
Rex Dieter |
adf30a |
QVariantList() << QVariant::fromValue( items )
|
|
Rex Dieter |
adf30a |
<< QVariant::fromValue( flags )
|
|
Rex Dieter |
adf30a |
+ << QVariant::fromValue( col )
|
|
Rex Dieter |
adf30a |
<< silent );
|
|
Rex Dieter |
adf30a |
- return DataStore::setItemsFlags( items, flags, flagsChanged, silent );
|
|
Rex Dieter |
adf30a |
+ return DataStore::setItemsFlags( items, flags, flagsChanged, col, silent );
|
|
Rex Dieter |
adf30a |
}
|
|
Rex Dieter |
adf30a |
|
|
Rex Dieter |
adf30a |
bool FakeDataStore::appendItemsFlags( const PimItem::List &items,
|
|
Rex Dieter |
adf30a |
@@ -119,13 +121,15 @@ bool FakeDataStore::appendItemsFlags( const PimItem::List &items,
|
|
Rex Dieter |
adf30a |
bool FakeDataStore::removeItemsFlags( const PimItem::List &items,
|
|
Rex Dieter |
adf30a |
const QVector<Flag> &flags,
|
|
Rex Dieter |
adf30a |
bool *flagsChanged,
|
|
Rex Dieter |
adf30a |
+ const Collection &col,
|
|
Rex Dieter |
adf30a |
bool silent )
|
|
Rex Dieter |
adf30a |
{
|
|
Rex Dieter |
adf30a |
mChanges.insert( QLatin1String( "removeItemsFlags" ),
|
|
Rex Dieter |
adf30a |
QVariantList() << QVariant::fromValue( items )
|
|
Rex Dieter |
adf30a |
<< QVariant::fromValue( flags )
|
|
Rex Dieter |
adf30a |
+ << QVariant::fromValue( col )
|
|
Rex Dieter |
adf30a |
<< silent );
|
|
Rex Dieter |
adf30a |
- return DataStore::removeItemsFlags( items, flags, flagsChanged, silent );
|
|
Rex Dieter |
adf30a |
+ return DataStore::removeItemsFlags( items, flags, flagsChanged, col, silent );
|
|
Rex Dieter |
adf30a |
}
|
|
Rex Dieter |
adf30a |
|
|
Rex Dieter |
adf30a |
|
|
Rex Dieter |
adf30a |
diff --git a/server/tests/unittest/fakedatastore.h b/server/tests/unittest/fakedatastore.h
|
|
Rex Dieter |
adf30a |
index 62c5b75..cd9ab13 100644
|
|
Rex Dieter |
adf30a |
--- a/server/tests/unittest/fakedatastore.h
|
|
Rex Dieter |
adf30a |
+++ b/server/tests/unittest/fakedatastore.h
|
|
Rex Dieter |
adf30a |
@@ -41,6 +41,7 @@ class FakeDataStore: public DataStore
|
|
Rex Dieter |
adf30a |
virtual bool setItemsFlags( const PimItem::List &items,
|
|
Rex Dieter |
adf30a |
const QVector<Flag> &flags,
|
|
Rex Dieter |
adf30a |
bool *flagsChanged = 0,
|
|
Rex Dieter |
adf30a |
+ const Collection &col = Collection(),
|
|
Rex Dieter |
adf30a |
bool silent = false );
|
|
Rex Dieter |
adf30a |
virtual bool appendItemsFlags( const PimItem::List &items,
|
|
Rex Dieter |
adf30a |
const QVector<Flag> &flags,
|
|
Rex Dieter |
adf30a |
@@ -51,6 +52,7 @@ class FakeDataStore: public DataStore
|
|
Rex Dieter |
adf30a |
virtual bool removeItemsFlags( const PimItem::List &items,
|
|
Rex Dieter |
adf30a |
const QVector<Flag> &flags,
|
|
Rex Dieter |
adf30a |
bool *flagsChanged = 0,
|
|
Rex Dieter |
adf30a |
+ const Collection &col = Collection(),
|
|
Rex Dieter |
adf30a |
bool silent = false );
|
|
Rex Dieter |
adf30a |
|
|
Rex Dieter |
adf30a |
virtual bool setItemsTags( const PimItem::List &items,
|
|
Rex Dieter |
adf30a |
--
|
|
Rex Dieter |
adf30a |
2.1.0
|
|
Rex Dieter |
adf30a |
|