प्रतिनिधि इंटरव्यू विषय

Linux इंटरव्यू: आप फ़ाइल के एटॉमिक अपडेट को क्रैश-सुरक्षित (Crash-Safe) कैसे बनाते हैं?

सामान्यकठिन
Offer.cc संपादकीय टीमप्रकाशित अपडेट किया गया

प्रश्न

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

समस्या और उपयोग के मामले (Use Cases)

इस समस्या में तीन अलग-अलग गारंटी शामिल हैं। एटॉमिक विजिबिलिटी (Atomic visibility) का अर्थ है कि टारगेट पाथ को खोलने वाले रीडर को एक पूरा वर्ज़न दिखाई देता है, न कि इन-प्लेस आंशिक रीराइट। क्रैश ड्यूरेबिलिटी (Crash durability) का अर्थ है कि रीबूट के बाद भी एक्नॉलेज्ड वर्ज़न पहुंच योग्य (reachable) बना रहता है। राइटर आइसोलेशन (Writer isolation) यह तय करता है कि जब दो अपडेट के बीच रेस होती है तो क्या होता है। एक अकेला rename() अपने फ़ाइल सिस्टम कॉन्ट्रैक्ट के तहत केवल पहली गारंटी को पूरा करता है।

एक लोकल Linux फ़ाइल सिस्टम मान लें जो fsync() और एटॉमिक सेम-फ़ाइलसिस्टम रिप्लेसमेंट, एक सीरियलाइज़्ड राइटर और उसी प्रोटोकॉल द्वारा लिखे गए पहले से कमिट किए गए वर्ज़न को सही ढंग से लागू करता है। 64 KiB का आकार इंटरव्यू की एक पूर्वधारणा (assumption) है। नेटवर्क फ़ाइल सिस्टम, ख़राब हार्डवेयर जो कैश फ़्लश के बारे में गलत जानकारी देता है, मल्टी-फ़ाइल ट्रांज़ैक्शन और प्रतिकूल डायरेक्टरी संशोधन के लिए अलग कॉन्ट्रैक्ट की आवश्यकता होती है।

विशिष्ट उपयोगों में कॉन्फ़िगरेशन स्नैपशॉट, लोकल एजेंट स्टेट, चेकपॉइंट मैनिफ़ेस्ट, पैकेज मेटाडेटा और एडिटर सेव शामिल हैं। यदि स्टेट कई फ़ाइलों में फैली हुई है या क्वेरीज़ और कंकरेंट ट्रांज़ैक्शन की आवश्यकता है, तो इस प्रोटोकॉल को मैन्युअली बढ़ाने की तुलना में एक एम्बेडेड डेटाबेस या जर्नल आमतौर पर अधिक सुरक्षित होता है।

इंटरव्यूअर क्या मूल्यांकन कर रहा है

पहला संकेत यह है कि क्या उम्मीदवार write() की सफलता, rename() की एटॉमीसिटी और ड्यूरेबल कमिट के बीच अंतर करता है। Linux दस्तावेज़ बताता है कि write() आंशिक हो सकता है और सफल रिटर्न डिस्क पर्सिस्टेंस साबित नहीं करता है। fsync(file) फ़ाइल के संशोधित डेटा और संबंधित मेटाडेटा को फ़्लश करता है, लेकिन ज़रूरी नहीं कि इसकी डायरेक्टरी एंट्री को पर्सिस्ट करे। उस अंतिम चरण के लिए fsync(parent_directory) की आवश्यकता होती है।

दूसरा संकेत क्रम (ordering) है। नेमस्पेस द्वारा टारगेट नाम को नए बाइट्स पर पॉइंट करने से पहले उन बाइट्स का ड्यूरेबल होना आवश्यक है। इसके बाद सफलता की रिपोर्ट करने से पहले डायरेक्टरी एंट्री का ड्यूरेबल होना आवश्यक है। किसी भी बैरियर को उलटने या छोड़ने से क्रैश विंडो बन जाती है।

