लिखने के नियमों की चुनौतियां

किसी समस्या की शिकायत करें सोर्स देखें रात · 7.4 को अपनाएं. 7.3 · 7.2 · 7.1 · 7.0 · 6.5

इस पेज पर खास समस्याओं और चुनौतियों के बारे में खास जानकारी दी गई है बेज़ेल के बेहतर नियमों को बनाया जा सकता है.

खास जानकारी में ज़रूरी शर्तें

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

अनुमान

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

सही नतीजे, थ्रूपुट, इस्तेमाल में आसानी, और इंतज़ार का समय

हम मान लेते हैं कि बिल्ड सिस्टम के साथ सबसे पहले और सबसे अच्छी तरह सही होने चाहिए काफ़ी अहम माने जाते हैं. दिए गए सोर्स ट्री के लिए, एक जैसा बिल्ड हमेशा एक जैसा होना चाहिए. इससे कोई फ़र्क़ नहीं पड़ता कि आउटपुट ट्री कैसा दिखता है पसंद. इसका मतलब है कि Bazel को किसी भी बिल्ड चरण में शामिल हर इनपुट के बारे में पता होना चाहिए, ताकि इनपुट में कोई बदलाव होने पर वह उस चरण को फिर से चला सके. Bazel के सटीक होने की सीमाएं होती हैं, क्योंकि यह कुछ जानकारी लीक करता है. जैसे, बिल्ड की तारीख / समय. साथ ही, यह कुछ तरह के बदलावों को अनदेखा करता है. जैसे, फ़ाइल एट्रिब्यूट में बदलाव. सैंडबॉक्सिंग इससे यह पक्का किया जाता है कि जानकारी सही है. ऐसा करने पर, ऐसी इनपुट फ़ाइलों को पढ़ने से रोका जाता है जिनका एलान नहीं किया गया है. सिस्टम की अंदरूनी सीमाओं के अलावा, सही होने से जुड़ी कुछ समस्याएं भी हैं. इनमें से ज़्यादातर समस्याएं, फ़ाइलसेट या C++ नियमों से जुड़ी हैं. ये दोनों समस्याएं हल करना मुश्किल है. हम इन्हें ठीक करने के लिए लंबे समय तक काम करते रहते हैं.

बिल्ड सिस्टम का दूसरा लक्ष्य ज़्यादा डेटा इकट्ठा करना है; हम हैं मौजूदा समय में किए जा सकने वाले कामों की सीमाओं को लगातार करना रिमोट एक्ज़ीक्यूशन सेवा के लिए मशीन आवंटन. अगर रिमोट तरीके से एक्ज़ीक्यूट किया जाता है, तो सेवा ओवरलोड हो जाती है, इसलिए कोई भी काम नहीं कर सकता.

आगे, इस्तेमाल करने में आसानी होगी. रिमोट तौर पर प्रोग्राम चलाने की सेवा के एक जैसे (या मिलते-जुलते) फ़ुटप्रिंट वाले कई सही तरीकों में से, हम उस तरीके को चुनते हैं जिसका इस्तेमाल करना आसान हो.

इंतज़ार का समय, किसी बिल्ड को शुरू करने से लेकर ज़रूरी नतीजा पाने में लगने वाले समय को दिखाता है. भले ही, वह नतीजा पास या फ़ेल हुए टेस्ट का टेस्ट लॉग हो या BUILD फ़ाइल में टाइप होने वाली गड़बड़ी का मैसेज.

ध्यान दें कि ये लक्ष्य अक्सर ओवरलैप होते हैं; इंतज़ार का समय उतना ही होता है जितना कि थ्रूपुट की रिमोट एक्ज़ीक्यूशन सेवा को सही तरीके से लागू करना हो.

डेटा स्टोर करने की बहुत बड़ी जगह

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

BUILD जैसी जानकारी वाली भाषा

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

ऐतिहासिक

Basel के अलग-अलग वर्शन में कुछ ऐसे अंतर होते हैं जिनकी वजह से चुनौतियां होती हैं. साथ ही, कुछ नीचे दिए गए सेक्शन में इनकी जानकारी दी गई है.

लोड करने, विश्लेषण करने, और लागू करने के बीच का फ़र्क़ अब पुराना हो गया है. हालांकि, अब भी इसका असर एपीआई पर पड़ता है

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

इसका मतलब है कि नियम एपीआई के लिए, नियम के बारे में जानकारी देना ज़रूरी है (इसमें क्या-क्या विशेषताएं हैं, और किस तरह के एट्रिब्यूट हैं). कुछ अपवाद, जहां API कस्टम कोड को लोडिंग चरण के दौरान आउटपुट फ़ाइलों के इंप्लिसिट नामों और एट्रिब्यूट की इंप्लिसिट वैल्यू का पता लगा सकता है. इसके लिए उदाहरण के लिए, 'foo' नाम का java_library नियम है इंप्लिसिट रूप से नाम का एक आउटपुट जनरेट करता है 'libfoo.Jar' में जोड़ा गया है, जिसका रेफ़रंस बिल्ड ग्राफ़ में दिए गए अन्य नियमों में दिया जा सकता है.

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

