Windows I/O की गहराई (भाग 4) — कैश मैनेजर: आपका WriteFile डिस्क तक कब पहुँचता है

· · Windows, Win32, I/O, कैश, कर्नेल, फ़ाइल सिस्टम, .NET, C#

WriteFile सफलता लौटाया। तो डेटा अभी कहाँ है?

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

शृंखला «Windows I/O की गहराई» का भाग 4 इस बीच खड़े कैश मैनेजर पर है। भाग 2 में «कैश पर हो तो अतुल्यकालिक I/O भी तुल्यकालिक पूरा» लिखा, भाग 1 में «IRP न बनाने वाला छोटा रास्ता (फ़ास्ट I/O)» होमवर्क छोड़ा। इस बार वे कड़ियाँ समेटते हैं।

1. निष्कर्ष पहले

  • Windows फ़ाइल कैश राइट-बैक तरीका है। पढ़ना पहले सिस्टम फ़ाइल कैश से, लिखना भी पहले कैश पर। डिस्क पर प्रतिबिंब OS बाद करता है।1
  • कैश का पदार्थ फ़ाइल मैपिंग है। कैश मैनेजर फ़ाइल के 256KB खंड सिस्टम एड्रेस स्पेस पर मैप करता है, पढ़ना-लिखना «उस व्यू और ऐप बफ़र के बीच मेमोरी कॉपी» बनता है (अध्याय 2)।1
  • लिखना हर सेकंड विलंबित लिखना (lazy writer) पीछे से प्रतिबिंबित करता है। ऐप क्रैश पर डेटा नहीं जाता, पर बिजली कटने या OS क्रैश पर गंदा कैश जाता है (अध्याय 4)।1
  • «पक्का लिखना» तीन उपकरण। FlushFileBuffers (= .NET का Flush(true)), FILE_FLAG_WRITE_THROUGH, FILE_FLAG_NO_BUFFERING। बार-बार लिखने पर हर बार फ़्लश अक्षम्य, आधिकारिक दस्तावेज़ NO_BUFFERING+WRITE_THROUGH साथ गिनाता है (अध्याय 5)।21
  • NO_BUFFERING पर संरेखण आवश्यकता है। आकार-ऑफ़सेट सेक्टर आकार का पूर्ण गुणज, बफ़र पता भी भौतिक सेक्टर सीमा पर संरेखित। और NO_BUFFERING पर भी मेटाडेटा कैश होता रहता है (अध्याय 5.3)।31
  • मैप व्यू और कैश वही डेटा साझा करते हैं। मेमोरी-मैप्ड फ़ाइल और सामान्य कैश I/O सुसंगत, मैप स्थायित्व FlushViewOfFile+FlushFileBuffers दो चरण (अध्याय 6)।45
  • कैश पर तुल्यकालिक पढ़ना-लिखना IRP भी न बनाए। फ़ास्ट I/O छोटा रास्ता कैश मैनेजर सीधा जाता है — भाग 1 होमवर्क का उत्तर (अध्याय 7)।6

इस लेख का ज्ञान मानचित्र

WriteFile सफलता डिस्क पर स्थायित्व नहीं दर्शाती; Windows फ़ाइल कैश पहले सिस्टम कैश व्यू पर कॉपी करता है, डिस्क प्रतिबिंब lazy writer हर सेकंड पीछे से करता है। बिजली कटने या OS क्रैश पर अभी न लिखे गंदा पृष्ठ जाते हैं, इसलिए पक्का लिखना हो तो FlushFileBuffers, FILE_FLAG_WRITE_THROUGH, FILE_FLAG_NO_BUFFERING का चुनाव करना पड़ता है।

कैश मैनेजर और राइट-बैक का ज्ञान मानचित्रकैश मैनेजर, राइट-बैक कैश, 256KB सिस्टम कैश व्यू, रीड-अहेड, lazy writer से विलंबित लिखना, बिजली कटने पर गंदा पृष्ठ जाना, FlushFileBuffers, FILE_FLAG_WRITE_THROUGH, FILE_FLAG_NO_BUFFERING से पक्का लिखना, संरेखण आवश्यकता, मेमोरी-मैप्ड फ़ाइल से सुसंगति, फ़ास्ट I/O का संबंध दर्शाने वाला चित्रलागू करता हैउपयोग करता हैउपयोग करता हैउपयोग करता हैउपयोग करता हैउपयोग करता हैस्वचालित करता हैकम करता हैअसंगतकारण बन सकतामें संग्रहीतकारण बन सकतारोकता हैउपयोग करता हैसे कॉन्फ़िगरसे कॉन्फ़िगररोकता हैरोकता हैकम करता हैअपेक्षितरोकता हैकारण बन सकताअनुशंसित नहींअनुशंसित उपायअनुशंसित उपायअसंगतअपेक्षितपहले करना चाहिएसे जाँच योग्यअपेक्षितअसंगतअपेक्षितकैश मैनेजरराइट-बैक कैश (विलंबित लिखना तरीका)फ़ाइल मैपिंग (मेमोरी-मैप्ड फ़ाइल)सिस्टम कैश व्यू (256KB स्लॉट)फ़ाइल ऑब्जेक्टlazy writer (विलंबित लिखना थ्रेड)अप्रतिबिंबित डेटा की हानिFILE_ATTRIBUTE_TEMPORARYगंदा पृष्ठ (dirty page)बिजली कटना या OS क्रैशरीड-अहेड (read-ahead)FILE_FLAG_SEQUENTIAL_SCANFILE_FLAG_RANDOM_ACCESSFlushFileBuffersFILE_FLAG_WRITE_THROUGHFILE_FLAG_NO_BUFFERINGसेक्टर संरेखण आवश्यकताERROR_INVALID_PARAMETER (87)बार-बार लिखने पर पक्की स्थायित्वFlushViewOfFileफ़ास्ट I/OProcess Monitor (procmon.exe)IRP (I/O अनुरोध पैकेट)तुल्यकालिक I/O

