2016-01-16 3 views
5

साथ serializing जबकि पर विचार इस तरह एक Cap'n'Proto स्कीमा:स्ट्रीम Cap'n'Proto

struct Document { 
    header @0 : Header; 
    records @1 :List(Record); // usually large number of records. 
    footer @2 :Footer; 
} 
struct Header { numberOfRecords : UInt32; /* some fields */ }; 
struct Footer { /* some fields */ }; 
struct Record { 
    type : UInt32; 
    desc : Text; 
    /* some more fields, relatively large in total */ 
} 

अब मैं क्रमानुसार करने (अर्थात निर्माण) एक दस्तावेज उदाहरण और एक रिमोट गंतव्य के लिए यह धारा चाहते हैं।

चूंकि दस्तावेज़ आमतौर पर बहुत बड़ा होता है, इसलिए मैं इसे भेजने से पहले इसे स्मृति में पूरी तरह से बनाना नहीं चाहता हूं। इसके बजाय मैं एक ऐसे निर्माता की तलाश में हूं जो सीधे तार पर संरचना द्वारा संरचना भेजता है। ऐसा कि अतिरिक्त आवश्यक मेमोरी बफर स्थिर है (यानी ओ (अधिकतम (आकार (हेडर), आकार (रिकॉर्ड), आकार (फुटर)))

ट्यूटोरियल सामग्री को देखते हुए मुझे ऐसा निर्माता नहीं मिला है। MallocMessageBuilder (तब आप उस पर writeMessageToFd कहते हैं) पहले स्मृति में सब कुछ बनाने के लिए लगता है।

करता Cap'n'Proto API समर्थन इस तरह के एक यूज-केस?

या Cap'n'Proto अधिक होती है संदेश भेजने के लिए स्मृति में फिट होने वाले संदेशों के लिए उपयोग किया जा सकता है?

इस उदाहरण में, दस्तावेज़ संरचना को छोड़ा जा सकता है और फिर ई सिर्फ एक शीर्षलेख संदेश, एन रिकॉर्ड संदेश और एक पाद लेख का अनुक्रम भेज सकता है। चूंकि कैप 'प्रोटो संदेश स्वयं-सीमित है, यह काम करना चाहिए। लेकिन आप अपना दस्तावेज़ रूट खो देते हैं - शायद कभी-कभी यह वास्तव में एक विकल्प नहीं है।

उत्तर

7

आपके द्वारा उल्लिखित समाधान - दस्तावेज़ के हिस्सों को अलग संदेशों के रूप में भेजना - शायद आपके उपयोग के मामले के लिए सबसे अच्छा है। मूल रूप से, कैप प्रोटो को एक संदेश के स्ट्रीमिंग स्ट्रीमिंग के लिए डिज़ाइन नहीं किया गया है, क्योंकि यह इसके यादृच्छिक-पहुंच गुणों के साथ अच्छी तरह से फिट नहीं होगा (उदाहरण के लिए जब आप एक पॉइंटर का पालन करने का प्रयास करते हैं जो आपको प्राप्त नहीं होता है अभी तक?)। इसके बजाय, जब आप स्ट्रीमिंग करना चाहते हैं, तो आपको एक बड़े संदेश को छोटे संदेशों की श्रृंखला में विभाजित करना चाहिए।

यह कहा गया है कि, अन्य समान प्रणालियों (जैसे प्रोटोबफ) के विपरीत, कैप प्रोटो को मेमोरी में फिट करने के लिए संदेशों की सख्ती से आवश्यकता नहीं होती है। विशेष रूप से, आप mmap(2) का उपयोग करके कुछ चालें कर सकते हैं। यदि आपका दस्तावेज़ डेटा डिस्क पर फ़ाइल से आ रहा है, तो आप फ़ाइल को स्मृति में mmap() कर सकते हैं और फिर इसे अपने संदेश में शामिल कर सकते हैं। mmap() के साथ, ऑपरेटिंग सिस्टम वास्तव में डिस्क से डेटा को तब तक नहीं पढ़ता जब तक आप स्मृति तक पहुंचने का प्रयास नहीं करते हैं, और ओएस पृष्ठों को स्मृति के बाद भी स्मृति से शुद्ध कर सकता है क्योंकि यह जानता है कि यह अभी भी डिस्क पर एक प्रति है। यह अक्सर आपको बहुत आसान कोड लिखने देता है, क्योंकि अब आपको स्मृति प्रबंधन के बारे में सोचना नहीं है।

एक कैप प्रोटो संदेश में mmap() एड खंड को शामिल करने के लिए, आप capnp::Orphanage::referenceExternalData() का उपयोग करना चाहेंगे। उदाहरण के लिए, दिए गए:

struct MyDocument { 
    body @0 :Data; 
    # (other fields) 
} 

आप लिख सकते हैं:

// Map file into memory. 
void* ptr = (kj::byte*)mmap(
    nullptr, size, PROT_READ, MAP_PRIVATE, fd, 0); 
if (ptr == MAP_FAILED) { 
    KJ_FAIL_SYSCALL("mmap", errno); 
} 
auto data = capnp::Data::Reader((kj::byte*)ptr, size); 

// Incorporate it into a message. 
capnp::MallocMessageBuilder message; 
auto root = message.getRoot<MyDocument>(); 
root.adoptDocumentBody(
    message.getOrphanage().referenceExternalData(data)); 

क्योंकि Cap'n आद्य शून्य-प्रतिलिपि है, यह कभी तक पहुँचने के बिना सॉकेट से बाहर सीधे mmap() एड स्मृति लेखन खत्म हो जाएगा यह। यह तब डिस्क से सामग्री को पढ़ने के लिए ओएस तक और सॉकेट में उपयुक्त के रूप में है।

बेशक, आपको अभी भी प्राप्त करने वाले अंत में कोई समस्या है। आपको mmap() एड मेमोरी में पढ़ने के लिए प्राप्त करने वाले अंत को डिज़ाइन करना बहुत मुश्किल लगेगा। एक रणनीति पूरी स्ट्रीम को पहले फ़ाइल (सीधे कैप प्रोटो लाइब्रेरी को शामिल किए बिना) को डंप करने के लिए हो सकती है, फिर mmap() फ़ाइल और का उपयोग mmap() एड डेटा को पढ़ने के लिए करें।

मैं ये सब वर्णन करता हूं क्योंकि यह कैप प्रोटो के साथ एक साफ चीज है लेकिन अधिकांश अन्य धारावाहिक ढांचे (उदाहरण के लिए आप प्रोटोबफ के साथ ऐसा नहीं कर सकते)। mmap() के साथ चाल चलाना कभी-कभी वास्तव में उपयोगी होता है - मैंने इसे Sandstorm, कैप प्रोटो की मूल परियोजना में कई स्थानों पर सफलतापूर्वक उपयोग किया है। हालांकि, मुझे संदेह है कि आपके उपयोग के मामले में, दस्तावेज़ों की एक श्रृंखला में दस्तावेज़ को विभाजित करना शायद अधिक समझ में आता है।

संबंधित मुद्दे