Intrinsic

कुछ ऐसी प्रॉपर्टी होती हैं जिनके लिए नियम लिखना मुश्किल होता है. इनमें से कुछ सबसे सामान्य प्रॉपर्टी के बारे में यहां बताया गया है.

रिमोट तरीके से एक्ज़ीक्यूट करना और कैश मेमोरी में सेव करना मुश्किल होता है

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

फ़िलहाल, प्रोटोकॉल के मुताबिक यह ज़रूरी है कि बिल्ड सिस्टम को किसी कार्रवाई के सभी इनपुट पहले से पता हों. इसके बाद, बिल्ड सिस्टम एक यूनीक ऐक्शन फ़िंगरप्रिंट कैलकुलेट करता है और शेड्यूलर से कैश मेमोरी में मौजूद डेटा का इस्तेमाल करने के लिए कहता है. कैश मेमोरी हिट मिलने पर, शेड्यूलर, आउटपुट फ़ाइलों के ब्यौरे के साथ जवाब देता है; फ़ाइलें अपने-आप जिसे डाइजेस्ट ने बाद में इकट्ठा किया था. हालांकि, इससे Bazel के नियमों पर पाबंदियां लगती हैं. इन नियमों के तहत, सभी इनपुट फ़ाइलों को पहले से एलान करना ज़रूरी होता है.

सही और तेज़ इंक्रीमेंटल बिल्ड के लिए बदलाव की जानकारी का इस्तेमाल करने के लिए, कोडिंग के असामान्य पैटर्न की ज़रूरत होती है

ऊपर, हमने तर्क दिया कि सही होने के लिए, बेज़ल को सभी इनपुट जानने की ज़रूरत है ऐसी फ़ाइलें जिन्हें बिल्ड चरण में भेजा जाता है, ताकि यह पता लगाया जा सके कि वह बिल्ड स्टेप अब भी अप-टू-डेट है. पैकेज लोडिंग और नियम के विश्लेषण पर भी यही बात लागू होती है. हम Skyframe को इस तरह डिज़ाइन किया गया है कि किया जा सकता है. Skyframe एक ग्राफ़ लाइब्रेरी और आकलन फ़्रेमवर्क है, जो लक्ष्य नोड (जैसे कि 'build //foo' के साथ इन विकल्पों का)) और उसे इसके तहत, कॉम्पोनेंट, ज़रूरी कॉम्पोनेंट का आकलन करके, इन्हें इकट्ठा किया जाता है. नतीजा. इस प्रोसेस के तहत, SkyFrame पैकेज को पढ़ता है, नियमों का विश्लेषण करता है, और कार्रवाइयों को लागू करता है.

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

इसके तहत, हर नोड डिपेंडेंसी खोजने की प्रोसेस करता है. हर नोड, डिपेंडेंसी का एलान कर सकता है. इसके बाद, उन डिपेंडेंसी के कॉन्टेंट का इस्तेमाल करके, और भी डिपेंडेंसी का एलान किया जा सकता है. सैद्धांतिक तौर पर, यह थ्रेड-पर-नोड मॉडल. हालांकि, मीडियम साइज़ के बिल्ड में हज़ारों Skyframe नोड होते हैं. इन्हें मौजूदा Java टेक्नोलॉजी की मदद से आसानी से नहीं बनाया जा सकता. साथ ही, पुरानी वजहों से, फ़िलहाल हमें Java का इस्तेमाल करना पड़ता है. इसलिए, इसमें लाइटवेट थ्रेड और कंटिन्यूएशन नहीं होते.

इसके बजाय, Bazel तय साइज़ वाले थ्रेड पूल का इस्तेमाल करता है. हालांकि, इसका मतलब है कि अगर कोई नोड ऐसी डिपेंडेंसी का एलान करता है जो अभी तक उपलब्ध नहीं है. हो सकता है कि हम उसे रद्द करना पड़े जांच करें और इसे (किसी दूसरे थ्रेड में) को रीस्टार्ट करें, जब डिपेंडेंसी उपलब्ध हैं. इसका मतलब है कि नोड को यह काम बहुत ज़्यादा नहीं करना चाहिए; एक वह नोड जो क्रम के हिसाब से N डिपेंडेंसी के बारे में बताता है, उसे N बार रीस्टार्ट किया जा सकता है. O(N^2) बार लागत आती है. इसके बजाय, हम पहले ही बल्क में एलान करते हैं डिपेंडेंसी के लिए कभी-कभी कोड को फिर से व्यवस्थित करने या उसे रीस्टार्ट की संख्या को सीमित करने के लिए, एक नोड को कई नोड में जोड़ देता है.

