[CardDB] Stream card properties from blobs (#7608)

* [CardDB] Stream card properties from blobs

Parsed and cached cards used to keep a materialized QHash<QString,
QString> for their properties: LazyPropertiesHash only deferred building
that hash until the first query, and the cache writer re-serialized it on
save.

- LazyPropertiesHash answers value(), contains(), size(), isEmpty() and
  keys() straight out of the serialized blob, so a property query no
  longer builds a hash.
- serialize() is public, and the cache writer passes the stored blob
  through instead of serializing a hash it just rebuilt.
- CardInfo and PrintingInfo expose getPropertiesBlob() and
  getPropertyCount(); PrintingInfo::operator== compares key by key
  without materializing either side.
- The XML parsers build cards via newInstanceFromPropertiesBlob(), which
  derives the simple name and the alternate names that the parser used
  to keep next to the hash.

The reload cycle fix stays out of this change; it depends on changing
the CardInfo self pointer and is reviewed separately.

* [CardDB] Address review comments on streaming properties

* [CardDB] Address final review nits on property streaming

Move BlobReader and the blob accessors into LazyPropertiesHash as private
members so the parsing helper is declared with the class instead of hiding
in the translation unit.

Add LazyPropertiesHash::serializedFrom() and use it where a PrintingInfo is
built from a fresh property hash, replacing the nested
LazyPropertiesHash(LazyPropertiesHash::serialize(props)) construction.

The pre-materialized QHash constructor stays: CardInfo's non-blob factory
still uses it for the oracle import path, and the tests cover it directly.

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
This commit is contained in:
BruebachL 2026-10-24 00:17:31 +02:00 • committed by GitHub
parent c25a2c5c3b
commit ad4320cd7b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 475 additions and 59 deletions

View file

@ -53,13 +53,10 @@ QString readString(QDataStream &in)
// Stores a QHash<QString, QString> as a single pre-serialized blob. The reader keeps the
// blob as-is and materializes the QHash<QString, QString> lazily on first query, which is
// what removes the allocation storm from database load (see card_info.cpp /
// printing_info.cpp).
void writeHashBlob(QDataStream &out, const QHash<QString, QString> &h)
// printing_info.cpp). Writing the already-serialized blob also keeps cache writes from
// materializing every card's property hash.
void writeBlob(QDataStream &out, const QByteArray &blob)
{
QByteArray blob;
QDataStream blobOut(&blob, QIODevice::WriteOnly);
blobOut.setVersion(QDataStream::Qt_6_4);
blobOut << h;
out << static_cast<quint32>(blob.size());
out.writeRawData(blob.constData(), blob.size());
}
@ -156,7 +153,7 @@ CardRelation *readRelation(QDataStream &in)
void writePrinting(QDataStream &out, const PrintingInfo &p)
{
writeString(out, p.getSet() ? p.getSet()->getShortName() : QString());
writeHashBlob(out, p.getPropertiesHash());
writeBlob(out, p.getPropertiesBlob());
}
PrintingInfo readPrinting(QDataStream &in, const SetNameMap &sets)
@ -198,7 +195,7 @@ void writeCard(QDataStream &out, const CardInfoPtr &card)
writeString(out, card->getName());
writeString(out, card->getText());
out << card->getIsToken();
writeHashBlob(out, card->getPropertiesHash());
writeBlob(out, card->getPropertiesBlob());
CardInfo::UiAttributes ui = card->getUiAttributes();
out << ui.cipt;