diff --git a/src/engine/documenturldb.cpp b/src/engine/documenturldb.cpp index 66a18281..afcd1a10 100644 --- a/src/engine/documenturldb.cpp +++ b/src/engine/documenturldb.cpp @@ -1,242 +1,229 @@ /* 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 "documenturldb.h" #include "idutils.h" #include "postingiterator.h" #include #include using namespace Baloo; DocumentUrlDB::DocumentUrlDB(MDB_dbi idTreeDb, MDB_dbi idFilenameDb, MDB_txn* txn) : m_txn(txn) , m_idFilenameDbi(idFilenameDb) , m_idTreeDbi(idTreeDb) { } DocumentUrlDB::~DocumentUrlDB() { } bool DocumentUrlDB::put(quint64 docId, const QByteArray& url) { if (!docId || url.isEmpty() || url.endsWith('/')) { return false; } IdFilenameDB idFilenameDb(m_idFilenameDbi, m_txn); typedef QPair IdNamePath; QByteArray arr = url; quint64 parentId; // // id and parent // { quint64 id = filePathToId(arr); if (!id) { return false; } Q_ASSERT(id == docId); int pos = arr.lastIndexOf('/'); QByteArray name = arr.mid(pos + 1); if (pos == 0) { add(id, 0, name); return true; } else { arr.resize(pos); parentId = filePathToId(arr); if (!parentId) { return false; } add(id, parentId, name); } if (idFilenameDb.contains(parentId)) return true; } // // The rest of the path // QVector list; while (parentId) { quint64 id = parentId; int pos = arr.lastIndexOf('/'); QByteArray name = arr.mid(pos + 1); list.prepend(qMakePair(id, name)); if (pos == 0) { break; } arr.resize(pos); parentId = filePathToId(arr); } for (int i = 0; i < list.size(); i++) { quint64 id = list[i].first; QByteArray name = list[i].second; // Update the IdTree quint64 parentId = 0; if (i) { parentId = list[i-1].first; } add(id, parentId, name); } return true; } void DocumentUrlDB::add(quint64 id, quint64 parentId, const QByteArray& name) { if (!id || name.isEmpty()) { return; } IdFilenameDB idFilenameDb(m_idFilenameDbi, m_txn); IdTreeDB idTreeDb(m_idTreeDbi, m_txn); QVector subDocs = idTreeDb.get(parentId); // insert if not there sortedIdInsert(subDocs, id); idTreeDb.put(parentId, subDocs); // Update the IdFileName IdFilenameDB::FilePath path; path.parentId = parentId; path.name = name; idFilenameDb.put(id, path); } QByteArray DocumentUrlDB::get(quint64 docId) const { if (!docId) { return QByteArray(); } IdFilenameDB idFilenameDb(m_idFilenameDbi, m_txn); auto path = idFilenameDb.get(docId); if (path.name.isEmpty()) { return QByteArray(); } QByteArray ret = path.name; quint64 id = path.parentId; // arbitrary path depth limit - we have to deal with // possibly corrupted DBs out in the wild int depth_limit = 512; while (id) { auto p = idFilenameDb.get(id); if (p.name.isEmpty()) { return QByteArray(); } if (!depth_limit--) { return QByteArray(); } ret = p.name + '/' + ret; id = p.parentId; } return '/' + ret; } QVector DocumentUrlDB::getChildren(quint64 docId) const { IdTreeDB idTreeDb(m_idTreeDbi, m_txn); return idTreeDb.get(docId); } -void DocumentUrlDB::rename(quint64 docId, const QByteArray& newFileName) -{ - if (!docId || newFileName.isEmpty()) { - return; - } - - IdFilenameDB idFilenameDb(m_idFilenameDbi, m_txn); - - auto path = idFilenameDb.get(docId); - path.name = newFileName; - idFilenameDb.put(docId, path); -} - quint64 DocumentUrlDB::getId(quint64 docId, const QByteArray& fileName) const { if (fileName.isEmpty()) { return 0; } IdFilenameDB idFilenameDb(m_idFilenameDbi, m_txn); IdTreeDB idTreeDb(m_idTreeDbi, m_txn); const QVector subFiles = idTreeDb.get(docId); for (quint64 id : subFiles) { IdFilenameDB::FilePath path = idFilenameDb.get(id); if (path.name == fileName) { return id; } } return 0; } QMap DocumentUrlDB::toTestMap() const { IdTreeDB idTreeDb(m_idTreeDbi, m_txn); QMap> idTreeMap = idTreeDb.toTestMap(); QSet allIds; for (auto it = idTreeMap.cbegin(); it != idTreeMap.cend(); it++) { allIds.insert(it.key()); for (quint64 id : it.value()) { allIds.insert(id); } } QMap map; for (quint64 id : allIds) { if (id) { QByteArray path = get(id); //FIXME: this prevents sanitizing // reactivate Q_ASSERT(!path.isEmpty()); map.insert(id, path); } } return map; } diff --git a/src/engine/documenturldb.h b/src/engine/documenturldb.h index 2c1ea6ad..eb908973 100644 --- a/src/engine/documenturldb.h +++ b/src/engine/documenturldb.h @@ -1,159 +1,157 @@ /* 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 * */ #ifndef BALOO_DOCUMENTURLDB_H #define BALOO_DOCUMENTURLDB_H #include "idtreedb.h" #include "idfilenamedb.h" #include #include namespace Baloo { class UrlTest; class PostingIterator; class BALOO_ENGINE_EXPORT DocumentUrlDB { public: explicit DocumentUrlDB(MDB_dbi idTreeDb, MDB_dbi idFileNameDb, MDB_txn* txn); ~DocumentUrlDB(); /** * Returns true if added * Returns false is the file no longer exists and could not be added */ bool put(quint64 docId, const QByteArray& url); QByteArray get(quint64 docId) const; QVector getChildren(quint64 docId) const; /** * \arg shouldDeleteFolder This function is called on any empty folder, and is used to * determine if that empty folder should be deleted. */ template void del(quint64 docId, Functor shouldDeleteFolder) { replace(docId, QByteArray(), shouldDeleteFolder); } /** * If \p url is empty then the docId is deleted */ template void replace(quint64 docId, const QByteArray& url, Functor shouldDeleteFolder); - void rename(quint64 docId, const QByteArray& newFileName); - quint64 getId(quint64 docId, const QByteArray& fileName) const; PostingIterator* iter(quint64 docId) { IdTreeDB db(m_idTreeDbi, m_txn); return db.iter(docId); } QMap toTestMap() const; private: void add(quint64 id, quint64 parentId, const QByteArray& name); MDB_txn* m_txn; MDB_dbi m_idFilenameDbi; MDB_dbi m_idTreeDbi; friend class UrlTest; }; template void DocumentUrlDB::replace(quint64 docId, const QByteArray& url, Functor shouldDeleteFolder) { Q_ASSERT(docId > 0); IdFilenameDB idFilenameDb(m_idFilenameDbi, m_txn); IdTreeDB idTreeDb(m_idTreeDbi, m_txn); // FIXME: Maybe this can be combined into one? auto path = idFilenameDb.get(docId); if (path.name.isEmpty()) { return; } idFilenameDb.del(docId); QVector subDocs = idTreeDb.get(path.parentId); subDocs.removeOne(docId); if (!subDocs.isEmpty()) { idTreeDb.put(path.parentId, subDocs); } else { idTreeDb.del(path.parentId); // // Delete every parent directory which only has 1 child // quint64 id = path.parentId; while (id) { auto path = idFilenameDb.get(id); // FIXME: Prevents database cleaning // Q_ASSERT(!path.name.isEmpty()); QVector subDocs = idTreeDb.get(path.parentId); if (subDocs.size() == 1 && shouldDeleteFolder(id)) { idTreeDb.del(path.parentId); idFilenameDb.del(id); } else { break; } id = path.parentId; } } if (url.isEmpty()) { const auto subDocs = idTreeDb.get(docId); if (!subDocs.isEmpty()) { // Check if subdocs actually exist or is it a curruption for (auto const& docId : subDocs) { auto filePath = idFilenameDb.get(docId); auto fileName = QFile::decodeName(filePath.name); if (QFile::exists(fileName)) { if (!idTreeDb.get(docId).isEmpty()) { qWarning() << "DocumentUrlDB::del" << "This folder still has sub-files in its cache. It cannot be deleted"; } } else { /* * FIXME: this is not an ideal solution we need to figure out how such currptions are * creeping in or at least if we detect some figure out a proper cleaning mechanism */ qWarning() << "Database has corrupted entries baloo may misbehave, please recreate the DB by running $ balooctl disable && balooctl enable"; } } } return; } put(docId, url); } } #endif // BALOO_DOCUMENTURLDB_H