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);