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:
Marco Bubke
2018-12-04 19:03:48 +01:00
parent 96eb407266
commit 390a227df6
34 changed files with 979 additions and 143 deletions

View File

@@ -190,9 +190,10 @@ public:
table.setUseIfNotExists(true); table.setUseIfNotExists(true);
table.setName("precompiledHeaders"); table.setName("precompiledHeaders");
table.addColumn("projectPartId", Sqlite::ColumnType::Integer, Sqlite::Contraint::PrimaryKey); table.addColumn("projectPartId", Sqlite::ColumnType::Integer, Sqlite::Contraint::PrimaryKey);
table.addColumn("pchPath", Sqlite::ColumnType::Text); table.addColumn("projectPchPath", Sqlite::ColumnType::Text);
table.addColumn("pchBuildTime", Sqlite::ColumnType::Integer); table.addColumn("projectPchBuildTime", Sqlite::ColumnType::Integer);
table.addColumn("systemPchPath", Sqlite::ColumnType::Text);
table.addColumn("systemPchBuildTime", Sqlite::ColumnType::Integer);
table.initialize(database); table.initialize(database);
} }

View File

@@ -133,10 +133,8 @@ bool BaseStatement::next() const
return true; return true;
else if (resultCode == SQLITE_DONE) else if (resultCode == SQLITE_DONE)
return false; return false;
else
checkForStepError(resultCode);
return false; checkForStepError(resultCode);
} }
void BaseStatement::step() const void BaseStatement::step() const

View File

@@ -6,7 +6,8 @@ SOURCES += \
$$PWD/projectparts.cpp \ $$PWD/projectparts.cpp \
$$PWD/projectpartqueue.cpp \ $$PWD/projectpartqueue.cpp \
$$PWD/pchtaskgenerator.cpp \ $$PWD/pchtaskgenerator.cpp \
$$PWD/pchtasksmerger.cpp $$PWD/pchtasksmerger.cpp \
$$PWD/pchtaskqueue.cpp
HEADERS += \ HEADERS += \
$$PWD/pchmanagerserver.h \ $$PWD/pchmanagerserver.h \
@@ -38,7 +39,8 @@ HEADERS += \
$$PWD/usedmacrofilter.h \ $$PWD/usedmacrofilter.h \
$$PWD/pchtasksmergerinterface.h \ $$PWD/pchtasksmergerinterface.h \
$$PWD/pchtasksmerger.h \ $$PWD/pchtasksmerger.h \
$$PWD/pchtaskqueueinterface.h $$PWD/pchtaskqueueinterface.h \
$$PWD/pchtaskqueue.h
!isEmpty(LIBTOOLING_LIBS) { !isEmpty(LIBTOOLING_LIBS) {
SOURCES += \ SOURCES += \

View File

@@ -326,11 +326,16 @@ IdPaths PchCreator::generateProjectPartPch(const V2::ProjectPartContainer &proje
return {projectPart.projectPartId.clone(), allIncludeIds(includes)}; return {projectPart.projectPartId.clone(), allIncludeIds(includes)};
} }
void PchCreator::generatePch(const V2::ProjectPartContainer &projectPart) void PchCreator::generatePchDeprecated(const V2::ProjectPartContainer &projectPart)
{ {
m_projectIncludeIds = generateProjectPartPch(projectPart); m_projectIncludeIds = generateProjectPartPch(projectPart);
} }
void PchCreator::generatePch(const PchTask &pchTask)
{
}
IdPaths PchCreator::takeProjectIncludes() IdPaths PchCreator::takeProjectIncludes()
{ {
return std::move(m_projectIncludeIds); return std::move(m_projectIncludeIds);

View File

@@ -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; IdPaths takeProjectIncludes() override;
const ProjectPartPch &projectPartPch() override; const ProjectPartPch &projectPartPch() override;
void setUnsavedFiles(const V2::FileContainers &fileContainers) override; void setUnsavedFiles(const V2::FileContainers &fileContainers) override;

View File

@@ -26,6 +26,7 @@
#pragma once #pragma once
#include "idpaths.h" #include "idpaths.h"
#include "pchtask.h"
#include "projectpartpch.h" #include "projectpartpch.h"
#include "processorinterface.h" #include "processorinterface.h"
@@ -41,7 +42,8 @@ public:
PchCreatorInterface(const PchCreatorInterface &) = delete; PchCreatorInterface(const PchCreatorInterface &) = delete;
PchCreatorInterface &operator=(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 IdPaths takeProjectIncludes() = 0;
virtual const ProjectPartPch &projectPartPch() = 0; virtual const ProjectPartPch &projectPartPch() = 0;

View File

@@ -40,7 +40,17 @@ public:
FilePathIds &&includes, FilePathIds &&includes,
CompilerMacros &&compilerMacros, CompilerMacros &&compilerMacros,
UsedMacros &&usedMacros) 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) , includes(includes)
, compilerMacros(compilerMacros) , compilerMacros(compilerMacros)
, usedMacros(usedMacros) , usedMacros(usedMacros)
@@ -48,15 +58,17 @@ public:
friend bool operator==(const PchTask &first, const PchTask &second) friend bool operator==(const PchTask &first, const PchTask &second)
{ {
return first.projectPartId == second.projectPartId return first.systemPchPath == second.systemPchPath
&& first.dependentIds == second.dependentIds && first.includes == second.includes && first.projectPartIds == second.projectPartIds && first.includes == second.includes
&& first.compilerMacros == second.compilerMacros && first.compilerMacros == second.compilerMacros
&& first.usedMacros == second.usedMacros; && first.usedMacros == second.usedMacros;
} }
Utils::SmallStringView projectPartId() const { return projectPartIds.front(); }
public: public:
Utils::SmallString projectPartId; Utils::PathString systemPchPath;
Utils::SmallStringVector dependentIds; Utils::SmallStringVector projectPartIds;
FilePathIds includes; FilePathIds includes;
CompilerMacros compilerMacros; CompilerMacros compilerMacros;
UsedMacros usedMacros; UsedMacros usedMacros;

View 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

View 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

View File

@@ -47,7 +47,7 @@ public:
m_transaction.commit(); m_transaction.commit();
} }
void insertPrecompiledHeader(Utils::SmallStringView projectPartName, void insertProjectPrecompiledHeader(Utils::SmallStringView projectPartName,
Utils::SmallStringView pchPath, Utils::SmallStringView pchPath,
long long pchBuildTime) override long long pchBuildTime) override
{ {
@@ -55,43 +55,104 @@ public:
Sqlite::ImmediateTransaction transaction{m_database}; Sqlite::ImmediateTransaction transaction{m_database};
m_insertProjectPartStatement.write(projectPartName); m_insertProjectPartStatement.write(projectPartName);
m_insertPrecompiledHeaderStatement .write(projectPartName, pchPath, pchBuildTime); m_insertProjectPrecompiledHeaderStatement.write(projectPartName, pchPath, pchBuildTime);
transaction.commit(); transaction.commit();
} catch (const Sqlite::StatementIsBusy) { } 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 { try {
Sqlite::ImmediateTransaction transaction{m_database}; Sqlite::ImmediateTransaction transaction{m_database};
m_deletePrecompiledHeaderStatement.write(projectPartName); m_deleteProjectPrecompiledHeaderStatement.write(projectPartName);
transaction.commit(); transaction.commit();
} catch (const Sqlite::StatementIsBusy) { } 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: public:
Sqlite::ImmediateNonThrowingDestructorTransaction m_transaction; Sqlite::ImmediateNonThrowingDestructorTransaction m_transaction;
Database &m_database; Database &m_database;
WriteStatement m_insertPrecompiledHeaderStatement { WriteStatement m_insertProjectPrecompiledHeaderStatement{
"INSERT OR REPLACE INTO precompiledHeaders(projectPartId, pchPath, pchBuildTime) VALUES((SELECT projectPartId FROM projectParts WHERE projectPartName = ?),?,?)", "INSERT INTO precompiledHeaders(projectPartId, projectPchPath, projectPchBuildTime) "
m_database "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{ WriteStatement m_insertProjectPartStatement{
"INSERT OR IGNORE INTO projectParts(projectPartName) VALUES (?)", "INSERT OR IGNORE INTO projectParts(projectPartName) VALUES (?)", m_database};
m_database WriteStatement m_deleteProjectPrecompiledHeaderStatement{
}; "UPDATE OR IGNORE precompiledHeaders SET projectPchPath=NULL,projectPchBuildTime=NULL "
WriteStatement m_deletePrecompiledHeaderStatement{ "WHERE projectPartId = (SELECT projectPartId FROM "
"DELETE FROM precompiledHeaders WHERE projectPartId = (SELECT projectPartId FROM projectParts WHERE projectPartName = ?)", "projectParts WHERE projectPartName = ?)",
m_database 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};
}; };
} }