चित्र में ठोस रेखा हमेशा सत्य रहने वाला संबंध दर्शाती है और धराशायी रेखा सशर्त संबंध दर्शाती है (शर्तें विस्तृत पृष्ठ पर प्रत्येक संबंध के स्पष्टीकरण में दी गई हैं)। संबंधों की पूरी सूची (कुल 32, साक्ष्य और निश्चितता सहित) तथा मुख्य अवधारणाओं की परिभाषाएँ ज्ञान मानचित्र के विस्तृत पृष्ठ पर संकलित हैं (जापानी में)। डेटा: JSON-LD / Turtle

2. कैश का असली रूप — फ़ाइल मेमोरी पर मैप होती है

2.1. 256KB स्लॉट और मेमोरी कॉपी

Windows फ़ाइल कैश «डिस्क ब्लॉक का बर्तन» सोचें तो कई व्यवहार समझ नहीं आते। सही चित्र यह — कैश मैनेजर फ़ाइल के 256KB खंड सिस्टम एड्रेस स्पेस के «स्लॉट» पर मैप करता है, कैश-सक्षम पढ़ना-लिखना उस स्लॉट और ऐप बफ़र के बीच मेमोरी कॉपी के रूप में चलता है1

सिस्टम एड्रेस स्पेसऐप (यूज़र मोड)ReadFile/WriteFile =स्लॉट के बीच मेमोरी कॉपीपहली पहुँच पर पढ़ना औरपीछे लिखना पृष्ठ इकाईसिस्टम फ़ाइल कैशफ़ाइल के 256KB खंड मैप किया स्लॉटऐप का बफ़र(ReadFile/WriteFile को दिया क्षेत्र)डिस्क पर फ़ाइल

चित्र 1: कैश-सक्षम I/O का यथार्थ। ऐप से देखा «फ़ाइल पढ़ना-लिखना» अधिकतर साधारण मेमोरी कॉपी

गलत समझ एक। 256KB व्यू (मैप) की कणिकता है, डिस्क I/O हमेशा 256KB इकाई चले — यह अर्थ नहीं। स्लॉट के पृष्ठ आवश्यकतानुसार पढ़े जाते हैं, वास्तव में डिस्क पर जाने वाला I/O मात्रा अनुरोध आकार और पहुँच पैटर्न से बदलती है। पहली बार पढ़े खंड पर भरने को डिस्क I/O (यहाँ भाग 1 का IRP नीचे स्टोरेज स्टैक जाता है)। पहले से कैश हो तो पढ़ना कॉपी मात्र से पूराभाग 2 अध्याय 5 का «कैश हिट पर अतुल्यकालिक जारी करें तो भी तुल्यकालिक पूरा» यही «तुरंत उत्तर दे सकें तो वहीं पूरा» चाल का प्रकटन था। उलटा, कैश-सक्षम रह पृष्ठ मेमोरी पर न हो तो पेज फ़ॉल्ट संसाधन में अतुल्यकालिक तंत्र नहीं, अतुल्यकालिक पढ़ना तुल्यकालिक संसाधित हो सकता है — यह जाल भी भाग 2 में।7

2.2. «खाली मेमोरी घटी» का असली रूप

कैश उपयोग और रीड-अहेड अवस्था खोलने के तरीके (फ़ाइल ऑब्जेक्ट इकाई) से प्रबंधित1, पर कैश डेटा पदार्थ फ़ाइल (स्ट्रीम) इकाई साझा। वही फ़ाइल बार खोलें तो अलग कैश नहीं बनते, किसी भी हैंडल से वही कैश सामग्री दिखती है (अध्याय 6 सुसंगति का आधार)। कैश Windows चलते कैश मैनेजर कमान में रहता है।1 बड़ी फ़ाइल कॉपी या बहुत पढ़ना-लिखना करें तो खाली भौतिक मेमोरी कैश में बदलती जाती है। टास्क मैनेजर खाली मेमोरी घटी दिखे, अधिकतर «ऐप माँगे तो जल्दी सौंपे जाने वाला, मूल्यवान उपयोग में स्टैंडबाय मेमोरी» है। मेमोरी कमी निदान में यह भेद न गलती करने को अवलोकन व्यवहार «.NET में GC प्रतीक्षा और मेमोरी लीक अलग करना» में भी है।

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

3. रीड-अहेड — पढ़ने की सट्टेबाज़ी

कैश मैनेजर पिछले पहुँच पैटर्न से आगे पढ़े जाने वाले खंड पहले से पढ़ता है (read-ahead)। क्रम से पढ़ी फ़ाइल पर ऐप माँगने से पहले आगे का डेटा पहले से कैश — यही अनुक्रमिक पढ़ने की गति का रहस्योद्घाटन। रीड-अहेड मात्रा स्थिर नहीं, पकड़े पैटर्न और अनुरोध आकार से बदलती है।

ऐप पढ़ने के अनुरोध का इतिहासआरंभ से क्रम से पढ़ रहा हैकैश मैनेजरपैटर्न पकड़ता हैरीड-अहेड: आगे का खंडमाँगने से पहले पढ़कर रखता है(मात्रा पैटर्न और अनुरोध आकार से परिवर्तनीय)संकेत FILE_FLAG_SEQUENTIAL_SCAN= रीड-अहेड सक्रियसंकेत FILE_FLAG_RANDOM_ACCESS= रीड-अहेड व्यर्थ, दबाएँ

चित्र 2: रीड-अहेड। पहुँच पैटर्न पकड़ने के साथ CreateFile फ़्लैग से संकेत दे सकते हैं

भाग 1 तालिका के FileOptions.SequentialScan / RandomAccess इसी रीड-अहेड इंजन के संकेत हैं। «सब चाटना» बैच संसाधन पर पहला, इंडेक्स घूमने जैसी पहुँच पर दूसरा — ऐप ही जानता भविष्य OS को बताने वाले फ़्लैग सोचें तो उपयोग स्थान स्पष्ट।

4. विलंबित लिखना — WriteFile «सफलता» का अर्थ

