किसी प्रोग्राम को चलाने के दौरान लाइव अपडेट करना कैसे संभव है?


15

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



@derobert बिलकुल नहीं: यह धागा निष्पादकों की विशिष्टताओं में नहीं जाता है। यह प्रासंगिक पृष्ठभूमि प्रदान करता है, लेकिन यह डुप्लिकेट नहीं है।
गाइल्स का SO- बुराई से रोकना '

@ अच्छी तरह से, यदि आप बाकी सामानों को छोड़ दें तो यह बहुत व्यापक है। यहां दो (कम से कम) प्रश्न हैं। और दूसरा सवाल बहुत करीब है, यह पूछ रहा है कि यूनिक्स पर काम करने के लिए फाइलों को बदलना क्यों है।
व्युत्पन्न

यदि आप वास्तव में अपने कोड के साथ ऐसा करना चाहते हैं, तो आप प्रोग्रामिंग भाषा Erlang को देखना चाह सकते हैं, जहां "हॉट" कोड अपडेट एक प्रमुख विशेषता है। learnyousererlang.com/relups
mattdm

1
@ गिल्स बीटीडब्ल्यू: निबंध को आपने प्रतिक्रिया में जोड़ दिया है, तब तक मैंने अपने करीबी वोट को वापस ले लिया है। आपने इस सवाल को एक अच्छी जगह में बदल दिया है ताकि कोई भी यह जान सके कि अपडेट कैसे काम करता है।
derobert

जवाबों:


21

सामान्य रूप से फ़ाइलों को बदलना

सबसे पहले, फ़ाइल को बदलने के लिए कई रणनीतियाँ हैं:

  1. लिखने के लिए मौजूदा फ़ाइल खोलें , इसे 0 लंबाई में काटें, और नई सामग्री लिखें। (एक कम सामान्य संस्करण मौजूदा फ़ाइल को खोलने के लिए है, नई सामग्री के साथ पुरानी सामग्री को अधिलेखित करें, फ़ाइल को छोटी होने पर नई लंबाई तक काट दें।) शेल शब्दों में:

    echo 'new content' >somefile
    
  2. पुरानी फ़ाइल को निकालें , और उसी नाम से एक नई फ़ाइल बनाएँ। शेल शब्दों में:

    rm somefile
    echo 'new content' >somefile
    
  3. एक अस्थायी नाम के तहत एक नई फ़ाइल में लिखें, तो ले जाने के मौजूदा नाम करने के लिए नई फ़ाइल। कदम पुरानी फ़ाइल को हटा देता है। शेल शब्दों में:

    echo 'new content' >somefile.new
    mv somefile.new somefile
    