तीसरा संकेत स्पष्ट फ़ेलियर सेमेंटिक्स है। fsync() विलंबित EIO, ENOSPC या कोटा विफलताओं को प्रकट कर सकता है। यदि अंतिम डायरेक्टरी सिंक विफल हो जाता है, तो हो सकता है कि रीनेम पहले से ही दिखाई दे रहा हो जबकि ड्यूरेबिलिटी अज्ञात हो। API को अनिर्धारित विफलता (indeterminate failure) रिटर्न करनी चाहिए, न कि सफलता का दावा करना चाहिए या यह दिखावा करना चाहिए कि यह हमेशा रोलबैक कर सकता है।

उत्तर देने से पहले स्पष्टीकरण हेतु प्रश्न

  • क्या "एटॉमिक" प्रोसेस क्रैश या होस्ट पावर लॉस को कवर करता है? केवल प्रोसेस का बंद होना कर्नेल पेज कैश को जीवित छोड़ देता है; प्रश्न में होस्ट-क्रैश ड्यूरेबिलिटी और इसलिए सिंक बैरियर की आवश्यकता है।
  • क्या टारगेट डॉक्यूमेंटेड सेमेंटिक्स वाले लोकल फ़ाइल सिस्टम पर है? NFS, FUSE, ओवरले फ़ाइल सिस्टम और असामान्य स्टोरेज स्टैक अलग-अलग एरर और पर्सिस्टेंस व्यवहार प्रदान कर सकते हैं। वास्तविक डिप्लॉयमेंट कॉन्ट्रैक्ट का परीक्षण करें।
  • क्या एक से अधिक राइटर हैं? यह बेस डिज़ाइन राइटर्स को सीरियलाइज़ करता है। यूनीक टेम्परेरी नाम टकराव को रोकते हैं लेकिन लास्ट-राइटर-विन्स अपडेट को नहीं रोकते।
  • क्या कई फ़ाइलें एक साथ बदलनी चाहिए? एक रीनेम केवल एक पाथनेम रिप्लेसमेंट को कमिट करता है। मल्टी-फ़ाइल इन्वेरिएंट के लिए जनरेशन डायरेक्टरी, जर्नल या डेटाबेस का उपयोग करें।
  • क्या कोई पुराना ओपन फ़ाइल डिस्क्रिप्टर पुराने वर्ज़न को पढ़ना जारी रख सकता है? हाँ। Rename डायरेक्टरी मैपिंग को बदल देता है; पहले से खुला डिस्क्रिप्टर अभी भी पुराने इनोड को संदर्भित करता है। नवीनतम जनरेशन की आवश्यकता होने पर रीडर्स को फ़ाइल फिर से खोलनी होगी।
  • मान्य कंटेंट क्या माना जाता है? पब्लिश करने से पहले सीरियलाइज़ेशन, स्कीमा, चेकसम और वर्ज़न को वैलिडेट करें। फ़ाइल सिस्टम की एटॉमीसिटी किसी मैलफ़ॉर्मड लेकिन पूर्ण पेलोड को सही नहीं बना सकती है।

30-सेकंड का उत्तर फ़्रेमवर्क

"मैं एटॉमिक विजिबिलिटी को ड्यूरेबिलिटी से अलग करता हूँ। मैं पैरेंट डायरेक्टरी खोलता हूँ, एक्सक्लूसिव क्रिएशन के साथ उसी डायरेक्टरी में एक यूनीक टेम्परेरी फ़ाइल बनाता हूँ, सभी बाइट्स स्वीकार होने तक लूप में लिखता हूँ, आवश्यक मेटाडेटा सेट करता हूँ और टेम्परेरी फ़ाइल पर fsync चलाता हूँ। फिर मैं इसे बंद करता हूँ, इसे टारगेट पर एटॉमिक रूप से रीनेम करता हूँ और सफलता रिटर्न करने से पहले पैरेंट डायरेक्टरी पर fsync चलाता हूँ। फ़ाइल सिंक नए इनोड कंटेंट को ड्यूरेबल बनाता है; रीनेम एक पूर्ण वर्ज़न पब्लिश करता है; डायरेक्टरी सिंक उस नेम-टू-इनोड बदलाव को ड्यूरेबल बनाता है। मैं राइटर्स को सीरियलाइज़ करता हूँ, हर सिस्कॉल एरर को—अंतिम डायरेक्टरी-सिंक विफलता सहित—एक स्पष्ट अनिर्धारित स्थिति के साथ गैर-सफलता मानता हूँ, रिकवरी के दौरान अनाथ टेम्परेरी फ़ाइलों को साफ़ करता हूँ, और ड्यूरेबिलिटी प्रमाण के रूप में प्रोसेस किल का उपयोग करने के बजाय हर स्टेप के बाद पावर-लॉस पॉइंट्स का परीक्षण करता हूँ।"

