ফাইল অ্যালোকেশন মেথড — কন্টিগুয়াস, লিংকড, ইনডেক্সড
এই পাঠে যা শিখবেন
- ফাইল সিস্টেম কীভাবে ঠিক করে কোন ফাইলের ডেটা কোন ডিস্ক ব্লকে বসবে
- কন্টিগুয়াস, লিংকড ও ইনডেক্সড অ্যালোকেশন — প্রতিটির সুবিধা, সীমাবদ্ধতা ও M7-এর মেমরি-অ্যালোকেশন সমস্যার সাথে সরাসরি সমান্তরাল
- কেন ইনডেক্সড অ্যালোকেশন বাস্তব ফাইল সিস্টেমে সবচেয়ে বেশি ব্যবহৃত হয়
- Python দিয়ে ইনডেক্সড অ্যালোকেশনের O(1) সরাসরি ব্লক-অ্যাক্সেস বাস্তবায়ন করে লিংকড অ্যালোকেশনের O(n) ট্রাভার্সালের সাথে সরাসরি তুলনা
১ · প্রশ্নটি — ফাইলের ডেটা কোন ব্লকে বসে?
L38-এর ডিরেক্টরি একটি ফাইলনামকে তার মেটাডেটার দিকে নিয়ে যায়, আর L37-এর মেটাডেটায় ছিল একটি "লোকেশন" অ্যাট্রিবিউট। কিন্তু সেই লোকেশন আসলে কী রূপে থাকে? এটিই ফাইল অ্যালোকেশন মেথডFile Allocation Methodফাইল সিস্টেম কীভাবে ঠিক করে কোন ডিস্ক ব্লকগুলো একটি নির্দিষ্ট ফাইলের ডেটা ধারণ করবে।-এর প্রশ্ন — এটি M7-এর মেমরি-অ্যালোকেশন সমস্যার (L28) সাথে একটি সরাসরি সমান্তরাল, শুধু এখানে মেমরি ফ্রেমের বদলে ডিস্ক ব্লক নিয়ে কাজ হচ্ছে।
২ · তিনটি প্রধান পদ্ধতি
ফাইলের সব ব্লক একটানা, পাশাপাশি ক্রমিক ব্লকে থাকে — যেকোনো অফসেটের ব্লক তুচ্ছভাবে গণনাযোগ্য (start_block + offset/block_size), চমৎকার সিকোয়েনশিয়াল ও র্যান্ডম অ্যাক্সেস। কিন্তু L28-এর মতোই এক্সটার্নাল ফ্র্যাগমেন্টেশনে ভোগে, এবং ফাইল সহজে বাড়তে পারে না।
ফাইলের ব্লক ডিস্কের যেকোনো জায়গায় ছড়িয়ে থাকতে পারে, প্রতিটি ব্লক পরের ব্লকের পয়েন্টার রাখে — কোনো এক্সটার্নাল ফ্র্যাগমেন্টেশন নেই, ফাইল অবাধে বাড়তে পারে। কিন্তু র্যান্ডম অ্যাক্সেস ধীর (শুরু থেকে লিংকড লিস্ট হাঁটতে হয়) এবং একটি পয়েন্টার নষ্ট হলে বাকি চেইন ভেঙে যায়।
প্রতিটি ফাইলের একটি নির্দিষ্ট ইনডেক্স ব্লক থাকে, যাতে সেই ফাইলের সব প্রকৃত ডেটা ব্লকের ঠিকানা থাকে — দ্রুত র্যান্ডম অ্যাক্সেস (সরাসরি ইনডেক্স লুকআপ, ট্রাভার্সাল লাগে না), কন্টিগুয়াসের ফ্র্যাগমেন্টেশন/গ্রোথ সমস্যা ছাড়াই — L31-এর পেজ টেবিলের ধারণাগত সমতুল্য।
৩ · ইনডেক্সড অ্যালোকেশনের O(1) অ্যাক্সেস
নিচের কোড সেলে একটি ফাইলের ইনডেক্স ব্লক বাস্তবায়ন করা হয়েছে — লজিক্যাল ব্লক নম্বরের একটি তালিকা, যেখানে প্রতিটি এন্ট্রি সরাসরি সেই লজিক্যাল ব্লকের প্রকৃত ফিজিক্যাল ব্লক নম্বর ধারণ করে। যেকোনো লজিক্যাল ব্লক নম্বর সরাসরি ইনডেক্স করে পাওয়া যায় — কোনো ট্রাভার্সাল ছাড়াই, অর্থাৎ O(1)। তুলনার জন্য একই ফাইলের একটি লিংকড-অ্যালোকেশন-স্টাইল চেইনও বাস্তবায়ন করা হয়েছে, যেখানে একই ব্লকে পৌঁছাতে ধাপে ধাপে হাঁটতে হয় — O(n)।
# L39 -- ইনডেক্সড অ্যালোকেশন সিমুলেশন (toy in-memory ডিস্ক ব্লক, বাস্তব ডিস্ক নয়)
# প্রতিটি ফাইলের নিজস্ব ইনডেক্স ব্লক -- লজিক্যাল ব্লক নম্বর -> ফিজিক্যাল ব্লক নম্বর
file_index = {
"movie.mp4": [42, 17, 88, 5, 63, 21], # লজিক্যাল ব্লক 0,1,2,3,4,5 -> ফিজিক্যাল ব্লক
}
def read_block(file_index_table, filename, logical_block_number):
if filename not in file_index_table:
return None, f"ব্যর্থ -> ফাইল '{filename}' পাওয়া যায়নি"
index_block = file_index_table[filename]
if logical_block_number < 0 or logical_block_number >= len(index_block):
return None, f"ব্যর্থ -> লজিক্যাল ব্লক {logical_block_number} সীমার বাইরে (ফাইলে মোট {len(index_block)}টি ব্লক)"
physical_block = index_block[logical_block_number] # O(1) সরাসরি লুকআপ -- কোনো ট্রাভার্সাল নেই
return physical_block, f"লজিক্যাল ব্লক {logical_block_number} -> ফিজিক্যাল ব্লক {physical_block} (O(1) সরাসরি অ্যাক্সেস)"
# লজিক্যাল ব্লক 0 এবং 5 -- উভয়ই সরাসরি, ট্রাভার্স না করেই
for lbn in [0, 5, 3]:
physical, message = read_block(file_index, "movie.mp4", lbn)
print(message)
# সীমার বাইরের অনুরোধ
physical, message = read_block(file_index, "movie.mp4", 10)
print(message)
# --- তুলনা: লিংকড অ্যালোকেশন হলে ব্লক 5 পেতে O(n) ট্রাভার্সাল লাগত ---
linked_chain = {0: (42, 1), 1: (17, 2), 2: (88, 3), 3: (5, 4), 4: (63, 5), 5: (21, None)}
# (physical_block, next_logical_block) -- শেষে None
def linked_read_block(chain, target_logical):
steps = 0
current = 0
while current is not None:
physical, nxt = chain[current]
steps += 1
if current == target_logical:
return physical, steps
current = nxt
return None, steps
physical, steps = linked_read_block(linked_chain, 5)
print(f"\nলিংকড অ্যালোকেশন হলে -> ব্লক 5 পেতে {steps}টি ধাপ ট্রাভার্স করতে হতো (O(n)), "
f"ইনডেক্সডে লাগে মাত্র ১টি ধাপ (O(1))")
তিনটি অ্যালোকেশন মেথডই মূলত একই ট্রেড-অফের ভিন্ন সমাধান — কন্টিগুয়াস গতি দেয় কিন্তু ফ্র্যাগমেন্টেশনের মূল্যে, লিংকড ফ্র্যাগমেন্টেশন এড়ায় কিন্তু র্যান্ডম-অ্যাক্সেস গতির মূল্যে, আর ইনডেক্সড একটি ছোট ইনডাইরেকশন লেয়ার (ইনডেক্স ব্লক) যোগ করে উভয় সমস্যাই এড়িয়ে যায় — ঠিক যেভাবে L31-এর পেজ টেবিল মেমরিতে একই কাজ করে।
ভাবনার প্রশ্ন
প্রতিটি প্রশ্ন নিজে কিছুক্ষণ ভাবুন — তারপর "→ উত্তর" চাপুন।
প্র ০১ কন্টিগুয়াস অ্যালোকেশন যদি অফসেট থেকে সরাসরি ব্লক গণনা করতে পারে (দ্রুততম), তাহলে সেটাই সবসময় কেন ব্যবহার করা হয় না?
কারণ এর ফ্র্যাগমেন্টেশন ও গ্রোথ সমস্যা বাস্তব ব্যবহারে মারাত্মক হয়ে ওঠে। ফাইল যত তৈরি ও মুছে ফেলা হয়, ডিস্কে ছোট ছোট বিক্ষিপ্ত ফ্রি "গর্ত" তৈরি হতে থাকে (ঠিক L28-এর মেমরির মতো) — এমনকি মোট ফ্রি স্পেস যথেষ্ট থাকলেও একটি বড় ফাইলের জন্য একটানা যথেষ্ট বড় জায়গা নাও পাওয়া যেতে পারে। এছাড়া একটি ফাইল তার বরাদ্দকৃত অঞ্চলের বাইরে বাড়তে চাইলে পুরো ফাইলটিকেই অন্য কোথাও নতুনভাবে কপি করতে হতে পারে — বাস্তব ব্যবহারে এই দুই সমস্যা একসাথে মিলে কন্টিগুয়াসকে ব্যবহারিকভাবে অগ্রহণযোগ্য করে তোলে বড় সাধারণ-উদ্দেশ্য ফাইল সিস্টেমের জন্য।
প্র ০২ লিংকড অ্যালোকেশনে "একটি পয়েন্টার নষ্ট হলে বাকি চেইন ভেঙে যায়" — এটি ইনডেক্সড অ্যালোকেশনেও কি একইভাবে ঘটতে পারে?
না, একই মাত্রায় নয়। লিংকডে প্রতিটি ব্লক শুধু পরের ব্লকের ঠিকানা জানে — মাঝের কোনো একটি ব্লক নষ্ট হলে তার পরের সব ব্লকের সাথে সংযোগ চিরতরে হারিয়ে যায় (কোনো বিকল্প পথ নেই)। ইনডেক্সডে সব ঠিকানা একটি কেন্দ্রীয় ইনডেক্স ব্লকে জমা থাকে — যদি একটি নির্দিষ্ট ডেটা ব্লক নষ্ট হয়, শুধু সেই একটি ব্লকের তথ্য হারায়, বাকি ব্লকগুলোর ঠিকানা ইনডেক্সে অক্ষত থাকে। তবে ইনডেক্স ব্লক নিজে নষ্ট হলে (একটি সিঙ্গেল পয়েন্ট অফ ফেলিওর) পুরো ফাইলের ম্যাপিং হারিয়ে যায় — এই কারণেই বাস্তব ফাইল সিস্টেম ইনডেক্স ব্লকের গুরুত্বপূর্ণ ডেটা অতিরিক্ত সতর্কতার সাথে সংরক্ষণ/ব্যাকআপ করে (L41-এর জার্নালিং এই ধরনের সমস্যারই একটি সমাধান)।
প্র ০৩
কোড সেলে read_block ফাংশনটি কেন O(1) কিন্তু linked_read_block ফাংশনটি O(n) — কোড দেখে ঠিক কোন লাইনটি এই পার্থক্যের কারণ?
read_block-এ মূল অপারেশন হলো index_block[logical_block_number] — এটি একটি
সরাসরি লিস্ট-ইনডেক্সিং, যার খরচ তালিকার আকার নির্বিশেষে সবসময় ধ্রুবক। বিপরীতে
linked_read_block-এ একটি while লুপ আছে যা current-কে ধাপে ধাপে
0 থেকে টার্গেট পর্যন্ত এগিয়ে নেয় — টার্গেট ব্লক যত পরে থাকবে (যেমন ব্লক 5), লুপ তত বেশিবার
চলবে। কোড সেলের আউটপুটে steps-এর মান (৬) সরাসরি এই ট্রাভার্সাল-নির্ভরতা প্রমাণ করে।
অনুশীলন
-
চিন্তা করুন: একটি বড় ভিডিও ফাইল যা শুধু সামনে থেকে পেছনে ক্রমান্বয়ে চালানো হবে (সিকোয়েনশিয়াল অ্যাক্সেস) — এর জন্য কন্টিগুয়াস, লিংকড ও ইনডেক্সড-এর মধ্যে কোনটি সবচেয়ে ভালো ফিট, এবং কেন?
বিশুদ্ধ সিকোয়েনশিয়াল অ্যাক্সেসের জন্য তিনটিই কার্যকরভাবে ভালো পারফর্ম করে, কারণ কখনোই র্যান্ডম-অ্যাক্সেসের দুর্বলতাগুলো (লিংকডের O(n) ট্রাভার্সাল) প্রকট হয় না — শুধু "পরের ব্লক কোনটা" জানলেই চলে। তবে বাস্তবে ইউজাররা প্রায়ই ভিডিওতে সিক (seek/স্কিপ ফরোয়ার্ড/ব্যাকওয়ার্ড) করে, যা কার্যত র্যান্ডম অ্যাক্সেস — তাই বাস্তব ফাইল সিস্টেম সাধারণত ইনডেক্সড অ্যালোকেশনই বেছে নেয়, শুধু বিশুদ্ধ তাত্ত্বিক সিকোয়েনশিয়াল ব্যবহারের জন্যও নয়, বাস্তব ব্যবহারকারীর অনির্দেশ্য আচরণের জন্যও।
-
পরীক্ষা করুন: উপরের কোড সেলে
file_index["movie.mp4"]-এ আরও একটি ব্লক নম্বর (যেমন99) যোগ করেread_block(file_index, "movie.mp4", 6)কল করে দেখুন — সঠিক ফলাফল আসে কি না।তালিকা
[42, 17, 88, 5, 63, 21, 99]-এ পরিণত হওয়ার পর, লজিক্যাল ব্লক 6 এখন বৈধ পরিসরের মধ্যে (len(index_block)এখন 7, তাই6 < 7সত্য) — ফলাফল হবে ফিজিক্যাল ব্লক99, একইভাবে O(1)-এ। এটি দেখায় ইনডেক্সড অ্যালোকেশনে একটি ফাইল বড় হলে শুধু ইনডেক্স তালিকায় একটি এন্ট্রি যোগ করলেই চলে — কন্টিগুয়াসের মতো পুরো ফাইল রিলোকেট করার দরকার নেই।
আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ
- পরবর্তী পাঠ — ফ্রি স্পেস ম্যানেজমেন্ট L40 নতুন ফাইলের জন্য ব্লক বরাদ্দ করতে হলে আগে জানতে হয় কোন ব্লক ফ্রি — সেই ট্র্যাকিং ব্যবস্থা এই পাঠে।
- কন্টিগুয়াস মেমরি অ্যালোকেশন L28 এই পাঠের কন্টিগুয়াস ডিস্ক অ্যালোকেশনের সরাসরি সমান্তরাল — একই ফ্র্যাগমেন্টেশন সমস্যা, ভিন্ন রিসোর্সে।
- কোর্সের সম্পূর্ণ সিলেবাস দেখুন ৫৬টি পাঠ প্রসেস, মেমরি, ফাইল সিস্টেম, I/O ও ভার্চুয়ালাইজেশন — সব মডিউল এক জায়গায়।
- সব Courses দেখুন ABCL TECH C, C++, Python, Java, JavaScript, DSA, DBMS, Discrete Mathematics, System Design, Cybersecurity, Cloud Computing & DevOps, Computer Networks ও Operating Systems — সব এক জায়গায়।