Akonadi

querycache.cpp
1 /*
2  SPDX-FileCopyrightText: 2012 Volker Krause <[email protected]>
3 
4  SPDX-License-Identifier: LGPL-2.0-or-later
5  */
6 
7 #include "querycache.h"
8 #include "dbtype.h"
9 #include "datastore.h"
10 
11 #include <QSqlQuery>
12 #include <QThreadStorage>
13 #include <QHash>
14 #include <QTimer>
15 
16 #include <chrono>
17 #include <list>
18 
19 using namespace std::chrono_literals;
20 using namespace Akonadi;
21 using namespace Akonadi::Server;
22 
23 namespace {
24 
25 // After these seconds without activity the cache is cleaned
26 constexpr auto CleanupTimeout = 60s;
27 constexpr int MaxCacheSize = 50;
28 
31 class Cache
32 {
33 public:
34  Cache()
35  {
36  QObject::connect(&m_cleanupTimer, &QTimer::timeout, std::bind(&Cache::cleanup, this));
37  m_cleanupTimer.setSingleShot(true);
38  }
39 
40  std::optional<QSqlQuery> query(const QString &queryStatement)
41  {
42  m_cleanupTimer.start(CleanupTimeout);
43  auto it = m_keys.find(queryStatement);
44  if (it == m_keys.end()) {
45  return std::nullopt;
46  }
47 
48  auto node = **it;
49  m_queries.erase(*it);
50  m_queries.push_front(node);
51  *it = m_queries.begin();
52  return node.query;
53  }
54 
55  void insert(const QString &queryStatement, const QSqlQuery &query)
56  {
57  if (m_queries.size() >= MaxCacheSize) {
58  m_keys.remove(m_queries.back().queryStatement);
59  m_queries.pop_back();
60  }
61 
62  m_queries.emplace_front(Node{queryStatement, query});
63  m_keys.insert(queryStatement, m_queries.begin());
64  }
65 
66  void cleanup()
67  {
68  m_keys.clear();
69  m_queries.clear();
70  }
71 
72 public: // public, this is just a helper class
73  struct Node {
74  QString queryStatement;
75  QSqlQuery query;
76  };
77  std::list<Node> m_queries;
79  QTimer m_cleanupTimer;
80 };
81 
82 QThreadStorage<Cache *> g_queryCache;
83 
84 Cache *perThreadCache()
85 {
86  if (!g_queryCache.hasLocalData()) {
87  g_queryCache.setLocalData(new Cache());
88  }
89 
90  return g_queryCache.localData();
91 }
92 
93 } // namespace
94 
95 std::optional<QSqlQuery> QueryCache::query(const QString &queryStatement)
96 {
97  return perThreadCache()->query(queryStatement);
98 }
99 
100 void QueryCache::insert(const QString &queryStatement, const QSqlQuery &query)
101 {
102  if (DbType::type(DataStore::self()->database()) != DbType::Sqlite) {
103  perThreadCache()->insert(queryStatement, query);
104  }
105 }
106 
107 void QueryCache::clear()
108 {
109  if (!g_queryCache.hasLocalData()) {
110  return;
111  }
112 
113  g_queryCache.localData()->cleanup();
114 }
115 
QList::iterator erase(QList::iterator pos)
KSERVICE_EXPORT KService::List query(FilterFunc filterFunc)
void setLocalData(T data)
void timeout()
bool hasLocalData() const const
KGuiItem insert()
Helper integration between Akonadi and Qt.
QString::iterator begin()
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Wed Sep 23 2020 23:17:31 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.