4.1. lazy writer हर सेकंड आता है

लिखने वाला पक्ष राइट-बैक कैश है। WriteFile डेटा स्लॉट पर कॉपी होते सफलता लौटाता है, डिस्क प्रतिबिंब बाद। यह «देर से लिखना» नीति विलंबित लिखना (lazy writing) है।1

प्रतिबिंब चलाता कैश मैनेजर हर सेकंड चला lazy writer। हाल फ़्लश न हुए पृष्ठों का 1/8 कतार में रखकर लिखता है, लिखने योग्य डेटा अधिक हो तो और बढ़ाता है। FILE_ATTRIBUTE_TEMPORARY गुण सहित बनी अस्थायी फ़ाइल lazy writer फ़्लश लक्ष्य से बाहर — जल्दी मिटने वाली लिखना व्यर्थ।1 पर यह गुण द्वारा संकेत है, मेमोरी तंग हो तो लिखी जा सकती है, और «नाम अस्थायी जैसा» फ़ाइल पर लागू नहीं।

डिस्कlazy writer (हर सेकंड)सिस्टम कैशऐपडिस्कlazy writer (हर सेकंड)सिस्टम कैशऐपस्लॉट पर कॉपी करपृष्ठ गंदा (न लिखा) चिह्नितयहाँ से लिखने तक «खतरनाक खिड़की»बिजली कटने · OS क्रैश पर यह डेटा जाता हैयहीं पहली बार स्थायी होता हैWriteFile (डेटा)तुरंत TRUE लौटता हैगंदे पृष्ठ का 1/8 चुनता हैएकत्र लिखता है

चित्र 3: विलंबित लिखना। WriteFile सफलता «OS को सौंपा» है, «स्थायी हुआ» नहीं

4.2. क्या हो तो कितना जाता है

«खतरनाक खिड़की» अर्थ सटीक करें। विफलता प्रकार से नियति बँटती है।

WriteFile सफल तुरंत बाद का डेटा(कैश पर गंदा पृष्ठ)क्या हुआऐप प्रक्रियाक्रैश / जबरन समाप्तOS सहित रुकना(बिजली कटना · ब्लू स्क्रीन)डेटा बचता हैकैश OS का है इसलिएlazy writer नियत लिखता हैगंदा पृष्ठ जाता हैडिस्क तक पहुँचा भाग मात्र बचता है

चित्र 4: विफलता प्रकार और बचने का विभाजन। कैश «प्रक्रिया की संपत्ति» नहीं «OS की संपत्ति»

  • ऐप मरे डेटा नहीं जाता। कैश कॉपी पूरा होते डेटा स्वामी OS। «सहेजते ऐप गिरा फ़ाइल सुरक्षित» इसी कारण।
  • OS सहित मरे गंदा भाग जाता है। फ़्लश आवृत्ति प्रदर्शन और विश्वसनीयता समझौता के रूप में समायोजित, «अचानक बिजली कटने पर कैश डेटा जाता है» दस्तावेज़ भी स्पष्ट कहता है।1

यानी व्यावसायिक ऐप डिज़ाइन का प्रश्न, «यह डेटा बिजली कटने के क्षण जा सकता है?» लॉग के कुछ सेकंड क्षमा हो सकते हैं। आदेश डेटा का निश्चित रिकॉर्ड नहीं। न क्षमा योग्य पर अगले अध्याय के उपकरण।

5. «पक्का लिखा» बनाने का औज़ार पेटी

5.1. FlushFileBuffers — अभी लिख डालें

FlushFileBuffers निर्दिष्ट फ़ाइल का बफ़र डेटा डिवाइस तक लिख देता है। फ़ाइल सिस्टम मेटाडेटा हमेशा कैश होता है, इसलिए मेटाडेटा तक पक्का पहुँचाने को फ़्लश (या WRITE_THROUGH) चाहिए — यह भी पकड़ने योग्य बिंदु।12 .NET में FileStream.Flush(true) इसके बराबर (Flush() अकेले .NET आंतरिक बफ़र OS को सौंपता है, OS कैश ज्यों का त्यों)।8

पर आधिकारिक दस्तावेज़ स्पष्ट कील ठोंकता है — लिखने हर बार बुलाना अक्षम्य। अनेक लिखने पर हर बार स्थायित्व चाहिए तो बाद के NO_BUFFERING+WRITE_THROUGH उपयोग करें।2

5.2. FILE_FLAG_WRITE_THROUGH — देरी मात्र हटाना

FILE_FLAG_WRITE_THROUGH से खोलें तो लिखना कैश पर भी लिखा जाता है, lazy writer प्रतीक्षा बिना तुरंत डिस्क पर भी1 पढ़ना कैश लाभ लेता रहता है — «पढ़ना तेज़ रहे, लिखने की देरी मात्र हटे» का सीधा उत्तर।

5.3. FILE_FLAG_NO_BUFFERING — कैश से नहीं गुज़रना

FILE_FLAG_NO_BUFFERING पढ़ने-लिखने से सिस्टम कैश स्वयं बाहर करता है। सब पढ़ना-लिखना कैश बिना हर बार डिस्क डिवाइस I/O।1 पर छोड़ सकने वाला Windows सिस्टम कैश तक, चित्र 5 के अनुसार डिवाइस भीतर लिखने का कैश अलग चरण। बिजली कटने तक प्रतिरोध चाहिए तो WRITE_THROUGH साथ या FlushFileBuffers अभी चाहिए। बड़ी डेटा एकमुश्त स्थानांतरण या स्वयं बफ़र प्रबंधन करने वाले डेटाबेस इंजन का उपकरण, पर कठोर वादे साथ।3

  • पढ़ने-लिखने का आकार और फ़ाइल ऑफ़सेट वॉल्यूम सेक्टर आकार का पूर्ण गुणज (512-बाइट सेक्टर पर 512 · 1024 · 1536…)।
  • बफ़र पता भी भौतिक सेक्टर आकार पर संरेखित (4096-बाइट भौतिक सेक्टर «Advanced Format» डिस्क का भी ध्यान)।
  • तब भी मेटाडेटा कैश होता रहता है, पूर्ण स्थायित्व को WRITE_THROUGH साथ या FlushFileBuffers चाहिए।12