View File

@@ -25,7 +25,7 @@
#pragma once #pragma once
#include <utils/smallstringview.h> #include <utils/smallstring.h>
namespace ClangBackEnd { namespace ClangBackEnd {
@@ -34,14 +34,21 @@ class PrecompiledHeaderStorageInterface
public: public:
PrecompiledHeaderStorageInterface() = default; PrecompiledHeaderStorageInterface() = default;
PrecompiledHeaderStorageInterface(const PrecompiledHeaderStorageInterface&) = delete; PrecompiledHeaderStorageInterface(const PrecompiledHeaderStorageInterface &) = delete;
PrecompiledHeaderStorageInterface &operator=(const PrecompiledHeaderStorageInterface&) = delete; PrecompiledHeaderStorageInterface &operator=(const PrecompiledHeaderStorageInterface &) = delete;
virtual void insertPrecompiledHeader(Utils::SmallStringView projectPartName, virtual void insertProjectPrecompiledHeader(Utils::SmallStringView projectPartName,
Utils::SmallStringView pchPath, Utils::SmallStringView pchPath,
long long pchBuildTime) = 0; long long pchBuildTime)
= 0;
virtual void deletePrecompiledHeader(Utils::SmallStringView projectPartName) = 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: protected:
~PrecompiledHeaderStorageInterface() = default; ~PrecompiledHeaderStorageInterface() = default;

View File

@@ -90,7 +90,7 @@ void ProjectPartQueue::removeProjectParts(const Utils::SmallStringVector &projec
void ProjectPartQueue::processEntries() 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()))); auto newEnd = std::prev(m_projectParts.end(), std::min<int>(int(taskCount), int(m_projectParts.size())));
m_taskScheduler.addTasks( m_taskScheduler.addTasks(
@@ -112,13 +112,13 @@ std::vector<ProjectPartQueue::Task> ProjectPartQueue::createPchTasks(
auto convert = [this] (auto &&projectPart) { auto convert = [this] (auto &&projectPart) {
return [projectPart=std::move(projectPart), this] (PchCreatorInterface &pchCreator) { return [projectPart=std::move(projectPart), this] (PchCreatorInterface &pchCreator) {
pchCreator.generatePch(projectPart); pchCreator.generatePchDeprecated(projectPart);
const auto &projectPartPch = pchCreator.projectPartPch(); const auto &projectPartPch = pchCreator.projectPartPch();
Sqlite::ImmediateTransaction transaction(m_transactionsInterface); Sqlite::ImmediateTransaction transaction(m_transactionsInterface);
if (projectPartPch.pchPath.empty()) { if (projectPartPch.pchPath.empty()) {
m_precompiledHeaderStorage.deletePrecompiledHeader(projectPartPch.projectPartId); m_precompiledHeaderStorage.deleteProjectPrecompiledHeader(projectPartPch.projectPartId);
} else { } else {
m_precompiledHeaderStorage.insertPrecompiledHeader(projectPartPch.projectPartId, m_precompiledHeaderStorage.insertProjectPrecompiledHeader(projectPartPch.projectPartId,
projectPartPch.pchPath, projectPartPch.pchPath,
projectPartPch.lastModified); projectPartPch.lastModified);
} }

View File

@@ -99,14 +99,15 @@ public:
return m_futures; return m_futures;
} }
uint freeSlots() SlotUsage slotUsage()
{ {
removeFinishedFutures(); removeFinishedFutures();
if (m_isDisabled) 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() void syncTasks()

View File

@@ -31,6 +31,12 @@ namespace ClangBackEnd {
using uint = unsigned int; using uint = unsigned int;
struct SlotUsage
{
uint free = 0;
uint used = 0;
};
template <typename Task> template <typename Task>
class TaskSchedulerInterface class TaskSchedulerInterface
{ {
@@ -40,7 +46,7 @@ public:
TaskSchedulerInterface &operator=(const TaskSchedulerInterface &) = delete; TaskSchedulerInterface &operator=(const TaskSchedulerInterface &) = delete;
virtual void addTasks(std::vector<Task> &&tasks) = 0; virtual void addTasks(std::vector<Task> &&tasks) = 0;
virtual uint freeSlots() = 0; virtual SlotUsage slotUsage() = 0;
protected: protected:
~TaskSchedulerInterface() = default; ~TaskSchedulerInterface() = default;

View File

@@ -94,7 +94,7 @@ public:
void processEntries() 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()))); auto newEnd = std::prev(m_tasks.end(), std::min<int>(int(taskCount), int(m_tasks.size())));
m_symbolIndexerScheduler.addTasks({std::make_move_iterator(newEnd), m_symbolIndexerScheduler.addTasks({std::make_move_iterator(newEnd),

View File

@@ -105,7 +105,7 @@ public:
m_indexerScheduler.disable(); m_indexerScheduler.disable();
while (!m_indexerScheduler.futures().empty()) { while (!m_indexerScheduler.futures().empty()) {
m_indexerScheduler.syncTasks(); m_indexerScheduler.syncTasks();
m_indexerScheduler.freeSlots(); m_indexerScheduler.slotUsage();
} }
} }

View File

@@ -332,7 +332,7 @@ public:
m_database m_database
}; };
mutable ReadStatement m_getPrecompiledHeader{ mutable ReadStatement m_getPrecompiledHeader{
"SELECT pchPath, pchBuildTime FROM precompiledHeaders WHERE projectPartId = ?", "SELECT projectPchPath, projectPchBuildTime FROM precompiledHeaders WHERE projectPartId = ?",
m_database m_database
}; };
}; };

View File

@@ -90,7 +90,7 @@ protected:
.Times(AnyNumber()); .Times(AnyNumber());
EXPECT_CALL(selectAllSources, valuesReturnStdVectorSource(_)) EXPECT_CALL(selectAllSources, valuesReturnStdVectorSource(_))
.Times(AnyNumber()); .Times(AnyNumber());
EXPECT_CALL(selectDirectoryPathFromDirectoriesByDirectoryId, valueReturnPathString(_)) EXPECT_CALL(selectDirectoryPathFromDirectoriesByDirectoryId, valueReturnPathString(An<int>()))
.Times(AnyNumber()); .Times(AnyNumber());
EXPECT_CALL(selectSourceNameAndDirectoryIdFromSourcesBySourceId, valueReturnSourceNameAndDirectoryId(_)) EXPECT_CALL(selectSourceNameAndDirectoryIdFromSourcesBySourceId, valueReturnSourceNameAndDirectoryId(_))
.Times(AnyNumber()); .Times(AnyNumber());

View File

@@ -1033,8 +1033,8 @@ 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 PchTask &task)
{ {
return out << "(" << task.projectPartId << ", " << task.dependentIds << ", " << task.includes return out << "(" << task.projectPartIds << ", " << task.includes << ", " << task.compilerMacros
<< ", " << task.compilerMacros << ", " << task.usedMacros << ")"; << ", " << task.usedMacros << ")";
} }
std::ostream &operator<<(std::ostream &out, const BuildDependency &dependency) 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) const char *sourceTypeString(SourceType sourceType)
{ {
using ClangBackEnd::SymbolTag; using ClangBackEnd::SymbolTag;

View File

@@ -175,6 +175,7 @@ class PchTask;
class BuildDependency; class BuildDependency;
class SourceEntry; class SourceEntry;
class FilePathCaching; class FilePathCaching;
class SlotUsage;
std::ostream &operator<<(std::ostream &out, const SourceLocationEntry &entry); std::ostream &operator<<(std::ostream &out, const SourceLocationEntry &entry);
std::ostream &operator<<(std::ostream &out, const IdPaths &idPaths); 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 PchTask &task);
std::ostream &operator<<(std::ostream &out, const BuildDependency &dependency); 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 SourceEntry &entry);
std::ostream &operator<<(std::ostream &out, const SlotUsage &slotUsage);
void PrintTo(const FilePath &filePath, ::std::ostream *os); void PrintTo(const FilePath &filePath, ::std::ostream *os);
void PrintTo(const FilePathView &filePathView, ::std::ostream *os); void PrintTo(const FilePathView &filePathView, ::std::ostream *os);

View File

@@ -35,21 +35,13 @@
class MockPchCreator : public ClangBackEnd::PchCreatorInterface class MockPchCreator : public ClangBackEnd::PchCreatorInterface
{ {
public: public:
MOCK_METHOD1(generatePch, MOCK_METHOD1(generatePchDeprecated, void(const ClangBackEnd::V2::ProjectPartContainer &projectPart));
void(const ClangBackEnd::V2::ProjectPartContainer &projectPart)); MOCK_METHOD1(generatePch, void(const ClangBackEnd::PchTask &pchTask));
MOCK_METHOD0(takeProjectIncludes, MOCK_METHOD0(takeProjectIncludes, ClangBackEnd::IdPaths());
ClangBackEnd::IdPaths()); MOCK_METHOD0(projectPartPch, const ClangBackEnd::ProjectPartPch &());
MOCK_METHOD0(projectPartPch, MOCK_METHOD1(setUnsavedFiles, void(const ClangBackEnd::V2::FileContainers &fileContainers));
const ClangBackEnd::ProjectPartPch &()); MOCK_METHOD0(clear, void());
MOCK_METHOD1(setUnsavedFiles, MOCK_METHOD0(doInMainThreadAfterFinished, void());
void (const ClangBackEnd::V2::FileContainers &fileContainers)); MOCK_CONST_METHOD0(isUsed, bool());
MOCK_METHOD0(clear, MOCK_METHOD1(setIsUsed, void(bool));
void());
MOCK_METHOD0(doInMainThreadAfterFinished,
void());
MOCK_CONST_METHOD0(isUsed,
bool());
MOCK_METHOD1(setIsUsed,
void(bool));
}; };

View File

@@ -32,10 +32,16 @@
class MockPrecompiledHeaderStorage : public ClangBackEnd::PrecompiledHeaderStorageInterface class MockPrecompiledHeaderStorage : public ClangBackEnd::PrecompiledHeaderStorageInterface
{ {
public: public:
MOCK_METHOD3(insertPrecompiledHeader, MOCK_METHOD3(insertProjectPrecompiledHeader,
void (Utils::SmallStringView projectPartName, void(Utils::SmallStringView projectPartName,
Utils::SmallStringView pchPath, Utils::SmallStringView pchPath,
long long pchBuildTime)); long long pchBuildTime));
MOCK_METHOD1(deleteProjectPrecompiledHeader, void(Utils::SmallStringView projectPartName));
MOCK_METHOD1(deletePrecompiledHeader, 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));
}; };

View File

@@ -137,6 +137,13 @@ MockSqliteReadStatement::value<Utils::PathString>(const int &directoryId)
return valueReturnPathString(directoryId); return valueReturnPathString(directoryId);
} }
template <>
Utils::optional<Utils::PathString>
MockSqliteReadStatement::value<Utils::PathString>(const Utils::SmallStringView &path)
{
return valueReturnPathString(path);
}
template <> template <>
Utils::optional<ClangBackEnd::ProjectPartArtefact> Utils::optional<ClangBackEnd::ProjectPartArtefact>
MockSqliteReadStatement::value<ClangBackEnd::ProjectPartArtefact, 4>(const int& sourceId) MockSqliteReadStatement::value<ClangBackEnd::ProjectPartArtefact, 4>(const int& sourceId)

