1/*
2 This file is part of the KDE Baloo project.
3 SPDX-FileCopyrightText: 2015 Vishesh Handa <vhanda@kde.org>
4
5 SPDX-License-Identifier: LGPL-2.1-or-later
6*/
7
8#include "idtreedb.h"
9#include "enginedebug.h"
10#include "postingiterator.h"
11
12#include <algorithm>
13
14using namespace Baloo;
15
16IdTreeDB::IdTreeDB(MDB_dbi dbi, MDB_txn* txn)
17 : m_txn(txn)
18 , m_dbi(dbi)
19{
20 Q_ASSERT(txn != nullptr);
21 Q_ASSERT(dbi != 0);
22}
23
24MDB_dbi IdTreeDB::create(MDB_txn* txn)
25{
26 MDB_dbi dbi = 0;
27 int rc = mdb_dbi_open(txn, name: "idtree", MDB_CREATE | MDB_INTEGERKEY, dbi: &dbi);
28 if (rc) {
29 qCWarning(ENGINE) << "IdTreeDB::create" << mdb_strerror(err: rc);
30 return 0;
31 }
32
33 return dbi;
34}
35
36MDB_dbi IdTreeDB::open(MDB_txn* txn)
37{
38 MDB_dbi dbi = 0;
39 int rc = mdb_dbi_open(txn, name: "idtree", MDB_INTEGERKEY, dbi: &dbi);
40 if (rc) {
41 qCWarning(ENGINE) << "IdTreeDB::open" << mdb_strerror(err: rc);
42 return 0;
43 }
44
45 return dbi;
46}
47
48void IdTreeDB::set(quint64 docId, const QVector<quint64> &subDocIds)
49{
50 Q_ASSERT(!subDocIds.contains(0));
51
52 MDB_val key;
53 key.mv_size = sizeof(quint64);
54 key.mv_data = static_cast<void*>(&docId);
55
56 int rc;
57 if (subDocIds.empty()) {
58 rc = mdb_del(txn: m_txn, dbi: m_dbi, key: &key, data: nullptr);
59 if (rc == MDB_NOTFOUND) {
60 rc = 0;
61 }
62 } else {
63 MDB_val val;
64 val.mv_size = subDocIds.size() * sizeof(quint64);
65 val.mv_data = static_cast<void*>(const_cast<quint64*>(subDocIds.constData()));
66
67 rc = mdb_put(txn: m_txn, dbi: m_dbi, key: &key, data: &val, flags: 0);
68 }
69 if (rc) {
70 qCWarning(ENGINE) << "IdTreeDB::set" << mdb_strerror(err: rc);
71 }
72}
73
74QVector<quint64> IdTreeDB::get(quint64 docId)
75{
76 MDB_val key;
77 key.mv_size = sizeof(quint64);
78 key.mv_data = static_cast<void*>(&docId);
79
80 MDB_val val{.mv_size: 0, .mv_data: nullptr};
81 int rc = mdb_get(txn: m_txn, dbi: m_dbi, key: &key, data: &val);
82 if (rc) {
83 if (rc != MDB_NOTFOUND) {
84 qCDebug(ENGINE) << "IdTreeDB::get" << docId << mdb_strerror(err: rc);
85 }
86 return QVector<quint64>();
87 }
88
89 // FIXME: This still makes a copy of the data. Perhaps we can avoid that?
90 QVector<quint64> list(val.mv_size / sizeof(quint64));
91 memcpy(dest: list.data(), src: val.mv_data, n: val.mv_size);
92
93 return list;
94}
95
96//
97// Iter
98//
99class IdTreePostingIterator : public PostingIterator {
100public:
101 IdTreePostingIterator(const IdTreeDB& db, const QVector<quint64> &list)
102 : m_db(db), m_pos(-1), m_idList(list) {}
103
104 quint64 docId() const override {
105 if (m_pos >= 0 && m_pos < m_resultList.size()) {
106 return m_resultList[m_pos];
107 }
108 return 0;
109 }
110
111 quint64 next() override {
112 if (m_resultList.isEmpty() && m_idList.isEmpty()) {
113 return 0;
114 }
115
116 if (m_resultList.isEmpty()) {
117 while (!m_idList.isEmpty()) {
118 quint64 id = m_idList.takeLast();
119 m_idList << m_db.get(docId: id);
120 m_resultList << id;
121 }
122 std::sort(first: m_resultList.begin(), last: m_resultList.end());
123 m_pos = 0;
124 }
125 else {
126 if (m_pos < m_resultList.size()) {
127 m_pos++;
128 } else {
129 m_resultList.clear();
130 }
131 }
132
133 if (m_pos < m_resultList.size()) {
134 return m_resultList[m_pos];
135 } else {
136 return 0;
137 }
138 }
139
140private:
141 IdTreeDB m_db;
142 int m_pos;
143 QVector<quint64> m_idList;
144 QVector<quint64> m_resultList;
145};
146
147PostingIterator* IdTreeDB::iter(quint64 docId)
148{
149 Q_ASSERT(docId > 0);
150
151 QVector<quint64> list = {docId};
152 return new IdTreePostingIterator(*this, list);
153}
154
155QMap<quint64, QVector<quint64>> IdTreeDB::toTestMap() const
156{
157 MDB_cursor* cursor;
158 mdb_cursor_open(txn: m_txn, dbi: m_dbi, cursor: &cursor);
159
160 MDB_val key = {.mv_size: 0, .mv_data: nullptr};
161 MDB_val val;
162
163 QMap<quint64, QVector<quint64>> map;
164 while (1) {
165 int rc = mdb_cursor_get(cursor, key: &key, data: &val, op: MDB_NEXT);
166 if (rc == MDB_NOTFOUND) {
167 break;
168 }
169 if (rc) {
170 qCDebug(ENGINE) << "IdTreeDB::toTestMap" << mdb_strerror(err: rc);
171 break;
172 }
173
174 const quint64 id = *(static_cast<quint64*>(key.mv_data));
175
176 QVector<quint64> list(val.mv_size / sizeof(quint64));
177 memcpy(dest: list.data(), src: val.mv_data, n: val.mv_size);
178
179 map.insert(key: id, value: list);
180 }
181
182 mdb_cursor_close(cursor);
183 return map;
184}
185

source code of baloo/src/engine/idtreedb.cpp