mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-10-14 09:14:14 +02:00
Open with every folio built when the database must come from them
With QET_LAZY_FOLIOS=1, a project whose database cannot be filled from the file (folios or symbols with no saved uuid, two symbols sharing one, a folio number using %autonum, wires naming their ends the older way) had its folios left unbuilt, then built all at once while the database was filled from them. That is slower than building them as they are read: a 17 MB project reported on the pull request took 24.8 s to open instead of 19.2 s, and most files saved by an older version have no folio uuids. The file is now checked for those reasons before the folios are read; when one applies the project opens as without QET_LAZY_FOLIOS. The rarer reasons, which need the definitions or every folio's links, still fall back as before. tst_lazyfolios opens a copy of industrial.qet with one symbol's uuid given to another, and checks no folio is built after reading. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -253,6 +253,58 @@ void projectDataBase::updateDB(const QDomDocument &document)
|
||||
updateDB();
|
||||
}
|
||||
|
||||
/**
|
||||
@brief projectDataBase::documentRefusal
|
||||
@return why populateFromDocument() will refuse @p document, for the
|
||||
reasons it gives that the document alone can tell -- a folio, symbol
|
||||
or wire with no saved uuid, two symbols sharing one, a folio number
|
||||
using %autonum -- or an empty string. The other reasons need the
|
||||
project's definitions or every folio's links; a document refused for
|
||||
one of those is still filled from the folios, only later.
|
||||
*/
|
||||
QString projectDataBase::documentRefusal(const QDomDocument &document)
|
||||
{
|
||||
if (qEnvironmentVariableIntValue("QET_DATABASE_FROM_FOLIOS") == 1) {
|
||||
return QStringLiteral("QET_DATABASE_FROM_FOLIOS is set");
|
||||
}
|
||||
QSet<QUuid> element_uuids;
|
||||
const QDomNodeList diagram_nodes = document.elementsByTagName(QStringLiteral("diagram"));
|
||||
for (int i = 0 ; i < diagram_nodes.size() ; ++i)
|
||||
{
|
||||
QDomElement diagram_xml = diagram_nodes.at(i).toElement();
|
||||
if (QUuid(diagram_xml.attribute(QStringLiteral("uuid"))).isNull()) {
|
||||
return QStringLiteral("a folio has no saved uuid");
|
||||
}
|
||||
if (diagram_xml.attribute(QStringLiteral("folio")).contains(QStringLiteral("%autonum"))) {
|
||||
return QStringLiteral("a folio number uses %autonum");
|
||||
}
|
||||
for (QDomElement element_xml : QET::findInDomElement(
|
||||
diagram_xml, QStringLiteral("elements"), QStringLiteral("element")))
|
||||
{
|
||||
//Skipped by Diagram::fromXml() as well
|
||||
if (!Element::valideXml(element_xml)) {
|
||||
continue;
|
||||
}
|
||||
const QUuid uuid(element_xml.attribute(QStringLiteral("uuid")));
|
||||
if (uuid.isNull() || element_uuids.contains(uuid)) {
|
||||
return QStringLiteral("an element has no saved uuid, or shares one");
|
||||
}
|
||||
element_uuids.insert(uuid);
|
||||
}
|
||||
for (QDomElement conductor_xml : QET::findInDomElement(
|
||||
diagram_xml, QStringLiteral("conductors"), QStringLiteral("conductor")))
|
||||
{
|
||||
if (Conductor::valideXml(conductor_xml)
|
||||
&& (QUuid(conductor_xml.attribute(QStringLiteral("uuid"))).isNull()
|
||||
|| !conductor_xml.hasAttribute(QStringLiteral("element1"))
|
||||
|| !conductor_xml.hasAttribute(QStringLiteral("element2")))) {
|
||||
return QStringLiteral("a conductor has no saved uuid, or names its ends the older way");
|
||||
}
|
||||
}
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct DocumentTerminal
|
||||
{
|
||||
|
||||
@@ -67,6 +67,14 @@ class projectDataBase : public QObject
|
||||
populateFromDocument()), from the built folios otherwise.
|
||||
*/
|
||||
void updateDB(const QDomDocument &document);
|
||||
/**
|
||||
Why updateDB(document) will fill the tables from the folios
|
||||
rather than from @p document, for the reasons the document
|
||||
alone can tell; empty when it knows of none. Read before the
|
||||
folios are: a project whose tables will come from the folios
|
||||
builds every folio as it opens, even with QET_LAZY_FOLIOS.
|
||||
*/
|
||||
static QString documentRefusal(const QDomDocument &document);
|
||||
/**
|
||||
Suppress the full rebuild performed by updateDB().
|
||||
|
||||
|
||||
+15
-2
@@ -3018,6 +3018,19 @@ void QETProject::readProjectXml(QDomDocument &xml_project)
|
||||
//built (DB-ACCESSORS-PLAN.md stage 4.6)
|
||||
m_data_base.prefillFromDocument(xml_project);
|
||||
|
||||
//QET_LAZY_FOLIOS leaves the folios to be built when needed only
|
||||
//when the database can be filled from the document: otherwise
|
||||
//filling it from the folios builds every one of them anyway, late
|
||||
//and more slowly than reading them now
|
||||
m_lazy_open = qEnvironmentVariableIntValue("QET_LAZY_FOLIOS") == 1;
|
||||
if (m_lazy_open) {
|
||||
const QString why = projectDataBase::documentRefusal(xml_project);
|
||||
if (!why.isEmpty()) {
|
||||
qInfo().noquote() << "Project opened with every folio built:" << why;
|
||||
m_lazy_open = false;
|
||||
}
|
||||
}
|
||||
|
||||
//Load the diagrams
|
||||
readDiagramsXml(xml_project);
|
||||
const qint64 diagrams_ms = phase_timer.restart();
|
||||
@@ -3134,7 +3147,7 @@ void QETProject::readDiagramsXml(QDomDocument &xml_project)
|
||||
//Where each line of the file starts, for a folio's text: lines
|
||||
//[its start, the next element's start) (QETProject::toXml())
|
||||
QList<qsizetype> line_starts;
|
||||
if (qEnvironmentVariableIntValue("QET_LAZY_FOLIOS") == 1 && !m_opened_content.isEmpty()) {
|
||||
if (m_lazy_open && !m_opened_content.isEmpty()) {
|
||||
line_starts << 0;
|
||||
for (qsizetype i = 0 ; i < m_opened_content.size() ; ++i)
|
||||
if (m_opened_content.at(i) == '\n') line_starts << i + 1;
|
||||
@@ -3181,7 +3194,7 @@ void QETProject::readDiagramsXml(QDomDocument &xml_project)
|
||||
connect(diagram, &Diagram::usedTitleBlockTemplateChanged,
|
||||
this, &QETProject::usedTitleBlockTemplateChanged);
|
||||
|
||||
m_deferring_folios = qEnvironmentVariableIntValue("QET_LAZY_FOLIOS") == 1;
|
||||
m_deferring_folios = m_lazy_open;
|
||||
diagram->initFromXml(diagram_xml_element);
|
||||
m_deferring_folios = false;
|
||||
if (!diagram->isLoaded() && !line_starts.isEmpty())
|
||||
|
||||
@@ -512,6 +512,9 @@ class QETProject : public QObject
|
||||
const DiagramContext &information,
|
||||
const QHash<QString, QStringList> &titles_by_formula) const;
|
||||
bool m_deferring_folios = false;
|
||||
/// Opening with folios built only when needed: QET_LAZY_FOLIOS
|
||||
/// is set and the database can be filled from the document
|
||||
bool m_lazy_open = false;
|
||||
/// Saving may write a folio not built as it was read
|
||||
/// (writesKeptFolios()): the file is this version's, its
|
||||
/// database rows came from it, and nothing project-wide that
|
||||
|
||||
@@ -37,6 +37,8 @@
|
||||
#include "../../sources/undocommand/deleteqgraphicsitemcommand.h"
|
||||
#include "../../sources/factory/elementfactory.h"
|
||||
#include "../../sources/undocommand/addgraphicsobjectcommand.h"
|
||||
#include "../../sources/dataBase/projectdatabase.h"
|
||||
#include <QDomDocument>
|
||||
|
||||
static void check(bool value, const char *message) { if (!value) throw std::runtime_error(message); }
|
||||
|
||||
@@ -567,6 +569,44 @@ int main(int argc, char **argv)
|
||||
check(potential(wire) == potential(usual_wire), "a potential followed as when built");
|
||||
std::printf("potential through reports: %d wires, %d folios not built\n",
|
||||
int(potential(wire).size()), followed.unloadedFolioCount());
|
||||
}
|
||||
//Two symbols sharing a uuid: the database is filled from the
|
||||
//folios, which builds every one of them, so the project opens
|
||||
//with every folio built rather than building them all later
|
||||
{
|
||||
QFile file(path);
|
||||
check(file.open(QIODevice::ReadOnly), "fixture read");
|
||||
QDomDocument document;
|
||||
check(bool(document.setContent(&file)), "fixture parsed");
|
||||
file.close();
|
||||
check(projectDataBase::documentRefusal(document).isEmpty(), "the fixture fills the database itself");
|
||||
QDomNodeList elements = document.elementsByTagName(QStringLiteral("element"));
|
||||
QList<QDomElement> placed;
|
||||
for (int i = 0; i < elements.size(); ++i) {
|
||||
QDomElement e = elements.at(i).toElement();
|
||||
if (Element::valideXml(e)) placed << e;
|
||||
}
|
||||
check(placed.size() > 1, "two placed symbols");
|
||||
placed.last().setAttribute(QStringLiteral("uuid"), placed.first().attribute(QStringLiteral("uuid")));
|
||||
check(!projectDataBase::documentRefusal(document).isEmpty(), "a shared uuid is seen before the folios are read");
|
||||
const QString shared = output + "/lazy_folios_shared_uuid.qet";
|
||||
QFile out(shared);
|
||||
check(out.open(QIODevice::WriteOnly), "copy written");
|
||||
out.write(document.toByteArray(4));
|
||||
out.close();
|
||||
qputenv("QET_LAZY_FOLIOS", "1");
|
||||
qputenv("QET_LAZY_FOLIOS_TRACE", "1");
|
||||
static int built_late; built_late = 0;
|
||||
const QtMessageHandler previous = qInstallMessageHandler(
|
||||
[](QtMsgType, const QMessageLogContext &, const QString &message) {
|
||||
if (message.contains(QStringLiteral("built for a caller of diagrams()"))) ++built_late;
|
||||
});
|
||||
QETProject opened(shared);
|
||||
qInstallMessageHandler(previous);
|
||||
qunsetenv("QET_LAZY_FOLIOS_TRACE");
|
||||
check(opened.state() == QETProject::Ok, "a project with a shared uuid opens");
|
||||
check(opened.unloadedFolioCount() == 0, "a project with a shared uuid opens with every folio built");
|
||||
check(built_late == 0, "a project with a shared uuid builds its folios as it reads them, not later");
|
||||
}
|
||||
std::printf("PASS: %d folios\n", int(folios.size()));
|
||||
} catch (const std::exception &error) {
|
||||
|
||||
Reference in New Issue
Block a user