View File

@@ -96,6 +96,9 @@ public:
MOCK_METHOD1(valueReturnPathString, MOCK_METHOD1(valueReturnPathString,
Utils::optional<Utils::PathString>(int)); Utils::optional<Utils::PathString>(int));
MOCK_METHOD1(valueReturnPathString,
Utils::optional<Utils::PathString>(Utils::SmallStringView));
MOCK_METHOD1(valueReturnSmallString, MOCK_METHOD1(valueReturnSmallString,
Utils::optional<Utils::SmallString>(int)); Utils::optional<Utils::SmallString>(int));
@@ -221,6 +224,10 @@ template <>
Utils::optional<Utils::PathString> Utils::optional<Utils::PathString>
MockSqliteReadStatement::value<Utils::PathString>(const int&); MockSqliteReadStatement::value<Utils::PathString>(const int&);
template <>
Utils::optional<Utils::PathString>
MockSqliteReadStatement::value<Utils::PathString>(const Utils::SmallStringView&);
template <> template <>
Utils::optional<ClangBackEnd::ProjectPartArtefact> Utils::optional<ClangBackEnd::ProjectPartArtefact>
MockSqliteReadStatement::value<ClangBackEnd::ProjectPartArtefact, 4>(const int&); MockSqliteReadStatement::value<ClangBackEnd::ProjectPartArtefact, 4>(const int&);