ध्यान दें कि यह तकनीक अभी नियम एपीआई में उपलब्ध नहीं है; इसके बजाय, एपीआई के नियम, लोडिंग, विश्लेषण, और और एक्ज़ीक्यूशन के चरण शामिल करें. हालांकि, एक बुनियादी पाबंदी यह है कि अन्य नोड को ऐक्सेस करने के लिए, फ़्रेमवर्क का इस्तेमाल करना ज़रूरी है, ताकि वह उनसे जुड़ी डिपेंडेंसी को ट्रैक कर सके. भले ही, वह भाषा कुछ भी हो जिसमें बिल्ड सिस्टम लागू किया गया हो या जिसमें नियम लिखे गए हों (उन्हें समान), नियम के लेखकों को स्टैंडर्ड लाइब्रेरी या पैटर्न का इस्तेमाल नहीं करना चाहिए स्काईफ़्रेम. Java के लिए, इसका मतलब है java.io.File और किसी भी तरह के प्रतिबिंब और किसी भी लाइब्रेरी से भी मिल सकता है. इन लो-लेवल इंटरफ़ेस के डिपेंडेंसी इंजेक्शन की सुविधा वाली लाइब्रेरी को, Skyframe के लिए अब भी सही तरीके से सेट अप करना होगा.

इसका सुझाव है कि नियम लिखने वाले लोगों की जानकारी, भाषा के पूरे रनटाइम पर न दिखे पहले स्थान पर हैं. ऐसे एपीआई के गलती से इस्तेमाल का खतरा बहुत ज़्यादा है - पहले कई Basel की गड़बड़ियां, असुरक्षित एपीआई का इस्तेमाल करने वाले नियमों की वजह से हुई थीं. यहां तक कि हालांकि, ये नियम बेज़ल टीम या अन्य डोमेन विशेषज्ञों ने लिखे थे.

क्वाड्रेटिक टाइम और मेमोरी के इस्तेमाल से बचना मुश्किल है

Skyframe की ज़रूरी शर्तों, Java का इस्तेमाल करने से जुड़ी पुरानी समस्याओं, और नियमों के एपीआई के पुराने होने के अलावा, लाइब्रेरी और बाइनरी नियमों पर आधारित किसी भी बिल्ड सिस्टम में, गलती से क्वाड्रैटिक समय या मेमोरी खर्च होने की समस्या एक बुनियादी समस्या है. दो ऐसे बहुत ही आम पैटर्न हैं जिनसे क्वाड्रेटिक मेमोरी के इस्तेमाल की जानकारी मिलती है. यही वजह है कि क्वाड्रेटिक टाइम कंज़म्पशन).

  1. लाइब्रेरी के नियमों की चेन - इस मामले में, लाइब्रेरी के नियमों की चेन A, B पर निर्भर करती है, जो C पर निर्भर करती है वगैरह. इसके बाद, हमें इन नियमों के ट्रांज़िशन क्लोज़र के आधार पर, कुछ प्रॉपर्टी का हिसाब लगाना है. जैसे, हर लाइब्रेरी के लिए Java रनटाइम क्लासपाथ या C++ लिंकर कमांड. इसलिए, शायद हम स्टैंडर्ड सूची को लागू करें; हालांकि, इसमें पहले से ही क्वाड्रेटिक मेमोरी इस्तेमाल की सुविधा है: पहली लाइब्रेरी क्लासपाथ पर एक एंट्री, दूसरी दो, तीसरी तीन, और इसलिए है चालू, कुल 1+2+3+...+N = O(N^2) एंट्री के लिए.

  2. एक जैसे लाइब्रेरी के नियमों के आधार पर बाइनरी नियम - ऐसा मामला देखें जिसमें एक ही लाइब्रेरी पर निर्भर बाइनरी का सेट हो नियम — जैसे कई टेस्ट नियम होने चाहिए, जो सभी एक जैसे टेस्ट करते हों लाइब्रेरी कोड. मान लें कि N नियमों में से आधे नियम बाइनरी नियम हैं, और में बताया गया है. अब मान लीजिए कि हर बाइनरी कुछ प्रॉपर्टी का आकलन, लाइब्रेरी के लिए तय समय के लिए तय किए गए समय के लिए किया जाता है, जैसे कि Java रनटाइम क्लासपाथ या C++ लिंकर कमांड लाइन का इस्तेमाल करें. उदाहरण के लिए, यह C++ लिंक ऐक्शन की कमांड लाइन स्ट्रिंग के तौर पर दिखाया जा सकता है. लागू नहीं N/2 एलिमेंट की कॉपी, O(N^2) मेमोरी होती है.

क्वाड्रेटिक कॉम्प्लेक्सिटी से बचने के लिए कस्टम कलेक्शन क्लास

इन दोनों स्थितियों से Bazel पर काफ़ी असर पड़ता है. इसलिए, हमने कस्टम कलेक्शन क्लास का एक सेट शुरू किया है. यह हर चरण में कॉपी करने से बचकर, मेमोरी में जानकारी को असरदार तरीके से कंप्रेस करता है. इनमें से करीब सभी डेटा स्ट्रक्चर को सिमेंटिक्स डिप्सेट (इंटरनल इंप्लीमेंटेशन में NestedSet के नाम से भी जाना जाता है). इसका ज़्यादातर हिस्सा पिछले कई सालों में Basel की मेमोरी की खपत कम करने के लिए, पहले उपयोग की गई चीज़ों के स्थान पर Depsets का इस्तेमाल करने के लिए बदलाव.

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