mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-10-12 23:44:25 +02:00
Rebuild the project database once per load instead of once per table model
ProjectDBModel::setQuery() calls projectDataBase::updateDB(), which drops and repopulates every table in the database. The rebuild does not depend on the query, so each table model that queries the database while a project is being read triggers another complete repopulate of the same content. Opening a 100 folio project ran updateDB() 26 times, 9.9 s of a 15.7 s load. Two changes, because the first alone is not enough: setUpdateBlocked() lets a bulk operation suppress the rebuild and do it once when it is done. readProjectXml() already wrapped the load in blockSignals(true) "to avoid hundreds of unnecessary emitted signal", but that suppresses only the signal, not the work it announces; this extends the same intent to the work. Both early returns in readProjectXml() sit before the block, so no path leaves the database permanently blocked. Further rebuilds are triggered after readProjectXml() returns, where the load phase timers cannot see them -- with only the block in place updateDB() still ran 5 times on examples/industrial.qet. So the database now also tracks whether anything has changed since the last rebuild, and skips repopulating when nothing has. dataBaseUpdated() is still emitted in that case: callers and models rely on it to refresh, and what they read back is the same either way. Every method of the class that writes rows marks the flag; from outside, the database is reachable only through newQuery(), and all five call sites read. Repeating the rebuild was wasteful rather than wrong -- each populate*Table() begins with a DELETE -- so this changes no output. Verified byte identical --info on all 23 example projects, and identical --export-bom, --export-wires, --export-cables, --export-nets and --export-wiring on industrial.qet. Its load drops from 5.51 s to 5.31 s (median of 6). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L6MRq2Ach1ogvnGcbuqNLr
This commit is contained in:
@@ -53,6 +53,7 @@ projectDataBase::projectDataBase(QETProject *project, QObject *parent) :
|
||||
});
|
||||
connect(m_project, &QETProject::projectDiagramsOrderChanged, [this]()
|
||||
{
|
||||
m_content_changed = true;
|
||||
for (auto diagram : m_project->diagrams())
|
||||
{
|
||||
m_diagram_order_changed.bindValue(":pos", m_project->folioIndex(diagram)+1);
|
||||
@@ -85,14 +86,42 @@ projectDataBase::~projectDataBase()
|
||||
*/
|
||||
void projectDataBase::updateDB()
|
||||
{
|
||||
//A bulk operation is in progress and updates the database itself once
|
||||
//it is done : rebuilding now would only be thrown away by that final
|
||||
//rebuild. @see setUpdateBlocked().
|
||||
if (m_update_blocked) {
|
||||
return;
|
||||
}
|
||||
|
||||
//Nothing in the project has changed since the last rebuild, so
|
||||
//repopulating would insert exactly the rows that are already there.
|
||||
//The signal is still emitted : callers and models rely on it to
|
||||
//refresh, and what they read back is unchanged either way.
|
||||
if (!m_content_changed)
|
||||
{
|
||||
emit dataBaseUpdated();
|
||||
return;
|
||||
}
|
||||
|
||||
populateDiagramTable();
|
||||
populateDiagramInfoTable();
|
||||
populateElementTable();
|
||||
populateElementInfoTable();
|
||||
populateConductorTable();
|
||||
m_content_changed = false;
|
||||
|
||||
emit dataBaseUpdated();
|
||||
}
|
||||
|
||||
/**
|
||||
@brief projectDataBase::setUpdateBlocked
|
||||
@param blocked : whether updateDB() should skip the full rebuild
|
||||
*/
|
||||
void projectDataBase::setUpdateBlocked(bool blocked)
|
||||
{
|
||||
m_update_blocked = blocked;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief projectDataBase::project
|
||||
@return the project of this database
|
||||
@@ -158,6 +187,7 @@ int projectDataBase::excludedConductorCount() const
|
||||
*/
|
||||
void projectDataBase::addElement(Element *element)
|
||||
{
|
||||
m_content_changed = true;
|
||||
if (!element || !element->diagram()) {
|
||||
qDebug() << "projectDataBase::addElement: null element or diagram";
|
||||
return;
|
||||
@@ -182,6 +212,7 @@ void projectDataBase::addElement(Element *element)
|
||||
*/
|
||||
void projectDataBase::removeElement(Element *element)
|
||||
{
|
||||
m_content_changed = true;
|
||||
m_remove_element_query.bindValue(":uuid", element->uuid().toString());
|
||||
if(!m_remove_element_query.exec()) {
|
||||
qDebug() << "projectDataBase::removeElement remove error : " << m_remove_element_query.lastError();
|
||||
@@ -196,6 +227,7 @@ void projectDataBase::removeElement(Element *element)
|
||||
*/
|
||||
void projectDataBase::elementInfoChanged(Element *element)
|
||||
{
|
||||
m_content_changed = true;
|
||||
auto hash = elementInfoToString(element);
|
||||
for (auto str : QETInformation::elementInfoKeys()) {
|
||||
m_update_element_query.bindValue(":" + str, hash.value(str));
|
||||
@@ -210,6 +242,7 @@ void projectDataBase::elementInfoChanged(Element *element)
|
||||
|
||||
void projectDataBase::elementInfoChanged(QList<Element *> elements)
|
||||
{
|
||||
m_content_changed = true;
|
||||
this->blockSignals(true);
|
||||
//Block signal for not emit dataBaseUpdated at
|
||||
//each call of the method elementInfoChanged(Element *element)
|
||||
@@ -226,6 +259,7 @@ void projectDataBase::elementInfoChanged(QList<Element *> elements)
|
||||
|
||||
void projectDataBase::addDiagram(Diagram *diagram)
|
||||
{
|
||||
m_content_changed = true;
|
||||
m_insert_diagram_query.bindValue(":uuid", diagram->uuid().toString());
|
||||
m_insert_diagram_query.bindValue(":pos", m_project->folioIndex(diagram)+1);
|
||||
if(!m_insert_diagram_query.exec()) {
|
||||
@@ -254,6 +288,7 @@ void projectDataBase::addDiagram(Diagram *diagram)
|
||||
|
||||
void projectDataBase::removeDiagram(Diagram *diagram)
|
||||
{
|
||||
m_content_changed = true;
|
||||
const QString uuid_str = diagram->uuid().toString();
|
||||
|
||||
//Order matters: element_info and terminal are scoped through a
|
||||
@@ -309,6 +344,7 @@ void projectDataBase::removeDiagram(Diagram *diagram)
|
||||
|
||||
void projectDataBase::diagramInfoChanged(Diagram *diagram)
|
||||
{
|
||||
m_content_changed = true;
|
||||
bindDiagramInfoValues(m_update_diagram_info_query, diagram);
|
||||
|
||||
if (!m_update_diagram_info_query.exec()) {
|
||||
@@ -320,6 +356,7 @@ void projectDataBase::diagramInfoChanged(Diagram *diagram)
|
||||
|
||||
void projectDataBase::diagramOrderChanged()
|
||||
{
|
||||
m_content_changed = true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -328,6 +365,7 @@ void projectDataBase::diagramOrderChanged()
|
||||
*/
|
||||
void projectDataBase::addConductor(Conductor *conductor)
|
||||
{
|
||||
m_content_changed = true;
|
||||
if (!conductor || !conductor->diagram()) {
|
||||
qDebug() << "projectDataBase::addConductor: null conductor or diagram";
|
||||
return;
|
||||
@@ -361,6 +399,7 @@ void projectDataBase::addConductor(Conductor *conductor)
|
||||
*/
|
||||
void projectDataBase::removeConductor(Conductor *conductor)
|
||||
{
|
||||
m_content_changed = true;
|
||||
m_remove_conductor_query.bindValue(":uuid", conductor->uuid().toString());
|
||||
if (!m_remove_conductor_query.exec()) {
|
||||
qDebug() << "projectDataBase::removeConductor delete error : " << m_remove_conductor_query.lastError();
|
||||
@@ -381,6 +420,7 @@ void projectDataBase::removeConductor(Conductor *conductor)
|
||||
*/
|
||||
void projectDataBase::updateConductor(Conductor *conductor)
|
||||
{
|
||||
m_content_changed = true;
|
||||
if (!conductor) {
|
||||
return;
|
||||
}
|
||||
@@ -423,6 +463,7 @@ void projectDataBase::watchConductor(Conductor *conductor)
|
||||
*/
|
||||
void projectDataBase::conductorPropertiesChanged()
|
||||
{
|
||||
m_content_changed = true;
|
||||
if (auto *conductor = qobject_cast<Conductor *>(sender())) {
|
||||
updateConductor(conductor);
|
||||
}
|
||||
|
||||
@@ -47,6 +47,17 @@ class projectDataBase : public QObject
|
||||
virtual ~projectDataBase() override;
|
||||
|
||||
void updateDB();
|
||||
/**
|
||||
Suppress the full rebuild performed by updateDB().
|
||||
|
||||
While blocked, updateDB() returns immediately instead of
|
||||
repopulating every table. Meant for bulk operations -- notably
|
||||
loading a project, where each table model re-queries the
|
||||
database as it is built and would otherwise trigger one
|
||||
complete rebuild of it. The caller unblocks and calls
|
||||
updateDB() once when done; @see QETProject::readProjectXml().
|
||||
*/
|
||||
void setUpdateBlocked(bool blocked);
|
||||
QETProject *project() const;
|
||||
QSqlQuery newQuery(const QString &query = QString());
|
||||
QSqlDatabase database() const {return m_data_base;}
|
||||
@@ -97,6 +108,12 @@ class projectDataBase : public QObject
|
||||
|
||||
private:
|
||||
QPointer<QETProject> m_project;
|
||||
bool m_update_blocked = false;
|
||||
//Starts true : the database is empty until the first rebuild.
|
||||
//Set by every method of this class that writes rows, cleared by
|
||||
//updateDB(). Callers reach the database from outside only through
|
||||
//newQuery(), and every such call site reads.
|
||||
bool m_content_changed = true;
|
||||
QSqlDatabase m_data_base;
|
||||
QSqlQuery m_insert_elements_query,
|
||||
m_insert_element_info_query,
|
||||
|
||||
Reference in New Issue
Block a user