यह «वादा» फ़्लैग जोड़ भर सोचने वाला पहले गिरता है। संरेखण न मान पढ़ें-लिखें तो ERROR_INVALID_PARAMETER (87) से विफल। मानने योग्य तीन बिंदु।3

मिलाना शर्त कैसे पूरा करें
पढ़ने-लिखने का आकार वॉल्यूम सेक्टर आकार का पूर्ण गुणज GetDiskFreeSpace का lpBytesPerSector लेकर उसके गुणज पर गोल करें
फ़ाइल ऑफ़सेट वही (OVERLAPPED के Offset निर्दिष्ट पर भी) सेक्टर आकार गुणज-दर आगे
बफ़र पता भौतिक सेक्टर आकार पर संरेखित VirtualAlloc से आवंटित करें (पृष्ठ सीमा = सामान्यतः 4096 बाइट संरेखित क्षेत्र लौटता है)

तीसरा विशेषकर छूटता है। malloc या new, C# सरणी लौटा पता सेक्टर सीमा संरेखण गारंटी नहीं रखते। पृष्ठ सीमा पर आवंटित VirtualAlloc उपयोग करें तो भौतिक सेक्टर 4096 बाइट «Advanced Format» डिस्क आवश्यकता भी साथ पूरी। न्यूनतम रूप इस प्रकार।

// C++ / Win32. त्रुटि प्रबंधन न्यूनतम रखा है
DWORD sectorsPerCluster = 0, bytesPerSector = 0, freeClusters = 0, totalClusters = 0;
if (!GetDiskFreeSpaceW(L"C:\\", &sectorsPerCluster, &bytesPerSector,
                       &freeClusters, &totalClusters))
{
    return GetLastError();
}

// पढ़ने-लिखने की इकाई सेक्टर आकार का पूर्ण गुणज करना (यहाँ 1MiB के बराबर)
const DWORD chunk = (1024 * 1024 / bytesPerSector) * bytesPerSector;

// बफ़र पृष्ठ सीमा पर संरेखित क्षेत्र लेना (malloc/new गारंटी नहीं रखते)
BYTE* buffer = static_cast<BYTE*>(
    VirtualAlloc(nullptr, chunk, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE));
if (buffer == nullptr) { return GetLastError(); }

HANDLE h = CreateFileW(L"C:\\temp\\big.bin", GENERIC_READ, FILE_SHARE_READ, nullptr,
                       OPEN_EXISTING, FILE_FLAG_NO_BUFFERING, nullptr);
if (h == INVALID_HANDLE_VALUE)
{
    // GetLastError «ठीक पहले के Win32 कॉल» का परिणाम लौटाता है। पहले VirtualFree
    // बुलाने पर CreateFileW की विफलता का कारण (पहुँच अस्वीकृत·पथ नहीं आदि)
    // सफ़ाई के परिणाम से अधिलेखित हो जाता है, कारण न समझ आने वाला कोड ही लौटता है
    const DWORD err = GetLastError();
    VirtualFree(buffer, 0, MEM_RELEASE);
    return err;
}

// हर बार chunk बाइट इकाई से आगे बढ़ने से आकार भी ऑफ़सेट भी संरेखित रहते हैं
DWORD read = 0;
while (ReadFile(h, buffer, chunk, &read, nullptr) && read > 0)
{
    // buffer के आरंभ के read बाइट संसाधित करें
    // (फ़ाइल अंत पर read < chunk होता है। यह सामान्य)
}

CloseHandle(h);
VirtualFree(buffer, 0, MEM_RELEASE);

साथ .NET FileOptions में FILE_FLAG_NO_BUFFERING अनुरूप मान नहीं। सच में चाहिए तो CreateFile सीधे बुलाना पड़ता है, तब भी ऊपर संरेखण आवश्यकता स्वयं माननी पड़ती है। «तेज़ चाहिए इसलिए NO_BUFFERING» नहीं, «स्वयं बफ़र प्रबंधन इसलिए NO_BUFFERING» क्रम से सोचें।

5.4. चुनाव व्यवस्थित

डिफ़ॉल्ट WriteFile: यहाँ तक सफलता लौटती हैlazy writer (हर सेकंड) / WRITE_THROUGH (तुरंत)डिवाइस समय /FlushFileBuffers लिख डालने की माँगNO_BUFFERING कैश छोड़ सीधेऐप का बफ़रसिस्टम फ़ाइल कैश(गंदा पृष्ठ)डिस्क डिवाइस भीतर का कैशअस्थिर न रहने वाला माध्यम

चित्र 5: डेटा की परतें और प्रत्येक उपकरण कितना आगे धकेलता है। «डिस्क डिवाइस भीतर का कैश» अंतिम चरण भी ध्यान दें

विधि क्या होता है उपयुक्त स्थान
डिफ़ॉल्ट (कैश सक्षम) कैश कॉपी से पूरा। प्रतिबिंब lazy writer अधिकतर फ़ाइल I/O
FlushFileBuffers / Flush(true) उस क्षण का डेटा+मेटाडेटा लिख डालना मोड़ पर निश्चित (लेनदेन कमिट आदि)
FILE_FLAG_WRITE_THROUGH लिखने हर बार तुरंत डिस्क (पढ़ना कैश) न खो सकने वाला लगातार लॉग · जर्नल
FILE_FLAG_NO_BUFFERING (+WRITE_THROUGH) कैश बिना। संरेखण आवश्यकता स्वयं बफ़र प्रबंधन · बड़ी एकमुश्त I/O

चुनने का क्रम «बिजली कटने पर कितने रिकॉर्ड जा सकते हैं» पहले तय, फिर «उसके लिए कितना धीमा चले» पुष्टि — दो चरण। तालिका ऊपर से न देखें, यह शाखा घूमें।