चरण-दर-चरण गहन विश्लेषण

कॉलर के दृष्टिकोण से कमिट पॉइंट को परिभाषित करें: केवल एक सफल पैरेंट-डायरेक्टरी fsync ही एक्नॉलेज्ड सफलता की अनुमति देता है। कार्यान्वयन की रूपरेखा है:

text
durableReplace(parentDir, targetName, bytes):
  dirfd = open(parentDir, read-only | directory | close-on-exec)
  tmpName = uniqueSiblingName(targetName)
  tmpfd = openat(dirfd, tmpName, create | exclusive | write-only | close-on-exec, mode)

  writeAll(tmpfd, bytes)          // retry EINTR; advance after partial writes
  setRequiredMetadata(tmpfd)      // mode/ownership if part of the contract
  fsync(tmpfd)                    // check delayed I/O and allocation errors
  close(tmpfd)                    // check the result

  renameat(dirfd, tmpName, dirfd, targetName)
  fsync(dirfd)                    // persist the namespace change
  close(dirfd)
  return committed

टेम्परेरी फ़ाइल टारगेट की सिबलिंग होनी चाहिए। समान-डायरेक्टरी प्लेसमेंट रीनेम को एक ही फ़ाइल सिस्टम पर रखता है और EXDEV कॉपी फ़ॉलबैक से बचाता है। एक्सक्लूसिव क्रिएशन और नॉन-प्रेडिक्टेबल प्रोसेस-लोकल सफ़िक्स का उपयोग करें; किसी अटैकर-नियंत्रित मौजूदा सिम्लिंक का अनुसरण न करें। फ़ाइल सिंक से पहले अनुमतियाँ (permissions) सेट करें ताकि आवश्यक मेटाडेटा ड्यूरेबल फ़ाइल स्टेट में शामिल हो जाए।

writeAll एक रेगुलर फ़ाइल के लिए भी मायने रखता है। अनुरोधित संख्या से छोटा पॉज़िटिव रिटर्न एक आंशिक राइट है, इसलिए बफ़र को आगे बढ़ाएँ और जारी रखें। केवल उचित इंटरप्टेड ऑपरेशन को पुनः प्रयास करें। एक सफल write() का अर्थ है कि डेटा कर्नेल की स्वीकृत स्थिति तक पहुँच गया है, स्थिर मीडिया पर नहीं। केवल close() कमिट बैरियर नहीं है, और त्रुटियों की सूचना बाद में fsync() द्वारा दी जा सकती है।

इसके बाद, टेम्परेरी फ़ाइल को सिंक करें। fsync संशोधित फ़ाइल डेटा और इनोड मेटाडेटा को कवर करता है और स्टोरेज डिवाइस द्वारा पूरा होने की रिपोर्ट करने की प्रतीक्षा करता है। fdatasync असंबंधित मेटाडेटा कार्य को कम कर सकता है, लेकिन इसे अभी भी डेटा प्राप्त करने के लिए आवश्यक मेटाडेटा (जैसे फ़ाइल का आकार) को पर्सिस्ट करना होगा। एक सरल और ऑडिट करने योग्य उत्तर के लिए, fsync का उपयोग करें जब तक कि माप और सटीक फ़ाइल सिस्टम कॉन्ट्रैक्ट fdatasync को उचित न ठहराएं।