View File

@@ -36,8 +36,8 @@ class MockTaskScheduler : public ClangBackEnd::TaskSchedulerInterface<Task>
public: public:
MOCK_METHOD1_T(addTasks, MOCK_METHOD1_T(addTasks,
void (const std::vector<Task> &)); void (const std::vector<Task> &));
MOCK_METHOD0(freeSlots, MOCK_METHOD0(slotUsage,
uint ()); ClangBackEnd::SlotUsage ());
void addTasks(std::vector<Task> &&tasks) void addTasks(std::vector<Task> &&tasks)
{ {

View File

@@ -223,14 +223,14 @@ TEST_F(PchCreator, CreateProjectPartClangCompilerArguments)
TEST_F(PchCreatorVerySlowTest, IncludesForCreatePchsForProjectParts) TEST_F(PchCreatorVerySlowTest, IncludesForCreatePchsForProjectParts)
{ {
creator.generatePch(projectPart1); creator.generatePchDeprecated(projectPart1);
ASSERT_THAT(creator.takeProjectIncludes().id, "project1"); ASSERT_THAT(creator.takeProjectIncludes().id, "project1");
} }
TEST_F(PchCreatorVerySlowTest, ProjectPartPchsSendToPchManagerClient) TEST_F(PchCreatorVerySlowTest, ProjectPartPchsSendToPchManagerClient)
{ {
creator.generatePch(projectPart1); creator.generatePchDeprecated(projectPart1);
EXPECT_CALL(mockPchManagerClient, EXPECT_CALL(mockPchManagerClient,
precompiledHeadersUpdated( precompiledHeadersUpdated(
@@ -242,7 +242,7 @@ TEST_F(PchCreatorVerySlowTest, ProjectPartPchsSendToPchManagerClient)
TEST_F(PchCreatorVerySlowTest, UpdateFileWatcherIncludes) TEST_F(PchCreatorVerySlowTest, UpdateFileWatcherIncludes)
{ {
creator.generatePch(projectPart1); creator.generatePchDeprecated(projectPart1);
EXPECT_CALL(mockClangPathWatcher, EXPECT_CALL(mockClangPathWatcher,
updateIdPaths(ElementsAre(creator.projectIncludes()))); updateIdPaths(ElementsAre(creator.projectIncludes())));
@@ -252,7 +252,7 @@ TEST_F(PchCreatorVerySlowTest, UpdateFileWatcherIncludes)
TEST_F(PchCreatorVerySlowTest, IdPathsForCreatePchsForProjectParts) TEST_F(PchCreatorVerySlowTest, IdPathsForCreatePchsForProjectParts)
{ {
creator.generatePch(projectPart1); creator.generatePchDeprecated(projectPart1);
ASSERT_THAT(creator.takeProjectIncludes(), ASSERT_THAT(creator.takeProjectIncludes(),
AllOf(Field(&IdPaths::id, "project1"), AllOf(Field(&IdPaths::id, "project1"),
@@ -263,7 +263,7 @@ TEST_F(PchCreatorVerySlowTest, IdPathsForCreatePchsForProjectParts)
TEST_F(PchCreatorVerySlowTest, ProjectPartPchForCreatesPchForProjectPart) TEST_F(PchCreatorVerySlowTest, ProjectPartPchForCreatesPchForProjectPart)
{ {
creator.generatePch(projectPart1); creator.generatePchDeprecated(projectPart1);
ASSERT_THAT(creator.projectPartPch(), ASSERT_THAT(creator.projectPartPch(),
AllOf(Field(&ProjectPartPch::projectPartId, Eq("project1")), AllOf(Field(&ProjectPartPch::projectPartId, Eq("project1")),
@@ -273,7 +273,7 @@ TEST_F(PchCreatorVerySlowTest, ProjectPartPchForCreatesPchForProjectPart)
TEST_F(PchCreatorVerySlowTest, ProjectPartPchCleared) TEST_F(PchCreatorVerySlowTest, ProjectPartPchCleared)
{ {
creator.generatePch(projectPart1); creator.generatePchDeprecated(projectPart1);
creator.clear(); creator.clear();
@@ -283,7 +283,7 @@ TEST_F(PchCreatorVerySlowTest, ProjectPartPchCleared)
TEST_F(PchCreatorVerySlowTest, ProjectIncludesCleared) TEST_F(PchCreatorVerySlowTest, ProjectIncludesCleared)
{ {
creator.generatePch(projectPart1); creator.generatePchDeprecated(projectPart1);
creator.clear(); creator.clear();
@@ -299,7 +299,7 @@ TEST_F(PchCreatorVerySlowTest, FaultyProjectPartPchForCreatesNoPchForProjectPart
{}, {},
{id(TESTDATA_DIR "/builddependencycollector/project/faulty.cpp")}}; {id(TESTDATA_DIR "/builddependencycollector/project/faulty.cpp")}};
creator.generatePch(faultyProjectPart); creator.generatePchDeprecated(faultyProjectPart);
ASSERT_THAT(creator.projectPartPch(), ASSERT_THAT(creator.projectPartPch(),
AllOf(Field(&ProjectPartPch::projectPartId, Eq("faultyProject")), AllOf(Field(&ProjectPartPch::projectPartId, Eq("faultyProject")),

View File

@@ -80,7 +80,7 @@ TEST_F(PchTaskGenerator, Create)
EXPECT_CALL(mockPchTaskMerger, EXPECT_CALL(mockPchTaskMerger,
mergeTasks(ElementsAre( mergeTasks(ElementsAre(
AllOf(Field(&PchTaskSet::system, AllOf(Field(&PchTaskSet::system,
AllOf(Field(&PchTask::projectPartId, Eq("ProjectPart1")), AllOf(Field(&PchTask::projectPartIds, ElementsAre("ProjectPart1")),
Field(&PchTask::includes, ElementsAre(4, 5)), Field(&PchTask::includes, ElementsAre(4, 5)),
Field(&PchTask::compilerMacros, Field(&PchTask::compilerMacros,
ElementsAre(CompilerMacro{"SE", "4", 4}, ElementsAre(CompilerMacro{"SE", "4", 4},
@@ -88,7 +88,8 @@ TEST_F(PchTaskGenerator, Create)
Field(&PchTask::usedMacros, Field(&PchTask::usedMacros,
ElementsAre(UsedMacro{"SE", 4}, UsedMacro{"WU", 5})))), ElementsAre(UsedMacro{"SE", 4}, UsedMacro{"WU", 5})))),
AllOf(Field(&PchTaskSet::project, AllOf(Field(&PchTaskSet::project,
AllOf(Field(&PchTask::projectPartId, Eq("ProjectPart1")), AllOf(Field(&PchTask::projectPartIds,
ElementsAre("ProjectPart1")),
Field(&PchTask::includes, ElementsAre(1, 3)), Field(&PchTask::includes, ElementsAre(1, 3)),
Field(&PchTask::compilerMacros, Field(&PchTask::compilerMacros,
ElementsAre(CompilerMacro{"YI", "1", 1}, ElementsAre(CompilerMacro{"YI", "1", 1},

View 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

View File

@@ -29,6 +29,7 @@
#include <precompiledheaderstorage.h> #include <precompiledheaderstorage.h>
#include <refactoringdatabaseinitializer.h> #include <refactoringdatabaseinitializer.h>
#include <sqlitedatabase.h> #include <sqlitedatabase.h>
#include <sqlitereadstatement.h>
#include <sqlitewritestatement.h> #include <sqlitewritestatement.h>
#include <sqlitetransaction.h> #include <sqlitetransaction.h>
@@ -41,9 +42,17 @@ class PrecompiledHeaderStorage : public testing::Test
protected: protected:
NiceMock<MockSqliteDatabase> database; NiceMock<MockSqliteDatabase> database;
Storage storage{database}; Storage storage{database};
MockSqliteWriteStatement &insertPrecompiledHeaderStatement = storage.m_insertPrecompiledHeaderStatement;
MockSqliteWriteStatement &insertProjectPartStatement = storage.m_insertProjectPartStatement; 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) TEST_F(PrecompiledHeaderStorage, UseTransaction)
@@ -56,76 +65,112 @@ TEST_F(PrecompiledHeaderStorage, UseTransaction)
Storage storage{database}; Storage storage{database};
} }
TEST_F(PrecompiledHeaderStorage, InsertPrecompiledHeader) TEST_F(PrecompiledHeaderStorage, InsertProjectPrecompiledHeader)
{ {
InSequence s; InSequence s;
EXPECT_CALL(database, immediateBegin()); EXPECT_CALL(database, immediateBegin());
EXPECT_CALL(insertProjectPartStatement, write(TypedEq<Utils::SmallStringView>("project1"))); EXPECT_CALL(insertProjectPartStatement, write(TypedEq<Utils::SmallStringView>("project1")));
EXPECT_CALL(insertPrecompiledHeaderStatement, EXPECT_CALL(insertProjectPrecompiledHeaderStatement,
write(TypedEq<Utils::SmallStringView>("project1"), write(TypedEq<Utils::SmallStringView>("project1"),
TypedEq<Utils::SmallStringView>("/path/to/pch"), TypedEq<Utils::SmallStringView>("/path/to/pch"),
TypedEq<long long>(22))); TypedEq<long long>(22)));
EXPECT_CALL(database, commit()); 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; InSequence s;
EXPECT_CALL(database, immediateBegin()).WillOnce(Throw(Sqlite::StatementIsBusy("busy"))); EXPECT_CALL(database, immediateBegin()).WillOnce(Throw(Sqlite::StatementIsBusy("busy")));
EXPECT_CALL(database, immediateBegin()); EXPECT_CALL(database, immediateBegin());
EXPECT_CALL(insertProjectPartStatement, write(TypedEq<Utils::SmallStringView>("project1"))); EXPECT_CALL(insertProjectPartStatement, write(TypedEq<Utils::SmallStringView>("project1")));
EXPECT_CALL(insertPrecompiledHeaderStatement, EXPECT_CALL(insertProjectPrecompiledHeaderStatement,
write(TypedEq<Utils::SmallStringView>("project1"), write(TypedEq<Utils::SmallStringView>("project1"),
TypedEq<Utils::SmallStringView>("/path/to/pch"), TypedEq<Utils::SmallStringView>("/path/to/pch"),
TypedEq<long long>(22))); TypedEq<long long>(22)));
EXPECT_CALL(database, commit()); 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; InSequence s;
EXPECT_CALL(database, immediateBegin()); EXPECT_CALL(database, immediateBegin());
EXPECT_CALL(deletePrecompiledHeaderStatement, write(TypedEq<Utils::SmallStringView>("project1"))); EXPECT_CALL(deleteProjectPrecompiledHeaderStatement, write(TypedEq<Utils::SmallStringView>("project1")));
EXPECT_CALL(database, commit()); EXPECT_CALL(database, commit());
storage.deletePrecompiledHeader("project1"); storage.deleteProjectPrecompiledHeader("project1");
} }
TEST_F(PrecompiledHeaderStorage, DeletePrecompiledHeaderStatementIsBusy) TEST_F(PrecompiledHeaderStorage, DeleteProjectPrecompiledHeaderStatementIsBusy)
{ {
InSequence s; InSequence s;
EXPECT_CALL(database, immediateBegin()).WillOnce(Throw(Sqlite::StatementIsBusy("busy"))); EXPECT_CALL(database, immediateBegin()).WillOnce(Throw(Sqlite::StatementIsBusy("busy")));
EXPECT_CALL(database, immediateBegin()); EXPECT_CALL(database, immediateBegin());
EXPECT_CALL(deletePrecompiledHeaderStatement, write(TypedEq<Utils::SmallStringView>("project1"))); EXPECT_CALL(deleteProjectPrecompiledHeaderStatement, write(TypedEq<Utils::SmallStringView>("project1")));
EXPECT_CALL(database, commit()); EXPECT_CALL(database, commit());
storage.deletePrecompiledHeader("project1"); storage.deleteProjectPrecompiledHeader("project1");
} }
TEST_F(PrecompiledHeaderStorage, InsertPrecompiledHeaderStatement) TEST_F(PrecompiledHeaderStorage, InsertSystemPrecompiledHeader)
{ {
ASSERT_THAT(insertPrecompiledHeaderStatement.sqlStatement, InSequence s;
Eq("INSERT OR REPLACE INTO precompiledHeaders(projectPartId, pchPath, pchBuildTime) VALUES((SELECT projectPartId FROM projectParts WHERE projectPartName = ?),?,?)"));
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, InSequence s;
Eq("INSERT OR IGNORE INTO projectParts(projectPartName) VALUES (?)"));
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, InSequence s;
Eq("DELETE FROM precompiledHeaders WHERE projectPartId = (SELECT projectPartId FROM projectParts WHERE projectPartName = ?)"));
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) TEST_F(PrecompiledHeaderStorage, CompilePrecompiledHeaderStatements)
@@ -136,4 +181,48 @@ TEST_F(PrecompiledHeaderStorage, CompilePrecompiledHeaderStatements)
ASSERT_NO_THROW(ClangBackEnd::PrecompiledHeaderStorage<>{database}); 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());
}
} }

View File

@@ -35,6 +35,9 @@
namespace { namespace {
using ClangBackEnd::SlotUsage;
using ClangBackEnd::V2::ProjectPartContainer;
class ProjectPartQueue : public testing::Test class ProjectPartQueue : public testing::Test
{ {
protected: protected:
@@ -83,7 +86,7 @@ TEST_F(ProjectPartQueue, AddProjectPartCallsProcessEntries)
{ {
InSequence s; InSequence s;
EXPECT_CALL(mockTaskScheduler, freeSlots()).WillRepeatedly(Return(2)); EXPECT_CALL(mockTaskScheduler, slotUsage()).WillRepeatedly(Return(SlotUsage{2, 0}));
EXPECT_CALL(mockTaskScheduler, addTasks(SizeIs(2))); EXPECT_CALL(mockTaskScheduler, addTasks(SizeIs(2)));
queue.addProjectParts({projectPart1, projectPart2}); queue.addProjectParts({projectPart1, projectPart2});
@@ -148,11 +151,11 @@ TEST_F(ProjectPartQueue, CreateTaskFromProjectPart)
ClangBackEnd::ProjectPartPch projectPartPch{"project1", "/path/to/pch", 99}; ClangBackEnd::ProjectPartPch projectPartPch{"project1", "/path/to/pch", 99};
auto tasks = queue.createPchTasks({projectPart1}); 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(mockPchCreator, projectPartPch()).WillOnce(ReturnRef(projectPartPch));
EXPECT_CALL(mockSqliteTransactionBackend, lock()); EXPECT_CALL(mockSqliteTransactionBackend, lock());
EXPECT_CALL(mockSqliteTransactionBackend, immediateBegin()); 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, commit());
EXPECT_CALL(mockSqliteTransactionBackend, unlock()); EXPECT_CALL(mockSqliteTransactionBackend, unlock());
@@ -166,24 +169,15 @@ TEST_F(ProjectPartQueue, DeletePchEntryInDatabaseIfNoPchIsGenerated)
ClangBackEnd::ProjectPartPch projectPartPch{"project1", "", 0}; ClangBackEnd::ProjectPartPch projectPartPch{"project1", "", 0};
auto tasks = queue.createPchTasks({projectPart1}); 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(mockPchCreator, projectPartPch()).WillOnce(ReturnRef(projectPartPch));
EXPECT_CALL(mockSqliteTransactionBackend, lock()); EXPECT_CALL(mockSqliteTransactionBackend, lock());
EXPECT_CALL(mockSqliteTransactionBackend, immediateBegin()); EXPECT_CALL(mockSqliteTransactionBackend, immediateBegin());
EXPECT_CALL(mockPrecompiledHeaderStorage, deletePrecompiledHeader(Eq("project1"))); EXPECT_CALL(mockPrecompiledHeaderStorage, deleteProjectPrecompiledHeader(Eq("project1")));
EXPECT_CALL(mockSqliteTransactionBackend, commit()); EXPECT_CALL(mockSqliteTransactionBackend, commit());
EXPECT_CALL(mockSqliteTransactionBackend, unlock()); EXPECT_CALL(mockSqliteTransactionBackend, unlock());
tasks.front()(mockPchCreator); tasks.front()(mockPchCreator);
} }
//TEST_F(PchManagerClient, ProjectPartPchRemovedFromDatabase)
//{
// EXPECT_CALL(mockPrecompiledHeaderStorage, deletePrecompiledHeader(TypedEq<Utils::SmallStringView>(projectPartId)));
// projectUpdater.removeProjectParts({QString(projectPartId)});
//}
} }

View File

@@ -139,7 +139,7 @@ TEST_F(RefactoringDatabaseInitializer, AddPrecompiledHeaderTable)
{ {
InSequence s; 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(); 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 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 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 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, commit());
EXPECT_CALL(mockDatabase, setIsInitialized(true)); EXPECT_CALL(mockDatabase, setIsInitialized(true));

View File

@@ -35,6 +35,7 @@ using ClangBackEnd::FilePathId;
using ClangBackEnd::SymbolsCollectorInterface; using ClangBackEnd::SymbolsCollectorInterface;
using ClangBackEnd::SymbolIndexerTask; using ClangBackEnd::SymbolIndexerTask;
using ClangBackEnd::SymbolStorageInterface; using ClangBackEnd::SymbolStorageInterface;
using ClangBackEnd::SlotUsage;
using Callable = ClangBackEnd::SymbolIndexerTask::Callable; using Callable = ClangBackEnd::SymbolIndexerTask::Callable;
@@ -167,7 +168,7 @@ TEST_F(SymbolIndexerTaskQueue, ProcessTasksCallsFreeSlotsAndAddTasksInScheduler)
{3, 1, Callable{}}, {3, 1, Callable{}},
{5, 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))); EXPECT_CALL(mockTaskScheduler, addTasks(SizeIs(2)));
queue.processEntries(); queue.processEntries();
@@ -177,7 +178,7 @@ TEST_F(SymbolIndexerTaskQueue, ProcessTasksCallsFreeSlotsAndAddTasksWithNoTaskIn
{ {
InSequence s; InSequence s;
EXPECT_CALL(mockTaskScheduler, freeSlots()).WillRepeatedly(Return(2)); EXPECT_CALL(mockTaskScheduler, slotUsage()).WillRepeatedly(Return(SlotUsage{2, 0}));
EXPECT_CALL(mockTaskScheduler, addTasks(IsEmpty())); EXPECT_CALL(mockTaskScheduler, addTasks(IsEmpty()));
queue.processEntries(); queue.processEntries();
@@ -190,7 +191,7 @@ TEST_F(SymbolIndexerTaskQueue, ProcessTasksCallsFreeSlotsAndMoveAllTasksInSchedu
{3, 1, Callable{}}, {3, 1, Callable{}},
{5, 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))); EXPECT_CALL(mockTaskScheduler, addTasks(SizeIs(3)));
queue.processEntries(); queue.processEntries();
@@ -201,7 +202,7 @@ TEST_F(SymbolIndexerTaskQueue, ProcessTasksRemovesProcessedTasks)
queue.addOrUpdateTasks({{1, 1, Callable{}}, queue.addOrUpdateTasks({{1, 1, Callable{}},
{3, 1, Callable{}}, {3, 1, Callable{}},
{5, 1, Callable{}}}); {5, 1, Callable{}}});
ON_CALL(mockTaskScheduler, freeSlots()).WillByDefault(Return(2)); ON_CALL(mockTaskScheduler, slotUsage()).WillByDefault(Return(SlotUsage{2, 0}));
queue.processEntries(); queue.processEntries();

View File

@@ -40,6 +40,7 @@ using Task = std::function<void(ClangBackEnd::ProcessorInterface&)>;
using ClangBackEnd::ProcessorInterface; using ClangBackEnd::ProcessorInterface;
using ClangBackEnd::SymbolsCollectorInterface; using ClangBackEnd::SymbolsCollectorInterface;
using ClangBackEnd::SymbolStorageInterface; using ClangBackEnd::SymbolStorageInterface;
using ClangBackEnd::SlotUsage;
using NiceMockProcessorManager = NiceMock<MockProcessorManager>; using NiceMockProcessorManager = NiceMock<MockProcessorManager>;
using Scheduler = ClangBackEnd::TaskScheduler<NiceMockProcessorManager, Task>; using Scheduler = ClangBackEnd::TaskScheduler<NiceMockProcessorManager, Task>;
@@ -95,18 +96,18 @@ TEST_F(TaskScheduler, FreeSlots)
{ {
deferredScheduler.addTasks({nocall, nocall}); 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) TEST_F(TaskScheduler, ReturnZeroFreeSlotsIfMoreCallsThanCores)
{ {
deferredScheduler.addTasks({nocall, nocall, nocall, nocall, nocall, nocall}); 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) TEST_F(TaskScheduler, FreeSlotsAfterFinishing)
@@ -114,9 +115,9 @@ TEST_F(TaskScheduler, FreeSlotsAfterFinishing)
scheduler.addTasks({nocall, nocall}); scheduler.addTasks({nocall, nocall});
scheduler.syncTasks(); 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) TEST_F(TaskScheduler, NoFuturesAfterFreeSlots)
@@ -124,7 +125,7 @@ TEST_F(TaskScheduler, NoFuturesAfterFreeSlots)
scheduler.addTasks({nocall, nocall}); scheduler.addTasks({nocall, nocall});
scheduler.syncTasks(); scheduler.syncTasks();
scheduler.freeSlots(); scheduler.slotUsage();
ASSERT_THAT(scheduler.futures(), IsEmpty()); ASSERT_THAT(scheduler.futures(), IsEmpty());
} }
@@ -142,7 +143,7 @@ TEST_F(TaskScheduler, FreeSlotsCallsCleanupMethodsAfterTheWorkIsDone)
EXPECT_CALL(mockSymbolsCollector, setIsUsed(false)); EXPECT_CALL(mockSymbolsCollector, setIsUsed(false));
EXPECT_CALL(mockSymbolsCollector, clear()); EXPECT_CALL(mockSymbolsCollector, clear());
scheduler.freeSlots(); scheduler.slotUsage();
} }
TEST_F(TaskScheduler, FreeSlotsCallsProgressMethodsAfterTheWorkIsDone) TEST_F(TaskScheduler, FreeSlotsCallsProgressMethodsAfterTheWorkIsDone)
@@ -153,7 +154,7 @@ TEST_F(TaskScheduler, FreeSlotsCallsProgressMethodsAfterTheWorkIsDone)
EXPECT_CALL(mockSetProgressCallback, Call(2, 100)); EXPECT_CALL(mockSetProgressCallback, Call(2, 100));
scheduler.freeSlots(); scheduler.slotUsage();
} }
TEST_F(TaskScheduler, AddTaskCallSymbolsCollectorManagerUnusedSymbolsCollector) TEST_F(TaskScheduler, AddTaskCallSymbolsCollectorManagerUnusedSymbolsCollector)

View File

@@ -109,7 +109,8 @@ SOURCES += \
builddependenciesprovider-test.cpp \ builddependenciesprovider-test.cpp \
builddependenciesstorage-test.cpp \ builddependenciesstorage-test.cpp \
usedmacrofilter-test.cpp \ usedmacrofilter-test.cpp \
pchtasksmerger-test.cpp pchtasksmerger-test.cpp \
pchtaskqueue-test.cpp
!isEmpty(LIBCLANG_LIBS) { !isEmpty(LIBCLANG_LIBS) {
SOURCES += \ SOURCES += \