क्षमा(हाल कुछ सेकंड का लॉग आदि)क्षमा नहींमोड़(लेनदेन निश्चित आदि)प्रत्येक रिकॉर्डनहीं (सामान्य ऐप)हाँ (DB इंजन आदि)यह डेटा लिखने जा रहे हैंबिजली कटने · ब्लू स्क्रीन के क्षणजाना क्षमा है?डिफ़ॉल्ट रहें (कैश सक्षम)सबसे तेज़। अधिकतर I/O यहाँन जा सकने वाला«मोड़» है या «प्रत्येक रिकॉर्ड»?मोड़ पर FlushFileBuffers.NET में Flush(true)लागत: मोड़ की प्रतीक्षा मात्रस्वयं बफ़र प्रबंधित कर5.3 संरेखण आवश्यकता पूरी कर सकते हैं?FILE_FLAG_WRITE_THROUGHलिखने हर बार तुरंत डिस्कपढ़ना कैश से तेज़ रहता हैFILE_FLAG_NO_BUFFERING+ FILE_FLAG_WRITE_THROUGHआधिकारिक «बार-बार स्थायित्व» रूप

चित्र 6: उपकरण चुनाव। पहला शाखा विश्वसनीयता माँग, दूसरा चुकाई जा सकने वाली लागत। «प्रत्येक रिकॉर्ड पर FlushFileBuffers» पथ नहीं, अध्याय 5.1 के अनुसार आधिकारिक दस्तावेज़ उसे अक्षम्य मानता है

व्यावहारिक पैटर्न तीन ही गिनाते हैं।

  1. «अस्थायी फ़ाइल पर लिखें → फ़्लश → नाम बदलें» अधूरी फ़ाइल न छोड़ने का नियम। सामग्री लिख डालकर नाम से निश्चित — यह परमाणु सौंपना «फ़ाइल एकीकरण के अनन्य नियंत्रण की मूल बात» में विस्तार से।
  2. डेटाबेस पर छोड़ना भी अच्छा डिज़ाइन है। SQLite WAL और फ़्लश से टिकाऊपन बनाता है — «C# से SQLite व्यावसायिक ऐप में» देखें। «स्वयं फ़्लश रणनीति न लिखें» विकल्प हमेशा मेज पर है।
  3. बेंचमार्क पर कैश संदेह करें। «पढ़ना बहुत तेज़» माप प्रायः दूसरी बार बाद कैश हिट मापता है। माप रीति «Windows पर प्रोग्राम संस्करण-दर गति सही तुलना» में है।

चित्र 5 का अंतिम चरण — डिस्क डिवाइस भीतर का कैश भी न भूलें। FlushFileBuffers वहाँ तक लिख डालने की माँग करता है, पर USB या बाहरी डिस्क पर डिवाइस पक्ष लिखने का कैश नीति («त्वरित निकालना» बनाम «उच्च प्रदर्शन») जुड़ती है। निकाले जाने योग्य डिवाइस व्यवहार «Windows ऐप में USB उपकरण» भी देखें।

6. मेमोरी-मैप्ड फ़ाइल से सुसंगति

भाग 1 में «कैश का पदार्थ फ़ाइल मैपिंग» सुनकर यह सोचा होगा — तो स्वयं MapViewOfFile किया व्यू और ReadFile/WriteFile का कैश लड़ते हैं?

नहीं। उसी तंत्र पर बैठे हैं। फ़ाइल मैपिंग ऑब्जेक्ट फ़ाइल पर आधारित, पृष्ठ निकालना फ़ाइल पर लिखने के रूप में होता है। उसी स्थानीय फ़ाइल पर कई प्रक्रियाएँ व्यू बनाएँ तो भी दिखने वाली सामग्री सुसंगत (कोहेरेंट) है।4

सिस्टम एड्रेस स्पेसप्रक्रिया A का एड्रेस स्पेसकैश मैनेजर का व्यू(ReadFile/WriteFile उपयोग स्लॉट)MapViewOfFile व्यूवही भौतिक पृष्ठ समूह(फ़ाइल पर आधारित मेमोरी)डिस्क पर फ़ाइलFILE_FLAG_NO_BUFFERING का I/Oइस साझा के बाहर (सीधे डिस्क)

चित्र 7: मैप व्यू भी कैश भी उसी «फ़ाइल पर आधारित पृष्ठ» देखते हैं। बाहर केवल NO_BUFFERING

दो सावधानियाँ।

  • FILE_FLAG_NO_BUFFERING I/O इस सुसंगति के बाहर है। कैश बिना पढ़ना-लिखना और मैप व्यू/कैश सामग्री नहीं मिलाए जाते। मिलाएँ तो स्वयं सुसंगति बनाएँ।
  • मैप व्यू स्थायित्व दो चरण है। FlushViewOfFile दायरे के गंदे पृष्ठ लिखना शुरू करता है, पर मेटाडेटा नहीं लिखता, डिस्क डिवाइस कैश से भौतिक लिखना भी प्रतीक्षा नहीं करता। पक्का पहुँचाने को FlushViewOfFile बाद FlushFileBuffers बुलाएँ।5

साझा मेमोरी के रूप में फ़ाइल मैपिंग व्यवहार (नामित साझा, तुल्यकालन, दुर्घटना पैटर्न) «साझा मेमोरी के जाल और व्यावहारिक सर्वोत्तम प्रथाएँ» में है।

7. फ़ास्ट I/O — भाग 1 होमवर्क समेटना

पहले दो पंक्ति। फ़ास्ट I/O कैश पर फ़ाइल के तुल्यकालिक पढ़ने-लिखने के लिए बना छोटा रास्ता है, IRP (I/O अनुरोध पैकेट। कर्नेल ड्राइवर को सौंपने वाला अनुरोध पात्र) बिना कैश से सीधे डेटा आदान-प्रदान करता है। Procmon Operation स्तंभ में IRP_MJ_READ और FASTIO_READ मिले इसलिए कि वही «पढ़ना» सामान्य पथ और छोटे रास्ते दोनों से जा सकता है।

