diff --git a/autotests/unit/engine/mtimedbtest.cpp b/autotests/unit/engine/mtimedbtest.cpp index 41573213..51cf2fc3 100644 --- a/autotests/unit/engine/mtimedbtest.cpp +++ b/autotests/unit/engine/mtimedbtest.cpp @@ -1,182 +1,185 @@ /* This file is part of the KDE Baloo project. * Copyright (C) 2015 Vishesh Handa * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include "mtimedb.h" #include "postingiterator.h" #include "singledbtest.h" using namespace Baloo; class MTimeDBTest : public SingleDBTest { Q_OBJECT private Q_SLOTS: void test() { MTimeDB db(MTimeDB::create(m_txn), m_txn); db.put(5, 1); QCOMPARE(db.get(5), QVector() << 1); db.del(5, 1); QCOMPARE(db.get(5), QVector()); } void testMultiple() { MTimeDB db(MTimeDB::create(m_txn), m_txn); db.put(5, 1); db.put(5, 2); db.put(5, 3); QCOMPARE(db.get(5), QVector() << 1 << 2 << 3); db.del(5, 2); QCOMPARE(db.get(5), QVector() << 1 << 3); + + QCOMPARE(db.get(4), QVector()); + QCOMPARE(db.get(6), QVector()); } void testIter() { MTimeDB db(MTimeDB::create(m_txn), m_txn); db.put(5, 1); db.put(6, 2); db.put(6, 3); db.put(7, 4); db.put(8, 5); db.put(9, 6); PostingIterator* it = db.iter(6, MTimeDB::GreaterEqual); QVERIFY(it); QVector result = {2, 3, 4, 5, 6}; for (quint64 val : result) { QCOMPARE(it->next(), static_cast(val)); QCOMPARE(it->docId(), static_cast(val)); } it = db.iter(7, MTimeDB::LessEqual); QVERIFY(it); result = {1, 2, 3, 4}; for (quint64 val : result) { QCOMPARE(it->next(), static_cast(val)); QCOMPARE(it->docId(), static_cast(val)); } it = db.iter(6, MTimeDB::LessEqual); QVERIFY(it); result = {1, 2, 3}; for (quint64 val : result) { QCOMPARE(it->next(), static_cast(val)); QCOMPARE(it->docId(), static_cast(val)); } } void testRangeIter() { MTimeDB db(MTimeDB::create(m_txn), m_txn); db.put(5, 1); db.put(6, 2); db.put(6, 3); db.put(7, 4); db.put(8, 5); db.put(9, 6); PostingIterator* it = db.iterRange(6, 8); QVERIFY(it); QVector result = {2, 3, 4, 5}; for (quint64 val : result) { QCOMPARE(it->next(), static_cast(val)); QCOMPARE(it->docId(), static_cast(val)); } // Empty range it = db.iterRange(4, 4); QVERIFY(!it); it = db.iterRange(10, 20); QVERIFY(!it); } void testSortedAndUnique() { MTimeDB db(MTimeDB::create(m_txn), m_txn); db.put(5, 1); db.put(6, 4); db.put(6, 2); db.put(6, 3); db.put(7, 3); QCOMPARE(db.get(6), QVector() << 2 << 3 << 4); PostingIterator* it = db.iterRange(5, 7); QVERIFY(it); { QVector result = {1, 2, 3, 4}; for (quint64 val : result) { QCOMPARE(it->next(), static_cast(val)); QCOMPARE(it->docId(), static_cast(val)); } } { it = db.iter(6, MTimeDB::GreaterEqual); QVERIFY(it); QVector result = {2, 3, 4}; for (quint64 val : result) { QCOMPARE(it->next(), static_cast(val)); QCOMPARE(it->docId(), static_cast(val)); } } } void testBeginOfEpoch() { MTimeDB db(MTimeDB::create(m_txn), m_txn); db.put(0, 1); db.put(0, 2); db.put(0, 3); db.put(1, 4); QCOMPARE(db.get(0), QVector({1, 2, 3})); db.del(99, 2); QCOMPARE(db.get(0), QVector({1, 2, 3})); QCOMPARE(db.get(1), QVector({4})); db.del(0, 2); QCOMPARE(db.get(0), QVector({1, 3})); PostingIterator* it = db.iter(0, MTimeDB::LessEqual); QVector result; while (it->next()) { result.append(it->docId()); } QCOMPARE(result, QVector({1, 3})); it = db.iter(1, MTimeDB::GreaterEqual); QVERIFY(it->next()); QCOMPARE(it->docId(), 4); } }; QTEST_MAIN(MTimeDBTest) #include "mtimedbtest.moc" diff --git a/src/engine/mtimedb.cpp b/src/engine/mtimedb.cpp index 05e90320..d3f7bb96 100644 --- a/src/engine/mtimedb.cpp +++ b/src/engine/mtimedb.cpp @@ -1,295 +1,295 @@ /* This file is part of the KDE Baloo project. * Copyright (C) 2015 Vishesh Handa * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include "mtimedb.h" #include "enginedebug.h" #include "vectorpostingiterator.h" #include using namespace Baloo; MTimeDB::MTimeDB(MDB_dbi dbi, MDB_txn* txn) : m_txn(txn) , m_dbi(dbi) { Q_ASSERT(txn != nullptr); Q_ASSERT(dbi != 0); } MTimeDB::~MTimeDB() { } MDB_dbi MTimeDB::create(MDB_txn* txn) { MDB_dbi dbi = 0; int rc = mdb_dbi_open(txn, "mtimedb", MDB_CREATE | MDB_INTEGERKEY | MDB_DUPSORT | MDB_DUPFIXED | MDB_INTEGERDUP, &dbi); if (rc) { qCWarning(ENGINE) << "MTimeDB::create" << mdb_strerror(rc); return 0; } return dbi; } MDB_dbi MTimeDB::open(MDB_txn* txn) { MDB_dbi dbi = 0; int rc = mdb_dbi_open(txn, "mtimedb", MDB_INTEGERKEY | MDB_DUPSORT | MDB_DUPFIXED | MDB_INTEGERDUP, &dbi); if (rc) { qCWarning(ENGINE) << "MTimeDB::open" << mdb_strerror(rc); return 0; } return dbi; } void MTimeDB::put(quint32 mtime, quint64 docId) { if (!docId) { qCWarning(ENGINE) << "MTimeDB::put - docId == 0"; return; } MDB_val key; key.mv_size = sizeof(quint32); key.mv_data = static_cast(&mtime); MDB_val val; val.mv_size = sizeof(quint64); val.mv_data = static_cast(&docId); int rc = mdb_put(m_txn, m_dbi, &key, &val, 0); if (rc) { qCWarning(ENGINE) << "MTimeDB::put" << mdb_strerror(rc); } } QVector MTimeDB::get(quint32 mtime) { MDB_val key; key.mv_size = sizeof(quint32); key.mv_data = static_cast(&mtime); QVector values; MDB_cursor* cursor; mdb_cursor_open(m_txn, m_dbi, &cursor); MDB_val val{0, nullptr}; - int rc = mdb_cursor_get(cursor, &key, &val, MDB_SET_RANGE); + int rc = mdb_cursor_get(cursor, &key, &val, MDB_SET); if (rc) { if (rc != MDB_NOTFOUND) { qCWarning(ENGINE) << "MTimeDB::get" << mtime << mdb_strerror(rc); } mdb_cursor_close(cursor); return values; } values << *static_cast(val.mv_data); while (1) { rc = mdb_cursor_get(cursor, &key, &val, MDB_NEXT_DUP); if (rc) { if (rc != MDB_NOTFOUND) { qCWarning(ENGINE) << "MTimeDB::get (loop)" << mtime << mdb_strerror(rc); } break; } values << *static_cast(val.mv_data); } mdb_cursor_close(cursor); std::sort(values.begin(), values.end()); values.erase(std::unique(values.begin(), values.end()), values.end()); return values; } void MTimeDB::del(quint32 mtime, quint64 docId) { MDB_val key; key.mv_size = sizeof(quint32); key.mv_data = static_cast(&mtime); MDB_val val; val.mv_size = sizeof(quint64); val.mv_data = static_cast(&docId); int rc = mdb_del(m_txn, m_dbi, &key, &val); if (rc != 0 && rc != MDB_NOTFOUND) { qCWarning(ENGINE) << "MTimeDB::del" << mtime << docId << mdb_strerror(rc); } } // // Posting Iterator // PostingIterator* MTimeDB::iter(quint32 mtime, MTimeDB::Comparator com) { if (com == Equal) { return new VectorPostingIterator(get(mtime)); } MDB_val key; key.mv_size = sizeof(quint32); key.mv_data = &mtime; MDB_cursor* cursor; mdb_cursor_open(m_txn, m_dbi, &cursor); MDB_val val{0, nullptr}; // Set cursor at first element greater or equal key int rc = mdb_cursor_get(cursor, &key, &val, MDB_SET_RANGE); if (rc) { if (rc != MDB_NOTFOUND) { qCWarning(ENGINE) << "MTimeDB::iter" << mtime << mdb_strerror(rc); } mdb_cursor_close(cursor); return nullptr; } QVector results; if (com == GreaterEqual) { results << *static_cast(val.mv_data); while (1) { rc = mdb_cursor_get(cursor, &key, &val, MDB_NEXT); if (rc) { if (rc != MDB_NOTFOUND) { qCWarning(ENGINE) << "MTimeDB::iter GreaterEqual (loop)" << mtime << mdb_strerror(rc); } break; } results << *static_cast(val.mv_data); } } else { quint32 time = *static_cast(key.mv_data); if (time == mtime) { // set cursor to last element equal key rc = mdb_cursor_get(cursor, &key, &val, MDB_LAST_DUP); } else { // set cursor to element less than key rc = mdb_cursor_get(cursor, &key, &val, MDB_PREV); } if (rc) { if (rc != MDB_NOTFOUND) { qCWarning(ENGINE) << "MTimeDB::iter LessEqual" << mtime << mdb_strerror(rc); } else { return nullptr; } } results << *static_cast(val.mv_data); while (1) { rc = mdb_cursor_get(cursor, &key, &val, MDB_PREV); if (rc) { if (rc != MDB_NOTFOUND) { qCWarning(ENGINE) << "MTimeDB::iter LessEqual (loop)" << mtime << mdb_strerror(rc); } break; } quint64 id = *static_cast(val.mv_data); results.push_front(id); } } mdb_cursor_close(cursor); std::sort(results.begin(), results.end()); results.erase(std::unique(results.begin(), results.end()), results.end()); return new VectorPostingIterator(results); } PostingIterator* MTimeDB::iterRange(quint32 beginTime, quint32 endTime) { if (endTime < beginTime) { return nullptr; } MDB_val key; key.mv_size = sizeof(quint32); key.mv_data = &beginTime; MDB_cursor* cursor; mdb_cursor_open(m_txn, m_dbi, &cursor); MDB_val val{0, nullptr}; int rc = mdb_cursor_get(cursor, &key, &val, MDB_SET_RANGE); if (rc) { if (rc != MDB_NOTFOUND) { qCWarning(ENGINE) << "MTimeDB::iterRange" << beginTime << endTime << mdb_strerror(rc); } mdb_cursor_close(cursor); return nullptr; } QVector results; while (1) { quint32 time = *static_cast(key.mv_data); if (time > endTime) { break; } results << *static_cast(val.mv_data); rc = mdb_cursor_get(cursor, &key, &val, MDB_NEXT); if (rc) { if (rc != MDB_NOTFOUND) { qCWarning(ENGINE) << "MTimeDB::iterRange (loop)" << beginTime << endTime << mdb_strerror(rc); } break; } } mdb_cursor_close(cursor); if (results.isEmpty()) { return nullptr; } std::sort(results.begin(), results.end()); results.erase(std::unique(results.begin(), results.end()), results.end()); return new VectorPostingIterator(results); } QMap MTimeDB::toTestMap() const { MDB_cursor* cursor; mdb_cursor_open(m_txn, m_dbi, &cursor); MDB_val key = {0, nullptr}; MDB_val val; QMap map; while (1) { int rc = mdb_cursor_get(cursor, &key, &val, MDB_NEXT); if (rc) { qCDebug(ENGINE) << "MTimeDB::toTestMap" << mdb_strerror(rc); break; } const quint32 time = *(static_cast(key.mv_data)); const quint64 id = *(static_cast(val.mv_data)); map.insert(time, id); } mdb_cursor_close(cursor); return map; }