File indexing completed on 2024-05-12 05:26:07

0001 /*
0002  * Copyright (C) 2016 Christian Mollekopf <mollekopf@kolabsys.com>
0003  *
0004  * This library is free software; you can redistribute it and/or
0005  * modify it under the terms of the GNU Lesser General Public
0006  * License as published by the Free Software Foundation; either
0007  * version 2.1 of the License, or (at your option) version 3, or any
0008  * later version accepted by the membership of KDE e.V. (or its
0009  * successor approved by the membership of KDE e.V.), which shall
0010  * act as a proxy defined in Section 6 of version 3 of the license.
0011  *
0012  * This library is distributed in the hope that it will be useful,
0013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0015  * Lesser General Public License for more details.
0016  *
0017  * You should have received a copy of the GNU Lesser General Public
0018  * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
0019  */
0020 #include "synchronizerstore.h"
0021 
0022 #include "index.h"
0023 #include "log.h"
0024 
0025 using namespace Sink;
0026 
0027 SynchronizerStore::SynchronizerStore(Sink::Storage::DataStore::Transaction &transaction)
0028     : mTransaction(transaction)
0029 {
0030 
0031 }
0032 
0033 void SynchronizerStore::recordRemoteId(const QByteArray &bufferType, const QByteArray &localId, const QByteArray &remoteId)
0034 {
0035     Index("rid.mapping." + bufferType, mTransaction).add(remoteId, localId);
0036     Index("localid.mapping." + bufferType, mTransaction).add(localId, remoteId);
0037 }
0038 
0039 void SynchronizerStore::removeRemoteId(const QByteArray &bufferType, const QByteArray &localId, const QByteArray &remoteId)
0040 {
0041     Index("rid.mapping." + bufferType, mTransaction).remove(remoteId, localId);
0042     Index("localid.mapping." + bufferType, mTransaction).remove(localId, remoteId);
0043 }
0044 
0045 void SynchronizerStore::updateRemoteId(const QByteArray &bufferType, const QByteArray &localId, const QByteArray &remoteId)
0046 {
0047     const auto oldRemoteId = Index("localid.mapping." + bufferType, mTransaction).lookup(localId);
0048     removeRemoteId(bufferType, localId, oldRemoteId);
0049     recordRemoteId(bufferType, localId, remoteId);
0050 }
0051 
0052 QByteArray SynchronizerStore::resolveRemoteId(const QByteArray &bufferType, const QByteArray &remoteId, bool insertIfMissing)
0053 {
0054     if (remoteId.isEmpty()) {
0055         SinkWarning() << "Cannot resolve empty remote id for type: " << bufferType;
0056         return {};
0057     }
0058     // Lookup local id for remote id, or insert a new pair otherwise
0059     Index index("rid.mapping." + bufferType, mTransaction);
0060     const QByteArray sinkId = index.lookup(remoteId);
0061     if (sinkId.isEmpty() && insertIfMissing) {
0062         const auto newId = Sink::Storage::DataStore::generateUid();
0063         index.add(remoteId, newId);
0064         Index("localid.mapping." + bufferType, mTransaction).add(newId, remoteId);
0065         return newId;
0066     }
0067     return sinkId;
0068 }
0069 
0070 QByteArray SynchronizerStore::resolveLocalId(const QByteArray &bufferType, const QByteArray &localId)
0071 {
0072     if (localId.isEmpty()) {
0073         SinkError() << "Tried to resolve an empty local id";
0074         Q_ASSERT(false);
0075         return {};
0076     }
0077     QByteArray remoteId = Index("localid.mapping." + bufferType, mTransaction).lookup(localId);
0078     if (remoteId.isEmpty()) {
0079         //This can happen if we didn't store the remote id in the first place
0080         SinkTrace() << "Couldn't find the remote id for " << bufferType << localId;
0081         return QByteArray();
0082     }
0083     return remoteId;
0084 }
0085 
0086 QByteArrayList SynchronizerStore::resolveLocalIds(const QByteArray &bufferType, const QByteArrayList &localIds)
0087 {
0088     QByteArrayList result;
0089     for (const auto &l : localIds) {
0090         const auto id = resolveLocalId(bufferType, l);
0091         if (!id.isEmpty()) {
0092             result << id;
0093         }
0094     }
0095     return result;
0096 }
0097 
0098 QByteArray SynchronizerStore::readValue(const QByteArray &key)
0099 {
0100     QByteArray value;
0101     mTransaction.openDatabase("values").scan(key, [&value](const QByteArray &, const QByteArray &v) {
0102         value = v;
0103         return false;
0104     }, [](const Sink::Storage::DataStore::Error &) {
0105         //Ignore errors because we may not find the value
0106     });
0107     return value;
0108 }
0109 
0110 QByteArray SynchronizerStore::readValue(const QByteArray &prefix, const QByteArray &key)
0111 {
0112     return readValue(prefix + key);
0113 }
0114 
0115 void SynchronizerStore::writeValue(const QByteArray &key, const QByteArray &value)
0116 {
0117     mTransaction.openDatabase("values").write(key, value);
0118 }
0119 
0120 void SynchronizerStore::writeValue(const QByteArray &prefix, const QByteArray &key, const QByteArray &value)
0121 {
0122     writeValue(prefix + key, value);
0123 }
0124 
0125 void SynchronizerStore::removeValue(const QByteArray &prefix, const QByteArray &key)
0126 {
0127     auto assembled = prefix + key;
0128     if (assembled.isEmpty()) {
0129         return;
0130     }
0131     mTransaction.openDatabase("values").remove(assembled, [&](const Sink::Storage::DataStore::Error &error) {
0132         SinkWarning() << "Failed to remove the value: " << prefix + key << error;
0133     });
0134 }
0135 
0136 void SynchronizerStore::removePrefix(const QByteArray &prefix)
0137 {
0138     if (prefix.isEmpty()) {
0139         return;
0140     }
0141     auto db = mTransaction.openDatabase("values");
0142     QByteArrayList keys;
0143     db.scan(prefix, [&] (const QByteArray &key, const QByteArray &value) {
0144         keys << key;
0145         return true;
0146     }, {}, true);
0147     for (const auto &k : keys) {
0148         db.remove(k);
0149     }
0150 }
0151 
0152 bool SynchronizerStore::contains(const QByteArray &key)
0153 {
0154     return !readValue(key).isEmpty();
0155 }
0156 
0157 bool SynchronizerStore::contains(const QByteArray &prefix, const QByteArray &key)
0158 {
0159     return contains(prefix + key);
0160 }
0161