File indexing completed on 2024-04-21 03:51:40

0001 /*
0002     This file is part of the KDE Baloo project.
0003     SPDX-FileCopyrightText: 2015 Vishesh Handa <vhanda@kde.org>
0004 
0005     SPDX-License-Identifier: LGPL-2.1-or-later
0006 */
0007 
0008 #include "idtreedb.h"
0009 #include "enginedebug.h"
0010 #include "postingiterator.h"
0011 
0012 #include <algorithm>
0013 
0014 using namespace Baloo;
0015 
0016 IdTreeDB::IdTreeDB(MDB_dbi dbi, MDB_txn* txn)
0017     : m_txn(txn)
0018     , m_dbi(dbi)
0019 {
0020     Q_ASSERT(txn != nullptr);
0021     Q_ASSERT(dbi != 0);
0022 }
0023 
0024 MDB_dbi IdTreeDB::create(MDB_txn* txn)
0025 {
0026     MDB_dbi dbi = 0;
0027     int rc = mdb_dbi_open(txn, "idtree", MDB_CREATE | MDB_INTEGERKEY, &dbi);
0028     if (rc) {
0029         qCWarning(ENGINE) << "IdTreeDB::create" << mdb_strerror(rc);
0030         return 0;
0031     }
0032 
0033     return dbi;
0034 }
0035 
0036 MDB_dbi IdTreeDB::open(MDB_txn* txn)
0037 {
0038     MDB_dbi dbi = 0;
0039     int rc = mdb_dbi_open(txn, "idtree", MDB_INTEGERKEY, &dbi);
0040     if (rc) {
0041         qCWarning(ENGINE) << "IdTreeDB::open" << mdb_strerror(rc);
0042         return 0;
0043     }
0044 
0045     return dbi;
0046 }
0047 
0048 void IdTreeDB::set(quint64 docId, const QVector<quint64> &subDocIds)
0049 {
0050     Q_ASSERT(!subDocIds.contains(0));
0051 
0052     MDB_val key;
0053     key.mv_size = sizeof(quint64);
0054     key.mv_data = static_cast<void*>(&docId);
0055 
0056     int rc;
0057     if (subDocIds.empty()) {
0058         rc = mdb_del(m_txn, m_dbi, &key, nullptr);
0059         if (rc == MDB_NOTFOUND) {
0060             rc = 0;
0061         }
0062     } else {
0063         MDB_val val;
0064         val.mv_size = subDocIds.size() * sizeof(quint64);
0065         val.mv_data = static_cast<void*>(const_cast<quint64*>(subDocIds.constData()));
0066 
0067         rc = mdb_put(m_txn, m_dbi, &key, &val, 0);
0068     }
0069     if (rc) {
0070         qCWarning(ENGINE) << "IdTreeDB::set" << mdb_strerror(rc);
0071     }
0072 }
0073 
0074 QVector<quint64> IdTreeDB::get(quint64 docId)
0075 {
0076     MDB_val key;
0077     key.mv_size = sizeof(quint64);
0078     key.mv_data = static_cast<void*>(&docId);
0079 
0080     MDB_val val{0, nullptr};
0081     int rc = mdb_get(m_txn, m_dbi, &key, &val);
0082     if (rc) {
0083         if (rc != MDB_NOTFOUND) {
0084             qCDebug(ENGINE) << "IdTreeDB::get" << docId << mdb_strerror(rc);
0085         }
0086         return QVector<quint64>();
0087     }
0088 
0089     // FIXME: This still makes a copy of the data. Perhaps we can avoid that?
0090     QVector<quint64> list(val.mv_size / sizeof(quint64));
0091     memcpy(list.data(), val.mv_data, val.mv_size);
0092 
0093     return list;
0094 }
0095 
0096 //
0097 // Iter
0098 //
0099 class IdTreePostingIterator : public PostingIterator {
0100 public:
0101     IdTreePostingIterator(const IdTreeDB& db, const QVector<quint64> &list)
0102         : m_db(db), m_pos(-1), m_idList(list) {}
0103 
0104     quint64 docId() const override {
0105         if (m_pos >= 0 && m_pos < m_resultList.size()) {
0106             return m_resultList[m_pos];
0107         }
0108         return 0;
0109     }
0110 
0111     quint64 next() override {
0112         if (m_resultList.isEmpty() && m_idList.isEmpty()) {
0113             return 0;
0114         }
0115 
0116         if (m_resultList.isEmpty()) {
0117             while (!m_idList.isEmpty()) {
0118                 quint64 id = m_idList.takeLast();
0119                 m_idList << m_db.get(id);
0120                 m_resultList << id;
0121             }
0122             std::sort(m_resultList.begin(), m_resultList.end());
0123             m_pos = 0;
0124         }
0125         else {
0126             if (m_pos < m_resultList.size()) {
0127                 m_pos++;
0128             } else {
0129                 m_resultList.clear();
0130             }
0131         }
0132 
0133         if (m_pos < m_resultList.size()) {
0134             return m_resultList[m_pos];
0135         } else {
0136             return 0;
0137         }
0138     }
0139 
0140 private:
0141     IdTreeDB m_db;
0142     int m_pos;
0143     QVector<quint64> m_idList;
0144     QVector<quint64> m_resultList;
0145 };
0146 
0147 PostingIterator* IdTreeDB::iter(quint64 docId)
0148 {
0149     Q_ASSERT(docId > 0);
0150 
0151     QVector<quint64> list = {docId};
0152     return new IdTreePostingIterator(*this, list);
0153 }
0154 
0155 QMap<quint64, QVector<quint64>> IdTreeDB::toTestMap() const
0156 {
0157     MDB_cursor* cursor;
0158     mdb_cursor_open(m_txn, m_dbi, &cursor);
0159 
0160     MDB_val key = {0, nullptr};
0161     MDB_val val;
0162 
0163     QMap<quint64, QVector<quint64>> map;
0164     while (1) {
0165         int rc = mdb_cursor_get(cursor, &key, &val, MDB_NEXT);
0166         if (rc == MDB_NOTFOUND) {
0167             break;
0168         }
0169         if (rc) {
0170             qCDebug(ENGINE) << "IdTreeDB::toTestMap" << mdb_strerror(rc);
0171             break;
0172         }
0173 
0174         const quint64 id = *(static_cast<quint64*>(key.mv_data));
0175 
0176         QVector<quint64> list(val.mv_size / sizeof(quint64));
0177         memcpy(list.data(), val.mv_data, val.mv_size);
0178 
0179         map.insert(id, list);
0180     }
0181 
0182     mdb_cursor_close(cursor);
0183     return map;
0184 }