भाग 1 अध्याय 5.2 में «सब I/O IRP नहीं बनता» लिखा। उत्तर मिलान।

कैश पर फ़ाइल का पढ़ना-लिखना IRP बना डिवाइस स्टैक बहाए बिना कैश से मेमोरी कॉपी से पूरा जाना जाता है। इसलिए Windows कैश वाली फ़ाइल के तुल्यकालिक I/O के लिए फ़ास्ट I/O छोटा रास्ता देता है — IRP न बना, फ़ाइल सिस्टम «फ़ास्ट I/O एंट्री पॉइंट» सीधे बुला, कैश मैनेजर से सीधे कॉपी।6 फ़ास्ट I/O न सँभाले (कैश पर नहीं, लॉक जुड़ा, फ़िल्टर बीच में आदि) तो सामान्य IRP पथ पर लौटता है। यह तुल्यकालिक अनुरोध का तेज़ पथ है, «कैश हिट = हमेशा फ़ास्ट I/O» नहीं। अतुल्यकालिक (FILE_FLAG_OVERLAPPED) हैंडल ऑपरेशन कैश से वहीं पूरा होने पर भी (भाग 2 अध्याय 5) IRP पथ से संसाधित हो सकता है।

हाँनहींकैश-सक्षम हैंडल पर तुल्यकालिक पढ़ना-लिखनाफ़ास्ट I/O से संसाधित हो सकता है?(कैश पर है आदि)फ़ास्ट I/OIRP बिना कैश से सीधे कॉपीProcmon पर FASTIO_ दिखता हैसामान्य पथIRP बना डिवाइस स्टैक(भाग 1 चित्र 6 की दुनिया)

चित्र 8: फ़ास्ट I/O शाखा। Procmon पर FASTIO_READ और IRP_MJ_READ मिलने का यही कारण

भाग 1 अध्याय 7 Procmon अवलोकन में FASTIO_ पंक्तियाँ मिली थीं, अब समझाया जा सकता है। कैश हिट पढ़ना IRP भी विलास है। यह पथ भाग 6 फ़िल्टर ड्राइवर पर भी प्रभाव डालता है (मिनीफ़िल्टर फ़ास्ट I/O पर भी बीच में आ सकते हैं)।

8. सारांश

  • Windows फ़ाइल कैश राइट-बैक, पदार्थ फ़ाइल 256KB खंड मैपिंग। कैश-सक्षम पढ़ना-लिखना स्लॉट से मेमोरी कॉपी।1
  • पढ़ना रीड-अहेड सट्टा लगाता है, SequentialScan/RandomAccess उसके संकेत।1
  • लिखना हर सेकंड lazy writer पीछे करता है। ऐप मरे डेटा बचता है, OS सहित मरे गंदा भाग जाता है। डिज़ाइन का प्रश्न «यह डेटा बिजली कटने के क्षण जा सकता है?»।1
  • पक्का लिखने के उपकरण FlushFileBuffers (मोड़ पर निश्चित) / WRITE_THROUGH (लिखने हर बार) / NO_BUFFERING (कैश बिना + संरेखण आवश्यकता)। हर बार फ़्लश अक्षम्य, बार-बार स्थायित्व पर NO_BUFFERING+WRITE_THROUGH साथ आधिकारिक अनुशंसा। मेटाडेटा हमेशा कैश — यह भी ध्यान।231
  • मैप व्यू और कैश वही पृष्ठ साझा सुसंगत। बाहर केवल NO_BUFFERING। मैप स्थायित्व FlushViewOfFile+FlushFileBuffers दो चरण।45
  • कैश हिट तुल्यकालिक पढ़ना-लिखना फ़ास्ट I/O से IRP भी छोड़ता है। भाग 1 Procmon FASTIO_ का असली रूप।6

आगे भाग 5 «NTFS आंतरिक संरचना — MFT से समझा फ़ाइल सिस्टम»। अब तक फ़ाइल «ऑफ़सेट और बाइट अनुक्रम» थी, पीछे NTFS डेटा कैसे रखता है — MFT, कई डेटा स्ट्रीम, जर्नल, हार्ड लिंक — डिस्क पर स्थिर संरचना की ओर उतरते हैं।

संबंधित लेख

संबंधित परामर्श क्षेत्र

KomuraSoft LLC «सहेजा डेटा गया», «फ़ाइल लिखना धीमा / बहुत तेज़ संदेह» जैसे Windows व्यावसायिक ऐप फ़ाइल I/O डिज़ाइन और त्रुटि जाँच सँभालता है।

