mirror of
https://github.com/facebook/sapling.git
synced 2024-10-05 14:28:17 +03:00
nfs: allow serializing/deserializing IOBuf
Summary: For the READ/WRITE RPC calls, copying data in and out of an IOBuf chain can be fairly expensive, to avoid this overhead, we can simply clone the data out of the IOBuf chain directly, saving on the cost of copy. Since the code uses a folly::io::Appender that doesn't support adding an IOBuf to it, we still pay the cost of copying data to it, switching to folly::io::QueueAppender may solve this. Reviewed By: chadaustin Differential Revision: D26671896 fbshipit-source-id: 0161f04cb820bf27ef66fdef6b4a1ce4eb778b96
This commit is contained in:
parent
b46a7b2a11
commit
0841d553fd
@ -31,6 +31,17 @@ void serialize_variable(folly::io::Appender& appender, folly::ByteRange value) {
|
||||
serialize_fixed(appender, value);
|
||||
}
|
||||
|
||||
void serialize_iobuf(folly::io::Appender& appender, const folly::IOBuf& buf) {
|
||||
auto len = buf.computeChainDataLength();
|
||||
if (len > std::numeric_limits<uint32_t>::max()) {
|
||||
throw std::length_error(
|
||||
"XDR cannot encode variable sized array bigger than 4GB");
|
||||
}
|
||||
XdrTrait<uint32_t>::serialize(appender, folly::to_narrow(len));
|
||||
appender.push(folly::io::Cursor(&buf), len);
|
||||
addPadding(appender, len);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace facebook::eden
|
||||
|
@ -105,6 +105,12 @@ void serialize_fixed(folly::io::Appender& appender, folly::ByteRange value);
|
||||
*/
|
||||
void serialize_variable(folly::io::Appender& appender, folly::ByteRange value);
|
||||
|
||||
/**
|
||||
* Serialize an IOBuf chain. This is serialized like a variable sized array,
|
||||
* ie: size first, followed by the content and aligned on a 4-byte boundary.
|
||||
*/
|
||||
void serialize_iobuf(folly::io::Appender& appender, const folly::IOBuf& buf);
|
||||
|
||||
/**
|
||||
* Skip the padding bytes that were written during serialization.
|
||||
*/
|
||||
@ -175,6 +181,33 @@ struct XdrTrait<std::vector<uint8_t>> {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* IOBuf are encoded as a variable sized array, similarly to a vector. IOBuf
|
||||
* should be preferred to a vector when the data to serialize/deserialize is
|
||||
* potentially large, a vector would copy all the data, while an IOBuf would
|
||||
* clone the existing cursor.
|
||||
*
|
||||
* TODO(xavierd): folly::io::Appender doesn't have a way to zero-copy append to
|
||||
* it, maybe a folly::io::QueueAppender would be better fit than
|
||||
* folly::io::Appender?
|
||||
*/
|
||||
template <>
|
||||
struct XdrTrait<std::unique_ptr<folly::IOBuf>> {
|
||||
static void serialize(
|
||||
folly::io::Appender& appender,
|
||||
const std::unique_ptr<folly::IOBuf>& buf) {
|
||||
detail::serialize_iobuf(appender, *buf);
|
||||
}
|
||||
|
||||
static std::unique_ptr<folly::IOBuf> deserialize(folly::io::Cursor& cursor) {
|
||||
auto len = XdrTrait<uint32_t>::deserialize(cursor);
|
||||
auto ret = std::make_unique<folly::IOBuf>();
|
||||
cursor.clone(ret, len);
|
||||
detail::skipPadding(cursor, len);
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct XdrTrait<
|
||||
std::vector<T>,
|
||||
|
@ -151,6 +151,44 @@ TEST(XdrSerialize, optionalVariant) {
|
||||
roundtrip(opt2, sizeof(uint32_t));
|
||||
}
|
||||
|
||||
struct IOBufStruct {
|
||||
uint32_t before;
|
||||
std::unique_ptr<folly::IOBuf> buf;
|
||||
uint32_t after;
|
||||
|
||||
bool operator==(const IOBufStruct& other) const {
|
||||
return before == other.before && after == other.after &&
|
||||
folly::IOBufEqualTo()(buf, other.buf);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct XdrTrait<IOBufStruct> {
|
||||
static void serialize(
|
||||
folly::io::Appender& appender,
|
||||
const IOBufStruct& value) {
|
||||
XdrTrait<uint32_t>::serialize(appender, value.before);
|
||||
XdrTrait<std::unique_ptr<folly::IOBuf>>::serialize(appender, value.buf);
|
||||
XdrTrait<uint32_t>::serialize(appender, value.after);
|
||||
}
|
||||
|
||||
static IOBufStruct deserialize(folly::io::Cursor& cursor) {
|
||||
IOBufStruct ret;
|
||||
ret.before = XdrTrait<uint32_t>::deserialize(cursor);
|
||||
ret.buf = XdrTrait<std::unique_ptr<folly::IOBuf>>::deserialize(cursor);
|
||||
ret.after = XdrTrait<uint32_t>::deserialize(cursor);
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
TEST(XdrSerialize, iobuf) {
|
||||
struct IOBufStruct buf {
|
||||
42, folly::IOBuf::copyBuffer("This is a test"), 10
|
||||
};
|
||||
auto bufLen = buf.buf->computeChainDataLength();
|
||||
roundtrip(std::move(buf), 3 * sizeof(uint32_t) + bufLen + 2 /*padding*/);
|
||||
}
|
||||
|
||||
} // namespace facebook::eden
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user