उस सिंक के सफल होने के बाद ही renameat को टारगेट को बदलना चाहिए। Linux गारंटी देता है कि, जब डेस्टिनेशन पहले से मौजूद होता है, तो डेस्टिनेशन खोलने वाला कोई अन्य प्रोसेस ऐसा कोई क्षण नहीं देखता जब वह गायब हो। जिस रीडर के पास पुरानी फ़ाइल पहले से खुली है, वह पुराने इनोड को पढ़ना समाप्त कर सकता है; बाद में ओपन करने पर नया इनोड प्राप्त होता है। दोनों पूर्ण वर्ज़न हैं, जो कि वांछित रीड कॉन्ट्रैक्ट है।

Rename डायरेक्टरी मेटाडेटा को अपडेट करता है। फ़ाइल fsync आवश्यक रूप से उस डायरेक्टरी एंट्री को ड्यूरेबल नहीं बनाता है, इसलिए पैरेंट डायरेक्टरी खोलें और रीनेम के बाद इसे सिंक करें। यह क्रम ही इसका प्रमाण है:

text
new contents durable
  -> target name atomically points to new inode
  -> target-name mapping durable
  -> caller may receive success

Rename से पहले, क्रैश होने पर पुराना टारगेट और एक अनाथ टेम्परेरी फ़ाइल रह सकती है। Rename के बाद लेकिन डायरेक्टरी सिंक से पहले, दिखाई देने वाला टारगेट नया हो सकता है, जबकि रीबूट के बाद की पहुंच का अभी वादा नहीं किया गया है। एक सफल डायरेक्टरी सिंक के बाद, एक्नॉलेज्ड टारगेट मैपिंग और पहले से सिंक किया गया कंटेंट कमिटेड जनरेशन बनाते हैं। रिकवरी ओनरशिप और नेमिंग को वैलिडेट करने के बाद केवल पहचानी जा सकने वाली पुरानी टेम्परेरी फ़ाइलों को हटाती है; यह केवल इसलिए टारगेट को कभी नहीं हटाती क्योंकि पिछले ऑपरेशन ने कोई एरर रिटर्न किया था।

एरर रिपोर्टिंग के लिए बूलियन सफलता की तुलना में अधिक समृद्ध स्थिति की आवश्यकता होती है। Rename से पहले, विफलता not_committed है और पुराना कमिटेड टारगेट आधिकारिक बना रहता है। Rename के बाद, डायरेक्टरी-सिंक विफलता indeterminate है: नई फ़ाइल दिखाई दे सकती है और क्रैश से बच भी सकती है या नहीं भी। एक एरर रिटर्न करें, डायग्नोस्टिक्स बनाए रखें, और रिकवरी को जनरेशन नंबर या चेकसम का निरीक्षण करने दें। पुराने मान को आँख मूंदकर वापस लिखने से एक और अनकमिटेड ट्रांज़िशन बनता है और यह किसी नए राइटर को ओवरराइट कर सकता है।

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

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

हर सीमा पर प्रोटोकॉल का परीक्षण करें: आंशिक राइट; EINTR; ENOSPC; फ़ाइल-सिंक EIO; फ़ाइल सिंक से पहले और बाद में क्रैश; रीनेम से पहले, दौरान और बाद में क्रैश; और डायरेक्टरी-सिंक विफलता। रीबूट के बाद, पुष्टि करें कि टारगेट पार्स होता है, या तो अंतिम एक्नॉलेज्ड जनरेशन या अनुमत अन-एक्नॉलेज्ड नई जनरेशन से मेल खाता है, और कभी भी बाइट मिश्रण नहीं है। यह भी सुनिश्चित करें कि प्रत्येक एक्नॉलेज्ड जनरेशन बची रहे। एक प्रोसेस SIGKILL टेस्ट क्लीनअप और फ़ाइल-डिस्क्रिप्टर व्यवहार की जाँच करता है, लेकिन केवल एक नियंत्रित VM या स्टोरेज क्रैश टेस्ट ही वोलेटाइल कैश के नुकसान की स्थिति का परीक्षण करता है।

