मैं कैसेंड्रा के समान एक डेटाबेस सर्वर विकसित कर रहा हूं।
सी में विकास शुरू किया गया था, लेकिन चीजें कक्षाओं के बिना बहुत जटिल हो गईं।
वर्तमान में मैंने C ++ 11 में सब कुछ चित्रित किया है, लेकिन मैं अभी भी "आधुनिक" C ++ सीख रहा हूं और बहुत सारी चीजों के बारे में संदेह है।
डेटाबेस कुंजी / मूल्य जोड़े के साथ काम करेगा। प्रत्येक जोड़ी के पास कुछ और जानकारी होती है - जब भी बनाई जाती है जब वह समाप्त हो जाएगी (0 यदि समाप्त नहीं होती है)। प्रत्येक जोड़ी अपरिवर्तनीय है।
कुंजी सी स्ट्रिंग है, मान शून्य है *, लेकिन कम से कम इस समय मैं सी स्ट्रिंग के साथ ही मूल्य के साथ काम कर रहा हूं।
अमूर्त IList
वर्ग हैं। यह तीन वर्गों से विरासत में मिला है
VectorList
- सी गतिशील सरणी - एसटीडी के समान :: वेक्टर, लेकिन उपयोग करता हैrealloc
LinkList
- जाँच और प्रदर्शन तुलना के लिए बनाया गया हैSkipList
- अंत में उपयोग किया जाएगा कि वर्ग।
भविष्य में मैं Red Black
पेड़ भी लगा सकता हूं ।
प्रत्येक IList
में जोड़े से शून्य या अधिक पॉइंटर्स होते हैं, जो कुंजी द्वारा क्रमबद्ध होते हैं।
यदि IList
बहुत लंबा हो गया, तो इसे डिस्क पर एक विशेष फ़ाइल में सहेजा जा सकता है। यह विशेष फ़ाइल एक तरह की है read only list
।
यदि आपको एक कुंजी की खोज करने की आवश्यकता है,
- पहले स्मृति
IList
में खोजा जाता है ( याSkipList
, )।SkipList
LinkList
- फिर खोज तिथि द्वारा सॉर्ट की गई फ़ाइलों
(नवीनतम फ़ाइल पहले, सबसे पुरानी फ़ाइल - अंतिम) पर भेजी जाती है ।
ये सभी फाइलें मेमोरी में mmap-ed हैं। - अगर कुछ नहीं मिला, तो चाबी नहीं मिली।
मुझे IList
चीजों के कार्यान्वयन के बारे में कोई संदेह नहीं है ।
वर्तमान में मुझे क्या उलझा रहा है:
जोड़े अलग-अलग आकार के होते हैं, वे द्वारा आवंटित किए जाते हैं new()
और उन्होंने std::shared_ptr
उन्हें इंगित किया है।
class Pair{
public:
// several methods...
private:
struct Blob;
std::shared_ptr<const Blob> _blob;
};
struct Pair::Blob{
uint64_t created;
uint32_t expires;
uint32_t vallen;
uint16_t keylen;
uint8_t checksum;
char buffer[2];
};
"बफर" सदस्य चर विभिन्न आकार के साथ एक है। यह कुंजी + मान संग्रहीत करता है।
उदाहरण के लिए, यदि कुंजी 10 वर्ण की है, और मान 10 बाइट्स का है, तो पूरी वस्तु होगी sizeof(Pair::Blob) + 20
(बफ़र का प्रारंभिक आकार 2 है, क्योंकि दो शून्य समाप्त बाइट्स हैं)
यह एक ही लेआउट डिस्क पर भी उपयोग किया जाता है, इसलिए मैं ऐसा कुछ कर सकता हूं:
// get the blob
Pair::Blob *blob = (Pair::Blob *) & mmaped_array[pos];
// create the pair, true makes std::shared_ptr not to delete the memory,
// since it does not own it.
Pair p = Pair(blob, true);
// however if I want the Pair to own the memory,
// I can copy it, but this is slower operation.
Pair p2 = Pair(blob);
हालाँकि यह भिन्न आकार C ++ कोड वाली बहुत सी जगहों पर एक समस्या है।
उदाहरण के लिए मैं उपयोग नहीं कर सकता std::make_shared()
। यह मेरे लिए महत्वपूर्ण है, क्योंकि अगर मेरे पास 1M जोड़े हैं, तो मेरे पास 2M आवंटन होंगे।
दूसरी तरफ से, अगर मैं डायनेमिक ऐरे (उदाहरण के लिए [चार [123]) को "बफर" करता हूं, तो मैं एमएमएपी "ट्रिक" खो दूंगा, अगर मैं कुंजी जांचना चाहता हूं तो मेरे पास दो डीरेफरेंस होंगे और मैं सिंगल पॉइंटर जोड़ दूंगा - कक्षा को 8 बाइट्स।
मैंने सभी सदस्यों को अंदर से "खींचने" का प्रयास Pair::Blob
किया Pair
, इसलिए Pair::Blob
बस बफर होना चाहिए, लेकिन जब मैंने इसका परीक्षण किया, तो यह काफी धीमा था, शायद ऑब्जेक्ट डेटा को कॉपी करने के कारण।
एक और बदलाव जो मैं सोच रहा हूं वह यह है कि Pair
कक्षा को हटा दें और इसे बदल दें और std::shared_ptr
सभी तरीकों को "पुश" करें Pair::Blob
, लेकिन यह मुझे चर आकार Pair::Blob
वर्ग के साथ मदद नहीं करेगा ।
मैं सोच रहा हूं कि मैं कैसे वस्तु डिजाइन पर अधिक सी + + अनुकूल होने के लिए सुधार कर सकता हूं।
पूर्ण स्रोत कोड यहाँ है:
https://github.com/nmmmnu/HM3
IList::remove
या जब IList नष्ट हो जाता है। इसमें बहुत समय लगता है, लेकिन मैं अलग धागे में करने जा रहा हूं। यह आसान होगा क्योंकि IList std::unique_ptr<IList>
वैसे भी होगा । इसलिए मैं इसे नई सूची के साथ "स्विच" करने में सक्षम होऊंगा और पुरानी वस्तु को कहीं रख सकता हूं जहां मैं डी-टॉर कह सकता हूं।
C string
और डेटा हमेशा कुछ बफर void *
या है char *
, इसलिए आप चार सरणी पास कर सकते हैं। आप समान में redis
या पा सकते हैं memcached
। कुछ बिंदु पर मैं std::string
कुंजी के लिए चार सरणी का उपयोग करने या तय करने का निर्णय ले सकता था , लेकिन यह अभी भी सी स्ट्रिंग होगा।
std::map
याstd::unordered_map
? मान (कुंजियों से जुड़े) कुछ क्यों हैंvoid*
? आपको शायद किसी समय उन्हें नष्ट करने की आवश्यकता होगी; कैसे कब? आप टेम्प्लेट का उपयोग क्यों नहीं करते हैं?