未经编码的编码 avro 消息的大小
Size of encoded avro message without encoding it
有没有办法在不实际编码的情况下获取编码后的 avro 消息的大小?
我正在为 C++ 使用 Avro 1.8.1。
我习惯了 google 协议缓冲区,您可以在其中调用 ByteSize()
protobuf 以获得编码大小,所以它与我正在寻找的类似。
由于消息本质上是一个原始结构,我知道无法从消息本身检索大小,但也许有一个我不知道的辅助方法?
不幸的是,没有办法解决...
下面是一个示例,展示了如何通过对对象进行编码来计算大小:
MyAvroStruct obj;
avro::EncoderPtr encoder = avro::binaryEncoder();
std::auto_ptr<avro::OutputStream> out = avro::memoryOutputStream(1);
encoder->init(*out);
avro::encode(*encoder, obj);
out->flush();
uint32_t bufferSize = out->byteCount();
(下面的编辑显示了一种在用 BinaryEncoder
写入后 shrink-to-fit 一个 OutputStream
的 hacky 方法)
遗憾的是 avro::encode()
没有在 OutputStream
上使用 backup
来释放编码后未使用的内存。 仅使用 avro 提供的工具给出了最佳解决方案,但如果序列化对象的大小为 N 字节,它会发出 N 次内存分配,每次分配 1 字节。
您可以实现一个自定义 avro::OutputStream
来简单地计算并丢弃所有写入的字节。这将摆脱内存分配。这仍然不是一个好方法,因为实际的编码器将不得不“询问”每个字节:
(代码未经测试,仅供演示)
#include <avro/Encoder.hh>
#include <cstdint>
class ByteCountOutputStream : public avro::OutputStream {
public:
size_t byteCount_ = 0;
uint8_t dummyWriteLocation_;
explicit ByteCountOutputStream() {};
bool next(uint8_t **data, size_t *len) final {
byteCount_ += 1;
*data = &dummyWriteLocation_;
*len = 1;
return true;
}
void backup(size_t len) final {
byteCount_ -= len;
}
uint64_t byteCount() const final {
return byteCount_;
}
void flush() final {}
};
这可以用作:
MyAvroStruct obj;
avro::EncoderPtr encoder = avro::binaryEncoder();
ByteCountOutputStream out();
encoder->init(out);
avro::encode(*encoder, obj);
size_t bufferSize = out.byteCount();
编辑:
遇到这个问题时,我最初的问题是:我如何知道 OutputStream
需要多少字节(用于存储/传输)?或者,等效地,如果 OutputStream.byteCount()
returns 到目前为止编码器分配的字节数,我怎样才能让编码器“备份”/释放它没有使用的字节?好吧,有一个 hacky 方法:
Encoder
摘要 class 提供了一个 init
method. For the BinaryEncoder, this is currently implemented as:
void BinaryEncoder::init(OutputStream &os) {
out_.reset(os);
}
其中 out_
是 internal StreamWriter
of the Encoder。
现在,StreamWriter
implements reset
as:
void reset(OutputStream &os) {
if (out_ != nullptr && end_ != next_) {
out_->backup(end_ - next_);
}
out_ = &os;
next_ = end_;
}
这将 return 未使用的内存在切换到新的之前返回到“旧的”OutputStream。
因此,您可以像这样滥用编码器的 init 方法:
// setup as always
MyAvroStruct obj;
avro::EncoderPtr encoder = avro::binaryEncoder();
std::auto_ptr<avro::OutputStream> out = avro::memoryOutputStream();
// actual serialization
encoder->init(*out);
avro::encode(*encoder, obj);
// re-init on the same OutputStream. Happens to shrink the stream to fit
encoder->init(*out);
size_t bufferSize = out->byteCount();
但是,这种行为是 not documented,因此它可能会在未来崩溃。
有没有办法在不实际编码的情况下获取编码后的 avro 消息的大小?
我正在为 C++ 使用 Avro 1.8.1。
我习惯了 google 协议缓冲区,您可以在其中调用 ByteSize()
protobuf 以获得编码大小,所以它与我正在寻找的类似。
由于消息本质上是一个原始结构,我知道无法从消息本身检索大小,但也许有一个我不知道的辅助方法?
不幸的是,没有办法解决...
下面是一个示例,展示了如何通过对对象进行编码来计算大小:
MyAvroStruct obj;
avro::EncoderPtr encoder = avro::binaryEncoder();
std::auto_ptr<avro::OutputStream> out = avro::memoryOutputStream(1);
encoder->init(*out);
avro::encode(*encoder, obj);
out->flush();
uint32_t bufferSize = out->byteCount();
(下面的编辑显示了一种在用 BinaryEncoder
写入后 shrink-to-fit 一个 OutputStream
的 hacky 方法)
遗憾的是 avro::encode()
没有在 OutputStream
上使用 backup
来释放编码后未使用的内存。
您可以实现一个自定义 avro::OutputStream
来简单地计算并丢弃所有写入的字节。这将摆脱内存分配。这仍然不是一个好方法,因为实际的编码器将不得不“询问”每个字节:
(代码未经测试,仅供演示)
#include <avro/Encoder.hh>
#include <cstdint>
class ByteCountOutputStream : public avro::OutputStream {
public:
size_t byteCount_ = 0;
uint8_t dummyWriteLocation_;
explicit ByteCountOutputStream() {};
bool next(uint8_t **data, size_t *len) final {
byteCount_ += 1;
*data = &dummyWriteLocation_;
*len = 1;
return true;
}
void backup(size_t len) final {
byteCount_ -= len;
}
uint64_t byteCount() const final {
return byteCount_;
}
void flush() final {}
};
这可以用作:
MyAvroStruct obj;
avro::EncoderPtr encoder = avro::binaryEncoder();
ByteCountOutputStream out();
encoder->init(out);
avro::encode(*encoder, obj);
size_t bufferSize = out.byteCount();
编辑:
遇到这个问题时,我最初的问题是:我如何知道 OutputStream
需要多少字节(用于存储/传输)?或者,等效地,如果 OutputStream.byteCount()
returns 到目前为止编码器分配的字节数,我怎样才能让编码器“备份”/释放它没有使用的字节?好吧,有一个 hacky 方法:
Encoder
摘要 class 提供了一个 init
method. For the BinaryEncoder, this is currently implemented as:
void BinaryEncoder::init(OutputStream &os) {
out_.reset(os);
}
其中 out_
是 internal StreamWriter
of the Encoder。
现在,StreamWriter
implements reset
as:
void reset(OutputStream &os) {
if (out_ != nullptr && end_ != next_) {
out_->backup(end_ - next_);
}
out_ = &os;
next_ = end_;
}
这将 return 未使用的内存在切换到新的之前返回到“旧的”OutputStream。
因此,您可以像这样滥用编码器的 init 方法:
// setup as always
MyAvroStruct obj;
avro::EncoderPtr encoder = avro::binaryEncoder();
std::auto_ptr<avro::OutputStream> out = avro::memoryOutputStream();
// actual serialization
encoder->init(*out);
avro::encode(*encoder, obj);
// re-init on the same OutputStream. Happens to shrink the stream to fit
encoder->init(*out);
size_t bufferSize = out->byteCount();
但是,这种行为是 not documented,因此它可能会在未来崩溃。