उच्च गुणवत्ता वाला नमूना उत्तर

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

मैं पैरेंट डायरेक्टरी खोलता हूँ और टारगेट के पास एक एक्सक्लूसिव, यूनीक टेम्परेरी फ़ाइल बनाता हूँ। मैं write पर लूप चलाता हूँ क्योंकि यह कम काउंट रिटर्न कर सकता है, आवश्यक अनुमतियाँ लागू करता हूँ, टेम्परेरी फ़ाइल पर fsync कॉल करता हूँ, और हर परिणाम की जाँच करता हूँ। फिर मैं सिबलिंग फ़ाइल को टारगेट पर रीनेम करता हूँ। वह रीनेम ही एटॉमिक विजिबिलिटी बाउंड्री है: मौजूदा रीडर्स पुराने इनोड को बनाए रख सकते हैं, जबकि नए ओपन पूर्ण नए इनोड को प्राप्त करते हैं।

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

मैं आंशिक राइट्स और प्रत्येक सिस्कॉल विफलता में फ़ॉल्ट इंजेक्ट करूँगा, फिर हर बाउंड्री पर एक VM को क्रैश करूँगा। इन्वेरिएंट यह है कि टारगेट हमेशा एक मान्य पुरानी या नई जनरेशन हो, कभी भी अधूरा मिश्रण न हो, और प्रत्येक एक्नॉलेज्ड जनरेशन रीबूट के बाद बनी रहे। यदि मुझे कंकरेंट राइटर्स या मल्टी-फ़ाइल ट्रांज़ैक्शन की आवश्यकता है, तो मैं यह दावा करने के बजाय कि रीनेम उन समस्याओं को हल करता है, जनरेशन चेक और लॉकिंग जोड़ता हूँ या जर्नल/डेटाबेस पर स्विच करता हूँ।"

सामान्य गलतियाँ

  • टारगेट को इन-प्लेस ओवरराइट करना → क्रैश होने पर अधूरा या मिश्रित कंटेंट सामने आता है → एक पूर्ण सिबलिंग फ़ाइल तैयार करें और उसे रीनेम करें।
  • यह मान लेना कि एक write() सब कुछ लिख देता है → शॉर्ट राइट्स स्टेज्ड फ़ाइल को चुपचाप काट (truncate) देते हैं → सभी बाइट्स लिखे जाने तक या कोई एरर ऑपरेशन समाप्त होने तक लूप चलाएँ।
  • टेम्परेरी फ़ाइल को सिंक करने से पहले रीनेम कॉल करना → ड्यूरेबल नाम अधूरे या खोए हुए डेटा को इंगित कर सकता है → पब्लिश करने से पहले नए इनोड को सिंक करें।
  • रीनेम को ड्यूरेबल कमिट मानना → एटॉमिक विजिबिलिटी डायरेक्टरी एंट्री को पर्सिस्ट नहीं करती है → रीनेम के बाद पैरेंट डायरेक्टरी को सिंक करें।
  • दूसरे माउंट पर टेम्प डायरेक्टरी का उपयोग करना → रीनेम EXDEV के साथ विफल हो जाता है या नॉन-एटॉमिक कॉपी में बदल जाता है → टारगेट डायरेक्टरी में ही टेम्प फ़ाइल बनाएं।
  • fsync एरर्स को अनदेखा करना → विलंबित स्टोरेज विफलता गलत सफलता बन जाती है → एक स्पष्ट गैर-सफलता या अनिर्धारित परिणाम प्रोपेगेट करें।
  • केवल SIGKILL से परीक्षण करना → कर्नेल कैश प्रोसेस समाप्त होने के बाद भी बच जाता है → नियंत्रित होस्ट/स्टोरेज क्रैश इंजेक्शन जोड़ें।
  • कंकरेंट राइटर्स को रेस करने देना → व्यक्तिगत रूप से एटॉमिक अपडेट भी एक जनरेशन खो देते हैं → सीरियलाइज़ करें या अपेक्षित जनरेशन की तुलना करें।