संदर्भ लिंक

  1. Microsoft Learn, File Caching. Windows डिफ़ॉल्ट फ़ाइल डेटा कैश करता है, पढ़ना सिस्टम फ़ाइल कैश से, लिखना भी कैश पर — राइट-बैक कैश; कैश फ़ाइल ऑब्जेक्ट इकाई प्रबंधित कैश मैनेजर कमान में; डिस्क लिखना देर से कैश रखकर नीति विलंबित लिखना (lazy writing); फ़ाइल पढ़ते 256KB खंड सिस्टम एड्रेस स्पेस 256KB स्लॉट में, यूज़र प्रक्रिया उस स्लॉट से डेटा कॉपी; कैश मैनेजर हर सेकंड lazy writer चला हाल फ़्लश न हुए पृष्ठों का 1/8 डिस्क लिखने की कतार में रख आवश्यकता हो तो और बढ़ाता है; अस्थायी फ़ाइल फ़्लश नहीं; बिजली कटने जैसी अचानक सिस्टम विफलता पर न लिखा कैश डेटा जाता है; FILE_FLAG_NO_BUFFERING से कैश अक्षम करें तो भी फ़ाइल मेटाडेटा कैश हो सकता है; FILE_FLAG_WRITE_THROUGH पर डेटा कैश पर भी लिखा lazy writer देरी बिना तुरंत डिस्क; फ़ाइल सिस्टम मेटाडेटा हमेशा कैश इसलिए मेटाडेटा स्थायित्व को फ़्लश या FILE_FLAG_WRITE_THROUGH चाहिए।  2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19

  2. Microsoft Learn, FlushFileBuffers function. WriteFile सामान्यतः आंतरिक बफ़र पर लिखता है, OS समय-समय डिस्क लिखता है; FlushFileBuffers निर्दिष्ट फ़ाइल की सब बफ़र जानकारी डिवाइस तक लिखता है; अनेक लिखने हर बार बुलाना अक्षम्य, बार-बार लिखने पर महत्वपूर्ण डेटा स्थायित्व चाहिए ऐप FILE_FLAG_NO_BUFFERING और FILE_FLAG_WRITE_THROUGH से बिना-बफ़र I/O उपयोग करें; वॉल्यूम हैंडल पर बुलाएँ (व्यवस्थापक अधिकार) तो वॉल्यूम की सब खुली फ़ाइलें फ़्लश।  2 3 4 5

  3. Microsoft Learn, File Buffering. FILE_FLAG_NO_BUFFERING से खुली फ़ाइल पहुँच आवश्यकता: पढ़ने-लिखने का आकार और फ़ाइल ऑफ़सेट (OVERLAPPED निर्दिष्ट सहित) वॉल्यूम सेक्टर आकार का पूर्ण गुणज; पढ़ने-लिखने बफ़र पता भौतिक सेक्टर आकार पर संरेखित; भौतिक सेक्टर 4,096 बाइट Advanced Format डिवाइस ध्यान।  2 3 4

  4. Microsoft Learn, File Mapping. फ़ाइल मैपिंग ऑब्जेक्ट डिस्क फ़ाइल पर आधारित, पृष्ठ स्वैप आउट बदलाव फ़ाइल पर लिखने के रूप में; कई प्रक्रियाएँ उसी फ़ाइल मैपिंग ऑब्जेक्ट से स्थानीय फ़ाइल व्यू बनाएँ तो डेटा सुसंगत (डिस्क फ़ाइल जैसी सामग्री)।  2 3

  5. Microsoft Learn, FlushViewOfFile function. FlushViewOfFile मैप व्यू दायरे के गंदे पृष्ठ डिस्क लिखना शुरू करता है; यह फ़ंक्शन फ़ाइल मेटाडेटा फ़्लश नहीं करता, हार्डवेयर डिस्क कैश से भौतिक लिखना पूरा प्रतीक्षा नहीं; गंदे पृष्ठ और मेटाडेटा सब भौतिक लिख डालने को FlushViewOfFile बाद FlushFileBuffers बुलाएँ।  2 3

  6. Microsoft Learn, IRPs Are Different From Fast I/O. फ़ास्ट I/O IRP उत्पन्न बिना फ़ाइल सिस्टम या कैश मैनेजर एंट्री पॉइंट सीधे बुलाने वाला, कैश फ़ाइल के तुल्यकालिक I/O का तेज़ पथ; कैश से सीधे यूज़र बफ़र (या उलटा) डेटा स्थानांतरित; फ़ास्ट I/O न सँभाले तो IRP-आधार सामान्य पथ।  2 3

  7. Microsoft Learn, Asynchronous disk I/O appears as synchronous on Windows. डेटा कैश हो तो अनुरोध वहीं पूरा TRUE लौटता है; Windows कैश फ़ाइल मैपिंग से लागू, पृष्ठ न हो अतुल्यकालिक पेज फ़ॉल्ट तंत्र नहीं, इसलिए कैश-सक्षम अतुल्यकालिक पढ़ना तुल्यकालिक संसाधित हो सकता है। 

  8. Microsoft Learn, FileStream.Flush method (.NET). Flush() स्ट्रीम आंतरिक बफ़र OS को लिखता है; Flush(true) निर्दिष्ट करें तो उसके साथ सब मध्य फ़ाइल बफ़र (OS बफ़र) भी फ़्लश। 

निकटवर्ती विषयों में गहराई से जाने के लिए समान टैग वाले नवीनतम लेख।

Windows I/O की गहराई (भाग 6, अंतिम) — फ़िल्टर ड्राइवर और मिनीफ़िल्टर: Procmon और वायरस स्कैन I/O में क्यों बीच में आ सकते हैं

Windows फ़िल्टर ड्राइवर और मिनीफ़िल्टर चित्रों से समझाने वाली शृंखला का अंतिम भाग। फ़िल्टर मैनेजर और अल्टिट्यूड, pre/post कॉलबैक, Procmon...

व्यावहारिक मल्टीथ्रेडिंग सर्वोत्तम प्रथाएँ: .NET संस्करण — और थ्रेड जोड़ने से पहले क्या तय करें

मल्टीथ्रेडेड .NET/C# कोड को कभी-कभी क्रैश या हैंग होने से बचाने वाले डिज़ाइन नियमों का व्यावहारिक सार: थ्रेड स्वयं न बनाकर Task पर चलें, ...

C# और PowerShell से WMI/CIM का उपयोग — हार्डवेयर जानकारी, प्रोसेस निगरानी और रिमोट क्वेरी की व्यावहारिक मार्गदर्शिका

PC का सीरियल नंबर लेना, डिस्क खाली स्थान की निगरानी, और प्रोसेस शुरू होने का पता लगाने का आम तरीका WMI/CIM है। यह लेख Get-CimInstance जैस...

Named Pipes व्यवहार में — डिज़ाइन से सुरक्षा तक, Windows की मानक IPC

Named pipes — Windows की मानक इंटर-प्रोसेस कम्युनिकेशन — की व्यावहारिक मार्गदर्शिका। यह लेख प्राथमिक स्रोतों से बाइट और मैसेज मोड का चुना...

ये पृष्ठ विषय को सेवाओं और निर्णयों के व्यापक संदर्भ में रखते हैं।

यह लेख निम्नलिखित सेवाओं से सीधे जुड़ा है।

अक्सर पूछे जाने वाले प्रश्न

इस लेख के विषय पर परामर्श में अक्सर पूछे जाने वाले प्रश्न।

