From 74b405a9f7bb74f17b14f892a5dd53ab0e4c5523 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Thu, 6 Aug 2026 10:16:34 +1000 Subject: [PATCH] Write GlobalId index when serializing to RocksDB rocks_db_file_storage already exposes a `g|`-prefixed guid -> instance name map, but RocksDbSerializer never populated it, so by_guid() on a converted file always threw. Co-Authored-By: Claude Opus 5 (1M context) --- ...st_streaming_rocksdb_and_simpletyperefs.py | 5 +++++ src/serializers/RocksDbSerializer.cpp | 22 +++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/src/ifcopenshell-python/test/test_streaming_rocksdb_and_simpletyperefs.py b/src/ifcopenshell-python/test/test_streaming_rocksdb_and_simpletyperefs.py index e34587a4e8..98e938d6ce 100644 --- a/src/ifcopenshell-python/test/test_streaming_rocksdb_and_simpletyperefs.py +++ b/src/ifcopenshell-python/test/test_streaming_rocksdb_and_simpletyperefs.py @@ -115,6 +115,11 @@ def test_rocks(): b = f.key_value_store_query(f"t|{iden}|0")[1:] assert set(struct.unpack("Q", b[i : i + 8])[0] for i in range(1, len(b), 9)) == {136, 138} + g = ifcopenshell.open(fn) + for inst in g.by_type("IfcRoot"): + assert f.by_guid(inst.GlobalId).id() == inst.id() + + del g del f gc.collect() diff --git a/src/serializers/RocksDbSerializer.cpp b/src/serializers/RocksDbSerializer.cpp index 40ab150d5e..b9ba0821e0 100644 --- a/src/serializers/RocksDbSerializer.cpp +++ b/src/serializers/RocksDbSerializer.cpp @@ -113,6 +113,10 @@ void RocksDbSerializer::write_streaming_() { std::string tmp; + // Resolved lazily from the first non-header declaration encountered, because + // the schema is only known once the header has been read. + const ifcopenshell::declaration* ifcroot_type = nullptr; + ifcopenshell::instance_streamer streamer(input_filename_); // We do not want to coerce attribute counts here, because we want @@ -279,6 +283,24 @@ void RocksDbSerializer::write_streaming_() { memcpy(s.data(), &v, sizeof(size_t)); storage.db->Merge(storage.wopts, "t|" + std::to_string(decl->index_in_schema()), s); } + + // GlobalId as numeric ref to instance name, so that the guid map in + // rocks_db_file_storage can resolve by_guid() lookups. + if (ifcroot_type == nullptr) { + ifcroot_type = decl->schema()->declaration_by_name("IfcRoot"); + } + if (decl->is(*ifcroot_type)) { + // @nb attribute counts are not coerced, so the attribute may be absent + const bool has_guid = data->storage_->size() > 0 && data->get_attribute_value(0).type() == ifcopenshell::Argument_STRING; + if (has_guid) { + size_t v = name; + std::string s(sizeof(size_t), ' '); + memcpy(s.data(), &v, sizeof(size_t)); + storage.db->Put(storage.wopts, "g|" + (std::string)data->get_attribute_value(0), s); + } else { + ::logger::root().error("Instance #" + std::to_string(name) + " has no GlobalId, omitted from guid index"); + } + } } streamer.references().clear();