फॉलो-अप प्रश्न और उत्तर

फॉलो-अप 1: fsync(temp) अपर्याप्त क्यों है?

यह फ़ाइल सिस्टम कॉन्ट्रैक्ट के तहत टेम्परेरी इनोड के कंटेंट और संबंधित मेटाडेटा को ड्यूरेबल बनाता है। टारगेट पाथनेम एक डायरेक्टरी एंट्री है। रीनेम के बाद, वह मैपिंग बदल गई है, और Linux स्पष्ट रूप से कहता है कि फ़ाइल सिंक आवश्यक रूप से युक्त डायरेक्टरी एंट्री को पर्सिस्ट नहीं करता है। एक्नॉलेज करने से पहले पैरेंट डायरेक्टरी को सिंक करें।

फॉलो-अप 2: यदि किसी अन्य प्रोसेस ने पहले से ही टारगेट खोल रखा है तो क्या rename() एटॉमिक है?

पाथ लुकअप के लिए नेमस्पेस रिप्लेसमेंट एटॉमिक है। एक मौजूदा डिस्क्रिप्टर पुराने इनोड को संदर्भित करना जारी रखता है, जबकि एक नया ओपन नए इनोड को प्राप्त करता है। यदि किसी रीडर को कई रीड्स में एक ही जनरेशन की आवश्यकता होती है, तो उसे बीच में दोबारा खोलने के बजाय एक डिस्क्रिप्टर को खुला रखना चाहिए।

फॉलो-अप 3: रीनेम के बाद डायरेक्टरी fsync विफल होने पर API को क्या रिटर्न करना चाहिए?

अनिर्धारित कमिट स्थिति के साथ एक एरर रिटर्न करें। रीनेम पहले से ही दिखाई दे सकता है, और एप्लिकेशन यह साबित नहीं कर सकता कि यह रीबूट के बाद बचेगा या नहीं। अभीष्ट जनरेशन और एरर को रिकॉर्ड करें, सफलता का दावा करना बंद करें, और रिकवरी को टारगेट को वैलिडेट करने दें। एक ऑटोमैटिक ब्लाइंड रोलबैक बाद के मान्य अपडेट को नष्ट कर सकता है।

फॉलो-अप 4: क्या fdatasync, fsync की जगह ले सकता है?

जब प्लेटफ़ॉर्म कॉन्ट्रैक्ट और माप इसे उचित ठहराते हैं तब यह ले सकता है। यह बाद में डेटा पुनः प्राप्ति से असंबंधित मेटाडेटा को छोड़ देता है, लेकिन फिर भी आवश्यक मेटाडेटा जैसे फ़ाइल आकार को पर्सिस्ट करना चाहिए। यह रीनेम के बाद पैरेंट डायरेक्टरी को सिंक करने की आवश्यकता को समाप्त नहीं करता है। सामान्य उत्तर में fsync को प्राथमिकता दें क्योंकि इसके कॉन्ट्रैक्ट का ऑडिट करना आसान है।

फॉलो-अप 5: आप तीन फ़ाइलों को एटॉमिक रूप से कैसे अपडेट करेंगे?

तीन स्वतंत्र रीनेम मिश्रित जनरेशन को उजागर कर सकते हैं। सभी फ़ाइलों को एक इम्यूटैबल जनरेशन डायरेक्टरी के तहत लिखें, उस डायरेक्टरी को ड्यूरेबल बनाएं, फिर एक मैनिफ़ेस्ट या पॉइंटर को एटॉमिक रूप से स्विच और सिंक करें; वैकल्पिक रूप से एक जर्नल या एम्बेडेड डेटाबेस का उपयोग करें। रीडर्स एक जनरेशन तय करते हैं और ऑपरेशन के लिए उसे बनाए रखते हैं।

फॉलो-अप 6: दो राइटर अपडेट खोने (lost updates) से कैसे बचते हैं?

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

सार्वजनिक स्रोत

संबंधित प्रश्न