WriteFile सफलता लौटाए तो डेटा डिस्क पर लिखा जा चुका है?
डिफ़ॉल्ट से नहीं। Windows फ़ाइल कैश राइट-बैक तरीका है, WriteFile डेटा सिस्टम फ़ाइल कैश में कॉपी होते ही सफलता लौटाता है। डिस्क पर लिखना कैश मैनेजर हर सेकंड चला विलंबित लिखना (lazy writer) बाद में करता है। महत्वपूर्ण विफलता प्रकार से अंतर। ऐप प्रक्रिया क्रैश हो तो कैश में गया डेटा OS जीवित रहे बाद लिखा जाता है, नहीं जाता। दूसरी ओर OS सहित गिरे (बिजली कटना, ब्लू स्क्रीन) तो अभी न लिखा गंदा कैश जाता है। «WriteFile सफल = स्थायी» नहीं, «सफल = OS को सौंपा» सटीक समझ है।
पक्का डिस्क पर लिखने के लिए क्या करें?
तीन उपकरण। पहला FlushFileBuffers, उस फ़ाइल का बफ़र डेटा और मेटाडेटा डिवाइस तक लिख देता है (.NET में FileStream.Flush(true) इसके बराबर)। दूसरा FILE_FLAG_WRITE_THROUGH, लिखने हर बार कैश पर लिखते तुरंत डिस्क पर भी। तीसरा FILE_FLAG_NO_BUFFERING, कैश स्वयं से नहीं गुज़रता। Microsoft दस्तावेज़ लिखने हर बार FlushFileBuffers बुलाना अक्षम्य मानता है, बार-बार लिखने पर पक्की स्थायित्व चाहिए तो FILE_FLAG_NO_BUFFERING और FILE_FLAG_WRITE_THROUGH साथ उपयोग कहता है। सब कैश लाभ छोड़ते धीमे होते हैं, इसलिए «सब पर लगाएँ» नहीं, न खो सकने वाले डेटा लिखने तक सीमित रखना व्यावहारिक कुंजी है।
FILE_FLAG_WRITE_THROUGH और FILE_FLAG_NO_BUFFERING में क्या अंतर है?
WRITE_THROUGH «कैश पर लिखें, पूरा होने से पहले डिस्क पर भी लिखें»। पढ़ना कैश लाभ लेता रहता है, विलंबित लिखने की देरी मात्र हटती है। NO_BUFFERING «पढ़ना-लिखना सिस्टम कैश से नहीं गुज़रता», पढ़ना और लिखना हर बार डिस्क डिवाइस I/O (पर छोड़ता Windows कैश तक, डिवाइस भीतर लिखने का कैश नहीं)। उसके बदले कठोर बाधा: पढ़ने-लिखने का आकार और फ़ाइल ऑफ़सेट वॉल्यूम सेक्टर आकार का पूर्ण गुणज, बफ़र पता भी भौतिक सेक्टर सीमा पर संरेखित। साथ NO_BUFFERING पर भी फ़ाइल सिस्टम मेटाडेटा कैश होता रहता है, मेटाडेटा तक पक्का लिखने को FlushFileBuffers या WRITE_THROUGH साथ चाहिए। डेटाबेस इंजन जैसे स्वयं बफ़र प्रबंधन करने वाला सॉफ़्टवेयर प्रतिनिधि; सामान्य ऐप पहले WRITE_THROUGH या FlushFileBuffers सोचें।
टास्क मैनेजर पर खाली मेमोरी कम दिखे तो फ़ाइल कैश कारण है?
अधिकतर हाँ, और यह सामान्य व्यवहार है। Windows खाली भौतिक मेमोरी सक्रिय फ़ाइल कैश के रूप में उपयोग करता है, बड़ी फ़ाइल कॉपी या बहुत पढ़ना-लिखना करें तो कैश फूल मेमोरी उपयोग बढ़ा दिखता है। पर कैश उपयोग पृष्ठ अधिकतर ऐप मेमोरी माँगे तो अपेक्षाकृत जल्दी सौंपे जाने वाले प्रकार के हैं, «मेमोरी खाकर कमी» अवस्था से अलग जाँचें। मेमोरी कमी संदेह पर दिखा खाली मात्रा भर नहीं, कमिटेड मेमोरी या हार्ड फ़ॉल्ट आवृत्ति जैसे संकेतक देखना व्यावहारिक है।
मेमोरी-मैप्ड फ़ाइल और ReadFile/WriteFile से वही फ़ाइल छुएँ तो सामग्री बिखरती है?
सामान्य कैश-सक्षम I/O के बीच नहीं। Windows कैश स्वयं फ़ाइल मैपिंग से लागू, उसी स्थानीय फ़ाइल पर मैप व्यू और कैश वही डेटा साझा करते हैं, एक का बदलाव दूसरे से दिखता है। कई प्रक्रियाएँ उसी फ़ाइल मैपिंग ऑब्जेक्ट से व्यू बनाएँ तो डेटा सुसंगत (कोहेरेंट) रहता है। पर FILE_FLAG_NO_BUFFERING से खुले हैंडल का पढ़ना-लिखना कैश से नहीं गुज़रता, इस सुसंगति के बाहर। मैप व्यू बदलाव पक्का डिस्क पर लिखने को FlushViewOfFile अकेले मेटाडेटा नहीं लिखता और हार्डवेयर कैश भी नहीं प्रतीक्षा करता, इसलिए FlushViewOfFile बाद FlushFileBuffers बुलाना पड़ता है।

लेखक की प्रोफ़ाइल

लेख के लेखक का परिचय पृष्ठ।

Go Komura

KomuraSoft LLC के प्रतिनिधि

Windows सॉफ़्टवेयर विकास, तकनीकी परामर्श और बग जाँच में विशेषज्ञ, विशेष रूप से मौजूदा सिस्टम वाली परियोजनाओं और पुनरुत्पादन में कठिन बग में।

सार्वजनिक लिंक

ब्लॉग पर लौटें