मैं रणनीतियों के बीच सभी अंतरों को सूचीबद्ध नहीं करूंगा, मैं बस कुछ का उल्लेख करूंगा जो यहां महत्वपूर्ण हैं। स्टैगेटी 1 के साथ, यदि कोई प्रक्रिया वर्तमान में फ़ाइल का उपयोग कर रही है, तो यह प्रक्रिया नई सामग्री को देखती है क्योंकि यह अपडेट हो रही है। यदि प्रक्रिया फ़ाइल सामग्री के समान रहने की अपेक्षा करती है तो यह कुछ भ्रम पैदा कर सकता है। ध्यान दें कि यह केवल उन प्रक्रियाओं के बारे में है, जिनके पास फ़ाइल खुली हुई है (जैसा कि दिखाई दे रहा है lsofया अंदर है ; इंटरैक्टिव एप्लिकेशन जिनके पास एक दस्तावेज़ खुला है (जैसे संपादक में फ़ाइल खोलना) आमतौर पर फ़ाइल को खुला नहीं रखते हैं, वे फ़ाइल सामग्री को लोड करते हैं "ओपन डॉक्यूमेंट" ऑपरेशन और वे "सेव डॉक्यूमेंट" ऑपरेशन के दौरान फाइल (ऊपर दी गई रणनीतियों में से एक का उपयोग करके) को बदलते हैं।/proc/PID/fd/

रणनीतियों 2 और 3 के साथ, यदि कुछ प्रक्रिया में फ़ाइल somefileखुली है, तो पुरानी फ़ाइल सामग्री के उन्नयन के दौरान खुली रहती है। रणनीति 2 के साथ, वास्तव में फ़ाइल को हटाने का चरण केवल निर्देशिका में फ़ाइल की प्रविष्टि को हटाता है। फ़ाइल को केवल तभी हटाया जाता है जब उसके पास कोई निर्देशिका प्रविष्टि नहीं होती है, जिसके कारण उस पर जाता है (विशिष्ट यूनिक्स फाइल सिस्टम पर, एक ही फ़ाइल के लिए एक से अधिक निर्देशिका प्रविष्टि हो सकती है ) और कोई प्रक्रिया नहीं खुली है। यहां इसका अवलोकन करने का एक तरीका है - फ़ाइल केवल तभी निकाली जाती है जब sleepप्रक्रिया को मार दिया जाता है ( rmकेवल इसकी निर्देशिका प्रविष्टि को हटा दिया जाता है)।

echo 'old content' >somefile
sleep 9999999 <somefile &
df .
rm somefile
df .
cat /proc/$!/fd/0
kill $!
df .

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

क्रियान्वयन की जगह

यदि आप लिनक्स पर चल रहे निष्पादन योग्य के साथ रणनीति 1 की कोशिश करते हैं, तो आपको एक त्रुटि मिलेगी।

cp /bin/sleep .
./sleep 999999 &
echo oops >|sleep
bash: sleep: Text file busy

एक "पाठ फ़ाइल" का अर्थ अस्पष्ट ऐतिहासिक कारणों के लिए निष्पादन योग्य कोड वाली फ़ाइल है । लिनक्स, कई अन्य यूनिक्स वेरिएंट की तरह, एक चल रहे प्रोग्राम के कोड को ओवरराइट करने से इनकार करता है; कुछ यूनिक्स वेरिएंट इसकी अनुमति देते हैं, जब तक कि नया कोड पुराने कोड के एक बहुत अच्छी तरह से संशोधित संशोधन नहीं हो जाता है।

लिनक्स पर, आप गतिशील रूप से भरी हुई लाइब्रेरी के कोड को ओवरराइट कर सकते हैं। इसका उपयोग करने वाले प्रोग्राम के क्रैश होने की संभावना है। (आप इसे इसलिए नहीं देख सकते sleepक्योंकि यह शुरू होने पर इसकी आवश्यकता वाले सभी लाइब्रेरी कोड को लोड करता है। अधिक जटिल प्रोग्राम आज़माएं जो सोने के बाद कुछ उपयोगी हो, जैसे perl -e 'sleep 9; print lc $ARGV[0]'।)

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

रणनीतियाँ 2 और 3 निष्पादनयोग्य के लिए भी सुरक्षित हैं: हालाँकि निष्पादन योग्य (और गतिशील रूप से भरी हुई लाइब्रेरी) फ़ाइल डिस्क्रिप्टर होने के अर्थ में फ़ाइलें नहीं खुली हैं, वे बहुत ही समान तरीके से व्यवहार करते हैं। जब तक कोई प्रोग्राम कोड चला रहा होता है, तब तक फ़ाइल बिना डिस्क प्रविष्टि के भी डिस्क पर रहती है।

किसी एप्लिकेशन को अपग्रेड करना

अधिकांश पैकेज प्रबंधक फ़ाइलों को बदलने के लिए रणनीति 3 का उपयोग करते हैं, क्योंकि ऊपर उल्लिखित प्रमुख लाभ - किसी भी समय, फ़ाइल को खोलने से इसका एक वैध संस्करण होता है।

जहां एप्लिकेशन अपग्रेड टूट सकता है, वह यह है कि एक फ़ाइल को अपग्रेड करते समय, एप्लिकेशन को अपग्रेड करना एक संपूर्ण के रूप में है यदि एप्लिकेशन में कई फाइलें (प्रोग्राम, लाइब्रेरी, डेटा,…) शामिल नहीं हैं। घटनाओं के निम्नलिखित अनुक्रम पर विचार करें:

  1. आवेदन का एक उदाहरण शुरू होता है।
  2. एप्लिकेशन अपग्रेड किया गया है।
  3. रनिंग इंस्टेंस एप्लिकेशन इसकी एक डेटा फ़ाइल खोलता है।

चरण 3 में, एप्लिकेशन के पुराने संस्करण की चल रही आवृत्ति नए संस्करण से डेटा फ़ाइल खोल रही है। यह काम करता है या नहीं यह आवेदन पर निर्भर करता है कि यह किस फ़ाइल का है और फ़ाइल को कितना संशोधित किया गया है।

अपग्रेड के बाद, आप ध्यान देंगे कि पुराना प्रोग्राम अभी भी चल रहा है। यदि आप नया संस्करण चलाना चाहते हैं, तो आपको पुराने कार्यक्रम से बाहर निकलकर नया संस्करण चलाना होगा। पैकेज प्रबंधक आमतौर पर एक अपग्रेड पर डेमॉन को मारते हैं और पुनः आरंभ करते हैं, लेकिन एंड-यूज़र एप्लिकेशन को अकेले छोड़ देते हैं।

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


"फिर नई फ़ाइल को मौजूदा नाम पर ले जाएँ। यह चाल पुरानी फ़ाइल को हटा देती है।" यह थोड़ा भ्रमित करने वाला है, क्योंकि यह वास्तव में सिर्फ एक है unlink, जैसा कि आप बाद में कवर करते हैं। शायद "मौजूदा नाम को बदल देता है", लेकिन यह अभी भी कुछ भ्रामक है।
derobert

@derobert मैं "अनलिंक" शब्दावली पर भारी नहीं पड़ना चाहता था। मैं निर्देशिका प्रविष्टि के संदर्भ में "डिलीट" का उपयोग कर रहा हूं, एक सूक्ष्मता जिसे बाद में समझाया गया है। क्या यह उस अवस्था में भ्रामक है?
गाइल्स का SO- बुराई पर रोक '16:

शायद एक अतिरिक्त पैराग्राफ को वारंट करने के लिए पर्याप्त भ्रमित नहीं किया जा सकता है या दो टॉप अप अनलिंक को स्पष्ट कर सकता है। मैं कुछ ऐसे शब्दों के लिए उम्मीद कर रहा हूं जो भ्रमित नहीं है, लेकिन तकनीकी रूप से भी सही है। शायद फिर से "हटाने" का उपयोग करें, जिसे आप पहले से ही समझाने के लिए एक लिंक डालते हैं?
derobert

3

अपग्रेड को प्रोग्राम के चलने के दौरान चलाया जा सकता है, लेकिन जो रनिंग प्रोग्राम आप देखते हैं, वह वास्तव में इसका पुराना संस्करण है। जब तक आप प्रोग्राम बंद नहीं करते तब तक बाइनरी डिस्क पर बनी रहती है।

स्पष्टीकरण: लिनक्स सिस्टम पर, एक फ़ाइल सिर्फ एक इनोड है, जिसमें इसके कई लिंक हो सकते हैं। उदाहरण के लिए। /bin/bashजैसा कि आप देख सिर्फ एक के लिए लिंक है inode 3932163अपने सिस्टम पर। आप पा सकते हैं कि कौन सा इनोड लिंक ls --inode /pathपर जारी करके कुछ लिंक करता है । एक फ़ाइल (इनकोड) केवल तभी हटा दी जाती है जब उसमें इंगित करने वाले शून्य लिंक होते हैं और किसी प्रोग्राम द्वारा उपयोग में नहीं होते हैं। जब पैकेज प्रबंधक उन्नयन उदा। /usr/bin/firefox, यह पहले (हार्ड लिंक को हटाता है /usr/bin/firefox) को अनलिंक करता है, फिर एक नई फ़ाइल बनाता है जिसे /usr/bin/firefoxएक अलग इनोड के लिए एक हार्डलिंक (जिसमें नया firefoxसंस्करण होता है) कहा जाता है। पुराने इनोड को अब मुफ्त में चिह्नित किया गया है और नए डेटा को संग्रहीत करने के लिए पुन: उपयोग किया जा सकता है लेकिन डिस्क पर रहता है (इनकोड केवल तब बनाए जाते हैं जब आप अपना फाइल सिस्टम बनाते हैं और कभी डिलीट नहीं होते हैं)। की अगली शुरुआत परfirefox, नया प्रयोग किया जाएगा।

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


1
दरअसल, यह यूनिक्स पर काम करना (हटाना) फ़ाइलों को हटाने के कारण है; देखें unix.stackexchange.com/questions/49299/… इसके अलावा, कम से कम लिनक्स पर, आप वास्तव में एक रनिंग बाइनरी को नहीं लिख सकते हैं, आपको "पाठ फ़ाइल व्यस्त" त्रुटि मिलेगी।
व्युत्पन्न

अजीब ... तो जैसे कैसे होता है। डेबियन का aptउन्नयन कार्य? मैं Iceweasel( Firefox) सहित समस्याओं के बिना किसी भी चल रहे कार्यक्रम को अपग्रेड कर सकता हूं ।
Psimon

2
APT (या, बल्कि dpkg) फ़ाइलों को अधिलेखित नहीं करता है। इसके बजाय यह उन्हें हटाता है और एक ही नाम के तहत एक नया डालता है। स्पष्टीकरण के लिए मैंने जो प्रश्न और उत्तर दिया है, उसे देखें।
derobert

2
यह सिर्फ इसलिए नहीं है क्योंकि यह अभी भी रैम में है, यह अभी भी डिस्क पर है। कार्यक्रम के अंतिम उदाहरण से बाहर निकलने तक फ़ाइल वास्तव में नष्ट नहीं हुई है।
व्युत्पन्न

2
साइट मुझे संपादित करने का सुझाव नहीं देगी (एक बार आपका प्रतिनिधि काफी अधिक होने के बाद, आप सिर्फ संपादन करते हैं, अब आप उन्हें सुझाव नहीं दे सकते हैं)। इसलिए, एक टिप्पणी के रूप में: यूनिक्स प्रणाली पर एक फ़ाइल (इनोड) का आमतौर पर एक नाम होता है। लेकिन यह अधिक हो सकता है यदि आप ln(हार्ड लिंक) के साथ नाम जोड़ते हैं । आप rm(अनलिंक) नामों को हटा सकते हैं । आप वास्तव में सीधे किसी फ़ाइल को हटा नहीं सकते, केवल उसके नाम हटा सकते हैं। जब किसी फ़ाइल का कोई नाम नहीं है और इसके अतिरिक्त नहीं खुला है, तो कर्नेल इसे हटा देगा। एक रनिंग प्रोग्राम में फ़ाइल खुले से चल रही है, इसलिए सभी नामों को हटाने के बाद भी, फ़ाइल अभी भी आसपास है।
व्युत्पन्न

0

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

अपडेट होने के दौरान पुराने कोड के साथ क्या होता है? आमतौर पर लिनक्स पर एक प्रोग्राम को मेमोरी में लोड किया जाता है, इसलिए प्रोग्राम के चलने के दौरान डिस्क पर निष्पादन योग्य की आवश्यकता नहीं होती है या इसका उपयोग नहीं किया जाता है। वास्तव में आप निष्पादन योग्य को हटा भी सकते हैं और प्रोग्राम को ध्यान नहीं देना चाहिए ... हालाँकि, कुछ प्रोग्रामों को निष्पादन योग्य की आवश्यकता हो सकती है, और कुछ OS (जैसे विंडोज़) निष्पादन योग्य फ़ाइल को लॉक कर देंगे, डिलीट या यहां तक ​​कि नाम बदलने / रोकने के लिए, कार्यक्रम चल रहा है। फ़ायरफ़ॉक्स टूट जाता है, क्योंकि इसका वास्तव में काफी जटिल है और डेटा फ़ाइलों का एक गुच्छा का उपयोग करता है जो यह बताता है कि इसका GUI (उपयोगकर्ता इंटरफ़ेस) कैसे बनाया जाए। एक पैकेज अपडेट के दौरान ये फाइलें अधिलेखित (अपडेट) हो जाती हैं, इसलिए जब एक पुराना फ़ायरफ़ॉक्स निष्पादन योग्य (मेमोरी में) नई GUI फ़ाइलों का उपयोग करने की कोशिश करता है, तो अजीब चीजें हो सकती हैं ...

जब मैं एक प्रोग्राम लिखना चाहता हूं, तो मुझे क्या करना होगा? आपके प्रश्न के बहुत सारे उत्तर पहले से ही हैं। इसे देखें: /programming/232347/how-should-i-implement-an-auto-updater वैसे, प्रोग्रामिंग के बारे में सवाल StackOverflow पर बेहतर हैं।


2
एक्जीक्यूटिव वास्तव में डिमांड-पीडेड (स्वैप किए गए) हैं। वे पूरी तरह से मेमोरी में लोड नहीं होते हैं, और जब भी सिस्टम किसी और चीज के लिए रैम चाहता है, मेमोरी से हटा दिया जा सकता है। पुराना संस्करण वास्तव में डिस्क पर शेष है; unix.stackexchange.com/questions/49299/… देखें । लिनक्स पर कम से कम, आप वास्तव में चल रहे निष्पादन योग्य के लिए नहीं लिख सकते हैं, आपको त्रुटि "पाठ फ़ाइल व्यस्त" मिलेगी। जड़ भी नहीं कर सकते। (आप फ़ायरफ़ॉक्स के बारे में काफी सही हैं, हालांकि)।
व्युत्पन्न
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.