aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarco Bubke <marco.bubke@qt.io>2019-05-20 16:46:22 +0200
committerMarco Bubke <marco.bubke@qt.io>2019-06-17 10:46:12 +0000
commit912cb9278f7528709f9edf08060d997c20d3ec8c (patch)
treee0bc19fbd679092c31cf57de59ebc7ce0ee1b9e2
parent60ea77f3ebb56931e95430a218f292e670654f3b (diff)
ClangRefactoring: Ensure that database is written to log after indexing
Change-Id: Ic2473d9fe8dc9b41a7da728c9e1b5202524c1a79 Reviewed-by: Tim Jenssen <tim.jenssen@qt.io>
-rw-r--r--src/libs/sqlite/sqlite-lib.pri1
-rw-r--r--src/libs/sqlite/sqlitedatabase.h24
-rw-r--r--src/libs/sqlite/sqlitedatabasebackend.cpp21
-rw-r--r--src/libs/sqlite/sqlitedatabasebackend.h2
-rw-r--r--src/libs/sqlite/sqlitedatabaseinterface.h37
-rw-r--r--src/tools/clangrefactoringbackend/source/symbolindexertaskqueue.h25
-rw-r--r--src/tools/clangrefactoringbackend/source/symbolindexing.h3
-rw-r--r--tests/unit/unittest/mocksqlitedatabase.h5
-rw-r--r--tests/unit/unittest/symbolindexer-test.cpp3
-rw-r--r--tests/unit/unittest/symbolindexertaskqueue-test.cpp35
10 files changed, 132 insertions, 24 deletions
diff --git a/src/libs/sqlite/sqlite-lib.pri b/src/libs/sqlite/sqlite-lib.pri
index 052e533d2e..22e92f9fcc 100644
--- a/src/libs/sqlite/sqlite-lib.pri
+++ b/src/libs/sqlite/sqlite-lib.pri
@@ -29,6 +29,7 @@ SOURCES += \
HEADERS += \
$$PWD/createtablesqlstatementbuilder.h \
$$PWD/sqlitedatabasebackend.h \
+ $$PWD/sqlitedatabaseinterface.h \
$$PWD/sqliteexception.h \
$$PWD/sqliteglobal.h \
$$PWD/sqlitereadstatement.h \
diff --git a/src/libs/sqlite/sqlitedatabase.h b/src/libs/sqlite/sqlitedatabase.h
index d0eae28f79..2c35a293c2 100644
--- a/src/libs/sqlite/sqlitedatabase.h
+++ b/src/libs/sqlite/sqlitedatabase.h
@@ -26,6 +26,7 @@
#pragma once
#include "sqlitedatabasebackend.h"
+#include "sqlitedatabaseinterface.h"
#include "sqliteglobal.h"
#include "sqlitetable.h"
#include "sqlitetransaction.h"
@@ -43,7 +44,7 @@ using namespace std::chrono_literals;
class ReadStatement;
class WriteStatement;
-class SQLITE_EXPORT Database final : public TransactionInterface
+class SQLITE_EXPORT Database final : public TransactionInterface, public DatabaseInterface
{
template <typename Database>
friend class Statement;
@@ -105,19 +106,18 @@ public:
return m_databaseBackend.changesCount();
}
- int totalChangesCount()
- {
- return m_databaseBackend.totalChangesCount();
- }
+ int totalChangesCount() { return m_databaseBackend.totalChangesCount(); }
+
+ void walCheckpointFull() override { m_databaseBackend.walCheckpointFull(); }
private:
- void deferredBegin();
- void immediateBegin();
- void exclusiveBegin();
- void commit();
- void rollback();
- void lock();
- void unlock();
+ void deferredBegin() override;
+ void immediateBegin() override;
+ void exclusiveBegin() override;
+ void commit() override;
+ void rollback() override;
+ void lock() override;
+ void unlock() override;
void initializeTables();
void registerTransactionStatements();
diff --git a/src/libs/sqlite/sqlitedatabasebackend.cpp b/src/libs/sqlite/sqlitedatabasebackend.cpp
index a42564aca5..bf9dfab6fc 100644
--- a/src/libs/sqlite/sqlitedatabasebackend.cpp
+++ b/src/libs/sqlite/sqlitedatabasebackend.cpp
@@ -406,6 +406,27 @@ void DatabaseBackend::setBusyTimeout(std::chrono::milliseconds timeout)
sqlite3_busy_timeout(m_databaseHandle, int(timeout.count()));
}
+void DatabaseBackend::walCheckpointFull()
+{
+ int resultCode = sqlite3_wal_checkpoint_v2(m_databaseHandle,
+ nullptr,
+ SQLITE_CHECKPOINT_TRUNCATE,
+ nullptr,
+ nullptr);
+
+ switch (resultCode) {
+ case SQLITE_OK:
+ break;
+ case SQLITE_BUSY:
+ throw DatabaseIsBusy("DatabaseBackend::walCheckpointFull: Operation could not concluded "
+ "because database is busy!");
+ case SQLITE_ERROR:
+ throwException("DatabaseBackend::walCheckpointFull: Error occurred!");
+ case SQLITE_MISUSE:
+ throwExceptionStatic("DatabaseBackend::walCheckpointFull: Misuse of database!");
+ }
+}
+
void DatabaseBackend::throwExceptionStatic(const char *whatHasHappens)
{
throw Exception(whatHasHappens);
diff --git a/src/libs/sqlite/sqlitedatabasebackend.h b/src/libs/sqlite/sqlitedatabasebackend.h
index 2de55672aa..7f3973f878 100644
--- a/src/libs/sqlite/sqlitedatabasebackend.h
+++ b/src/libs/sqlite/sqlitedatabasebackend.h
@@ -85,6 +85,8 @@ public:
void setBusyTimeout(std::chrono::milliseconds timeout);
+ void walCheckpointFull();
+
protected:
bool databaseIsOpen() const;
diff --git a/src/libs/sqlite/sqlitedatabaseinterface.h b/src/libs/sqlite/sqlitedatabaseinterface.h
new file mode 100644
index 0000000000..61ea3ac928
--- /dev/null
+++ b/src/libs/sqlite/sqlitedatabaseinterface.h
@@ -0,0 +1,37 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#pragma once
+
+namespace Sqlite {
+class DatabaseInterface
+{
+public:
+ virtual void walCheckpointFull() = 0;
+
+protected:
+ ~DatabaseInterface() = default;
+};
+} // namespace Sqlite
diff --git a/src/tools/clangrefactoringbackend/source/symbolindexertaskqueue.h b/src/tools/clangrefactoringbackend/source/symbolindexertaskqueue.h
index 7ca3513284..1f15f2ffaa 100644
--- a/src/tools/clangrefactoringbackend/source/symbolindexertaskqueue.h
+++ b/src/tools/clangrefactoringbackend/source/symbolindexertaskqueue.h
@@ -30,6 +30,7 @@
#include <filepathid.h>
#include <progresscounter.h>
+#include <sqlitedatabase.h>
#include <taskschedulerinterface.h>
#include <utils/algorithm.h>
@@ -38,10 +39,6 @@
#include <functional>
#include <vector>
-namespace Sqlite {
-class TransactionInterface;
-}
-
namespace ClangBackEnd {
class SymbolsCollectorInterface;
@@ -53,9 +50,11 @@ public:
using Task = SymbolIndexerTask::Callable;
SymbolIndexerTaskQueue(TaskSchedulerInterface<Task> &symbolIndexerTaskScheduler,
- ProgressCounter &progressCounter)
- : m_symbolIndexerScheduler(symbolIndexerTaskScheduler),
- m_progressCounter(progressCounter)
+ ProgressCounter &progressCounter,
+ Sqlite::DatabaseInterface &database)
+ : m_symbolIndexerScheduler(symbolIndexerTaskScheduler)
+ , m_progressCounter(progressCounter)
+ , m_database(database)
{}
void addOrUpdateTasks(std::vector<SymbolIndexerTask> &&tasks)
@@ -94,12 +93,21 @@ public:
void processEntries()
{
- uint taskCount = m_symbolIndexerScheduler.slotUsage().free;
+ auto slotUsage = m_symbolIndexerScheduler.slotUsage();
+ uint taskCount = slotUsage.free;
auto newEnd = std::prev(m_tasks.end(), std::min<int>(int(taskCount), int(m_tasks.size())));
m_symbolIndexerScheduler.addTasks({std::make_move_iterator(newEnd),
std::make_move_iterator(m_tasks.end())});
m_tasks.erase(newEnd, m_tasks.end());
+
+ if (m_tasks.empty() && slotUsage.used == 0) {
+ try {
+ m_database.walCheckpointFull();
+ } catch (Sqlite::Exception &exception) {
+ exception.printWarning();
+ }
+ }
}
void syncTasks();
@@ -108,6 +116,7 @@ private:
std::vector<SymbolIndexerTask> m_tasks;
TaskSchedulerInterface<Task> &m_symbolIndexerScheduler;
ProgressCounter &m_progressCounter;
+ Sqlite::DatabaseInterface &m_database;
};
} // namespace ClangBackEnd
diff --git a/src/tools/clangrefactoringbackend/source/symbolindexing.h b/src/tools/clangrefactoringbackend/source/symbolindexing.h
index d4e36499b1..5c391503bf 100644
--- a/src/tools/clangrefactoringbackend/source/symbolindexing.h
+++ b/src/tools/clangrefactoringbackend/source/symbolindexing.h
@@ -105,6 +105,7 @@ public:
m_projectPartsStorage,
m_modifiedTimeChecker,
environment)
+ , m_indexerQueue(m_indexerScheduler, m_progressCounter, database)
, m_indexerScheduler(m_collectorManger,
m_indexerQueue,
m_progressCounter,
@@ -152,7 +153,7 @@ private:
ModifiedTimeChecker<ClangBackEnd::SourceTimeStamps> m_modifiedTimeChecker{getModifiedTime,
m_filePathCache};
SymbolIndexer m_indexer;
- SymbolIndexerTaskQueue m_indexerQueue{m_indexerScheduler, m_progressCounter};
+ SymbolIndexerTaskQueue m_indexerQueue;
SymbolIndexerTaskScheduler m_indexerScheduler;
};
diff --git a/tests/unit/unittest/mocksqlitedatabase.h b/tests/unit/unittest/mocksqlitedatabase.h
index 5bef2ba8c5..05f6f4e958 100644
--- a/tests/unit/unittest/mocksqlitedatabase.h
+++ b/tests/unit/unittest/mocksqlitedatabase.h
@@ -31,12 +31,13 @@
#include "mocksqlitetransactionbackend.h"
#include "mocksqlitewritestatement.h"
+#include <sqlitedatabaseinterface.h>
#include <sqlitetable.h>
#include <sqlitetransaction.h>
#include <utils/smallstringview.h>
-class MockSqliteDatabase : public MockSqliteTransactionBackend
+class MockSqliteDatabase : public MockSqliteTransactionBackend, public Sqlite::DatabaseInterface
{
public:
using ReadStatement = NiceMock<MockSqliteReadStatement>;
@@ -56,5 +57,7 @@ public:
MOCK_METHOD1(setIsInitialized,
void (bool));
+
+ MOCK_METHOD0(walCheckpointFull, void());
};
diff --git a/tests/unit/unittest/symbolindexer-test.cpp b/tests/unit/unittest/symbolindexer-test.cpp
index 2972e2019e..a03f2be507 100644
--- a/tests/unit/unittest/symbolindexer-test.cpp
+++ b/tests/unit/unittest/symbolindexer-test.cpp
@@ -267,7 +267,8 @@ protected:
mockProjectPartsStorage,
mockModifiedTimeChecker,
testEnvironment};
- SymbolIndexerTaskQueue indexerQueue{indexerScheduler, progressCounter};
+ NiceMock<MockSqliteDatabase> mockSqliteDatabase;
+ SymbolIndexerTaskQueue indexerQueue{indexerScheduler, progressCounter, mockSqliteDatabase};
Scheduler indexerScheduler{collectorManger,
indexerQueue,
progressCounter,
diff --git a/tests/unit/unittest/symbolindexertaskqueue-test.cpp b/tests/unit/unittest/symbolindexertaskqueue-test.cpp
index 2932310eb0..1364091161 100644
--- a/tests/unit/unittest/symbolindexertaskqueue-test.cpp
+++ b/tests/unit/unittest/symbolindexertaskqueue-test.cpp
@@ -25,6 +25,7 @@
#include "googletest.h"
+#include "mocksqlitedatabase.h"
#include "mocktaskscheduler.h"
#include <symbolindexertaskqueue.h>
@@ -54,7 +55,8 @@ protected:
NiceMock<MockFunction<void(int, int)>> mockSetProgressCallback;
ClangBackEnd::ProgressCounter progressCounter{mockSetProgressCallback.AsStdFunction()};
NiceMock<MockTaskScheduler<Callable>> mockTaskScheduler;
- ClangBackEnd::SymbolIndexerTaskQueue queue{mockTaskScheduler, progressCounter};
+ NiceMock<MockSqliteDatabase> mockSqliteDatabase;
+ ClangBackEnd::SymbolIndexerTaskQueue queue{mockTaskScheduler, progressCounter, mockSqliteDatabase};
};
TEST_F(SymbolIndexerTaskQueue, AddTasks)
@@ -208,4 +210,35 @@ TEST_F(SymbolIndexerTaskQueue, ProcessTasksRemovesProcessedTasks)
ASSERT_THAT(queue.tasks(), SizeIs(1));
}
+
+TEST_F(SymbolIndexerTaskQueue,
+ ProcessTasksWritesBackTheDatabaseLogIfTheQueueIsEmptyAndTheIndexerHasNothingToDo)
+{
+ InSequence s;
+
+ EXPECT_CALL(mockTaskScheduler, slotUsage()).WillRepeatedly(Return(SlotUsage{2, 0}));
+ EXPECT_CALL(mockSqliteDatabase, walCheckpointFull());
+
+ queue.processEntries();
+}
+
+TEST_F(SymbolIndexerTaskQueue, ProcessTasksDoesNotWritesBackTheDatabaseLogIfTheIndexerHasSomethingToDo)
+{
+ InSequence s;
+
+ EXPECT_CALL(mockTaskScheduler, slotUsage()).WillRepeatedly(Return(SlotUsage{1, 1}));
+ EXPECT_CALL(mockSqliteDatabase, walCheckpointFull()).Times(0);
+
+ queue.processEntries();
+}
+
+TEST_F(SymbolIndexerTaskQueue, HandleExeptionInWalCheckPoint)
+{
+ InSequence s;
+
+ EXPECT_CALL(mockTaskScheduler, slotUsage()).WillRepeatedly(Return(SlotUsage{2, 0}));
+ EXPECT_CALL(mockSqliteDatabase, walCheckpointFull()).WillOnce(Throw(Sqlite::DatabaseIsBusy{""}));
+
+ queue.processEntries();
}
+} // namespace