forked from qt-creator/qt-creator
ClangPchManager: Introduce PchTaskQueue
With the PchTaskQueue the pipeline is almost complete. Task-number: QTCREATORBUG-21346 Change-Id: I5f05d525db1679eb37dd1d462076c1ed42958099 Reviewed-by: Ivan Donchevskii <ivan.donchevskii@qt.io>
This commit is contained in:
@@ -190,9 +190,10 @@ public:
|
||||
table.setUseIfNotExists(true);
|
||||
table.setName("precompiledHeaders");
|
||||
table.addColumn("projectPartId", Sqlite::ColumnType::Integer, Sqlite::Contraint::PrimaryKey);
|
||||
table.addColumn("pchPath", Sqlite::ColumnType::Text);
|
||||
table.addColumn("pchBuildTime", Sqlite::ColumnType::Integer);
|
||||
|
||||
table.addColumn("projectPchPath", Sqlite::ColumnType::Text);
|
||||
table.addColumn("projectPchBuildTime", Sqlite::ColumnType::Integer);
|
||||
table.addColumn("systemPchPath", Sqlite::ColumnType::Text);
|
||||
table.addColumn("systemPchBuildTime", Sqlite::ColumnType::Integer);
|
||||
table.initialize(database);
|
||||
}
|
||||
|
||||
|
@@ -133,10 +133,8 @@ bool BaseStatement::next() const
|
||||
return true;
|
||||
else if (resultCode == SQLITE_DONE)
|
||||
return false;
|
||||
else
|
||||
checkForStepError(resultCode);
|
||||
|
||||
return false;
|
||||
checkForStepError(resultCode);
|
||||
}
|
||||
|
||||
void BaseStatement::step() const
|
||||
|
@@ -6,7 +6,8 @@ SOURCES += \
|
||||
$$PWD/projectparts.cpp \
|
||||
$$PWD/projectpartqueue.cpp \
|
||||
$$PWD/pchtaskgenerator.cpp \
|
||||
$$PWD/pchtasksmerger.cpp
|
||||
$$PWD/pchtasksmerger.cpp \
|
||||
$$PWD/pchtaskqueue.cpp
|
||||
|
||||
HEADERS += \
|
||||
$$PWD/pchmanagerserver.h \
|
||||
@@ -38,7 +39,8 @@ HEADERS += \
|
||||
$$PWD/usedmacrofilter.h \
|
||||
$$PWD/pchtasksmergerinterface.h \
|
||||
$$PWD/pchtasksmerger.h \
|
||||
$$PWD/pchtaskqueueinterface.h
|
||||
$$PWD/pchtaskqueueinterface.h \
|
||||
$$PWD/pchtaskqueue.h
|
||||
|
||||
!isEmpty(LIBTOOLING_LIBS) {
|
||||
SOURCES += \
|
||||
|
@@ -326,11 +326,16 @@ IdPaths PchCreator::generateProjectPartPch(const V2::ProjectPartContainer &proje
|
||||
return {projectPart.projectPartId.clone(), allIncludeIds(includes)};
|
||||
}
|
||||
|
||||
void PchCreator::generatePch(const V2::ProjectPartContainer &projectPart)
|
||||
void PchCreator::generatePchDeprecated(const V2::ProjectPartContainer &projectPart)
|
||||
{
|
||||
m_projectIncludeIds = generateProjectPartPch(projectPart);
|
||||
}
|
||||
|
||||
void PchCreator::generatePch(const PchTask &pchTask)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
IdPaths PchCreator::takeProjectIncludes()
|
||||
{
|
||||
return std::move(m_projectIncludeIds);
|
||||
|
@@ -69,7 +69,8 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
void generatePch(const V2::ProjectPartContainer &projectsPart) override;
|
||||
void generatePchDeprecated(const V2::ProjectPartContainer &projectsPart) override;
|
||||
void generatePch(const PchTask &pchTask) override;
|
||||
IdPaths takeProjectIncludes() override;
|
||||
const ProjectPartPch &projectPartPch() override;
|
||||
void setUnsavedFiles(const V2::FileContainers &fileContainers) override;
|
||||
|
@@ -26,6 +26,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "idpaths.h"
|
||||
#include "pchtask.h"
|
||||
#include "projectpartpch.h"
|
||||
#include "processorinterface.h"
|
||||
|
||||
@@ -41,7 +42,8 @@ public:
|
||||
PchCreatorInterface(const PchCreatorInterface &) = delete;
|
||||
PchCreatorInterface &operator=(const PchCreatorInterface &) = delete;
|
||||
|
||||
virtual void generatePch(const V2::ProjectPartContainer &projectsPart) = 0;
|
||||
virtual void generatePchDeprecated(const V2::ProjectPartContainer &projectsPart) = 0;
|
||||
virtual void generatePch(const PchTask &pchTask) = 0;
|
||||
virtual IdPaths takeProjectIncludes() = 0;
|
||||
virtual const ProjectPartPch &projectPartPch() = 0;
|
||||
|
||||
|
@@ -40,7 +40,17 @@ public:
|
||||
FilePathIds &&includes,
|
||||
CompilerMacros &&compilerMacros,
|
||||
UsedMacros &&usedMacros)
|
||||
: projectPartId(projectPartId)
|
||||
: projectPartIds({projectPartId})
|
||||
, includes(includes)
|
||||
, compilerMacros(compilerMacros)
|
||||
, usedMacros(usedMacros)
|
||||
{}
|
||||
|
||||
PchTask(Utils::SmallStringVector &&projectPartIds,
|
||||
FilePathIds &&includes,
|
||||
CompilerMacros &&compilerMacros,
|
||||
UsedMacros &&usedMacros)
|
||||
: projectPartIds(std::move(projectPartIds))
|
||||
, includes(includes)
|
||||
, compilerMacros(compilerMacros)
|
||||
, usedMacros(usedMacros)
|
||||
@@ -48,15 +58,17 @@ public:
|
||||
|
||||
friend bool operator==(const PchTask &first, const PchTask &second)
|
||||
{
|
||||
return first.projectPartId == second.projectPartId
|
||||
&& first.dependentIds == second.dependentIds && first.includes == second.includes
|
||||
return first.systemPchPath == second.systemPchPath
|
||||
&& first.projectPartIds == second.projectPartIds && first.includes == second.includes
|
||||
&& first.compilerMacros == second.compilerMacros
|
||||
&& first.usedMacros == second.usedMacros;
|
||||
}
|
||||
|
||||
Utils::SmallStringView projectPartId() const { return projectPartIds.front(); }
|
||||
|
||||
public:
|
||||
Utils::SmallString projectPartId;
|
||||
Utils::SmallStringVector dependentIds;
|
||||
Utils::PathString systemPchPath;
|
||||
Utils::SmallStringVector projectPartIds;
|
||||
FilePathIds includes;
|
||||
CompilerMacros compilerMacros;
|
||||
UsedMacros usedMacros;
|
||||
|
205
src/tools/clangpchmanagerbackend/source/pchtaskqueue.cpp
Normal file
205
src/tools/clangpchmanagerbackend/source/pchtaskqueue.cpp
Normal file
@@ -0,0 +1,205 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2018 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.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "pchtaskqueue.h"
|
||||
|
||||
#include <pchcreatorinterface.h>
|
||||
#include <precompiledheaderstorageinterface.h>
|
||||
#include <progresscounter.h>
|
||||
#include <sqlitetransaction.h>
|
||||
|
||||
namespace ClangBackEnd {
|
||||
|
||||
void PchTaskQueue::addPchTasks(PchTasks &&newPchTasks, PchTasks &destination)
|
||||
{
|
||||
auto compare = [](const PchTask &first, const PchTask &second) {
|
||||
return first.projectPartIds < second.projectPartIds;
|
||||
};
|
||||
|
||||
const std::size_t oldSize = destination.size();
|
||||
|
||||
PchTasks mergedPchTasks;
|
||||
mergedPchTasks.reserve(destination.size() + newPchTasks.size());
|
||||
std::set_union(std::make_move_iterator(newPchTasks.begin()),
|
||||
std::make_move_iterator(newPchTasks.end()),
|
||||
std::make_move_iterator(destination.begin()),
|
||||
std::make_move_iterator(destination.end()),
|
||||
std::back_inserter(mergedPchTasks),
|
||||
compare);
|
||||
|
||||
destination = std::move(mergedPchTasks);
|
||||
|
||||
m_progressCounter.addTotal(int(destination.size() - oldSize));
|
||||
|
||||
processEntries();
|
||||
}
|
||||
|
||||
void PchTaskQueue::removePchTasksByProjectPartId(const Utils::SmallStringVector &projectsPartIds,
|
||||
PchTasks &destination)
|
||||
{
|
||||
class CompareDifference
|
||||
{
|
||||
public:
|
||||
bool operator()(const PchTask &first, const Utils::SmallString &second)
|
||||
{
|
||||
return first.projectPartId() < second;
|
||||
}
|
||||
|
||||
bool operator()(const Utils::SmallString &first, const PchTask &second)
|
||||
{
|
||||
return first < second.projectPartId();
|
||||
}
|
||||
};
|
||||
|
||||
const std::size_t oldSize = destination.size();
|
||||
|
||||
PchTasks notToBeRemovedProjectParts;
|
||||
notToBeRemovedProjectParts.reserve(destination.size());
|
||||
std::set_difference(std::make_move_iterator(destination.begin()),
|
||||
std::make_move_iterator(destination.end()),
|
||||
projectsPartIds.begin(),
|
||||
projectsPartIds.end(),
|
||||
std::back_inserter(notToBeRemovedProjectParts),
|
||||
CompareDifference{});
|
||||
|
||||
destination = std::move(notToBeRemovedProjectParts);
|
||||
|
||||
m_progressCounter.removeTotal(int(oldSize - destination.size()));
|
||||
}
|
||||
|
||||
void PchTaskQueue::addSystemPchTasks(PchTasks &&pchTasks)
|
||||
{
|
||||
addPchTasks(std::move(pchTasks), m_systemPchTasks);
|
||||
}
|
||||
|
||||
void PchTaskQueue::addProjectPchTasks(PchTasks &&pchTasks)
|
||||
{
|
||||
addPchTasks(std::move(pchTasks), m_projectPchTasks);
|
||||
}
|
||||
|
||||
void PchTaskQueue::removePchTasks(const Utils::SmallStringVector &projectsPartIds)
|
||||
{
|
||||
removePchTasksByProjectPartId(projectsPartIds, m_projectPchTasks);
|
||||
}
|
||||
|
||||
void PchTaskQueue::processProjectPchTasks()
|
||||
{
|
||||
uint systemRunningTaskCount = m_systemPchTaskScheduler.slotUsage().used;
|
||||
|
||||
if (!systemRunningTaskCount) {
|
||||
uint freeTaskCount = m_projectPchTaskScheduler.slotUsage().free;
|
||||
|
||||
auto newEnd = std::prev(m_projectPchTasks.end(),
|
||||
std::min<int>(int(freeTaskCount), int(m_projectPchTasks.size())));
|
||||
m_projectPchTaskScheduler.addTasks(createProjectTasks(
|
||||
{std::make_move_iterator(newEnd), std::make_move_iterator(m_projectPchTasks.end())}));
|
||||
m_projectPchTasks.erase(newEnd, m_projectPchTasks.end());
|
||||
}
|
||||
}
|
||||
|
||||
void PchTaskQueue::processSystemPchTasks()
|
||||
{
|
||||
uint freeTaskCount = m_systemPchTaskScheduler.slotUsage().free;
|
||||
|
||||
auto newEnd = std::prev(m_systemPchTasks.end(),
|
||||
std::min<int>(int(freeTaskCount), int(m_systemPchTasks.size())));
|
||||
m_systemPchTaskScheduler.addTasks(createSystemTasks(
|
||||
{std::make_move_iterator(newEnd), std::make_move_iterator(m_systemPchTasks.end())}));
|
||||
m_systemPchTasks.erase(newEnd, m_systemPchTasks.end());
|
||||
}
|
||||
|
||||
void PchTaskQueue::processEntries()
|
||||
{
|
||||
processSystemPchTasks();
|
||||
processProjectPchTasks();
|
||||
}
|
||||
|
||||
std::vector<PchTaskQueue::Task> PchTaskQueue::createProjectTasks(PchTasks &&pchTasks) const
|
||||
{
|
||||
std::vector<Task> tasks;
|
||||
tasks.reserve(pchTasks.size());
|
||||
|
||||
auto convert = [this](auto &&pchTask) {
|
||||
return [pchTask = std::move(pchTask), this](PchCreatorInterface &pchCreator) mutable {
|
||||
Sqlite::DeferredTransaction readTransaction(m_transactionsInterface);
|
||||
pchTask.systemPchPath = m_precompiledHeaderStorage.fetchSystemPrecompiledHeaderPath(
|
||||
pchTask.projectPartId());
|
||||
readTransaction.commit();
|
||||
pchCreator.generatePch(pchTask);
|
||||
const auto &projectPartPch = pchCreator.projectPartPch();
|
||||
Sqlite::ImmediateTransaction writeTransaction(m_transactionsInterface);
|
||||
if (projectPartPch.pchPath.empty()) {
|
||||
m_precompiledHeaderStorage.deleteProjectPrecompiledHeader(pchTask.projectPartId());
|
||||
} else {
|
||||
m_precompiledHeaderStorage
|
||||
.insertProjectPrecompiledHeader(pchTask.projectPartId(),
|
||||
projectPartPch.pchPath,
|
||||
projectPartPch.lastModified);
|
||||
}
|
||||
writeTransaction.commit();
|
||||
};
|
||||
};
|
||||
|
||||
std::transform(std::make_move_iterator(pchTasks.begin()),
|
||||
std::make_move_iterator(pchTasks.end()),
|
||||
std::back_inserter(tasks),
|
||||
convert);
|
||||
|
||||
return tasks;
|
||||
}
|
||||
|
||||
std::vector<PchTaskQueue::Task> PchTaskQueue::createSystemTasks(PchTasks &&pchTasks) const
|
||||
{
|
||||
std::vector<Task> tasks;
|
||||
tasks.reserve(pchTasks.size());
|
||||
|
||||
auto convert = [this](auto &&pchTask) {
|
||||
return [pchTask = std::move(pchTask), this](PchCreatorInterface &pchCreator) {
|
||||
pchCreator.generatePch(pchTask);
|
||||
const auto &projectPartPch = pchCreator.projectPartPch();
|
||||
Sqlite::ImmediateTransaction transaction(m_transactionsInterface);
|
||||
for (Utils::SmallStringView projectPartId : pchTask.projectPartIds) {
|
||||
if (projectPartPch.pchPath.empty()) {
|
||||
m_precompiledHeaderStorage.deleteSystemPrecompiledHeader(projectPartId);
|
||||
} else {
|
||||
m_precompiledHeaderStorage
|
||||
.insertSystemPrecompiledHeader(projectPartId,
|
||||
projectPartPch.pchPath,
|
||||
projectPartPch.lastModified);
|
||||
}
|
||||
}
|
||||
transaction.commit();
|
||||
};
|
||||
};
|
||||
|
||||
std::transform(std::make_move_iterator(pchTasks.begin()),
|
||||
std::make_move_iterator(pchTasks.end()),
|
||||
std::back_inserter(tasks),
|
||||
convert);
|
||||
|
||||
return tasks;
|
||||
}
|
||||
|
||||
} // namespace ClangBackEnd
|
86
src/tools/clangpchmanagerbackend/source/pchtaskqueue.h
Normal file
86
src/tools/clangpchmanagerbackend/source/pchtaskqueue.h
Normal file
@@ -0,0 +1,86 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2018 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
|
||||
|
||||
#include "pchtaskqueueinterface.h"
|
||||
#include "taskschedulerinterface.h"
|
||||
|
||||
namespace Sqlite {
|
||||
class TransactionInterface;
|
||||
}
|
||||
|
||||
namespace ClangBackEnd {
|
||||
class PchCreatorInterface;
|
||||
class PrecompiledHeaderStorageInterface;
|
||||
class ProgressCounter;
|
||||
|
||||
class PchTaskQueue final : public PchTaskQueueInterface
|
||||
{
|
||||
public:
|
||||
using Task = std::function<void (PchCreatorInterface&)>;
|
||||
|
||||
PchTaskQueue(TaskSchedulerInterface<Task> &systemPchTaskScheduler,
|
||||
TaskSchedulerInterface<Task> &projectPchTaskScheduler,
|
||||
ProgressCounter &progressCounter,
|
||||
PrecompiledHeaderStorageInterface &precompiledHeaderStorage,
|
||||
Sqlite::TransactionInterface &transactionsInterface)
|
||||
: m_systemPchTaskScheduler(systemPchTaskScheduler)
|
||||
, m_projectPchTaskScheduler(projectPchTaskScheduler)
|
||||
, m_precompiledHeaderStorage(precompiledHeaderStorage)
|
||||
, m_transactionsInterface(transactionsInterface)
|
||||
, m_progressCounter(progressCounter)
|
||||
{}
|
||||
|
||||
void addSystemPchTasks(PchTasks &&pchTasks) override;
|
||||
void addProjectPchTasks(PchTasks &&pchTasks) override;
|
||||
void removePchTasks(const Utils::SmallStringVector &projectsPartIds) override;
|
||||
|
||||
void processEntries() override;
|
||||
|
||||
const PchTasks &systemPchTasks() const { return m_systemPchTasks; }
|
||||
const PchTasks &projectPchTasks() const { return m_projectPchTasks; }
|
||||
|
||||
std::vector<Task> createProjectTasks(PchTasks &&pchTasks) const;
|
||||
std::vector<Task> createSystemTasks(PchTasks &&pchTasks) const;
|
||||
|
||||
private:
|
||||
void addPchTasks(PchTasks &&pchTasks, PchTasks &destination);
|
||||
void removePchTasksByProjectPartId(const Utils::SmallStringVector &projectsPartIds,
|
||||
PchTasks &destination);
|
||||
void processProjectPchTasks();
|
||||
void processSystemPchTasks();
|
||||
|
||||
private:
|
||||
PchTasks m_systemPchTasks;
|
||||
PchTasks m_projectPchTasks;
|
||||
TaskSchedulerInterface<Task> &m_systemPchTaskScheduler;
|
||||
TaskSchedulerInterface<Task> &m_projectPchTaskScheduler;
|
||||
PrecompiledHeaderStorageInterface &m_precompiledHeaderStorage;
|
||||
Sqlite::TransactionInterface &m_transactionsInterface;
|
||||
ProgressCounter &m_progressCounter;
|
||||
};
|
||||
|
||||
} // namespace ClangBackEnd
|
@@ -47,7 +47,7 @@ public:
|
||||
m_transaction.commit();
|
||||
}
|
||||
|
||||
void insertPrecompiledHeader(Utils::SmallStringView projectPartName,
|
||||
void insertProjectPrecompiledHeader(Utils::SmallStringView projectPartName,
|
||||
Utils::SmallStringView pchPath,
|
||||
long long pchBuildTime) override
|
||||
{
|
||||
@@ -55,43 +55,104 @@ public:
|
||||
Sqlite::ImmediateTransaction transaction{m_database};
|
||||
|
||||
m_insertProjectPartStatement.write(projectPartName);
|
||||
m_insertPrecompiledHeaderStatement .write(projectPartName, pchPath, pchBuildTime);
|
||||
m_insertProjectPrecompiledHeaderStatement.write(projectPartName, pchPath, pchBuildTime);
|
||||
|
||||
transaction.commit();
|
||||
} catch (const Sqlite::StatementIsBusy) {
|
||||
insertPrecompiledHeader(projectPartName, pchPath, pchBuildTime);
|
||||
insertProjectPrecompiledHeader(projectPartName, pchPath, pchBuildTime);
|
||||
}
|
||||
}
|
||||
|
||||
void deletePrecompiledHeader(Utils::SmallStringView projectPartName) override
|
||||
void deleteProjectPrecompiledHeader(Utils::SmallStringView projectPartName) override
|
||||
{
|
||||
try {
|
||||
Sqlite::ImmediateTransaction transaction{m_database};
|
||||
|
||||
m_deletePrecompiledHeaderStatement.write(projectPartName);
|
||||
m_deleteProjectPrecompiledHeaderStatement.write(projectPartName);
|
||||
|
||||
transaction.commit();
|
||||
} catch (const Sqlite::StatementIsBusy) {
|
||||
deletePrecompiledHeader(projectPartName);
|
||||
deleteProjectPrecompiledHeader(projectPartName);
|
||||
}
|
||||
}
|
||||
|
||||
void insertSystemPrecompiledHeader(Utils::SmallStringView projectPartName,
|
||||
Utils::SmallStringView pchPath,
|
||||
long long pchBuildTime) override
|
||||
{
|
||||
try {
|
||||
Sqlite::ImmediateTransaction transaction{m_database};
|
||||
|
||||
m_insertProjectPartStatement.write(projectPartName);
|
||||
m_insertSystemPrecompiledHeaderStatement.write(projectPartName, pchPath, pchBuildTime);
|
||||
|
||||
transaction.commit();
|
||||
} catch (const Sqlite::StatementIsBusy) {
|
||||
insertSystemPrecompiledHeader(projectPartName, pchPath, pchBuildTime);
|
||||
}
|
||||
}
|
||||
|
||||
void deleteSystemPrecompiledHeader(Utils::SmallStringView projectPartName) override
|
||||
{
|
||||
try {
|
||||
Sqlite::ImmediateTransaction transaction{m_database};
|
||||
|
||||
m_deleteSystemPrecompiledHeaderStatement.write(projectPartName);
|
||||
|
||||
transaction.commit();
|
||||
} catch (const Sqlite::StatementIsBusy) {
|
||||
deleteSystemPrecompiledHeader(projectPartName);
|
||||
}
|
||||
}
|
||||
|
||||
Utils::PathString fetchSystemPrecompiledHeaderPath(Utils::SmallStringView projectPartName) override
|
||||
{
|
||||
try {
|
||||
Sqlite::DeferredTransaction transaction{m_database};
|
||||
|
||||
auto value = m_fetchSystemPrecompiledHeaderPathStatement
|
||||
.template value<Utils::PathString>(projectPartName);
|
||||
|
||||
if (value)
|
||||
return value.value();
|
||||
|
||||
transaction.commit();
|
||||
} catch (const Sqlite::StatementIsBusy) {
|
||||
return fetchSystemPrecompiledHeaderPath(projectPartName);
|
||||
}
|
||||
|
||||
return Utils::SmallStringView("");
|
||||
}
|
||||
|
||||
public:
|
||||
Sqlite::ImmediateNonThrowingDestructorTransaction m_transaction;
|
||||
Database &m_database;
|
||||
WriteStatement m_insertPrecompiledHeaderStatement {
|
||||
"INSERT OR REPLACE INTO precompiledHeaders(projectPartId, pchPath, pchBuildTime) VALUES((SELECT projectPartId FROM projectParts WHERE projectPartName = ?),?,?)",
|
||||
m_database
|
||||
};
|
||||
WriteStatement m_insertProjectPrecompiledHeaderStatement{
|
||||
"INSERT INTO precompiledHeaders(projectPartId, projectPchPath, projectPchBuildTime) "
|
||||
"VALUES((SELECT projectPartId FROM projectParts WHERE projectPartName = ?001),?002,?003) "
|
||||
"ON CONFLICT (projectPartId) DO UPDATE SET projectPchPath=?002,projectPchBuildTime=?003",
|
||||
m_database};
|
||||
WriteStatement m_insertSystemPrecompiledHeaderStatement{
|
||||
"INSERT INTO precompiledHeaders(projectPartId, systemPchPath, systemPchBuildTime) "
|
||||
"VALUES((SELECT projectPartId FROM projectParts WHERE projectPartName = ?001),?002,?003) "
|
||||
"ON CONFLICT (projectPartId) DO UPDATE SET systemPchPath=?002,systemPchBuildTime=?003",
|
||||
m_database};
|
||||
WriteStatement m_insertProjectPartStatement{
|
||||
"INSERT OR IGNORE INTO projectParts(projectPartName) VALUES (?)",
|
||||
m_database
|
||||
};
|
||||
WriteStatement m_deletePrecompiledHeaderStatement{
|
||||
"DELETE FROM precompiledHeaders WHERE projectPartId = (SELECT projectPartId FROM projectParts WHERE projectPartName = ?)",
|
||||
m_database
|
||||
};
|
||||
"INSERT OR IGNORE INTO projectParts(projectPartName) VALUES (?)", m_database};
|
||||
WriteStatement m_deleteProjectPrecompiledHeaderStatement{
|
||||
"UPDATE OR IGNORE precompiledHeaders SET projectPchPath=NULL,projectPchBuildTime=NULL "
|
||||
"WHERE projectPartId = (SELECT projectPartId FROM "
|
||||
"projectParts WHERE projectPartName = ?)",
|
||||
m_database};
|
||||
WriteStatement m_deleteSystemPrecompiledHeaderStatement{
|
||||
"UPDATE OR IGNORE precompiledHeaders SET systemPchPath=NULL,systemPchBuildTime=NULL "
|
||||
"WHERE projectPartId = (SELECT projectPartId FROM "
|
||||
"projectParts WHERE projectPartName = ?)",
|
||||
m_database};
|
||||
ReadStatement m_fetchSystemPrecompiledHeaderPathStatement{
|
||||
"SELECT systemPchPath FROM precompiledHeaders WHERE projectPartId = (SELECT projectPartId "
|
||||
"FROM projectParts WHERE projectPartName = ?)",
|
||||
m_database};
|
||||
};
|
||||
|
||||
}
|
||||
|
@@ -25,7 +25,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <utils/smallstringview.h>
|
||||
#include <utils/smallstring.h>
|
||||
|
||||
namespace ClangBackEnd {
|
||||
|
||||
@@ -34,14 +34,21 @@ class PrecompiledHeaderStorageInterface
|
||||
public:
|
||||
PrecompiledHeaderStorageInterface() = default;
|
||||
|
||||
PrecompiledHeaderStorageInterface(const PrecompiledHeaderStorageInterface&) = delete;
|
||||
PrecompiledHeaderStorageInterface &operator=(const PrecompiledHeaderStorageInterface&) = delete;
|
||||
PrecompiledHeaderStorageInterface(const PrecompiledHeaderStorageInterface &) = delete;
|
||||
PrecompiledHeaderStorageInterface &operator=(const PrecompiledHeaderStorageInterface &) = delete;
|
||||
|
||||
virtual void insertPrecompiledHeader(Utils::SmallStringView projectPartName,
|
||||
virtual void insertProjectPrecompiledHeader(Utils::SmallStringView projectPartName,
|
||||
Utils::SmallStringView pchPath,
|
||||
long long pchBuildTime) = 0;
|
||||
|
||||
virtual void deletePrecompiledHeader(Utils::SmallStringView projectPartName) = 0;
|
||||
long long pchBuildTime)
|
||||
= 0;
|
||||
virtual void deleteProjectPrecompiledHeader(Utils::SmallStringView projectPartName) = 0;
|
||||
virtual void insertSystemPrecompiledHeader(Utils::SmallStringView projectPartName,
|
||||
Utils::SmallStringView pchPath,
|
||||
long long pchBuildTime)
|
||||
= 0;
|
||||
virtual void deleteSystemPrecompiledHeader(Utils::SmallStringView projectPartName) = 0;
|
||||
virtual Utils::PathString fetchSystemPrecompiledHeaderPath(
|
||||
Utils::SmallStringView projectPartName) = 0;
|
||||
|
||||
protected:
|
||||
~PrecompiledHeaderStorageInterface() = default;
|
||||
|
@@ -90,7 +90,7 @@ void ProjectPartQueue::removeProjectParts(const Utils::SmallStringVector &projec
|
||||
|
||||
void ProjectPartQueue::processEntries()
|
||||
{
|
||||
uint taskCount = m_taskScheduler.freeSlots();
|
||||
uint taskCount = m_taskScheduler.slotUsage().free;
|
||||
|
||||
auto newEnd = std::prev(m_projectParts.end(), std::min<int>(int(taskCount), int(m_projectParts.size())));
|
||||
m_taskScheduler.addTasks(
|
||||
@@ -112,13 +112,13 @@ std::vector<ProjectPartQueue::Task> ProjectPartQueue::createPchTasks(
|
||||
|
||||
auto convert = [this] (auto &&projectPart) {
|
||||
return [projectPart=std::move(projectPart), this] (PchCreatorInterface &pchCreator) {
|
||||
pchCreator.generatePch(projectPart);
|
||||
pchCreator.generatePchDeprecated(projectPart);
|
||||
const auto &projectPartPch = pchCreator.projectPartPch();
|
||||
Sqlite::ImmediateTransaction transaction(m_transactionsInterface);
|
||||
if (projectPartPch.pchPath.empty()) {
|
||||
m_precompiledHeaderStorage.deletePrecompiledHeader(projectPartPch.projectPartId);
|
||||
m_precompiledHeaderStorage.deleteProjectPrecompiledHeader(projectPartPch.projectPartId);
|
||||
} else {
|
||||
m_precompiledHeaderStorage.insertPrecompiledHeader(projectPartPch.projectPartId,
|
||||
m_precompiledHeaderStorage.insertProjectPrecompiledHeader(projectPartPch.projectPartId,
|
||||
projectPartPch.pchPath,
|
||||
projectPartPch.lastModified);
|
||||
}
|
||||
|
@@ -99,14 +99,15 @@ public:
|
||||
return m_futures;
|
||||
}
|
||||
|
||||
uint freeSlots()
|
||||
SlotUsage slotUsage()
|
||||
{
|
||||
removeFinishedFutures();
|
||||
|
||||
if (m_isDisabled)
|
||||
return 0;
|
||||
return {};
|
||||
|
||||
return uint(std::max(int(m_hardwareConcurrency) - int(m_futures.size()), 0));
|
||||
return {uint(std::max(int(m_hardwareConcurrency) - int(m_futures.size()), 0)),
|
||||
uint(m_futures.size())};
|
||||
}
|
||||
|
||||
void syncTasks()
|
||||
|
@@ -31,6 +31,12 @@ namespace ClangBackEnd {
|
||||
|
||||
using uint = unsigned int;
|
||||
|
||||
struct SlotUsage
|
||||
{
|
||||
uint free = 0;
|
||||
uint used = 0;
|
||||
};
|
||||
|
||||
template <typename Task>
|
||||
class TaskSchedulerInterface
|
||||
{
|
||||
@@ -40,7 +46,7 @@ public:
|
||||
TaskSchedulerInterface &operator=(const TaskSchedulerInterface &) = delete;
|
||||
|
||||
virtual void addTasks(std::vector<Task> &&tasks) = 0;
|
||||
virtual uint freeSlots() = 0;
|
||||
virtual SlotUsage slotUsage() = 0;
|
||||
|
||||
protected:
|
||||
~TaskSchedulerInterface() = default;
|
||||
|
@@ -94,7 +94,7 @@ public:
|
||||
|
||||
void processEntries()
|
||||
{
|
||||
uint taskCount = m_symbolIndexerScheduler.freeSlots();
|
||||
uint taskCount = m_symbolIndexerScheduler.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),
|
||||
|
@@ -105,7 +105,7 @@ public:
|
||||
m_indexerScheduler.disable();
|
||||
while (!m_indexerScheduler.futures().empty()) {
|
||||
m_indexerScheduler.syncTasks();
|
||||
m_indexerScheduler.freeSlots();
|
||||
m_indexerScheduler.slotUsage();
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -332,7 +332,7 @@ public:
|
||||
m_database
|
||||
};
|
||||
mutable ReadStatement m_getPrecompiledHeader{
|
||||
"SELECT pchPath, pchBuildTime FROM precompiledHeaders WHERE projectPartId = ?",
|
||||
"SELECT projectPchPath, projectPchBuildTime FROM precompiledHeaders WHERE projectPartId = ?",
|
||||
m_database
|
||||
};
|
||||
};
|
||||
|
@@ -90,7 +90,7 @@ protected:
|
||||
.Times(AnyNumber());
|
||||
EXPECT_CALL(selectAllSources, valuesReturnStdVectorSource(_))
|
||||
.Times(AnyNumber());
|
||||
EXPECT_CALL(selectDirectoryPathFromDirectoriesByDirectoryId, valueReturnPathString(_))
|
||||
EXPECT_CALL(selectDirectoryPathFromDirectoriesByDirectoryId, valueReturnPathString(An<int>()))
|
||||
.Times(AnyNumber());
|
||||
EXPECT_CALL(selectSourceNameAndDirectoryIdFromSourcesBySourceId, valueReturnSourceNameAndDirectoryId(_))
|
||||
.Times(AnyNumber());
|
||||
|
@@ -1033,8 +1033,8 @@ std::ostream &operator<<(std::ostream &out, const PchCreatorIncludes &includes)
|
||||
}
|
||||
std::ostream &operator<<(std::ostream &out, const PchTask &task)
|
||||
{
|
||||
return out << "(" << task.projectPartId << ", " << task.dependentIds << ", " << task.includes
|
||||
<< ", " << task.compilerMacros << ", " << task.usedMacros << ")";
|
||||
return out << "(" << task.projectPartIds << ", " << task.includes << ", " << task.compilerMacros
|
||||
<< ", " << task.usedMacros << ")";
|
||||
}
|
||||
|
||||
std::ostream &operator<<(std::ostream &out, const BuildDependency &dependency)
|
||||
@@ -1048,6 +1048,11 @@ std::ostream &operator<<(std::ostream &out, const BuildDependency &dependency)
|
||||
<< ")";
|
||||
}
|
||||
|
||||
std::ostream &operator<<(std::ostream &out, const SlotUsage &slotUsage)
|
||||
{
|
||||
return out << "(" << slotUsage.free << ", " << slotUsage.used << ")";
|
||||
}
|
||||
|
||||
const char *sourceTypeString(SourceType sourceType)
|
||||
{
|
||||
using ClangBackEnd::SymbolTag;
|
||||
|
@@ -175,6 +175,7 @@ class PchTask;
|
||||
class BuildDependency;
|
||||
class SourceEntry;
|
||||
class FilePathCaching;
|
||||
class SlotUsage;
|
||||
|
||||
std::ostream &operator<<(std::ostream &out, const SourceLocationEntry &entry);
|
||||
std::ostream &operator<<(std::ostream &out, const IdPaths &idPaths);
|
||||
@@ -259,6 +260,7 @@ std::ostream &operator<<(std::ostream &out, const PchCreatorIncludes &includes);
|
||||
std::ostream &operator<<(std::ostream &out, const PchTask &task);
|
||||
std::ostream &operator<<(std::ostream &out, const BuildDependency &dependency);
|
||||
std::ostream &operator<<(std::ostream &out, const SourceEntry &entry);
|
||||
std::ostream &operator<<(std::ostream &out, const SlotUsage &slotUsage);
|
||||
|
||||
void PrintTo(const FilePath &filePath, ::std::ostream *os);
|
||||
void PrintTo(const FilePathView &filePathView, ::std::ostream *os);
|
||||
|
@@ -35,21 +35,13 @@
|
||||
class MockPchCreator : public ClangBackEnd::PchCreatorInterface
|
||||
{
|
||||
public:
|
||||
MOCK_METHOD1(generatePch,
|
||||
void(const ClangBackEnd::V2::ProjectPartContainer &projectPart));
|
||||
MOCK_METHOD0(takeProjectIncludes,
|
||||
ClangBackEnd::IdPaths());
|
||||
MOCK_METHOD0(projectPartPch,
|
||||
const ClangBackEnd::ProjectPartPch &());
|
||||
MOCK_METHOD1(setUnsavedFiles,
|
||||
void (const ClangBackEnd::V2::FileContainers &fileContainers));
|
||||
MOCK_METHOD0(clear,
|
||||
void());
|
||||
MOCK_METHOD0(doInMainThreadAfterFinished,
|
||||
void());
|
||||
MOCK_CONST_METHOD0(isUsed,
|
||||
bool());
|
||||
MOCK_METHOD1(setIsUsed,
|
||||
void(bool));
|
||||
|
||||
MOCK_METHOD1(generatePchDeprecated, void(const ClangBackEnd::V2::ProjectPartContainer &projectPart));
|
||||
MOCK_METHOD1(generatePch, void(const ClangBackEnd::PchTask &pchTask));
|
||||
MOCK_METHOD0(takeProjectIncludes, ClangBackEnd::IdPaths());
|
||||
MOCK_METHOD0(projectPartPch, const ClangBackEnd::ProjectPartPch &());
|
||||
MOCK_METHOD1(setUnsavedFiles, void(const ClangBackEnd::V2::FileContainers &fileContainers));
|
||||
MOCK_METHOD0(clear, void());
|
||||
MOCK_METHOD0(doInMainThreadAfterFinished, void());
|
||||
MOCK_CONST_METHOD0(isUsed, bool());
|
||||
MOCK_METHOD1(setIsUsed, void(bool));
|
||||
};
|
||||
|
@@ -32,10 +32,16 @@
|
||||
class MockPrecompiledHeaderStorage : public ClangBackEnd::PrecompiledHeaderStorageInterface
|
||||
{
|
||||
public:
|
||||
MOCK_METHOD3(insertPrecompiledHeader,
|
||||
void (Utils::SmallStringView projectPartName,
|
||||
MOCK_METHOD3(insertProjectPrecompiledHeader,
|
||||
void(Utils::SmallStringView projectPartName,
|
||||
Utils::SmallStringView pchPath,
|
||||
long long pchBuildTime));
|
||||
|
||||
MOCK_METHOD1(deletePrecompiledHeader, void (Utils::SmallStringView projectPartName));
|
||||
MOCK_METHOD1(deleteProjectPrecompiledHeader, void(Utils::SmallStringView projectPartName));
|
||||
MOCK_METHOD3(insertSystemPrecompiledHeader,
|
||||
void(Utils::SmallStringView projectPartName,
|
||||
Utils::SmallStringView pchPath,
|
||||
long long pchBuildTime));
|
||||
MOCK_METHOD1(deleteSystemPrecompiledHeader, void(Utils::SmallStringView projectPartName));
|
||||
MOCK_METHOD1(fetchSystemPrecompiledHeaderPath,
|
||||
Utils::PathString(Utils::SmallStringView projectPartName));
|
||||
};
|
||||
|
@@ -137,6 +137,13 @@ MockSqliteReadStatement::value<Utils::PathString>(const int &directoryId)
|
||||
return valueReturnPathString(directoryId);
|
||||
}
|
||||
|
||||
template <>
|
||||
Utils::optional<Utils::PathString>
|
||||
MockSqliteReadStatement::value<Utils::PathString>(const Utils::SmallStringView &path)
|
||||
{
|
||||
return valueReturnPathString(path);
|
||||
}
|
||||
|
||||
template <>
|
||||
Utils::optional<ClangBackEnd::ProjectPartArtefact>
|
||||
MockSqliteReadStatement::value<ClangBackEnd::ProjectPartArtefact, 4>(const int& sourceId)
|
||||
|
@@ -96,6 +96,9 @@ public:
|
||||
MOCK_METHOD1(valueReturnPathString,
|
||||
Utils::optional<Utils::PathString>(int));
|
||||
|
||||
MOCK_METHOD1(valueReturnPathString,
|
||||
Utils::optional<Utils::PathString>(Utils::SmallStringView));
|
||||
|
||||
MOCK_METHOD1(valueReturnSmallString,
|
||||
Utils::optional<Utils::SmallString>(int));
|
||||
|
||||
@@ -221,6 +224,10 @@ template <>
|
||||
Utils::optional<Utils::PathString>
|
||||
MockSqliteReadStatement::value<Utils::PathString>(const int&);
|
||||
|
||||
template <>
|
||||
Utils::optional<Utils::PathString>
|
||||
MockSqliteReadStatement::value<Utils::PathString>(const Utils::SmallStringView&);
|
||||
|
||||
template <>
|
||||
Utils::optional<ClangBackEnd::ProjectPartArtefact>
|
||||
MockSqliteReadStatement::value<ClangBackEnd::ProjectPartArtefact, 4>(const int&);
|
||||
|
@@ -36,8 +36,8 @@ class MockTaskScheduler : public ClangBackEnd::TaskSchedulerInterface<Task>
|
||||
public:
|
||||
MOCK_METHOD1_T(addTasks,
|
||||
void (const std::vector<Task> &));
|
||||
MOCK_METHOD0(freeSlots,
|
||||
uint ());
|
||||
MOCK_METHOD0(slotUsage,
|
||||
ClangBackEnd::SlotUsage ());
|
||||
|
||||
void addTasks(std::vector<Task> &&tasks)
|
||||
{
|
||||
|
@@ -223,14 +223,14 @@ TEST_F(PchCreator, CreateProjectPartClangCompilerArguments)
|
||||
|
||||
TEST_F(PchCreatorVerySlowTest, IncludesForCreatePchsForProjectParts)
|
||||
{
|
||||
creator.generatePch(projectPart1);
|
||||
creator.generatePchDeprecated(projectPart1);
|
||||
|
||||
ASSERT_THAT(creator.takeProjectIncludes().id, "project1");
|
||||
}
|
||||
|
||||
TEST_F(PchCreatorVerySlowTest, ProjectPartPchsSendToPchManagerClient)
|
||||
{
|
||||
creator.generatePch(projectPart1);
|
||||
creator.generatePchDeprecated(projectPart1);
|
||||
|
||||
EXPECT_CALL(mockPchManagerClient,
|
||||
precompiledHeadersUpdated(
|
||||
@@ -242,7 +242,7 @@ TEST_F(PchCreatorVerySlowTest, ProjectPartPchsSendToPchManagerClient)
|
||||
|
||||
TEST_F(PchCreatorVerySlowTest, UpdateFileWatcherIncludes)
|
||||
{
|
||||
creator.generatePch(projectPart1);
|
||||
creator.generatePchDeprecated(projectPart1);
|
||||
|
||||
EXPECT_CALL(mockClangPathWatcher,
|
||||
updateIdPaths(ElementsAre(creator.projectIncludes())));
|
||||
@@ -252,7 +252,7 @@ TEST_F(PchCreatorVerySlowTest, UpdateFileWatcherIncludes)
|
||||
|
||||
TEST_F(PchCreatorVerySlowTest, IdPathsForCreatePchsForProjectParts)
|
||||
{
|
||||
creator.generatePch(projectPart1);
|
||||
creator.generatePchDeprecated(projectPart1);
|
||||
|
||||
ASSERT_THAT(creator.takeProjectIncludes(),
|
||||
AllOf(Field(&IdPaths::id, "project1"),
|
||||
@@ -263,7 +263,7 @@ TEST_F(PchCreatorVerySlowTest, IdPathsForCreatePchsForProjectParts)
|
||||
|
||||
TEST_F(PchCreatorVerySlowTest, ProjectPartPchForCreatesPchForProjectPart)
|
||||
{
|
||||
creator.generatePch(projectPart1);
|
||||
creator.generatePchDeprecated(projectPart1);
|
||||
|
||||
ASSERT_THAT(creator.projectPartPch(),
|
||||
AllOf(Field(&ProjectPartPch::projectPartId, Eq("project1")),
|
||||
@@ -273,7 +273,7 @@ TEST_F(PchCreatorVerySlowTest, ProjectPartPchForCreatesPchForProjectPart)
|
||||
|
||||
TEST_F(PchCreatorVerySlowTest, ProjectPartPchCleared)
|
||||
{
|
||||
creator.generatePch(projectPart1);
|
||||
creator.generatePchDeprecated(projectPart1);
|
||||
|
||||
creator.clear();
|
||||
|
||||
@@ -283,7 +283,7 @@ TEST_F(PchCreatorVerySlowTest, ProjectPartPchCleared)
|
||||
|
||||
TEST_F(PchCreatorVerySlowTest, ProjectIncludesCleared)
|
||||
{
|
||||
creator.generatePch(projectPart1);
|
||||
creator.generatePchDeprecated(projectPart1);
|
||||
|
||||
creator.clear();
|
||||
|
||||
@@ -299,7 +299,7 @@ TEST_F(PchCreatorVerySlowTest, FaultyProjectPartPchForCreatesNoPchForProjectPart
|
||||
{},
|
||||
{id(TESTDATA_DIR "/builddependencycollector/project/faulty.cpp")}};
|
||||
|
||||
creator.generatePch(faultyProjectPart);
|
||||
creator.generatePchDeprecated(faultyProjectPart);
|
||||
|
||||
ASSERT_THAT(creator.projectPartPch(),
|
||||
AllOf(Field(&ProjectPartPch::projectPartId, Eq("faultyProject")),
|
||||
|
@@ -80,7 +80,7 @@ TEST_F(PchTaskGenerator, Create)
|
||||
EXPECT_CALL(mockPchTaskMerger,
|
||||
mergeTasks(ElementsAre(
|
||||
AllOf(Field(&PchTaskSet::system,
|
||||
AllOf(Field(&PchTask::projectPartId, Eq("ProjectPart1")),
|
||||
AllOf(Field(&PchTask::projectPartIds, ElementsAre("ProjectPart1")),
|
||||
Field(&PchTask::includes, ElementsAre(4, 5)),
|
||||
Field(&PchTask::compilerMacros,
|
||||
ElementsAre(CompilerMacro{"SE", "4", 4},
|
||||
@@ -88,7 +88,8 @@ TEST_F(PchTaskGenerator, Create)
|
||||
Field(&PchTask::usedMacros,
|
||||
ElementsAre(UsedMacro{"SE", 4}, UsedMacro{"WU", 5})))),
|
||||
AllOf(Field(&PchTaskSet::project,
|
||||
AllOf(Field(&PchTask::projectPartId, Eq("ProjectPart1")),
|
||||
AllOf(Field(&PchTask::projectPartIds,
|
||||
ElementsAre("ProjectPart1")),
|
||||
Field(&PchTask::includes, ElementsAre(1, 3)),
|
||||
Field(&PchTask::compilerMacros,
|
||||
ElementsAre(CompilerMacro{"YI", "1", 1},
|
||||
|
343
tests/unit/unittest/pchtaskqueue-test.cpp
Normal file
343
tests/unit/unittest/pchtaskqueue-test.cpp
Normal file
@@ -0,0 +1,343 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2018 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.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "googletest.h"
|
||||
|
||||
#include "mockpchcreator.h"
|
||||
#include "mockprecompiledheaderstorage.h"
|
||||
#include "mocksqlitetransactionbackend.h"
|
||||
#include "mocktaskscheduler.h"
|
||||
|
||||
#include <pchtaskqueue.h>
|
||||
#include <progresscounter.h>
|
||||
|
||||
namespace {
|
||||
|
||||
using ClangBackEnd::PchTask;
|
||||
using ClangBackEnd::SlotUsage;
|
||||
|
||||
class PchTaskQueue : public testing::Test
|
||||
{
|
||||
protected:
|
||||
NiceMock<MockTaskScheduler<ClangBackEnd::PchTaskQueue::Task>> mockSytemPchTaskScheduler;
|
||||
NiceMock<MockTaskScheduler<ClangBackEnd::PchTaskQueue::Task>> mockProjectPchTaskScheduler;
|
||||
MockPrecompiledHeaderStorage mockPrecompiledHeaderStorage;
|
||||
MockSqliteTransactionBackend mockSqliteTransactionBackend;
|
||||
NiceMock<MockFunction<void(int, int)>> mockSetProgressCallback;
|
||||
ClangBackEnd::ProgressCounter progressCounter{mockSetProgressCallback.AsStdFunction()};
|
||||
ClangBackEnd::PchTaskQueue queue{mockSytemPchTaskScheduler,
|
||||
mockProjectPchTaskScheduler,
|
||||
progressCounter,
|
||||
mockPrecompiledHeaderStorage,
|
||||
mockSqliteTransactionBackend};
|
||||
PchTask systemTask1{"ProjectPart1",
|
||||
{1, 2},
|
||||
{{"YI", "1", 1}, {"SAN", "3", 3}},
|
||||
{{"LIANG", 0}, {"YI", 1}}};
|
||||
PchTask systemTask2{"ProjectPart2",
|
||||
{1, 2},
|
||||
{{"YI", "1", 1}, {"SAN", "3", 3}},
|
||||
{{"LIANG", 0}, {"YI", 1}}};
|
||||
PchTask systemTask2b{"ProjectPart2",
|
||||
{3, 4},
|
||||
{{"YI", "1", 1}, {"SAN", "3", 3}},
|
||||
{{"LIANG", 0}, {"YI", 1}}};
|
||||
PchTask systemTask3{"ProjectPart3",
|
||||
{1, 2},
|
||||
{{"YI", "1", 1}, {"SAN", "3", 3}},
|
||||
{{"LIANG", 0}, {"YI", 1}}};
|
||||
PchTask projectTask1{"ProjectPart1",
|
||||
{11, 12},
|
||||
{{"SE", "4", 4}, {"WU", "5", 5}},
|
||||
{{"ER", 2}, {"SAN", 3}}};
|
||||
PchTask projectTask2{"ProjectPart2",
|
||||
{11, 12},
|
||||
{{"SE", "4", 4}, {"WU", "5", 5}},
|
||||
{{"ER", 2}, {"SAN", 3}}};
|
||||
PchTask projectTask2b{"ProjectPart2",
|
||||
{21, 22},
|
||||
{{"SE", "4", 4}, {"WU", "5", 5}},
|
||||
{{"ER", 2}, {"SAN", 3}}};
|
||||
PchTask projectTask3{"ProjectPart3",
|
||||
{21, 22},
|
||||
{{"SE", "4", 4}, {"WU", "5", 5}},
|
||||
{{"ER", 2}, {"SAN", 3}}};
|
||||
PchTask systemTask4{Utils::SmallStringVector{"ProjectPart1", "ProjectPart3"},
|
||||
{1, 2},
|
||||
{{"YI", "1", 1}, {"SAN", "3", 3}},
|
||||
{{"LIANG", 0}, {"YI", 1}}};
|
||||
};
|
||||
|
||||
TEST_F(PchTaskQueue, AddProjectPchTask)
|
||||
{
|
||||
queue.addProjectPchTasks({projectTask1});
|
||||
|
||||
queue.addProjectPchTasks({projectTask2});
|
||||
|
||||
ASSERT_THAT(queue.projectPchTasks(), ElementsAre(projectTask1, projectTask2));
|
||||
}
|
||||
|
||||
TEST_F(PchTaskQueue, AddSystemPchTask)
|
||||
{
|
||||
queue.addSystemPchTasks({systemTask1});
|
||||
|
||||
queue.addSystemPchTasks({systemTask2});
|
||||
|
||||
ASSERT_THAT(queue.systemPchTasks(), ElementsAre(systemTask1, systemTask2));
|
||||
}
|
||||
|
||||
TEST_F(PchTaskQueue, AddProjectPchTasksCallsProcessEntriesForSystemTaskSchedulerIsNotBusy)
|
||||
{
|
||||
InSequence s;
|
||||
|
||||
EXPECT_CALL(mockSytemPchTaskScheduler, slotUsage()).WillRepeatedly(Return(SlotUsage{2, 0}));
|
||||
EXPECT_CALL(mockProjectPchTaskScheduler, slotUsage()).WillRepeatedly(Return(SlotUsage{2, 0}));
|
||||
EXPECT_CALL(mockProjectPchTaskScheduler, addTasks(SizeIs(2)));
|
||||
|
||||
queue.addProjectPchTasks({projectTask1, projectTask2});
|
||||
}
|
||||
|
||||
TEST_F(PchTaskQueue, AddProjectPchTasksCallsProcessEntriesForSystemTaskSchedulerIsBusy)
|
||||
{
|
||||
InSequence s;
|
||||
|
||||
EXPECT_CALL(mockSytemPchTaskScheduler, slotUsage()).WillRepeatedly(Return(SlotUsage{2, 1}));
|
||||
EXPECT_CALL(mockProjectPchTaskScheduler, slotUsage()).Times(0);
|
||||
EXPECT_CALL(mockProjectPchTaskScheduler, addTasks(_)).Times(0);
|
||||
|
||||
queue.addProjectPchTasks({projectTask1, projectTask2});
|
||||
}
|
||||
|
||||
TEST_F(PchTaskQueue, AddSystemPchTasksCallsProcessEntries)
|
||||
{
|
||||
InSequence s;
|
||||
|
||||
EXPECT_CALL(mockSytemPchTaskScheduler, slotUsage()).WillRepeatedly(Return(SlotUsage{2, 0}));
|
||||
EXPECT_CALL(mockSytemPchTaskScheduler, addTasks(SizeIs(2)));
|
||||
EXPECT_CALL(mockSytemPchTaskScheduler, slotUsage()).WillRepeatedly(Return(SlotUsage{2, 1}));
|
||||
EXPECT_CALL(mockProjectPchTaskScheduler, slotUsage()).Times(0);
|
||||
EXPECT_CALL(mockProjectPchTaskScheduler, addTasks(_)).Times(0);
|
||||
|
||||
queue.addSystemPchTasks({projectTask1, projectTask2});
|
||||
}
|
||||
|
||||
TEST_F(PchTaskQueue, AddProjectPchTasksCallsProgressCounter)
|
||||
{
|
||||
queue.addProjectPchTasks({projectTask1, projectTask2});
|
||||
|
||||
EXPECT_CALL(mockSetProgressCallback, Call(0, 3));
|
||||
|
||||
queue.addProjectPchTasks({projectTask2b, projectTask3});
|
||||
}
|
||||
|
||||
TEST_F(PchTaskQueue, AddSystemPchTasksCallsProgressCounter)
|
||||
{
|
||||
queue.addSystemPchTasks({systemTask1, systemTask2});
|
||||
|
||||
EXPECT_CALL(mockSetProgressCallback, Call(0, 3));
|
||||
|
||||
queue.addSystemPchTasks({systemTask2b, systemTask3});
|
||||
}
|
||||
|
||||
TEST_F(PchTaskQueue, AddPchCallsProgressCounter)
|
||||
{
|
||||
queue.addSystemPchTasks({systemTask1, systemTask2});
|
||||
|
||||
EXPECT_CALL(mockSetProgressCallback, Call(0, 3));
|
||||
|
||||
queue.addSystemPchTasks({systemTask2b, systemTask3});
|
||||
}
|
||||
|
||||
TEST_F(PchTaskQueue, ReplaceIdenticalProjectPchTasks)
|
||||
{
|
||||
queue.addProjectPchTasks({projectTask1, projectTask2});
|
||||
|
||||
queue.addProjectPchTasks({projectTask1, projectTask2});
|
||||
|
||||
ASSERT_THAT(queue.projectPchTasks(), ElementsAre(projectTask1, projectTask2));
|
||||
}
|
||||
|
||||
TEST_F(PchTaskQueue, ReplaceIdenticalSystemPchTasks)
|
||||
{
|
||||
queue.addSystemPchTasks({systemTask1, systemTask2});
|
||||
|
||||
queue.addSystemPchTasks({systemTask1, systemTask2});
|
||||
|
||||
ASSERT_THAT(queue.systemPchTasks(), ElementsAre(systemTask1, systemTask2));
|
||||
}
|
||||
|
||||
TEST_F(PchTaskQueue, ReplaceProjectPchTasksWithSameId)
|
||||
{
|
||||
queue.addProjectPchTasks({projectTask1, projectTask2});
|
||||
|
||||
queue.addProjectPchTasks({projectTask1, projectTask2b, projectTask3});
|
||||
|
||||
ASSERT_THAT(queue.projectPchTasks(), ElementsAre(projectTask1, projectTask2b, projectTask3));
|
||||
}
|
||||
|
||||
TEST_F(PchTaskQueue, ReplaceSystemPchTasksWithSameId)
|
||||
{
|
||||
queue.addSystemPchTasks({systemTask1, systemTask2});
|
||||
|
||||
queue.addSystemPchTasks({systemTask1, systemTask2b, systemTask3});
|
||||
|
||||
ASSERT_THAT(queue.systemPchTasks(), ElementsAre(systemTask1, systemTask2b, systemTask3));
|
||||
}
|
||||
|
||||
TEST_F(PchTaskQueue, RemoveProjectPchTasksByProjectPartId)
|
||||
{
|
||||
queue.addProjectPchTasks({projectTask1, projectTask2, projectTask3});
|
||||
|
||||
queue.removePchTasks(projectTask2.projectPartIds);
|
||||
|
||||
ASSERT_THAT(queue.projectPchTasks(), ElementsAre(projectTask1, projectTask3));
|
||||
}
|
||||
|
||||
TEST_F(PchTaskQueue, DontRemoveSystemPchTasksByProjectPartId)
|
||||
{
|
||||
queue.addSystemPchTasks({systemTask1, systemTask2, systemTask3});
|
||||
|
||||
queue.removePchTasks(systemTask2.projectPartIds);
|
||||
|
||||
ASSERT_THAT(queue.systemPchTasks(), ElementsAre(systemTask1, systemTask2, systemTask3));
|
||||
}
|
||||
|
||||
TEST_F(PchTaskQueue, RemovePchTasksCallsProgressCounter)
|
||||
{
|
||||
queue.addSystemPchTasks({systemTask1, systemTask2, systemTask3});
|
||||
queue.addProjectPchTasks({projectTask1, projectTask2, projectTask3});
|
||||
|
||||
EXPECT_CALL(mockSetProgressCallback, Call(0, 5));
|
||||
|
||||
queue.removePchTasks(systemTask2.projectPartIds);
|
||||
}
|
||||
|
||||
TEST_F(PchTaskQueue, CreateProjectTasksSizeEqualsInputSize)
|
||||
{
|
||||
auto tasks = queue.createProjectTasks({projectTask1, projectTask1});
|
||||
|
||||
ASSERT_THAT(tasks, SizeIs(2));
|
||||
}
|
||||
|
||||
TEST_F(PchTaskQueue, CreateProjectTaskFromPchTask)
|
||||
{
|
||||
InSequence s;
|
||||
MockPchCreator mockPchCreator;
|
||||
ClangBackEnd::ProjectPartPch projectPartPch{"", "/path/to/pch", 99};
|
||||
auto tasks = queue.createProjectTasks({projectTask1});
|
||||
auto projectTask = projectTask1;
|
||||
projectTask.systemPchPath = "/path/to/pch";
|
||||
|
||||
EXPECT_CALL(mockSqliteTransactionBackend, lock());
|
||||
EXPECT_CALL(mockSqliteTransactionBackend, deferredBegin());
|
||||
EXPECT_CALL(mockPrecompiledHeaderStorage, fetchSystemPrecompiledHeaderPath(Eq("ProjectPart1")))
|
||||
.WillOnce(Return(Utils::PathString{"/path/to/pch"}));
|
||||
EXPECT_CALL(mockSqliteTransactionBackend, commit());
|
||||
EXPECT_CALL(mockSqliteTransactionBackend, unlock());
|
||||
EXPECT_CALL(mockPchCreator, generatePch(Eq(projectTask)));
|
||||
EXPECT_CALL(mockPchCreator, projectPartPch()).WillOnce(ReturnRef(projectPartPch));
|
||||
EXPECT_CALL(mockSqliteTransactionBackend, lock());
|
||||
EXPECT_CALL(mockSqliteTransactionBackend, immediateBegin());
|
||||
EXPECT_CALL(mockPrecompiledHeaderStorage,
|
||||
insertProjectPrecompiledHeader(Eq("ProjectPart1"), Eq("/path/to/pch"), 99));
|
||||
EXPECT_CALL(mockSqliteTransactionBackend, commit());
|
||||
EXPECT_CALL(mockSqliteTransactionBackend, unlock());
|
||||
|
||||
tasks.front()(mockPchCreator);
|
||||
}
|
||||
|
||||
TEST_F(PchTaskQueue, DeleteProjectPchEntryInDatabaseIfNoPchIsGenerated)
|
||||
{
|
||||
InSequence s;
|
||||
MockPchCreator mockPchCreator;
|
||||
ClangBackEnd::ProjectPartPch projectPartPch{"", "", 0};
|
||||
auto tasks = queue.createProjectTasks({projectTask1});
|
||||
auto projectTask = projectTask1;
|
||||
projectTask.systemPchPath = "/path/to/pch";
|
||||
|
||||
EXPECT_CALL(mockSqliteTransactionBackend, lock());
|
||||
EXPECT_CALL(mockSqliteTransactionBackend, deferredBegin());
|
||||
EXPECT_CALL(mockPrecompiledHeaderStorage, fetchSystemPrecompiledHeaderPath(Eq("ProjectPart1")))
|
||||
.WillOnce(Return(Utils::PathString{"/path/to/pch"}));
|
||||
EXPECT_CALL(mockSqliteTransactionBackend, commit());
|
||||
EXPECT_CALL(mockSqliteTransactionBackend, unlock());
|
||||
EXPECT_CALL(mockPchCreator, generatePch(Eq(projectTask)));
|
||||
EXPECT_CALL(mockPchCreator, projectPartPch()).WillOnce(ReturnRef(projectPartPch));
|
||||
EXPECT_CALL(mockSqliteTransactionBackend, lock());
|
||||
EXPECT_CALL(mockSqliteTransactionBackend, immediateBegin());
|
||||
EXPECT_CALL(mockPrecompiledHeaderStorage, deleteProjectPrecompiledHeader(Eq("ProjectPart1")));
|
||||
EXPECT_CALL(mockSqliteTransactionBackend, commit());
|
||||
EXPECT_CALL(mockSqliteTransactionBackend, unlock());
|
||||
|
||||
tasks.front()(mockPchCreator);
|
||||
}
|
||||
|
||||
TEST_F(PchTaskQueue, CreateSystemTasksSizeEqualsInputSize)
|
||||
{
|
||||
auto tasks = queue.createSystemTasks({systemTask1, systemTask2});
|
||||
|
||||
ASSERT_THAT(tasks, SizeIs(2));
|
||||
}
|
||||
|
||||
TEST_F(PchTaskQueue, CreateSystemTaskFromPchTask)
|
||||
{
|
||||
InSequence s;
|
||||
MockPchCreator mockPchCreator;
|
||||
ClangBackEnd::ProjectPartPch projectPartPch{"", "/path/to/pch", 99};
|
||||
auto tasks = queue.createSystemTasks({systemTask4});
|
||||
|
||||
EXPECT_CALL(mockPchCreator, generatePch(Eq(systemTask4)));
|
||||
EXPECT_CALL(mockPchCreator, projectPartPch()).WillOnce(ReturnRef(projectPartPch));
|
||||
EXPECT_CALL(mockSqliteTransactionBackend, lock());
|
||||
EXPECT_CALL(mockSqliteTransactionBackend, immediateBegin());
|
||||
EXPECT_CALL(mockPrecompiledHeaderStorage,
|
||||
insertSystemPrecompiledHeader(Eq("ProjectPart1"), Eq("/path/to/pch"), 99));
|
||||
EXPECT_CALL(mockPrecompiledHeaderStorage,
|
||||
insertSystemPrecompiledHeader(Eq("ProjectPart3"), Eq("/path/to/pch"), 99));
|
||||
EXPECT_CALL(mockSqliteTransactionBackend, commit());
|
||||
EXPECT_CALL(mockSqliteTransactionBackend, unlock());
|
||||
|
||||
tasks.front()(mockPchCreator);
|
||||
}
|
||||
|
||||
TEST_F(PchTaskQueue, DeleteSystemPchEntryInDatabaseIfNoPchIsGenerated)
|
||||
{
|
||||
InSequence s;
|
||||
MockPchCreator mockPchCreator;
|
||||
ClangBackEnd::ProjectPartPch projectPartPch{"", "", 0};
|
||||
auto tasks = queue.createSystemTasks({systemTask4});
|
||||
|
||||
EXPECT_CALL(mockPchCreator, generatePch(Eq(systemTask4)));
|
||||
EXPECT_CALL(mockPchCreator, projectPartPch()).WillOnce(ReturnRef(projectPartPch));
|
||||
EXPECT_CALL(mockSqliteTransactionBackend, lock());
|
||||
EXPECT_CALL(mockSqliteTransactionBackend, immediateBegin());
|
||||
EXPECT_CALL(mockPrecompiledHeaderStorage, deleteSystemPrecompiledHeader(Eq("ProjectPart1")));
|
||||
EXPECT_CALL(mockPrecompiledHeaderStorage, deleteSystemPrecompiledHeader(Eq("ProjectPart3")));
|
||||
EXPECT_CALL(mockSqliteTransactionBackend, commit());
|
||||
EXPECT_CALL(mockSqliteTransactionBackend, unlock());
|
||||
|
||||
tasks.front()(mockPchCreator);
|
||||
}
|
||||
} // namespace
|
@@ -29,6 +29,7 @@
|
||||
#include <precompiledheaderstorage.h>
|
||||
#include <refactoringdatabaseinitializer.h>
|
||||
#include <sqlitedatabase.h>
|
||||
#include <sqlitereadstatement.h>
|
||||
#include <sqlitewritestatement.h>
|
||||
#include <sqlitetransaction.h>
|
||||
|
||||
@@ -41,9 +42,17 @@ class PrecompiledHeaderStorage : public testing::Test
|
||||
protected:
|
||||
NiceMock<MockSqliteDatabase> database;
|
||||
Storage storage{database};
|
||||
MockSqliteWriteStatement &insertPrecompiledHeaderStatement = storage.m_insertPrecompiledHeaderStatement;
|
||||
MockSqliteWriteStatement &insertProjectPartStatement = storage.m_insertProjectPartStatement;
|
||||
MockSqliteWriteStatement &deletePrecompiledHeaderStatement = storage.m_deletePrecompiledHeaderStatement;
|
||||
MockSqliteWriteStatement &insertProjectPrecompiledHeaderStatement
|
||||
= storage.m_insertProjectPrecompiledHeaderStatement;
|
||||
MockSqliteWriteStatement &deleteProjectPrecompiledHeaderStatement
|
||||
= storage.m_deleteProjectPrecompiledHeaderStatement;
|
||||
MockSqliteWriteStatement &insertSystemPrecompiledHeaderStatement
|
||||
= storage.m_insertSystemPrecompiledHeaderStatement;
|
||||
MockSqliteWriteStatement &deleteSystemPrecompiledHeaderStatement
|
||||
= storage.m_deleteSystemPrecompiledHeaderStatement;
|
||||
MockSqliteReadStatement &fetchSystemPrecompiledHeaderPathStatement
|
||||
= storage.m_fetchSystemPrecompiledHeaderPathStatement;
|
||||
};
|
||||
|
||||
TEST_F(PrecompiledHeaderStorage, UseTransaction)
|
||||
@@ -56,76 +65,112 @@ TEST_F(PrecompiledHeaderStorage, UseTransaction)
|
||||
Storage storage{database};
|
||||
}
|
||||
|
||||
TEST_F(PrecompiledHeaderStorage, InsertPrecompiledHeader)
|
||||
TEST_F(PrecompiledHeaderStorage, InsertProjectPrecompiledHeader)
|
||||
{
|
||||
InSequence s;
|
||||
|
||||
EXPECT_CALL(database, immediateBegin());
|
||||
EXPECT_CALL(insertProjectPartStatement, write(TypedEq<Utils::SmallStringView>("project1")));
|
||||
EXPECT_CALL(insertPrecompiledHeaderStatement,
|
||||
EXPECT_CALL(insertProjectPrecompiledHeaderStatement,
|
||||
write(TypedEq<Utils::SmallStringView>("project1"),
|
||||
TypedEq<Utils::SmallStringView>("/path/to/pch"),
|
||||
TypedEq<long long>(22)));
|
||||
EXPECT_CALL(database, commit());
|
||||
|
||||
storage.insertPrecompiledHeader("project1", "/path/to/pch", 22);
|
||||
storage.insertProjectPrecompiledHeader("project1", "/path/to/pch", 22);
|
||||
}
|
||||
|
||||
TEST_F(PrecompiledHeaderStorage, InsertPrecompiledHeaderStatementIsBusy)
|
||||
TEST_F(PrecompiledHeaderStorage, InsertProjectPrecompiledHeaderStatementIsBusy)
|
||||
{
|
||||
InSequence s;
|
||||
|
||||
EXPECT_CALL(database, immediateBegin()).WillOnce(Throw(Sqlite::StatementIsBusy("busy")));
|
||||
EXPECT_CALL(database, immediateBegin());
|
||||
EXPECT_CALL(insertProjectPartStatement, write(TypedEq<Utils::SmallStringView>("project1")));
|
||||
EXPECT_CALL(insertPrecompiledHeaderStatement,
|
||||
EXPECT_CALL(insertProjectPrecompiledHeaderStatement,
|
||||
write(TypedEq<Utils::SmallStringView>("project1"),
|
||||
TypedEq<Utils::SmallStringView>("/path/to/pch"),
|
||||
TypedEq<long long>(22)));
|
||||
EXPECT_CALL(database, commit());
|
||||
|
||||
storage.insertPrecompiledHeader("project1", "/path/to/pch", 22);
|
||||
storage.insertProjectPrecompiledHeader("project1", "/path/to/pch", 22);
|
||||
}
|
||||
|
||||
TEST_F(PrecompiledHeaderStorage, DeletePrecompiledHeader)
|
||||
TEST_F(PrecompiledHeaderStorage, DeleteProjectPrecompiledHeader)
|
||||
{
|
||||
InSequence s;
|
||||
|
||||
EXPECT_CALL(database, immediateBegin());
|
||||
EXPECT_CALL(deletePrecompiledHeaderStatement, write(TypedEq<Utils::SmallStringView>("project1")));
|
||||
EXPECT_CALL(deleteProjectPrecompiledHeaderStatement, write(TypedEq<Utils::SmallStringView>("project1")));
|
||||
EXPECT_CALL(database, commit());
|
||||
|
||||
storage.deletePrecompiledHeader("project1");
|
||||
storage.deleteProjectPrecompiledHeader("project1");
|
||||
}
|
||||
|
||||
TEST_F(PrecompiledHeaderStorage, DeletePrecompiledHeaderStatementIsBusy)
|
||||
TEST_F(PrecompiledHeaderStorage, DeleteProjectPrecompiledHeaderStatementIsBusy)
|
||||
{
|
||||
InSequence s;
|
||||
|
||||
EXPECT_CALL(database, immediateBegin()).WillOnce(Throw(Sqlite::StatementIsBusy("busy")));
|
||||
EXPECT_CALL(database, immediateBegin());
|
||||
EXPECT_CALL(deletePrecompiledHeaderStatement, write(TypedEq<Utils::SmallStringView>("project1")));
|
||||
EXPECT_CALL(deleteProjectPrecompiledHeaderStatement, write(TypedEq<Utils::SmallStringView>("project1")));
|
||||
EXPECT_CALL(database, commit());
|
||||
|
||||
storage.deletePrecompiledHeader("project1");
|
||||
storage.deleteProjectPrecompiledHeader("project1");
|
||||
}
|
||||
|
||||
TEST_F(PrecompiledHeaderStorage, InsertPrecompiledHeaderStatement)
|
||||
TEST_F(PrecompiledHeaderStorage, InsertSystemPrecompiledHeader)
|
||||
{
|
||||
ASSERT_THAT(insertPrecompiledHeaderStatement.sqlStatement,
|
||||
Eq("INSERT OR REPLACE INTO precompiledHeaders(projectPartId, pchPath, pchBuildTime) VALUES((SELECT projectPartId FROM projectParts WHERE projectPartName = ?),?,?)"));
|
||||
InSequence s;
|
||||
|
||||
EXPECT_CALL(database, immediateBegin());
|
||||
EXPECT_CALL(insertProjectPartStatement, write(TypedEq<Utils::SmallStringView>("project1")));
|
||||
EXPECT_CALL(insertSystemPrecompiledHeaderStatement,
|
||||
write(TypedEq<Utils::SmallStringView>("project1"),
|
||||
TypedEq<Utils::SmallStringView>("/path/to/pch"),
|
||||
TypedEq<long long>(22)));
|
||||
EXPECT_CALL(database, commit());
|
||||
|
||||
storage.insertSystemPrecompiledHeader("project1", "/path/to/pch", 22);
|
||||
}
|
||||
|
||||
TEST_F(PrecompiledHeaderStorage, InsertProjectPartStatement)
|
||||
TEST_F(PrecompiledHeaderStorage, InsertSystemPrecompiledHeaderStatementIsBusy)
|
||||
{
|
||||
ASSERT_THAT(insertProjectPartStatement.sqlStatement,
|
||||
Eq("INSERT OR IGNORE INTO projectParts(projectPartName) VALUES (?)"));
|
||||
InSequence s;
|
||||
|
||||
EXPECT_CALL(database, immediateBegin()).WillOnce(Throw(Sqlite::StatementIsBusy("busy")));
|
||||
EXPECT_CALL(database, immediateBegin());
|
||||
EXPECT_CALL(insertProjectPartStatement, write(TypedEq<Utils::SmallStringView>("project1")));
|
||||
EXPECT_CALL(insertSystemPrecompiledHeaderStatement,
|
||||
write(TypedEq<Utils::SmallStringView>("project1"),
|
||||
TypedEq<Utils::SmallStringView>("/path/to/pch"),
|
||||
TypedEq<long long>(22)));
|
||||
EXPECT_CALL(database, commit());
|
||||
|
||||
storage.insertSystemPrecompiledHeader("project1", "/path/to/pch", 22);
|
||||
}
|
||||
|
||||
TEST_F(PrecompiledHeaderStorage, DeletePrecompiledHeaderStatement)
|
||||
TEST_F(PrecompiledHeaderStorage, DeleteSystemPrecompiledHeader)
|
||||
{
|
||||
ASSERT_THAT(deletePrecompiledHeaderStatement.sqlStatement,
|
||||
Eq("DELETE FROM precompiledHeaders WHERE projectPartId = (SELECT projectPartId FROM projectParts WHERE projectPartName = ?)"));
|
||||
InSequence s;
|
||||
|
||||
EXPECT_CALL(database, immediateBegin());
|
||||
EXPECT_CALL(deleteSystemPrecompiledHeaderStatement, write(TypedEq<Utils::SmallStringView>("project1")));
|
||||
EXPECT_CALL(database, commit());
|
||||
|
||||
storage.deleteSystemPrecompiledHeader("project1");
|
||||
}
|
||||
|
||||
TEST_F(PrecompiledHeaderStorage, DeleteSystemPrecompiledHeaderStatementIsBusy)
|
||||
{
|
||||
InSequence s;
|
||||
|
||||
EXPECT_CALL(database, immediateBegin()).WillOnce(Throw(Sqlite::StatementIsBusy("busy")));
|
||||
EXPECT_CALL(database, immediateBegin());
|
||||
EXPECT_CALL(deleteSystemPrecompiledHeaderStatement, write(TypedEq<Utils::SmallStringView>("project1")));
|
||||
EXPECT_CALL(database, commit());
|
||||
|
||||
storage.deleteSystemPrecompiledHeader("project1");
|
||||
}
|
||||
|
||||
TEST_F(PrecompiledHeaderStorage, CompilePrecompiledHeaderStatements)
|
||||
@@ -136,4 +181,48 @@ TEST_F(PrecompiledHeaderStorage, CompilePrecompiledHeaderStatements)
|
||||
ASSERT_NO_THROW(ClangBackEnd::PrecompiledHeaderStorage<>{database});
|
||||
}
|
||||
|
||||
TEST_F(PrecompiledHeaderStorage, FetchSystemPrecompiledHeaderCalls)
|
||||
{
|
||||
InSequence s;
|
||||
|
||||
EXPECT_CALL(database, deferredBegin());
|
||||
EXPECT_CALL(fetchSystemPrecompiledHeaderPathStatement,
|
||||
valueReturnPathString(TypedEq<Utils::SmallStringView>("project1")));
|
||||
EXPECT_CALL(database, commit());
|
||||
|
||||
storage.fetchSystemPrecompiledHeaderPath("project1");
|
||||
}
|
||||
|
||||
TEST_F(PrecompiledHeaderStorage, FetchSystemPrecompiledHeader)
|
||||
{
|
||||
EXPECT_CALL(fetchSystemPrecompiledHeaderPathStatement,
|
||||
valueReturnPathString(TypedEq<Utils::SmallStringView>("project1")))
|
||||
.WillOnce(Return(Utils::PathString{"/path/to/pch"}));
|
||||
|
||||
auto path = storage.fetchSystemPrecompiledHeaderPath("project1");
|
||||
|
||||
ASSERT_THAT(path, "/path/to/pch");
|
||||
}
|
||||
|
||||
TEST_F(PrecompiledHeaderStorage, FetchSystemPrecompiledHeaderReturnsEmptyPath)
|
||||
{
|
||||
EXPECT_CALL(fetchSystemPrecompiledHeaderPathStatement,
|
||||
valueReturnPathString(TypedEq<Utils::SmallStringView>("project1")))
|
||||
.WillOnce(Return(Utils::PathString{}));
|
||||
|
||||
auto path = storage.fetchSystemPrecompiledHeaderPath("project1");
|
||||
|
||||
ASSERT_THAT(path, IsEmpty());
|
||||
}
|
||||
|
||||
TEST_F(PrecompiledHeaderStorage, FetchSystemPrecompiledHeaderReturnsNullOptional)
|
||||
{
|
||||
EXPECT_CALL(fetchSystemPrecompiledHeaderPathStatement,
|
||||
valueReturnPathString(TypedEq<Utils::SmallStringView>("project1")))
|
||||
.WillOnce(Return(Utils::optional<Utils::PathString>{}));
|
||||
|
||||
auto path = storage.fetchSystemPrecompiledHeaderPath("project1");
|
||||
|
||||
ASSERT_THAT(path, IsEmpty());
|
||||
}
|
||||
}
|
||||
|
@@ -35,6 +35,9 @@
|
||||
|
||||
namespace {
|
||||
|
||||
using ClangBackEnd::SlotUsage;
|
||||
using ClangBackEnd::V2::ProjectPartContainer;
|
||||
|
||||
class ProjectPartQueue : public testing::Test
|
||||
{
|
||||
protected:
|
||||
@@ -83,7 +86,7 @@ TEST_F(ProjectPartQueue, AddProjectPartCallsProcessEntries)
|
||||
{
|
||||
InSequence s;
|
||||
|
||||
EXPECT_CALL(mockTaskScheduler, freeSlots()).WillRepeatedly(Return(2));
|
||||
EXPECT_CALL(mockTaskScheduler, slotUsage()).WillRepeatedly(Return(SlotUsage{2, 0}));
|
||||
EXPECT_CALL(mockTaskScheduler, addTasks(SizeIs(2)));
|
||||
|
||||
queue.addProjectParts({projectPart1, projectPart2});
|
||||
@@ -148,11 +151,11 @@ TEST_F(ProjectPartQueue, CreateTaskFromProjectPart)
|
||||
ClangBackEnd::ProjectPartPch projectPartPch{"project1", "/path/to/pch", 99};
|
||||
auto tasks = queue.createPchTasks({projectPart1});
|
||||
|
||||
EXPECT_CALL(mockPchCreator, generatePch(Eq(projectPart1)));
|
||||
EXPECT_CALL(mockPchCreator, generatePchDeprecated(Eq(projectPart1)));
|
||||
EXPECT_CALL(mockPchCreator, projectPartPch()).WillOnce(ReturnRef(projectPartPch));
|
||||
EXPECT_CALL(mockSqliteTransactionBackend, lock());
|
||||
EXPECT_CALL(mockSqliteTransactionBackend, immediateBegin());
|
||||
EXPECT_CALL(mockPrecompiledHeaderStorage, insertPrecompiledHeader(Eq("project1"), Eq("/path/to/pch"), 99));
|
||||
EXPECT_CALL(mockPrecompiledHeaderStorage, insertProjectPrecompiledHeader(Eq("project1"), Eq("/path/to/pch"), 99));
|
||||
EXPECT_CALL(mockSqliteTransactionBackend, commit());
|
||||
EXPECT_CALL(mockSqliteTransactionBackend, unlock());
|
||||
|
||||
@@ -166,24 +169,15 @@ TEST_F(ProjectPartQueue, DeletePchEntryInDatabaseIfNoPchIsGenerated)
|
||||
ClangBackEnd::ProjectPartPch projectPartPch{"project1", "", 0};
|
||||
auto tasks = queue.createPchTasks({projectPart1});
|
||||
|
||||
EXPECT_CALL(mockPchCreator, generatePch(Eq(projectPart1)));
|
||||
EXPECT_CALL(mockPchCreator, generatePchDeprecated(Eq(projectPart1)));
|
||||
EXPECT_CALL(mockPchCreator, projectPartPch()).WillOnce(ReturnRef(projectPartPch));
|
||||
EXPECT_CALL(mockSqliteTransactionBackend, lock());
|
||||
EXPECT_CALL(mockSqliteTransactionBackend, immediateBegin());
|
||||
EXPECT_CALL(mockPrecompiledHeaderStorage, deletePrecompiledHeader(Eq("project1")));
|
||||
EXPECT_CALL(mockPrecompiledHeaderStorage, deleteProjectPrecompiledHeader(Eq("project1")));
|
||||
EXPECT_CALL(mockSqliteTransactionBackend, commit());
|
||||
EXPECT_CALL(mockSqliteTransactionBackend, unlock());
|
||||
|
||||
tasks.front()(mockPchCreator);
|
||||
}
|
||||
|
||||
|
||||
//TEST_F(PchManagerClient, ProjectPartPchRemovedFromDatabase)
|
||||
//{
|
||||
// EXPECT_CALL(mockPrecompiledHeaderStorage, deletePrecompiledHeader(TypedEq<Utils::SmallStringView>(projectPartId)));
|
||||
|
||||
// projectUpdater.removeProjectParts({QString(projectPartId)});
|
||||
//}
|
||||
|
||||
|
||||
}
|
||||
|
@@ -139,7 +139,7 @@ TEST_F(RefactoringDatabaseInitializer, AddPrecompiledHeaderTable)
|
||||
{
|
||||
InSequence s;
|
||||
|
||||
EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS precompiledHeaders(projectPartId INTEGER PRIMARY KEY, pchPath TEXT, pchBuildTime INTEGER)")));
|
||||
EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS precompiledHeaders(projectPartId INTEGER PRIMARY KEY, projectPchPath TEXT, projectPchBuildTime INTEGER, systemPchPath TEXT, systemPchBuildTime INTEGER)")));
|
||||
|
||||
initializer.createPrecompiledHeadersTable();
|
||||
}
|
||||
@@ -171,7 +171,7 @@ TEST_F(RefactoringDatabaseInitializer, CreateInTheContructor)
|
||||
EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS fileStatuses(sourceId INTEGER PRIMARY KEY, size INTEGER, lastModified INTEGER, buildDependencyTimeStamp INTEGER, isInPrecompiledHeader INTEGER)")));
|
||||
EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS sourceDependencies(sourceId INTEGER, dependencySourceId INTEGER)")));
|
||||
EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_sourceDependencies_sourceId_dependencySourceId ON sourceDependencies(sourceId, dependencySourceId)")));
|
||||
EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS precompiledHeaders(projectPartId INTEGER PRIMARY KEY, pchPath TEXT, pchBuildTime INTEGER)")));
|
||||
EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS precompiledHeaders(projectPartId INTEGER PRIMARY KEY, projectPchPath TEXT, projectPchBuildTime INTEGER, systemPchPath TEXT, systemPchBuildTime INTEGER)")));
|
||||
EXPECT_CALL(mockDatabase, commit());
|
||||
EXPECT_CALL(mockDatabase, setIsInitialized(true));
|
||||
|
||||
|
@@ -35,6 +35,7 @@ using ClangBackEnd::FilePathId;
|
||||
using ClangBackEnd::SymbolsCollectorInterface;
|
||||
using ClangBackEnd::SymbolIndexerTask;
|
||||
using ClangBackEnd::SymbolStorageInterface;
|
||||
using ClangBackEnd::SlotUsage;
|
||||
|
||||
using Callable = ClangBackEnd::SymbolIndexerTask::Callable;
|
||||
|
||||
@@ -167,7 +168,7 @@ TEST_F(SymbolIndexerTaskQueue, ProcessTasksCallsFreeSlotsAndAddTasksInScheduler)
|
||||
{3, 1, Callable{}},
|
||||
{5, 1, Callable{}}});
|
||||
|
||||
EXPECT_CALL(mockTaskScheduler, freeSlots()).WillRepeatedly(Return(2));
|
||||
EXPECT_CALL(mockTaskScheduler, slotUsage()).WillRepeatedly(Return(SlotUsage{2, 0}));
|
||||
EXPECT_CALL(mockTaskScheduler, addTasks(SizeIs(2)));
|
||||
|
||||
queue.processEntries();
|
||||
@@ -177,7 +178,7 @@ TEST_F(SymbolIndexerTaskQueue, ProcessTasksCallsFreeSlotsAndAddTasksWithNoTaskIn
|
||||
{
|
||||
InSequence s;
|
||||
|
||||
EXPECT_CALL(mockTaskScheduler, freeSlots()).WillRepeatedly(Return(2));
|
||||
EXPECT_CALL(mockTaskScheduler, slotUsage()).WillRepeatedly(Return(SlotUsage{2, 0}));
|
||||
EXPECT_CALL(mockTaskScheduler, addTasks(IsEmpty()));
|
||||
|
||||
queue.processEntries();
|
||||
@@ -190,7 +191,7 @@ TEST_F(SymbolIndexerTaskQueue, ProcessTasksCallsFreeSlotsAndMoveAllTasksInSchedu
|
||||
{3, 1, Callable{}},
|
||||
{5, 1, Callable{}}});
|
||||
|
||||
EXPECT_CALL(mockTaskScheduler, freeSlots()).WillRepeatedly(Return(4));
|
||||
EXPECT_CALL(mockTaskScheduler, slotUsage()).WillRepeatedly(Return(SlotUsage{4, 0}));
|
||||
EXPECT_CALL(mockTaskScheduler, addTasks(SizeIs(3)));
|
||||
|
||||
queue.processEntries();
|
||||
@@ -201,7 +202,7 @@ TEST_F(SymbolIndexerTaskQueue, ProcessTasksRemovesProcessedTasks)
|
||||
queue.addOrUpdateTasks({{1, 1, Callable{}},
|
||||
{3, 1, Callable{}},
|
||||
{5, 1, Callable{}}});
|
||||
ON_CALL(mockTaskScheduler, freeSlots()).WillByDefault(Return(2));
|
||||
ON_CALL(mockTaskScheduler, slotUsage()).WillByDefault(Return(SlotUsage{2, 0}));
|
||||
|
||||
queue.processEntries();
|
||||
|
||||
|
@@ -40,6 +40,7 @@ using Task = std::function<void(ClangBackEnd::ProcessorInterface&)>;
|
||||
using ClangBackEnd::ProcessorInterface;
|
||||
using ClangBackEnd::SymbolsCollectorInterface;
|
||||
using ClangBackEnd::SymbolStorageInterface;
|
||||
using ClangBackEnd::SlotUsage;
|
||||
using NiceMockProcessorManager = NiceMock<MockProcessorManager>;
|
||||
using Scheduler = ClangBackEnd::TaskScheduler<NiceMockProcessorManager, Task>;
|
||||
|
||||
@@ -95,18 +96,18 @@ TEST_F(TaskScheduler, FreeSlots)
|
||||
{
|
||||
deferredScheduler.addTasks({nocall, nocall});
|
||||
|
||||
auto count = deferredScheduler.freeSlots();
|
||||
auto slotUsage = deferredScheduler.slotUsage();
|
||||
|
||||
ASSERT_THAT(count, 2);
|
||||
ASSERT_THAT(slotUsage, AllOf(Field(&SlotUsage::free, 2), Field(&SlotUsage::used, 2)));
|
||||
}
|
||||
|
||||
TEST_F(TaskScheduler, ReturnZeroFreeSlotsIfMoreCallsThanCores)
|
||||
{
|
||||
deferredScheduler.addTasks({nocall, nocall, nocall, nocall, nocall, nocall});
|
||||
|
||||
auto count = deferredScheduler.freeSlots();
|
||||
auto slotUsage = deferredScheduler.slotUsage();
|
||||
|
||||
ASSERT_THAT(count, 0);
|
||||
ASSERT_THAT(slotUsage, AllOf(Field(&SlotUsage::free, 0), Field(&SlotUsage::used, 6)));
|
||||
}
|
||||
|
||||
TEST_F(TaskScheduler, FreeSlotsAfterFinishing)
|
||||
@@ -114,9 +115,9 @@ TEST_F(TaskScheduler, FreeSlotsAfterFinishing)
|
||||
scheduler.addTasks({nocall, nocall});
|
||||
scheduler.syncTasks();
|
||||
|
||||
auto count = scheduler.freeSlots();
|
||||
auto slotUsage = scheduler.slotUsage();
|
||||
|
||||
ASSERT_THAT(count, 4);
|
||||
ASSERT_THAT(slotUsage, AllOf(Field(&SlotUsage::free, 4), Field(&SlotUsage::used, 0)));
|
||||
}
|
||||
|
||||
TEST_F(TaskScheduler, NoFuturesAfterFreeSlots)
|
||||
@@ -124,7 +125,7 @@ TEST_F(TaskScheduler, NoFuturesAfterFreeSlots)
|
||||
scheduler.addTasks({nocall, nocall});
|
||||
scheduler.syncTasks();
|
||||
|
||||
scheduler.freeSlots();
|
||||
scheduler.slotUsage();
|
||||
|
||||
ASSERT_THAT(scheduler.futures(), IsEmpty());
|
||||
}
|
||||
@@ -142,7 +143,7 @@ TEST_F(TaskScheduler, FreeSlotsCallsCleanupMethodsAfterTheWorkIsDone)
|
||||
EXPECT_CALL(mockSymbolsCollector, setIsUsed(false));
|
||||
EXPECT_CALL(mockSymbolsCollector, clear());
|
||||
|
||||
scheduler.freeSlots();
|
||||
scheduler.slotUsage();
|
||||
}
|
||||
|
||||
TEST_F(TaskScheduler, FreeSlotsCallsProgressMethodsAfterTheWorkIsDone)
|
||||
@@ -153,7 +154,7 @@ TEST_F(TaskScheduler, FreeSlotsCallsProgressMethodsAfterTheWorkIsDone)
|
||||
|
||||
EXPECT_CALL(mockSetProgressCallback, Call(2, 100));
|
||||
|
||||
scheduler.freeSlots();
|
||||
scheduler.slotUsage();
|
||||
}
|
||||
|
||||
TEST_F(TaskScheduler, AddTaskCallSymbolsCollectorManagerUnusedSymbolsCollector)
|
||||
|
@@ -109,7 +109,8 @@ SOURCES += \
|
||||
builddependenciesprovider-test.cpp \
|
||||
builddependenciesstorage-test.cpp \
|
||||
usedmacrofilter-test.cpp \
|
||||
pchtasksmerger-test.cpp
|
||||
pchtasksmerger-test.cpp \
|
||||
pchtaskqueue-test.cpp
|
||||
|
||||
!isEmpty(LIBCLANG_LIBS) {
|
||||
SOURCES += \
|
||||
|
Reference in New Issue
Block a user