विषय पर बढ़ें

अंतिम अद्यतन:2026-10-12

Protobuf ZeroCopy serialization

1. ZeroCopyStream

protobuf के io interface पर एक ZeroCopyStream है, IO के interface design के लिए, pb ने serialization और deserialization के संबंधित interfaces दिए हैं, जैसे:

// Read a protocol buffer from the given zero-copy input stream.  If
// successful, the entire input will be consumed.
bool ParseFromZeroCopyStream(io::ZeroCopyInputStream* input);

// Write the message to the given zero-copy output stream.  All required
// fields must be set.
bool SerializeToZeroCopyStream(io::ZeroCopyOutputStream* output) const;

ZeroCopyStream के design का मूल उद्देश्य buffer की copy की संख्या को न्यूनतम करना है, यानी stream के आंतरिक data को user buffer में copy करना हटाना। इसलिए, stream एक buffer return कर सकता है, जो buffer वास्तव में सीधे उस final data structure की ओर point करता है जिसमें bytes store होंगे, और caller उस buffer से सीधे interact कर सकता है, जिससे बीच की copy operations हट जाती हैं।

उदाहरण के लिए: classic IO stream:

char buffer[[]BUFFER_SIZE];
input->Read(buffer, BUFFER_SIZE);
DoSomething(buffer, BUFFER_SIZE);

फिर, stream मूल रूप से सिर्फ memcpy() call करके data को pb से user buffer में copy करता है। अगर ZeroCopyInputStream उपयोग करें, तो हमें बस चाहिए:

const void* buffer;
int size;
input->Next(&buffer, &size);
DoSomething(buffer, size);

यहाँ कोई copy नहीं होती, caller अंत में सीधे buffer से पढ़ता है।

ZeroCopyStream दो base classes देता है: ZeroCopyOutputStream/ZeroCopyInputStream।

InputStream का उदाहरण लें, आमतौर पर हम inherit करके अपना ZerCopyStream custom define कर सकते हैं, नीचे के चार interfaces implement करने होंगे।

// implements ZeroCopyInputStream ----------------------------------
bool Next(const void** data, int* size);
void BackUp(int count);
bool Skip(int count);
int64 ByteCount() const;

कुछ rpc frameworks मूल रूप से अपने Stream custom define करते हैं, उदाहरण के लिए: sofa-pbrpc

https://github.com/baidu/sofa-pbrpc/blob/master/src/sofa/pbrpc/buffer.h

2. Demo

एक pb protocol define करें, उदाहरण के लिए: authorization verification:

syntax = "proto3";

message BasicAuth {
  string username = 1;
  string password = 2;
}

फिर serialization और deserialization लिखें:

  • Serialization
BasicAuth auth_message;
auth_message.set_username("user123");
auth_message.set_password("password");

StringOutputStream output_stream(&buf);

auth_message.SerializeToZeroCopyStream(&output_stream);
  • Deserialization
ArrayInputStream input_stream(buf.data(), buf.size());
BasicAuth auth_message;
if (!auth_message.ParseFromZeroCopyStream(&input_stream)) {
    std::cerr << "Failed to parse data." << std::endl;
}

std::cout << "Username: " << auth_message.username() << std::endl;
std::cout << "Password: " << auth_message.password() << std::endl;

इसके बाद हम इसे call कर सकते हैं:

int main() {
    std::string buf;
    buf.reserve(512);
    ser(buf);
    deser(buf);
    return 0;
}

आउटपुट:

Username: user123
Password: password

इस section का अंत, ऊपर का पूरा code 知识星球 में देखें, rpc से जुड़ी सामग्री पर मेरे साथ चर्चा करने के लिए स्वागत है।

(gdb) p *dsr
$8 = {typeInfo = {datumlen = 4, typid = 1082, align = 105 'i', byval = true}, datumStreamVersion = DatumStreamVersion_Original, nth = -1,
  logical_row_count = 16382, datump = 0x3840470 "\277\377\377\377\231\002", physical_datum_index = -1, physical_datum_count = 0,
  datum_beginp = 0x3840470 "\277\377\377\377\231\002", datum_afterp = 0x38503dc "", has_null = true, buffer_beginp = 0x383fc60 "",
  null_bitmap = {buffer = 0x383fc70 "", byteBit = 0 '\000', bytePointer = 0x383fc70 "", bitCount = 16382, bitPosition = -1,
    readBitOnCount = 58981488}, null_bitmap_beginp = 0x0, rle_can_have_compression = false, rle_compress_beginp = 0x0, rle_repeatcountsp = 0x0,
  delta_beginp = 0x0, delta_deltasp = 0x0, delta_datum_p = 0, rle_norepeats_null_bitmap_count = 0, rle_compress_bitmap_count = 0,
  rle_repeatcounts_count = 0, rle_repeatcounts_size = 0, delta_item = false, delta_bitmap_count = 0, deltas_count = 0, deltas_size = 0,
  rle_block_was_compressed = false, rle_compress_bitmap = {buffer = 0x0, byteBit = 0 '\000', bytePointer = 0x0, bitCount = 0, bitPosition = 0,
    readBitOnCount = 0}, rle_repeatcounts_index = 0, rle_in_repeated_item = false, rle_repeated_item_count = 0,
  rle_total_repeat_items_read = 0, delta_block_was_compressed = false, delta_bitmap = {buffer = 0x0, byteBit = 0 '\000',
    bytePointer = 0xff6c00454244 <error: Cannot access memory at address 0xff6c00454244>, bitCount = 0, bitPosition = 0,
    readBitOnCount = 13651600}, eyecatcher = "\000\000\000", physical_data_size = 0, maxDataBlockSize = 13652112,
  errdetailCallback = 0x35daeb0, errdetailArg = 0x34c4e18, errcontextCallback = 0x34c4e18, errcontextArg = 0x383fc60, memctxt = 0x1077c}

संबंधित विषय

टिप्पणियाँ