存储 flatbuffers 对象的非根 table 以供以后反序列化
storing non-root table of flatbuffers object for later deserialization
考虑以下平面缓冲区架构(来自 ):
table Foo {
...
}
table Bar {
value:[Foo];
}
root_type Bar;
假设典型对象中 Foo
的数量很大,因此我们希望避免修改架构以使 Foo
成为 root_type
.
场景:
C++ 客户端序列化一个合适的 flatbuffers 对象并将其 post 发送到另一个组件(nodejs 后端),该组件部分反序列化该对象并将表示每个 Foo
的二进制文件作为单独的文档存储在数据库中:
const buf = new flatbuffers.ByteBuffer(req.body)
const bar = fbs.Bar.getRootAsBar(buf)
for (let i = 0; i < bar.valueLength(); i++) {
const foo = bar.value(i)
let item = {
'raw': foo.bb.bytes_ // <-- primary suspect
}
// ... store `item` as an individual entity (mongodb doc)
}
稍后,第三个组件获取存储在 mongodb 文档的 "raw" 键中的二进制数据,并尝试将其反序列化为 Foo
对象:
auto mongoCol = db.collection("results");
auto mongoResult = mongoCol.find_one(
bsoncxx::builder::stream::document{}
<< "_id" << oid << bsoncxx::builder::stream::finalize);
// ...check that mongoResult is not null
const auto result = mongoResult->view();
const auto& binary = result["raw"].get_binary();
std::string content((const char*)binary.bytes, binary.size);
const auto& foo = flatbuffers::GetRoot<fbs::Foo>(content.c_str());
问题:
但是作为 foo
给出的指针没有指向预期的数据,并且对 foo
的任何操作都可能导致段错误或访问冲突。
怀疑:
我推测根本原因是存储在数据库中的二进制文件根据原始消息使用了偏移量。所以它本身的原始格式本质上是无效的,在插入数据库之前应该重新调整偏移量。但是我没有看到任何 flatbuffers 函数 API 来重新调整偏移量?
一个不太可能的根本原因可能是最终的反序列化代码不完整,我们必须重新调整偏移量?
我怀疑它与偏移量有关的原因是,如果我们做出妥协并且 post 更小的 flatbuffers 对象在每个 Bar 向量中都有一个 Foo 元素(并更改后端),那么相同的代码工作得很好将 bar.bb.bytes
存储在 raw
中的代码)。
问题:
以任何方式,是否有可能获取一个更大的正确构造的 flatbuffers 二进制文件的一部分,你 知道 代表你想要的 table 并在其上反序列化它拥有?
您不能简单地按字节从较大的 FlatBuffer 中复制子 table,因为该数据不一定是连续的。最好的解决方法是让 Bar
在 table FooBuffer { buf:[byte] (nested_flatbuffer: Foo) }
中存储 [FooBuffer]
。当您构造其中之一时,您将每个 Foo
构造成它自己的 FlatBufferBuilder
,然后将生成的字节存储在父级中。然后,当您需要单独存储 Foo
时,这就变成了一个简单的副本。
考虑以下平面缓冲区架构(来自
table Foo {
...
}
table Bar {
value:[Foo];
}
root_type Bar;
假设典型对象中 Foo
的数量很大,因此我们希望避免修改架构以使 Foo
成为 root_type
.
场景:
C++ 客户端序列化一个合适的 flatbuffers 对象并将其 post 发送到另一个组件(nodejs 后端),该组件部分反序列化该对象并将表示每个 Foo
的二进制文件作为单独的文档存储在数据库中:
const buf = new flatbuffers.ByteBuffer(req.body)
const bar = fbs.Bar.getRootAsBar(buf)
for (let i = 0; i < bar.valueLength(); i++) {
const foo = bar.value(i)
let item = {
'raw': foo.bb.bytes_ // <-- primary suspect
}
// ... store `item` as an individual entity (mongodb doc)
}
稍后,第三个组件获取存储在 mongodb 文档的 "raw" 键中的二进制数据,并尝试将其反序列化为 Foo
对象:
auto mongoCol = db.collection("results");
auto mongoResult = mongoCol.find_one(
bsoncxx::builder::stream::document{}
<< "_id" << oid << bsoncxx::builder::stream::finalize);
// ...check that mongoResult is not null
const auto result = mongoResult->view();
const auto& binary = result["raw"].get_binary();
std::string content((const char*)binary.bytes, binary.size);
const auto& foo = flatbuffers::GetRoot<fbs::Foo>(content.c_str());
问题:
但是作为 foo
给出的指针没有指向预期的数据,并且对 foo
的任何操作都可能导致段错误或访问冲突。
怀疑:
我推测根本原因是存储在数据库中的二进制文件根据原始消息使用了偏移量。所以它本身的原始格式本质上是无效的,在插入数据库之前应该重新调整偏移量。但是我没有看到任何 flatbuffers 函数 API 来重新调整偏移量?
一个不太可能的根本原因可能是最终的反序列化代码不完整,我们必须重新调整偏移量?
我怀疑它与偏移量有关的原因是,如果我们做出妥协并且 post 更小的 flatbuffers 对象在每个 Bar 向量中都有一个 Foo 元素(并更改后端),那么相同的代码工作得很好将 bar.bb.bytes
存储在 raw
中的代码)。
问题:
以任何方式,是否有可能获取一个更大的正确构造的 flatbuffers 二进制文件的一部分,你 知道 代表你想要的 table 并在其上反序列化它拥有?
您不能简单地按字节从较大的 FlatBuffer 中复制子 table,因为该数据不一定是连续的。最好的解决方法是让 Bar
在 table FooBuffer { buf:[byte] (nested_flatbuffer: Foo) }
中存储 [FooBuffer]
。当您构造其中之一时,您将每个 Foo
构造成它自己的 FlatBufferBuilder
,然后将生成的字节存储在父级中。然后,当您需要单独存储 Foo
时,这就变成了一个简单的副本。