File indexing completed on 2024-05-12 05:26:04
0001 /* 0002 * Copyright (C) 2014 Christian Mollekopf <chrigi_1@fastmail.fm> 0003 * Copyright (C) 2014 Aaron Seigo <aseigo@kde.org> 0004 * 0005 * This library is free software; you can redistribute it and/or 0006 * modify it under the terms of the GNU Lesser General Public 0007 * License as published by the Free Software Foundation; either 0008 * version 2.1 of the License, or (at your option) version 3, or any 0009 * later version accepted by the membership of KDE e.V. (or its 0010 * successor approved by the membership of KDE e.V.), which shall 0011 * act as a proxy defined in Section 6 of version 3 of the license. 0012 * 0013 * This library is distributed in the hope that it will be useful, 0014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0016 * Lesser General Public License for more details. 0017 * 0018 * You should have received a copy of the GNU Lesser General Public 0019 * License along with this library. If not, see <http://www.gnu.org/licenses/>. 0020 */ 0021 0022 #pragma once 0023 0024 #include "sink_export.h" 0025 #include "utils.h" 0026 #include "storage/key.h" 0027 #include <string> 0028 #include <functional> 0029 #include <QString> 0030 #include <QMap> 0031 0032 namespace Sink { 0033 namespace Storage { 0034 0035 extern SINK_EXPORT int AllowDuplicates; 0036 extern SINK_EXPORT int IntegerKeys; 0037 // Only useful with AllowDuplicates 0038 extern SINK_EXPORT int IntegerValues; 0039 0040 struct SINK_EXPORT DbLayout { 0041 typedef QMap<QByteArray, int> Databases; 0042 DbLayout(); 0043 DbLayout(const QByteArray &, const Databases &); 0044 QByteArray name; 0045 Databases tables; 0046 }; 0047 0048 class SINK_EXPORT DataStore 0049 { 0050 public: 0051 enum AccessMode 0052 { 0053 ReadOnly, 0054 ReadWrite 0055 }; 0056 0057 enum ErrorCodes 0058 { 0059 GenericError, 0060 NotOpen, 0061 ReadOnlyError, 0062 TransactionError, 0063 NotFound 0064 }; 0065 0066 class SINK_EXPORT Error 0067 { 0068 public: 0069 Error(const QByteArray &s, int c, const QByteArray &m) : store(s), message(m), code(c) 0070 { 0071 } 0072 QByteArray store; 0073 QByteArray message; 0074 int code; 0075 }; 0076 0077 class Transaction; 0078 class SINK_EXPORT NamedDatabase 0079 { 0080 public: 0081 NamedDatabase(); 0082 ~NamedDatabase(); 0083 /** 0084 * Write a value 0085 */ 0086 bool write(const QByteArray &key, const QByteArray &value, const std::function<void(const DataStore::Error &error)> &errorHandler = std::function<void(const DataStore::Error &error)>()); 0087 0088 // of QByteArray for keys 0089 bool write(const size_t key, const QByteArray &value, const std::function<void(const DataStore::Error &error)> &errorHandler = std::function<void(const DataStore::Error &error)>()); 0090 0091 /** 0092 * Remove a key 0093 */ 0094 void remove(const QByteArray &key, const std::function<void(const DataStore::Error &error)> &errorHandler = std::function<void(const DataStore::Error &error)>()); 0095 0096 void remove(const size_t key, const std::function<void(const DataStore::Error &error)> &errorHandler = std::function<void(const DataStore::Error &error)>()); 0097 0098 /** 0099 * Remove a key-value pair 0100 */ 0101 void remove(const QByteArray &key, const QByteArray &value, const std::function<void(const DataStore::Error &error)> &errorHandler = std::function<void(const DataStore::Error &error)>()); 0102 0103 void remove(const size_t key, const QByteArray &value, const std::function<void(const DataStore::Error &error)> &errorHandler = std::function<void(const DataStore::Error &error)>()); 0104 0105 /** 0106 * Read values with a given key. 0107 * 0108 * * An empty @param key results in a full scan 0109 * * If duplicates are existing (revisions), all values are returned. 0110 * * The pointers of the returned values are valid during the execution of the @param resultHandler 0111 * 0112 * @return The number of values retrieved. 0113 */ 0114 int scan(const QByteArray &key, const std::function<bool(const QByteArray &key, const QByteArray &value)> &resultHandler, 0115 const std::function<void(const DataStore::Error &error)> &errorHandler = std::function<void(const DataStore::Error &error)>(), bool findSubstringKeys = false) const; 0116 0117 int scan(const size_t key, const std::function<bool(size_t key, const QByteArray &value)> &resultHandler, 0118 const std::function<void(const DataStore::Error &error)> &errorHandler = std::function<void(const DataStore::Error &error)>()) const; 0119 0120 /** 0121 * Finds the last value in a series matched by prefix. 0122 * 0123 * This is used to match by uid prefix and find the highest revision. 0124 * Note that this relies on a key scheme like $uid$revision. 0125 */ 0126 void findLatest(const QByteArray &uid, const std::function<void(const QByteArray &key, const QByteArray &value)> &resultHandler, 0127 const std::function<void(const DataStore::Error &error)> &errorHandler = std::function<void(const DataStore::Error &error)>()) const; 0128 0129 void findLatest(size_t key, const std::function<void(size_t key, const QByteArray &value)> &resultHandler, 0130 const std::function<void(const DataStore::Error &error)> &errorHandler = std::function<void(const DataStore::Error &error)>()) const; 0131 0132 /** 0133 * Finds the last value by key in sorted duplicates. 0134 * 0135 * Only makes sense for a database with AllowDuplicates 0136 */ 0137 void findLast(const QByteArray &uid, const std::function<void(const QByteArray &key, const QByteArray &value)> &resultHandler, 0138 const std::function<void(const DataStore::Error &error)> &errorHandler = std::function<void(const DataStore::Error &error)>()) const; 0139 0140 /** 0141 * Finds all the keys and values whose keys are in a given range 0142 * (inclusive). 0143 */ 0144 int findAllInRange(const QByteArray &lowerBound, const QByteArray &upperBound, 0145 const std::function<void(const QByteArray &key, const QByteArray &value)> &resultHandler, 0146 const std::function<void(const DataStore::Error &error)> &errorHandler = 0147 std::function<void(const DataStore::Error &error)>()) const; 0148 0149 int findAllInRange(const size_t lowerBound, const size_t upperBound, 0150 const std::function<void(size_t key, const QByteArray &value)> &resultHandler, 0151 const std::function<void(const DataStore::Error &error)> &errorHandler = {}) const; 0152 0153 /** 0154 * Returns true if the database contains the substring key. 0155 */ 0156 bool contains(const QByteArray &uid); 0157 0158 NamedDatabase(NamedDatabase &&other); 0159 NamedDatabase &operator=(NamedDatabase &&other); 0160 0161 operator bool() const 0162 { 0163 return (d != nullptr); 0164 } 0165 0166 qint64 getSize(); 0167 0168 struct Stat { 0169 size_t branchPages; 0170 size_t leafPages; 0171 size_t overflowPages; 0172 size_t numEntries; 0173 }; 0174 Stat stat(); 0175 0176 bool allowsDuplicates() const; 0177 0178 private: 0179 friend Transaction; 0180 NamedDatabase(NamedDatabase &other); 0181 NamedDatabase &operator=(NamedDatabase &other); 0182 class Private; 0183 NamedDatabase(Private *); 0184 Private *d; 0185 }; 0186 0187 class SINK_EXPORT Transaction 0188 { 0189 public: 0190 Transaction(); 0191 ~Transaction(); 0192 bool commit(const std::function<void(const DataStore::Error &error)> &errorHandler = {}); 0193 void abort(); 0194 0195 QList<QByteArray> getDatabaseNames() const; 0196 0197 NamedDatabase openDatabase(const QByteArray &name = { "default" }, 0198 const std::function<void(const DataStore::Error &error)> &errorHandler = {}, 0199 int flags = 0) const; 0200 0201 Transaction(Transaction &&other); 0202 Transaction &operator=(Transaction &&other); 0203 0204 operator bool() const; 0205 0206 struct Stat { 0207 size_t totalPages; 0208 size_t freePages; 0209 size_t pageSize; 0210 NamedDatabase::Stat mainDbStat; 0211 NamedDatabase::Stat freeDbStat; 0212 }; 0213 Stat stat(bool printDetails = true); 0214 0215 private: 0216 Transaction(Transaction &other); 0217 Transaction &operator=(Transaction &other); 0218 friend DataStore; 0219 class Private; 0220 Transaction(Private *); 0221 Private *d; 0222 }; 0223 0224 DataStore(const QString &storageRoot, const QString &name, AccessMode mode = ReadOnly); 0225 DataStore(const QString &storageRoot, const DbLayout &layout, AccessMode mode = ReadOnly); 0226 ~DataStore(); 0227 0228 Transaction createTransaction(AccessMode mode = ReadWrite, const std::function<void(const DataStore::Error &error)> &errorHandler = std::function<void(const DataStore::Error &error)>()); 0229 0230 /** 0231 * Set the default error handler. 0232 */ 0233 void setDefaultErrorHandler(const std::function<void(const DataStore::Error &error)> &errorHandler); 0234 std::function<void(const DataStore::Error &error)> defaultErrorHandler() const; 0235 0236 /** 0237 * A basic error handler that writes to std::cerr. 0238 * 0239 * Used if nothing else is configured. 0240 */ 0241 static std::function<void(const DataStore::Error &error)> basicErrorHandler(); 0242 0243 qint64 diskUsage() const; 0244 void removeFromDisk() const; 0245 0246 /** 0247 * Clears all cached environments. 0248 * 0249 * This only ever has to be called if a database was removed from another process. 0250 */ 0251 static void clearEnv(); 0252 0253 static qint64 maxRevision(const Transaction &); 0254 static void setMaxRevision(Transaction &, qint64 revision); 0255 0256 static qint64 cleanedUpRevision(const Transaction &); 0257 static void setCleanedUpRevision(Transaction &, qint64 revision); 0258 0259 static Identifier getUidFromRevision(const Transaction &, size_t revision); 0260 static size_t getLatestRevisionFromUid(Transaction &, const Identifier &uid); 0261 static QList<size_t> getRevisionsUntilFromUid(DataStore::Transaction &, const Identifier &uid, size_t lastRevision); 0262 static QList<size_t> getRevisionsFromUid(DataStore::Transaction &, const Identifier &uid); 0263 static QByteArray getTypeFromRevision(const Transaction &, size_t revision); 0264 static void recordRevision(Transaction &, size_t revision, const Identifier &uid, const QByteArray &type); 0265 static void removeRevision(Transaction &, size_t revision); 0266 static void recordUid(DataStore::Transaction &transaction, const Identifier &uid, const QByteArray &type); 0267 static void removeUid(DataStore::Transaction &transaction, const Identifier &uid, const QByteArray &type); 0268 static void getUids(const QByteArray &type, const Transaction &, const std::function<void(const Identifier &uid)> &); 0269 static bool hasUid(const QByteArray &type, const Transaction &, const Identifier &uid); 0270 0271 bool exists() const; 0272 static bool exists(const QString &storageRoot, const QString &name); 0273 0274 static NamedDatabase mainDatabase(const Transaction &, const QByteArray &type); 0275 0276 static QByteArray generateUid(); 0277 0278 static qint64 databaseVersion(const Transaction &); 0279 static void setDatabaseVersion(Transaction &, qint64 revision); 0280 0281 static QMap<QByteArray, int> baseDbs(); 0282 0283 private: 0284 std::function<void(const DataStore::Error &error)> mErrorHandler; 0285 0286 private: 0287 class Private; 0288 Private *const d; 0289 }; 0290 0291 } 0292 } // namespace Sink 0293 0294 SINK_EXPORT QDebug& operator<<(QDebug &dbg, const Sink::Storage::DataStore::Error &error);