iOS ایپلی کیشنز میں کلیدی قدر ڈیٹا بیس LMDB کی چمک اور غربت

iOS ایپلی کیشنز میں کلیدی قدر ڈیٹا بیس LMDB کی چمک اور غربت

2019 کے موسم خزاں میں، Mail.ru Cloud iOS ٹیم میں ایک طویل انتظار کا واقعہ پیش آیا۔ ایپلیکیشن سٹیٹ کے مستقل ذخیرہ کرنے کا مرکزی ڈیٹا بیس موبائل کی دنیا کے لیے بہت غیر ملکی ہو گیا ہے۔ لائٹننگ میموری میپڈ ڈیٹا بیس (LMDB)۔ کٹ کے نیچے ہم آپ کو چار حصوں میں اس کا تفصیلی جائزہ پیش کرتے ہیں۔ سب سے پہلے، اس طرح کے ایک غیر معمولی اور مشکل انتخاب کی وجوہات کے بارے میں بات کرتے ہیں. پھر ہم LMDB فن تعمیر کے مرکز میں تین ستونوں پر غور کرنے کے لیے آگے بڑھیں گے: میموری میپڈ فائلز، B+-ٹری، لین دین اور ملٹی ورشن کو نافذ کرنے کے لیے کاپی آن رائٹ اپروچ۔ آخر میں، میٹھی کے لئے - عملی حصہ. اس میں ہم دیکھیں گے کہ ڈیٹا بیس اسکیما کو کس طرح ڈیزائن اور لاگو کرنا ہے جس میں متعدد ٹیبلز، بشمول ایک انڈیکس ایک، کم سطح کی کلیدی قدر API کے اوپر ہے۔

مواد

  1. نفاذ کے لیے ترغیب
  2. LMDB پوزیشننگ
  3. LMDB کے تین ستون
    3.1. وہیل #1۔ میموری میپ شدہ فائلیں۔
    3.2. وہیل #2۔ B+ درخت
    3.3. وہیل #3۔ کاپی آن رائٹ
  4. کلیدی قدر API کے اوپری حصے میں ڈیٹا اسکیما ڈیزائن کرنا
    4.1. بنیادی تجریدات
    4.2. ٹیبل ماڈلنگ
    4.3. میزوں کے درمیان تعلقات کی ماڈلنگ

1. نفاذ کے لیے ترغیب

2015 میں ایک سال، ہم نے یہ پیمائش کرنے میں پریشانی کا سامنا کیا کہ ہماری درخواست کا انٹرفیس کتنی بار پیچھے رہ جاتا ہے۔ ہم نے یہ ایک وجہ سے کیا۔ ہمیں زیادہ بار بار شکایات موصول ہوئی ہیں کہ بعض اوقات ایپلیکیشن صارف کی کارروائیوں کا جواب دینا بند کر دیتی ہے: بٹن دبایا نہیں جا سکتا، فہرستیں اسکرول نہیں ہوتی، وغیرہ۔ پیمائش کے میکانکس کے بارے میں بتایا AvitoTech پر، تو یہاں میں صرف نمبروں کی ترتیب دیتا ہوں۔

iOS ایپلی کیشنز میں کلیدی قدر ڈیٹا بیس LMDB کی چمک اور غربت

پیمائش کے نتائج ہمارے لیے سرد شاور بن گئے۔ یہ پتہ چلا کہ کسی بھی دوسرے کے مقابلے میں منجمد کی وجہ سے بہت زیادہ مسائل ہیں. اگر اس حقیقت کو سمجھنے سے پہلے معیار کا اہم تکنیکی اشارے حادثے سے پاک تھا، تو توجہ کے بعد منتقل منجمد فری پر.

تعمیر کر کے منجمد کے ساتھ ڈیش بورڈ اور خرچ کرنے کے بعد مقداری и معیار ان کی وجوہات کا تجزیہ، اہم دشمن واضح ہو گیا - بھاری کاروباری منطق درخواست کے مرکزی دھاگے میں پھانسی دی گئی. اس بے عزتی کا فطری ردعمل اسے کام کی ندیوں میں دھکیلنے کی جلتی خواہش تھی۔ اس مسئلے کو منظم طریقے سے حل کرنے کے لیے، ہم نے ہلکے وزن کے اداکاروں پر مبنی ملٹی تھریڈڈ فن تعمیر کا سہارا لیا۔ میں نے اسے iOS کی دنیا کے لیے اس کی موافقت کے لیے وقف کیا۔ دو دھاگے اجتماعی ٹویٹر پر اور Habré پر مضمون. موجودہ بیانیہ کے حصے کے طور پر، میں فیصلے کے ان پہلوؤں پر زور دینا چاہتا ہوں جنہوں نے ڈیٹا بیس کے انتخاب کو متاثر کیا۔

سسٹم آرگنائزیشن کا ایکٹر ماڈل فرض کرتا ہے کہ ملٹی تھریڈنگ اس کا دوسرا جوہر بن جاتا ہے۔ اس میں ماڈل آبجیکٹ ندی کی حدود کو عبور کرنا پسند کرتے ہیں۔ اور وہ ایسا کبھی کبھی یہاں اور وہاں نہیں کرتے بلکہ تقریباً مسلسل اور ہر جگہ کرتے ہیں۔

iOS ایپلی کیشنز میں کلیدی قدر ڈیٹا بیس LMDB کی چمک اور غربت

ڈیٹابیس پیش کردہ خاکہ میں سنگ بنیاد کے اجزاء میں سے ایک ہے۔ اس کا بنیادی کام میکرو پیٹرن کو نافذ کرنا ہے۔ مشترکہ ڈیٹا بیس. اگر انٹرپرائز کی دنیا میں یہ خدمات کے مابین ڈیٹا کی ہم آہنگی کو منظم کرنے کے لئے استعمال کیا جاتا ہے، تو اداکار فن تعمیر کے معاملے میں - دھاگوں کے درمیان ڈیٹا۔ اس طرح، ہمیں ایک ایسے ڈیٹا بیس کی ضرورت تھی جو کثیر تھریڈ والے ماحول میں اس کے ساتھ کام کرتے وقت معمولی مشکلات کا باعث نہ ہو۔ خاص طور پر، اس کا مطلب یہ ہے کہ اس سے حاصل کردہ اشیاء کم از کم دھاگے سے محفوظ، اور مثالی طور پر مکمل طور پر غیر متغیر ہونی چاہئیں۔ جیسا کہ آپ جانتے ہیں، مؤخر الذکر کو کئی دھاگوں سے بیک وقت استعمال کیا جا سکتا ہے بغیر کسی تالے کا سہارا لیے، جس کا کارکردگی پر فائدہ مند اثر پڑتا ہے۔

iOS ایپلی کیشنز میں کلیدی قدر ڈیٹا بیس LMDB کی چمک اور غربتدوسرا اہم عنصر جس نے ڈیٹا بیس کے انتخاب کو متاثر کیا وہ ہمارا کلاؤڈ API تھا۔ یہ گٹ کے ذریعہ اختیار کردہ ہم آہنگی کے نقطہ نظر سے متاثر ہوا تھا۔ اس کی طرح، ہم نے مقصد کیا آف لائن-پہلا API، جو کلاؤڈ کلائنٹس کے لیے مناسب سے زیادہ لگتا ہے۔ یہ فرض کیا گیا تھا کہ وہ صرف ایک بار بادل کی مکمل حالت کو پمپ کریں گے، اور پھر زیادہ تر معاملات میں ہم آہنگی تبدیلیوں کو رول آؤٹ کرنے کے ذریعے واقع ہوگی۔ افسوس، یہ موقع اب بھی صرف نظریاتی زون میں ہے، اور کلائنٹس نے یہ نہیں سیکھا ہے کہ عملی طور پر پیچ کے ساتھ کیسے کام کرنا ہے۔ اس کی بہت سی معروضی وجوہات ہیں، جن کی وجہ سے تعارف میں تاخیر نہ ہو، ہم اسے پیچھے چھوڑ دیں گے۔ اب، جو چیز زیادہ دلچسپی کا باعث ہے وہ سبق کے سبق آموز نتائج ہیں کہ جب ایک API کہتا ہے "A" اور اس کا صارف "B" نہیں کہتا ہے تو کیا ہوتا ہے۔

لہذا، اگر آپ گٹ کا تصور کرتے ہیں، جو پل کمانڈ پر عمل کرتے وقت، مقامی اسنیپ شاٹ پر پیچ لگانے کے بجائے، اس کی پوری حالت کا مکمل سرور اسٹیٹ سے موازنہ کرتا ہے، تو آپ کو کافی حد تک درست اندازہ ہوگا کہ کلاؤڈ میں ہم آہنگی کیسے ہوتی ہے۔ کلائنٹس یہ اندازہ لگانا آسان ہے کہ اسے لاگو کرنے کے لیے، آپ کو تمام سرور اور مقامی فائلوں کے بارے میں میٹا معلومات کے ساتھ میموری میں دو DOM درخت مختص کرنے کی ضرورت ہے۔ یہ پتہ چلتا ہے کہ اگر کوئی صارف کلاؤڈ میں 500 ہزار فائلوں کو ذخیرہ کرتا ہے، تو اسے مطابقت پذیر کرنے کے لئے 1 ملین نوڈس کے ساتھ دو درختوں کو دوبارہ بنانا اور تباہ کرنا ضروری ہے. لیکن ہر نوڈ ایک مجموعی ہے جس میں ذیلی اشیاء کا گراف ہوتا ہے۔ اس روشنی میں، پروفائلنگ کے نتائج متوقع تھے۔ یہ پتہ چلا کہ ضم ہونے والے الگورتھم کو مدنظر رکھے بغیر بھی، بڑی تعداد میں چھوٹی اشیاء کو بنانے اور اسے تباہ کرنے کے طریقہ کار پر ایک پیسہ خرچ ہوتا ہے اس حقیقت کی وجہ سے کہ بنیادی مطابقت پذیری کا عمل بڑی تعداد میں شامل ہے۔ صارف کے اسکرپٹس کا۔ نتیجے کے طور پر، ہم ڈیٹا بیس کے انتخاب میں دوسرا اہم معیار طے کرتے ہیں - اشیاء کی متحرک تخصیص کے بغیر CRUD آپریشنز کو لاگو کرنے کی صلاحیت۔

دیگر تقاضے زیادہ روایتی ہیں اور ان کی پوری فہرست درج ذیل ہے۔

  1. دھاگے کی حفاظت۔
  2. ملٹی پروسیسنگ۔ ریاست کو نہ صرف تھریڈز کے درمیان بلکہ مرکزی ایپلیکیشن اور iOS ایکسٹینشنز کے درمیان بھی ہم آہنگ کرنے کے لیے ایک ہی ڈیٹا بیس مثال کو استعمال کرنے کی خواہش کے مطابق۔
  3. ذخیرہ شدہ اداروں کو غیر متغیر اشیاء کے طور پر پیش کرنے کی صلاحیت
  4. CRUD آپریشنز کے اندر کوئی متحرک مختص نہیں ہے۔
  5. بنیادی جائیدادوں کے لیے لین دین کی معاونت ایسڈ: جوہری، مستقل مزاجی، تنہائی اور وشوسنییتا۔
  6. سب سے زیادہ مقبول مقدمات پر رفتار.

ضروریات کے اس سیٹ کے ساتھ، SQLite ایک اچھا انتخاب تھا اور اب بھی ہے۔ تاہم، متبادلات کے مطالعہ کے حصے کے طور پر، مجھے ایک کتاب ملی "لیول ڈی بی کے ساتھ شروع کرنا". اس کی قیادت میں، ایک بینچ مارک لکھا گیا تھا جس میں کام کی رفتار کا مختلف ڈیٹا بیس کے ساتھ حقیقی کلاؤڈ منظرناموں میں موازنہ کیا گیا تھا۔ نتیجہ ہماری جنگلی توقعات سے بڑھ گیا۔ سب سے زیادہ مقبول معاملات میں - تمام فائلوں کی ترتیب شدہ فہرست اور دی گئی ڈائریکٹری کے لیے تمام فائلوں کی ترتیب شدہ فہرست پر کرسر حاصل کرنا - LMDB SQLite سے 10 گنا تیز نکلا۔ انتخاب واضح ہو گیا۔

iOS ایپلی کیشنز میں کلیدی قدر ڈیٹا بیس LMDB کی چمک اور غربت

2. LMDB پوزیشننگ

LMDB ایک بہت چھوٹی لائبریری ہے (صرف 10K قطاریں) جو ڈیٹا بیس کی سب سے کم بنیادی تہہ - اسٹوریج کو لاگو کرتی ہے۔

iOS ایپلی کیشنز میں کلیدی قدر ڈیٹا بیس LMDB کی چمک اور غربت

مندرجہ بالا خاکہ ظاہر کرتا ہے کہ LMDB کا SQLite کے ساتھ موازنہ کرنا، جو کہ اعلیٰ سطحوں کو بھی لاگو کرتا ہے، عام طور پر کور ڈیٹا والے SQLite سے زیادہ درست نہیں ہے۔ یکساں حریفوں - برکلے ڈی بی، لیول ڈی بی، سوفیا، راکس ڈی بی، وغیرہ کے طور پر ایک ہی اسٹوریج انجن کا حوالہ دینا زیادہ مناسب ہوگا۔ اس طرح کا پہلا تجربہ 2012 میں کیا گیا تھا۔ خرچ کیا LMDB کی طرف سے ہاورڈ چو. نتائج اتنا دلچسپ نکلا کہ اس کی پہل کو OSS کے شائقین نے اٹھایا، اور اس شخص میں اس کا تسلسل پایا LumoSQL. جنوری 2020 میں، اس پروجیکٹ کے مصنف ڈین شیئرر تھے۔ پیش کیا یہ LinuxConfAu پر ہے۔

LMDB بنیادی طور پر ایپلیکیشن ڈیٹا بیس کے انجن کے طور پر استعمال ہوتا ہے۔ لائبریری اس کی ظاہری شکل ڈویلپرز کی مرہون منت ہے۔ OpenLDAP، جو اپنے پروجیکٹ کی بنیاد کے طور پر برکلے ڈی بی سے انتہائی غیر مطمئن تھے۔ ایک معمولی لائبریری سے شروع btree، ہاورڈ چو ہمارے وقت کے سب سے زیادہ مقبول متبادلوں میں سے ایک بنانے کے قابل تھا۔ اس نے اپنی بہت عمدہ رپورٹ اس کہانی کے ساتھ ساتھ LMDB کے اندرونی ڈھانچے کے لیے وقف کی۔ "دی لائٹننگ میموری میپڈ ڈیٹا بیس". اسٹوریج کی سہولت کو فتح کرنے کی ایک اچھی مثال لیونیڈ یورییف (عرف yleoہائی لوڈ 2015 میں اپنی رپورٹ میں مثبت ٹیکنالوجیز سے "LMDB انجن ایک خاص چیمپئن ہے". اس میں، وہ LMDB کے بارے میں ReOpenLDAP کو لاگو کرنے کے اسی طرح کے کام کے تناظر میں بات کرتا ہے، اور LevelDB پہلے ہی تقابلی تنقید کا نشانہ بن چکا ہے۔ نفاذ کے نتیجے میں، مثبت ٹیکنالوجیز میں بھی فعال طور پر ترقی پذیر کانٹا تھا۔ ایم ڈی بی ایکس بہت سوادج خصوصیات کے ساتھ، اصلاح اور بگ کی اصلاحات.

LMDB اکثر بطور سٹوریج کے طور پر استعمال ہوتا ہے۔ مثال کے طور پر، موزیلا فائر فاکس براؤزر منتخب کیا یہ متعدد ضروریات کے لیے، اور ورژن 9، Xcode سے شروع ہوتا ہے۔ ترجیحی اشاریہ جات کو ذخیرہ کرنے کے لیے اس کا SQLite۔

انجن نے موبائل کی ترقی کی دنیا میں بھی اپنی شناخت بنائی ہے۔ اس کے استعمال کے آثار ہو سکتے ہیں۔ تلاش کرنے کے لئے ٹیلیگرام کے لیے iOS کلائنٹ میں۔ LinkedIn اور بھی آگے بڑھا اور LMDB کو اپنے آبائی ڈیٹا کیشنگ فریم ورک راکٹ ڈیٹا کے لیے ڈیفالٹ اسٹوریج کے طور پر منتخب کیا، جس کے بارے میں بتایا 2016 میں اپنے مضمون میں۔

LMDB اوریکل کے کنٹرول میں آنے کے بعد برکلے ڈی بی کے چھوڑے ہوئے طاق میں سورج میں جگہ کے لیے کامیابی سے لڑ رہا ہے۔ لائبریری کو اس کی رفتار اور قابل اعتمادی کے لیے پسند کیا جاتا ہے، یہاں تک کہ اس کے ساتھیوں کے مقابلے میں۔ جیسا کہ آپ جانتے ہیں، کوئی مفت لنچ نہیں ہے، اور میں اس تجارت پر زور دینا چاہوں گا جس کا سامنا آپ کو LMDB اور SQLite کے درمیان انتخاب کرتے وقت کرنا پڑے گا۔ اوپر والا خاکہ واضح طور پر ظاہر کرتا ہے کہ رفتار میں اضافہ کیسے کیا جاتا ہے۔ سب سے پہلے، ہم ڈسک اسٹوریج کے اوپر تجرید کی اضافی تہوں کے لیے ادائیگی نہیں کرتے ہیں۔ یہ واضح ہے کہ ایک اچھا فن تعمیر اب بھی ان کے بغیر نہیں کر سکتا، اور وہ لازمی طور پر ایپلیکیشن کوڈ میں ظاہر ہوں گے، لیکن وہ زیادہ لطیف ہوں گے۔ ان میں ایسی خصوصیات نہیں ہوں گی جن کی کسی مخصوص ایپلیکیشن کے لیے ضرورت نہیں ہے، مثال کے طور پر، SQL زبان میں سوالات کے لیے تعاون۔ دوم، ڈسک اسٹوریج کی درخواستوں پر ایپلیکیشن آپریشنز کی میپنگ کو بہترین طریقے سے نافذ کرنا ممکن ہو جاتا ہے۔ اگر SQLite میرے کام میں اوسط ایپلی کیشن کی اوسط شماریاتی ضروریات پر مبنی ہے، پھر آپ، ایک ایپلیکیشن ڈویلپر کے طور پر، کام کے بوجھ کے اہم منظرناموں سے بخوبی واقف ہیں۔ زیادہ نتیجہ خیز حل کے لیے، آپ کو ابتدائی حل کی ترقی اور اس کے بعد کے تعاون کے لیے قیمت میں اضافہ ادا کرنا ہوگا۔

3. LMDB کے تین ستون

ایل ایم ڈی بی کو برڈز آئی ویو سے دیکھنے کے بعد، یہ گہرائی میں جانے کا وقت تھا۔ اگلے تین حصے ان اہم ستونوں کے تجزیہ کے لیے وقف کیے جائیں گے جن پر سٹوریج کا فن تعمیر ہے:

  1. ڈسک کے ساتھ کام کرنے اور اندرونی ڈیٹا ڈھانچے کو ہم آہنگ کرنے کے طریقہ کار کے طور پر میموری سے نقشہ شدہ فائلیں۔
  2. B+-درخت ذخیرہ شدہ ڈیٹا کی ساخت کی تنظیم کے طور پر۔
  3. ACID ٹرانزیکشن پراپرٹیز اور ملٹی ورشن فراہم کرنے کے نقطہ نظر کے طور پر کاپی آن رائٹ۔

3.1 وہیل #1۔ میموری میپ شدہ فائلیں۔

میموری میپڈ فائلیں ایک ایسا اہم آرکیٹیکچرل عنصر ہیں کہ وہ ریپوزٹری کے نام سے بھی ظاہر ہوتی ہیں۔ ذخیرہ شدہ معلومات تک رسائی کی کیشنگ اور مطابقت پذیری کے مسائل مکمل طور پر آپریٹنگ سسٹم پر چھوڑے گئے ہیں۔ LMDB اپنے اندر کوئی کیش نہیں رکھتا ہے۔ یہ مصنف کا ایک شعوری فیصلہ ہے، کیونکہ میپ شدہ فائلوں سے براہ راست ڈیٹا پڑھنے سے آپ انجن کے نفاذ میں بہت سے کونوں کو کاٹ سکتے ہیں۔ ذیل میں ان میں سے کچھ کی مکمل فہرست سے بہت دور ہے۔

  1. سٹوریج میں ڈیٹا کی مستقل مزاجی کو برقرار رکھنا آپریٹنگ سسٹم کی ذمہ داری بن جاتا ہے۔ اگلے حصے میں، اس میکانکس پر تفصیل اور تصویروں کے ساتھ بحث کی گئی ہے۔
  2. کیشز کی عدم موجودگی LMDB کو متحرک مختص سے وابستہ اوور ہیڈ سے مکمل طور پر ختم کر دیتی ہے۔ عملی طور پر ڈیٹا پڑھنے کا مطلب ہے کہ ورچوئل میموری میں درست ایڈریس پر پوائنٹر سیٹ کرنا اور اس سے زیادہ کچھ نہیں۔ یہ سائنس فکشن کی طرح لگتا ہے، لیکن سٹوریج سورس کوڈ میں کالوک کی تمام کالیں اسٹوریج کنفیگریشن فنکشن میں مرکوز ہیں۔
  3. کیچز کی عدم موجودگی کا مطلب یہ بھی ہے کہ ان کی رسائی کی مطابقت پذیری سے وابستہ تالے کی عدم موجودگی۔ قارئین، جن میں سے ایک ہی وقت میں قارئین کی ایک صوابدیدی تعداد ہوسکتی ہے، ڈیٹا کے راستے پر کسی ایک میوٹیکس کا سامنا نہیں کرتے ہیں۔ اس کی وجہ سے، CPUs کی تعداد کی بنیاد پر پڑھنے کی رفتار میں مثالی لکیری اسکیل ایبلٹی ہے۔ LMDB میں، صرف ترمیمی کارروائیوں کو ہم آہنگ کیا جاتا ہے۔ ایک وقت میں صرف ایک لکھاری ہو سکتا ہے۔
  4. کم از کم کیشنگ اور سنکرونائزیشن منطق کثیر تھریڈڈ ماحول میں کام کرنے سے وابستہ انتہائی پیچیدہ قسم کی خرابیوں کو ختم کرتی ہے۔ Usenix OSDI 2014 کانفرنس میں ڈیٹا بیس کے دو دلچسپ مطالعہ تھے: "تمام فائل سسٹمز برابر نہیں بنائے گئے ہیں: کریش-مسلسل ایپلی کیشنز کو تیار کرنے کی پیچیدگی پر" и "تفریح ​​اور منافع کے لیے ڈیٹا بیس کو اذیت دینا". ان سے آپ LMDB کی بے مثال وشوسنییتا اور ACID ٹرانزیکشن پراپرٹیز کے تقریباً بے عیب نفاذ کے بارے میں معلومات اکٹھا کر سکتے ہیں، جو SQLite سے برتر ہے۔
  5. LMDB کی minimalism اس کے کوڈ کی مشین کی نمائندگی کو پروسیسر کے L1 کیشے میں آنے والی رفتار کی خصوصیات کے ساتھ مکمل طور پر واقع ہونے کی اجازت دیتی ہے۔

بدقسمتی سے، iOS میں، میموری کے نقشے والی فائلوں کے ساتھ، ہر چیز اتنی بادل کے بغیر نہیں ہے جیسا کہ ہم چاہتے ہیں۔ ان سے منسلک کوتاہیوں کے بارے میں زیادہ شعوری طور پر بات کرنے کے لیے، آپریٹنگ سسٹمز میں اس طریقہ کار کو لاگو کرنے کے عمومی اصولوں کو یاد رکھنا ضروری ہے۔

میموری میپ شدہ فائلوں کے بارے میں عمومی معلومات

iOS ایپلی کیشنز میں کلیدی قدر ڈیٹا بیس LMDB کی چمک اور غربتچلنے والی ہر ایپلیکیشن کے ساتھ، آپریٹنگ سسٹم ایک ہستی کو جوڑتا ہے جسے عمل کہتے ہیں۔ ہر عمل کو پتے کی ایک متضاد رینج مختص کی جاتی ہے جس میں وہ ہر وہ چیز رکھتا ہے جس کی اسے کام کرنے کی ضرورت ہوتی ہے۔ سب سے کم پتوں پر کوڈ اور ہارڈ کوڈ شدہ ڈیٹا اور وسائل والے حصے ہیں۔ اس کے بعد ڈائنامک ایڈریس اسپیس کا ایک بڑھتا ہوا بلاک آتا ہے، جو ہمیں ہیپ کے نام سے جانا جاتا ہے۔ اس میں ان اداروں کے پتے ہوتے ہیں جو پروگرام کے آپریشن کے دوران ظاہر ہوتے ہیں۔ سب سے اوپر ایپلی کیشن اسٹیک کے ذریعہ استعمال ہونے والا میموری ایریا ہے۔ یہ یا تو بڑھتا ہے یا سکڑتا ہے؛ دوسرے لفظوں میں، اس کا سائز بھی ایک متحرک نوعیت رکھتا ہے۔ اسٹیک اور ہیپ کو ایک دوسرے کے ساتھ دھکیلنے اور مداخلت کرنے سے روکنے کے لیے، وہ ایڈریس اسپیس کے مختلف سروں پر واقع ہیں۔ اوپر اور نیچے دو متحرک حصوں کے درمیان ایک سوراخ ہے۔ آپریٹنگ سسٹم اس درمیانی حصے میں ایڈریس کا استعمال کرتا ہے تاکہ مختلف اداروں کو عمل کے ساتھ منسلک کیا جا سکے۔ خاص طور پر، یہ پتوں کے ایک مخصوص مسلسل سیٹ کو ڈسک پر موجود فائل کے ساتھ منسلک کر سکتا ہے۔ ایسی فائل کو میموری میپڈ کہا جاتا ہے۔

اس عمل کے لیے مختص ایڈریس کی جگہ بہت بڑی ہے۔ نظریاتی طور پر، پتوں کی تعداد صرف پوائنٹر کے سائز سے محدود ہوتی ہے، جس کا تعین سسٹم کی بٹ صلاحیت سے ہوتا ہے۔ اگر فزیکل میموری کو اس میں 1-to-1 میپ کیا جاتا ہے، تو پھر پہلا ہی عمل پوری RAM کو ختم کر دے گا، اور کسی ملٹی ٹاسکنگ کی کوئی بات نہیں ہوگی۔

تاہم، ہمارے تجربے سے ہم جانتے ہیں کہ جدید آپریٹنگ سسٹمز ایک ہی وقت میں مطلوبہ عمل کو انجام دے سکتے ہیں۔ یہ اس حقیقت کی وجہ سے ممکن ہے کہ وہ صرف کاغذ پر عمل کے لیے بہت زیادہ میموری مختص کرتے ہیں، لیکن حقیقت میں وہ مرکزی جسمانی میموری میں صرف وہی حصہ لوڈ کرتے ہیں جس کی یہاں اور اب مانگ ہے۔ اس لیے کسی عمل سے وابستہ میموری کو ورچوئل کہا جاتا ہے۔

iOS ایپلی کیشنز میں کلیدی قدر ڈیٹا بیس LMDB کی چمک اور غربت

آپریٹنگ سسٹم ورچوئل اور فزیکل میموری کو ایک خاص سائز کے صفحات میں ترتیب دیتا ہے۔ جیسے ہی ورچوئل میموری کے کسی مخصوص صفحے کی مانگ ہوتی ہے، آپریٹنگ سسٹم اسے فزیکل میموری میں لوڈ کرتا ہے اور انہیں ایک خاص ٹیبل میں ملا دیتا ہے۔ اگر کوئی مفت سلاٹ نہیں ہے، تو پہلے سے بھری ہوئی صفحات میں سے ایک کو ڈسک پر کاپی کیا جاتا ہے، اور جس کی مانگ ہوتی ہے وہ اس کی جگہ لے لیتا ہے۔ یہ طریقہ کار، جس پر ہم جلد ہی واپس جائیں گے، کو تبادلہ کہتے ہیں۔ ذیل کی تصویر بیان کردہ عمل کی وضاحت کرتی ہے۔ اس پر صفحہ A کو ایڈریس 0 کے ساتھ لوڈ کیا گیا تھا اور ایڈریس 4 کے ساتھ مرکزی میموری والے صفحے پر رکھا گیا تھا۔ یہ حقیقت سیل نمبر 0 میں خط و کتابت کی میز میں ظاہر ہوئی تھی۔

iOS ایپلی کیشنز میں کلیدی قدر ڈیٹا بیس LMDB کی چمک اور غربت

کہانی بالکل ویسا ہی ہے جس میں فائلوں کو میموری میں میپ کیا گیا ہے۔ منطقی طور پر، وہ قیاس مسلسل اور مکمل طور پر ورچوئل ایڈریس اسپیس میں واقع ہیں۔ تاہم، وہ فزیکل میموری کا صفحہ بہ صفحہ اور صرف درخواست پر داخل کرتے ہیں۔ ایسے صفحات کی ترمیم کو ڈسک پر موجود فائل کے ساتھ ہم آہنگ کیا جاتا ہے۔ اس طرح، آپ صرف میموری میں بائٹس کے ساتھ کام کرکے فائل I/O کو انجام دے سکتے ہیں - تمام تبدیلیاں آپریٹنگ سسٹم کے کرنل کے ذریعہ خود بخود سورس فائل میں منتقل ہوجائیں گی۔

نیچے دی گئی تصویر یہ ظاہر کرتی ہے کہ LMDB مختلف پروسیسز سے ڈیٹا بیس کے ساتھ کام کرتے وقت اپنی حالت کو کیسے ہم آہنگ کرتا ہے۔ مختلف پروسیسز کی ورچوئل میموری کو ایک ہی فائل میں میپ کر کے، ہم آپریٹنگ سسٹم کو ان کے ایڈریس اسپیس کے کچھ بلاکس کو ایک دوسرے کے ساتھ عبوری طور پر ہم آہنگ کرنے کا پابند کرتے ہیں، جہاں LMDB نظر آتا ہے۔

iOS ایپلی کیشنز میں کلیدی قدر ڈیٹا بیس LMDB کی چمک اور غربت

ایک اہم بات یہ ہے کہ LMDB، بطور ڈیفالٹ، رائٹ سسٹم کال میکانزم کے ذریعے ڈیٹا فائل میں ترمیم کرتا ہے، اور فائل کو صرف پڑھنے کے موڈ میں دکھاتا ہے۔ اس نقطہ نظر کے دو اہم نتائج ہیں۔

پہلا نتیجہ تمام آپریٹنگ سسٹمز کے لیے عام ہے۔ اس کا جوہر یہ ہے کہ غلط کوڈ کے ذریعے ڈیٹا بیس کو غیر ارادی نقصان سے تحفظ فراہم کیا جائے۔ جیسا کہ آپ جانتے ہیں، کسی عمل کی قابل عمل ہدایات اس کے ایڈریس اسپیس میں کہیں سے بھی ڈیٹا تک رسائی کے لیے آزاد ہیں۔ ایک ہی وقت میں، جیسا کہ ہم نے ابھی یاد کیا، ایک فائل کو پڑھنے لکھنے کے موڈ میں ڈسپلے کرنے کا مطلب ہے کہ کوئی بھی ہدایت اس میں ترمیم بھی کر سکتی ہے۔ اگر وہ غلطی سے ایسا کرتی ہے، مثال کے طور پر، کسی غیر موجود انڈیکس پر کسی سرنی عنصر کو اوور رائٹ کرنے کی کوشش کر رہی ہے، تو وہ غلطی سے اس ایڈریس پر میپ کی گئی فائل کو تبدیل کر سکتی ہے، جس سے ڈیٹا بیس خراب ہو جائے گا۔ اگر فائل صرف پڑھنے کے موڈ میں ظاہر ہوتی ہے، تو متعلقہ ایڈریس کی جگہ کو تبدیل کرنے کی کوشش سگنل کے ساتھ پروگرام کو ہنگامی طور پر ختم کرنے کا باعث بنے گی۔ SIGSEGV، اور فائل برقرار رہے گی۔

دوسرا نتیجہ پہلے ہی iOS کے لیے مخصوص ہے۔ نہ تو مصنف اور نہ ہی کسی دوسرے ذرائع نے واضح طور پر اس کا ذکر کیا ہے، لیکن اس کے بغیر LMDB اس موبائل آپریٹنگ سسٹم پر چلنے کے لیے موزوں نہیں ہوگا۔ اگلا حصہ اس پر غور کرنے کے لیے وقف ہے۔

iOS میں میموری میپڈ فائلوں کی تفصیلات

WWDC میں 2018 میں ایک شاندار رپورٹ سامنے آئی تھی۔ "iOS میموری ڈیپ ڈائیو". یہ ہمیں بتاتا ہے کہ iOS میں، جسمانی میموری میں موجود تمام صفحات 3 اقسام میں سے ایک ہیں: گندے، کمپریسڈ اور صاف۔

iOS ایپلی کیشنز میں کلیدی قدر ڈیٹا بیس LMDB کی چمک اور غربت

کلین میموری صفحات کا ایک مجموعہ ہے جسے جسمانی میموری سے بغیر درد کے اتارا جا سکتا ہے۔ ان میں موجود ڈیٹا کو اس کے اصل ذرائع سے ضرورت کے مطابق دوبارہ لوڈ کیا جا سکتا ہے۔ صرف پڑھنے کے لیے میموری میپ شدہ فائلیں اس زمرے میں آتی ہیں۔ iOS کسی بھی وقت میموری سے فائل میں میپ کیے گئے صفحات کو اتارنے سے نہیں ڈرتا، کیونکہ ان کے ڈسک پر موجود فائل کے ساتھ مطابقت پذیر ہونے کی ضمانت ہے۔

تمام ترمیم شدہ صفحات گندی یادداشت میں ختم ہو جاتے ہیں، چاہے وہ اصل میں کہاں واقع ہوں۔ خاص طور پر، میموری میپ شدہ فائلوں کو ان کے ساتھ منسلک ورچوئل میموری پر لکھ کر تبدیل کیا جائے گا اس طرح درجہ بندی کی جائے گی۔ LMDB کو جھنڈے کے ساتھ کھولنا MDB_WRITEMAPاس میں تبدیلیاں کرنے کے بعد، آپ ذاتی طور پر اس کی تصدیق کر سکتے ہیں۔

جیسے ہی کوئی ایپلی کیشن بہت زیادہ جسمانی میموری لینا شروع کر دیتی ہے، iOS اسے صفحہ کے گندے کمپریشن سے مشروط کر دیتا ہے۔ گندے اور کمپریسڈ صفحات کے زیر قبضہ کل میموری ایپلی کیشن کے نام نہاد میموری فوٹ پرنٹ کو تشکیل دیتی ہے۔ ایک بار جب یہ ایک خاص حد کی قیمت تک پہنچ جاتا ہے، OOM قاتل سسٹم ڈیمون عمل کے بعد آتا ہے اور اسے زبردستی ختم کر دیتا ہے۔ یہ ڈیسک ٹاپ آپریٹنگ سسٹم کے مقابلے iOS کی خاصیت ہے۔ اس کے برعکس، صفحات کو فزیکل میموری سے ڈسک میں تبدیل کرکے میموری کے نشان کو کم کرنا iOS میں فراہم نہیں کیا جاتا ہے، اس کی وجوہات کا صرف اندازہ لگایا جا سکتا ہے۔ ہو سکتا ہے کہ صفحات کو ڈسک پر اور پیچھے منتقل کرنے کا طریقہ کار موبائل آلات کے لیے بہت زیادہ توانائی خرچ کرتا ہے، یا iOS SSD ڈرائیوز پر سیلز کو دوبارہ لکھنے کے وسائل کو بچاتا ہے، یا ہو سکتا ہے کہ ڈیزائنرز سسٹم کی مجموعی کارکردگی سے مطمئن نہ ہوں، جہاں سب کچھ ہے۔ مسلسل تبدیل. چاہے جیسا بھی ہو، حقیقت ایک حقیقت ہی رہتی ہے۔

اچھی خبر، جس کا پہلے ہی ذکر کیا جا چکا ہے، یہ ہے کہ LMDB بذریعہ ڈیفالٹ فائلوں کو اپ ڈیٹ کرنے کے لیے mmap میکانزم کا استعمال نہیں کرتا ہے۔ اس کا مطلب یہ ہے کہ ظاہر کردہ ڈیٹا کو iOS کی طرف سے کلین میموری کے طور پر درجہ بندی کیا گیا ہے اور یہ میموری فوٹ پرنٹ میں حصہ نہیں ڈالتا ہے۔ آپ VM ٹریکر نامی Xcode ٹول کا استعمال کرکے اس کی تصدیق کر سکتے ہیں۔ ذیل کا اسکرین شاٹ آپریشن کے دوران کلاؤڈ ایپلیکیشن کی iOS ورچوئل میموری کی حالت کو ظاہر کرتا ہے۔ شروع میں، 2 LMDB مثالیں اس میں شروع کی گئیں۔ پہلے کو اپنی فائل کو ورچوئل میموری کے 1GiB پر ظاہر کرنے کی اجازت تھی، دوسری - 512MiB۔ اس حقیقت کے باوجود کہ دونوں سٹوریج رہائشی میموری کی ایک خاص مقدار پر قبضہ کرتے ہیں، ان میں سے کوئی بھی گندے سائز میں حصہ نہیں ڈالتا ہے۔

iOS ایپلی کیشنز میں کلیدی قدر ڈیٹا بیس LMDB کی چمک اور غربت

اور اب بری خبر کا وقت آگیا ہے۔ 64-بٹ ڈیسک ٹاپ آپریٹنگ سسٹم میں سویپ میکانزم کی بدولت، ہر عمل اتنی زیادہ ورچوئل ایڈریس اسپیس پر قبضہ کرسکتا ہے جتنا کہ اس کے ممکنہ تبادلہ کے لیے مفت ہارڈ ڈسک کی جگہ اجازت دیتی ہے۔ آئی او ایس میں کمپریشن کے ساتھ سویپ کو تبدیل کرنا نظریاتی زیادہ سے زیادہ کو یکسر کم کر دیتا ہے۔ اب تمام زندہ عملوں کو مین (ریم کو پڑھیں) میموری میں فٹ ہونا چاہیے، اور وہ تمام جو فٹ نہیں ہوتے انہیں ختم کرنے پر مجبور کیا جانا چاہیے۔ یہ جیسا کہ اوپر بیان ہوا ہے۔ رپورٹ، اور میں سرکاری دستاویزات. نتیجے کے طور پر، iOS mmap کے ذریعے مختص کرنے کے لیے دستیاب میموری کی مقدار کو سختی سے محدود کرتا ہے۔ یہاں یہاں آپ میموری کی مقدار کی تجرباتی حدود کو دیکھ سکتے ہیں جو اس سسٹم کال کا استعمال کرتے ہوئے مختلف آلات پر مختص کی جاسکتی ہیں۔ جدید ترین سمارٹ فون ماڈلز پر، iOS 2 گیگا بائٹس، اور آئی پیڈ کے ٹاپ ورژنز پر - 4 تک فیاض ہو گیا ہے۔ عملی طور پر، آپ کو سب سے کم تعاون یافتہ ڈیوائس ماڈلز پر توجہ مرکوز کرنی ہوگی، جہاں سب کچھ بہت افسوسناک ہے۔ اس سے بھی بدتر، VM ٹریکر میں ایپلی کیشن کی میموری کی حالت کو دیکھ کر، آپ کو معلوم ہوگا کہ LMDB صرف ایک سے بہت دور ہے جو میموری میپ ہونے کا دعوی کرتا ہے۔ اچھے ٹکڑوں کو سسٹم مختص کرنے والے، وسائل کی فائلیں، تصویری فریم ورک، اور دوسرے چھوٹے شکاری کھا جاتے ہیں۔

کلاؤڈ میں تجربات کے نتائج کی بنیاد پر، ہم LMDB کی طرف سے مختص کردہ میموری کے لیے درج ذیل سمجھوتے کی اقدار پر پہنچے: 384-بٹ ڈیوائسز کے لیے 32 میگا بائٹس اور 768-بٹ ڈیوائسز کے لیے 64۔ اس حجم کے استعمال ہونے کے بعد، کوئی بھی ترمیمی کارروائی کوڈ کے ساتھ ختم ہونا شروع ہو جاتی ہے۔ MDB_MAP_FULL. ہم اپنی نگرانی میں ایسی خرابیوں کا مشاہدہ کرتے ہیں، لیکن وہ اتنی چھوٹی ہیں کہ اس مرحلے پر ان کو نظرانداز کیا جا سکتا ہے۔

اسٹوریج کے ذریعہ ضرورت سے زیادہ میموری کی کھپت کی ایک غیر واضح وجہ طویل المدت لین دین ہو سکتی ہے۔ یہ سمجھنے کے لیے کہ یہ دونوں مظاہر کیسے جڑے ہوئے ہیں، ہمیں LMDB کے بقیہ دو ستونوں پر غور کرنے سے مدد ملے گی۔

3.2 وہیل #2۔ B+ درخت

کلیدی ویلیو اسٹوریج کے اوپر ٹیبلز کی تقلید کرنے کے لیے، اس کے API میں درج ذیل آپریشنز کا ہونا ضروری ہے:

  1. ایک نیا عنصر داخل کرنا۔
  2. دی گئی کلید کے ساتھ ایک عنصر تلاش کریں۔
  3. ایک عنصر کو ہٹانا۔
  4. چابیاں کے وقفوں پر اس ترتیب سے اعادہ کریں جس ترتیب سے ان کو ترتیب دیا گیا ہے۔

iOS ایپلی کیشنز میں کلیدی قدر ڈیٹا بیس LMDB کی چمک اور غربتسب سے آسان ڈیٹا ڈھانچہ جو چاروں کارروائیوں کو آسانی سے نافذ کر سکتا ہے بائنری سرچ ٹری ہے۔ اس کا ہر نوڈ ایک کلید کی نمائندگی کرتا ہے جو چائلڈ کیز کے پورے سب سیٹ کو دو ذیلی درختوں میں تقسیم کرتا ہے۔ بائیں میں وہ ہیں جو والدین سے چھوٹے ہیں، اور دائیں میں وہ ہیں جو بڑے ہیں۔ کلیدوں کا آرڈرڈ سیٹ حاصل کرنا کلاسک ٹری ٹراورسلز میں سے ایک کے ذریعے حاصل کیا جاتا ہے۔

بائنری درختوں میں دو بنیادی خامیاں ہیں جو انہیں ڈسک پر مبنی ڈیٹا سٹرکچر کے طور پر موثر ہونے سے روکتی ہیں۔ سب سے پہلے، ان کے توازن کی ڈگری غیر متوقع ہے. درختوں کو حاصل کرنے کا کافی خطرہ ہے جس میں مختلف شاخوں کی اونچائیوں میں بہت فرق ہوسکتا ہے، جو توقع کے مقابلے میں تلاش کی الگورتھمک پیچیدگی کو نمایاں طور پر خراب کرتا ہے۔ دوم، نوڈس کے درمیان کراس روابط کی کثرت میموری میں بائنری ٹری کو لوکلٹی سے محروم کرتی ہے (ان کے درمیان کنکشن کے لحاظ سے) ورچوئل میموری میں بالکل مختلف صفحات پر واقع ہوسکتے ہیں۔ نتیجے کے طور پر، یہاں تک کہ ایک درخت میں کئی ہمسایہ نوڈس کے ایک سادہ سے گزرنے کے لیے بھی صفحات کی ایک تقابلی تعداد کو دیکھنے کی ضرورت پڑ سکتی ہے۔ یہ ایک مسئلہ ہے یہاں تک کہ جب ہم بائنری درختوں کی تاثیر کے بارے میں ایک ان میموری ڈیٹا سٹرکچر کے طور پر بات کرتے ہیں، کیونکہ پروسیسر کیشے میں صفحات کو مسلسل گھومنا کوئی سستی خوشی نہیں ہے۔ جب ڈسک سے نوڈس سے وابستہ صفحات کو کثرت سے بازیافت کرنے کی بات آتی ہے تو صورتحال مکمل طور پر بن جاتی ہے۔ افسوسناک.

iOS ایپلی کیشنز میں کلیدی قدر ڈیٹا بیس LMDB کی چمک اور غربتB-trees، بائنری درختوں کا ارتقاء ہونے کے ناطے، پچھلے پیراگراف میں جن مسائل کی نشاندہی کی گئی ہے ان کو حل کرتے ہیں۔ سب سے پہلے، وہ خود توازن ہیں. دوم، ان کا ہر نوڈ چائلڈ کیز کے سیٹ کو 2 میں نہیں، بلکہ M آرڈر شدہ سب سیٹس میں تقسیم کرتا ہے، اور M کی تعداد کئی سو، یا اس سے بھی ہزاروں کے آرڈر پر کافی بڑی ہو سکتی ہے۔

اس طرح:

  1. ہر نوڈ میں پہلے سے آرڈر کی گئی چابیاں کی ایک بڑی تعداد ہوتی ہے اور درخت بہت چھوٹے ہوتے ہیں۔
  2. درخت میموری میں محل وقوع کی خاصیت حاصل کرتا ہے، کیونکہ کلید جو قدر میں قریب ہوتی ہیں قدرتی طور پر ایک دوسرے کے ساتھ ایک ہی یا پڑوسی نوڈس پر واقع ہوتی ہیں۔
  3. تلاشی آپریشن کے دوران درخت سے اترتے وقت ٹرانزٹ نوڈس کی تعداد کم ہو جاتی ہے۔
  4. رینج کے سوالات کے دوران پڑھے جانے والے ٹارگٹ نوڈس کی تعداد کم ہو جاتی ہے، کیونکہ ان میں سے ہر ایک میں پہلے سے ہی بڑی تعداد میں آرڈر کی گئی کیز ہوتی ہیں۔

iOS ایپلی کیشنز میں کلیدی قدر ڈیٹا بیس LMDB کی چمک اور غربت

LMDB ڈیٹا کو ذخیرہ کرنے کے لیے B-tree کی ایک تبدیلی کا استعمال کرتا ہے جسے B+ درخت کہتے ہیں۔ اوپر والا خاکہ اس میں موجود نوڈس کی تین اقسام کو ظاہر کرتا ہے:

  1. سب سے اوپر جڑ ہے. یہ گودام کے اندر ڈیٹا بیس کے تصور سے زیادہ کچھ نہیں کرتا ہے۔ ایک LMDB مثال کے اندر، آپ متعدد ڈیٹا بیس بنا سکتے ہیں جو میپ شدہ ورچوئل ایڈریس اسپیس کا اشتراک کرتے ہیں۔ ان میں سے ہر ایک اپنی جڑ سے شروع ہوتا ہے۔
  2. سب سے نچلی سطح پر پتے ہیں۔ وہ اور صرف ان میں ڈیٹا بیس میں ذخیرہ شدہ کلیدی قدر کے جوڑے ہوتے ہیں۔ ویسے یہ B+-درختوں کی خاصیت ہے۔ اگر ایک باقاعدہ B-tree تمام سطحوں کے نوڈس میں قیمتی حصوں کو ذخیرہ کرتا ہے، تو B+ تغیر صرف سب سے نچلی سطح پر ہوتا ہے۔ اس حقیقت کو طے کرنے کے بعد، ہم مزید LMDB میں استعمال ہونے والے درخت کی ذیلی قسم کو صرف B-tree کہیں گے۔
  3. جڑ اور پتوں کے درمیان نیویگیشنل (برانچ) نوڈس کے ساتھ 0 یا اس سے زیادہ تکنیکی سطحیں ہوتی ہیں۔ ان کا کام پتوں کے درمیان چابیاں کے ترتیب شدہ سیٹ کو تقسیم کرنا ہے۔

جسمانی طور پر، نوڈس پہلے سے طے شدہ لمبائی کی میموری کے بلاکس ہیں۔ ان کا سائز آپریٹنگ سسٹم میں میموری پیجز کے سائز کا ایک کثیر ہے، جس پر ہم نے اوپر بات کی ہے۔ نوڈ کا ڈھانچہ ذیل میں دکھایا گیا ہے۔ ہیڈر میٹا معلومات پر مشتمل ہے، جس میں سب سے واضح مثال کے طور پر چیکسم ہے۔ اس کے بعد آفسیٹس کے بارے میں معلومات آتی ہیں جس میں ڈیٹا والے سیلز واقع ہیں۔ ڈیٹا یا تو کلید ہو سکتا ہے، اگر ہم نیویگیشن نوڈس کے بارے میں بات کر رہے ہیں، یا پتیوں کے معاملے میں کلیدی قدر کے پورے جوڑوں کے بارے میں۔ آپ کام میں صفحات کی ساخت کے بارے میں مزید پڑھ سکتے ہیں۔ "اعلی کارکردگی والے کلیدی قدر والے اسٹورز کی تشخیص".

iOS ایپلی کیشنز میں کلیدی قدر ڈیٹا بیس LMDB کی چمک اور غربت

صفحہ نوڈس کے اندرونی مواد سے نمٹنے کے بعد، ہم درج ذیل شکل میں مزید آسان طریقے سے LMDB B-tree کی نمائندگی کریں گے۔

iOS ایپلی کیشنز میں کلیدی قدر ڈیٹا بیس LMDB کی چمک اور غربت

نوڈس والے صفحات ترتیب وار ڈسک پر واقع ہوتے ہیں۔ اعلی نمبر والے صفحات فائل کے آخر میں واقع ہیں۔ نام نہاد میٹا صفحہ ان آفسیٹس کے بارے میں معلومات پر مشتمل ہے جس کے ذریعے تمام درختوں کی جڑیں تلاش کی جا سکتی ہیں۔ فائل کو کھولتے وقت، LMDB درست میٹا پیج کی تلاش میں فائل پیج کو صفحہ کے آخر سے شروع تک اسکین کرتا ہے اور اس کے ذریعے موجودہ ڈیٹا بیس کو تلاش کرتا ہے۔

iOS ایپلی کیشنز میں کلیدی قدر ڈیٹا بیس LMDB کی چمک اور غربت

اب، ڈیٹا آرگنائزیشن کی منطقی اور جسمانی ساخت کا خیال رکھتے ہوئے، ہم LMDB کے تیسرے ستون پر غور کرنے کے لیے آگے بڑھ سکتے ہیں۔ یہ اس کی مدد سے ہے کہ تمام سٹوریج کی تبدیلیاں لین دین کے ساتھ اور ایک دوسرے سے الگ تھلگ ہو کر ہوتی ہیں، جس سے ڈیٹا بیس کو مجموعی طور پر ملٹی ورشن کی خاصیت ملتی ہے۔

3.3 وہیل #3۔ کاپی آن رائٹ

کچھ بی ٹری آپریشنز میں اس کے نوڈس میں تبدیلیوں کا ایک سلسلہ شامل ہوتا ہے۔ ایک مثال نوڈ میں ایک نئی کلید شامل کر رہی ہے جو پہلے ہی اپنی زیادہ سے زیادہ صلاحیت تک پہنچ چکی ہے۔ اس صورت میں، ضروری ہے، سب سے پہلے، نوڈ کو دو حصوں میں تقسیم کیا جائے، اور دوم، اس کے والدین میں نئے ابھرتے ہوئے چائلڈ نوڈ کا لنک شامل کیا جائے۔ یہ طریقہ کار ممکنہ طور پر بہت خطرناک ہے۔ اگر کسی وجہ سے (حادثہ، بجلی کی بندش، وغیرہ) سیریز سے تبدیلیوں کا صرف ایک حصہ ہوتا ہے، تو درخت ایک متضاد حالت میں رہے گا۔

ڈیٹا بیس کو فالٹ ٹولرنٹ بنانے کا ایک روایتی حل یہ ہے کہ B-tree کے آگے ایک اضافی آن ڈسک ڈیٹا ڈھانچہ شامل کیا جائے - ایک ٹرانزیکشن لاگ، جسے رائٹ-ہیڈ لاگ (WAL) بھی کہا جاتا ہے۔ یہ ایک فائل ہے جس کے آخر میں B-tree میں ترمیم کرنے سے پہلے مطلوبہ آپریشن سختی سے لکھا جاتا ہے۔ اس طرح، اگر خود تشخیص کے دوران ڈیٹا میں بدعنوانی کا پتہ چل جاتا ہے، تو ڈیٹا بیس خود کو ترتیب دینے کے لیے لاگ سے مشورہ کرتا ہے۔

LMDB نے غلطی کو برداشت کرنے کے طریقہ کار کے طور پر ایک مختلف طریقہ کا انتخاب کیا ہے، جسے کاپی آن رائٹ کہتے ہیں۔ اس کا خلاصہ یہ ہے کہ موجودہ صفحہ پر ڈیٹا کو اپ ڈیٹ کرنے کے بجائے، یہ پہلے اسے مکمل طور پر کاپی کرتا ہے اور کاپی میں تمام ترامیم کرتا ہے۔

iOS ایپلی کیشنز میں کلیدی قدر ڈیٹا بیس LMDB کی چمک اور غربت

اگلا، اپ ڈیٹ شدہ ڈیٹا کے دستیاب ہونے کے لیے، اس نوڈ کے لنک کو تبدیل کرنا ضروری ہے جو اس کے پیرنٹ نوڈ میں کرنٹ ہو چکا ہے۔ چونکہ اس کے لیے اس میں بھی ترمیم کی ضرورت ہے اس لیے اس کی نقل بھی پہلے سے کی جاتی ہے۔ یہ عمل جڑ تک بار بار جاری رہتا ہے۔ تبدیل کرنے کی آخری چیز میٹا پیج پر ڈیٹا ہے۔

iOS ایپلی کیشنز میں کلیدی قدر ڈیٹا بیس LMDB کی چمک اور غربت

اگر اپ ڈیٹ کے طریقہ کار کے دوران اچانک عمل کریش ہو جاتا ہے، تو یا تو نیا میٹا صفحہ نہیں بنے گا، یا اسے مکمل طور پر ڈسک پر نہیں لکھا جائے گا، اور اس کا چیکسم غلط ہو گا۔ ان دونوں صورتوں میں سے کسی بھی صورت میں، نئے صفحات ناقابل رسائی ہوں گے، لیکن پرانے صفحات متاثر نہیں ہوں گے۔ اس سے ڈیٹا کی مستقل مزاجی کو برقرار رکھنے کے لیے LMDB کو آگے لاگ لکھنے کی ضرورت ختم ہو جاتی ہے۔ اصل میں، اوپر بیان کردہ ڈسک پر ڈیٹا سٹوریج کی ساخت بیک وقت اپنا کام کرتی ہے۔ واضح ٹرانزیکشن لاگ کی عدم موجودگی LMDB کی خصوصیات میں سے ایک ہے جو ڈیٹا پڑھنے کی تیز رفتار فراہم کرتی ہے۔

iOS ایپلی کیشنز میں کلیدی قدر ڈیٹا بیس LMDB کی چمک اور غربت

نتیجہ خیز ڈیزائن، جسے اپینڈ اونلی بی ٹری کہتے ہیں، قدرتی طور پر لین دین کو الگ تھلگ اور ملٹی ورژن فراہم کرتا ہے۔ LMDB میں، ہر کھلا لین دین موجودہ متعلقہ درخت کی جڑ سے منسلک ہوتا ہے۔ جب تک لین دین مکمل نہیں ہو جاتا، اس سے منسلک درخت کے صفحات کو کبھی بھی ڈیٹا کے نئے ورژنز کے لیے تبدیل یا دوبارہ استعمال نہیں کیا جائے گا، اس طرح، آپ اس وقت تک متعلقہ ڈیٹا کے سیٹ کے ساتھ جب تک چاہیں کام کر سکتے ہیں۔ ٹرانزیکشن کو کھول دیا گیا تھا، یہاں تک کہ اگر اس وقت اسٹوریج کو فعال طور پر اپ ڈیٹ کرنا جاری ہے۔ یہ ملٹی ورشن کا نچوڑ ہے، جو LMDB کو ہمارے پیاروں کے لیے ڈیٹا کا ایک مثالی ذریعہ بناتا ہے۔ UICollectionView. ٹرانزیکشن کھولنے کے بعد، کچھ بھی نہ رہ جانے کے خوف سے، عجلت میں موجودہ ڈیٹا کو کچھ ان میموری ڈھانچے میں پمپ کرکے ایپلیکیشن کے میموری فوٹ پرنٹ کو بڑھانے کی ضرورت نہیں ہے۔ یہ خصوصیت LMDB کو اسی SQLite سے ممتاز کرتی ہے، جو اس طرح کی مکمل تنہائی پر فخر نہیں کر سکتا۔ مؤخر الذکر میں دو ٹرانزیکشنز کھولنے اور ان میں سے ایک کے اندر ایک مخصوص ریکارڈ کو حذف کرنے کے بعد، دوسرے باقی ایک میں وہی ریکارڈ حاصل کرنا اب ممکن نہیں رہے گا۔

سکے کا فلپ سائیڈ ورچوئل میموری کی ممکنہ طور پر نمایاں طور پر زیادہ کھپت ہے۔ سلائیڈ دکھاتی ہے کہ ڈیٹا بیس کا ڈھانچہ کیسا نظر آئے گا اگر ڈیٹا بیس کے مختلف ورژنز کو دیکھتے ہوئے 3 اوپن ریڈ ٹرانزیکشنز کے ساتھ بیک وقت اس میں ترمیم کی جائے۔ چونکہ LMDB موجودہ لین دین سے منسلک جڑوں سے قابل رسائی نوڈس کو دوبارہ استعمال نہیں کر سکتا، اس لیے اسٹور کے پاس اس کے علاوہ کوئی چارہ نہیں ہے کہ وہ میموری میں ایک اور چوتھا روٹ مختص کرے اور ایک بار پھر اس کے نیچے ترمیم شدہ صفحات کو کلون کرے۔

iOS ایپلی کیشنز میں کلیدی قدر ڈیٹا بیس LMDB کی چمک اور غربت

یہاں میموری میپڈ فائلوں کے حصے کو یاد کرنا مفید ہوگا۔ ایسا لگتا ہے کہ ورچوئل میموری کی اضافی کھپت سے ہمیں زیادہ پریشان نہیں ہونا چاہئے، کیونکہ یہ ایپلی کیشن کے میموری فوٹ پرنٹ میں حصہ نہیں ڈالتا ہے۔ تاہم، ساتھ ہی، یہ بھی نوٹ کیا گیا کہ iOS اسے مختص کرنے میں بہت کنجوس ہے، اور ہم سرور یا ڈیسک ٹاپ کی طرح 1 ٹیرا بائٹ کا LMDB علاقہ فراہم نہیں کر سکتے اور اس خصوصیت کے بارے میں بالکل بھی نہیں سوچ سکتے۔ اگر ممکن ہو تو، آپ کو لین دین کی زندگی کو جتنا ممکن ہو سکے مختصر کرنے کی کوشش کرنی چاہیے۔

4. کلیدی قدر API کے سب سے اوپر ڈیٹا سکیما ڈیزائن کرنا

آئیے LMDB کی طرف سے فراہم کردہ بنیادی تجریدوں کو دیکھ کر اپنا API تجزیہ شروع کریں: ماحولیات اور ڈیٹا بیس، کلیدیں اور اقدار، لین دین اور کرسر۔

کوڈ لسٹنگ کے بارے میں ایک نوٹ

عوامی LMDB API میں تمام فنکشنز اپنے کام کا نتیجہ ایک ایرر کوڈ کی صورت میں واپس کرتے ہیں، لیکن بعد کی تمام فہرستوں میں اس کی تصدیق کو اختصار کی وجہ سے چھوڑ دیا جاتا ہے۔ کانٹا C++ ریپرز lmdbxx، جس میں غلطیاں C++ مستثنیات کے طور پر پیش کی جاتی ہیں۔

LMDB کو iOS یا macOS کے پروجیکٹ سے جوڑنے کے تیز ترین طریقے کے طور پر، میں اپنا CocoaPod تجویز کرتا ہوں POSLMDB.

4.1. بنیادی تجریدات

ماحولیات

ساخت MDB_env LMDB کی اندرونی حالت کا ذخیرہ ہے۔ پریفکسڈ فنکشن فیملی mdb_env آپ کو اس کی کچھ خصوصیات کو ترتیب دینے کی اجازت دیتا ہے۔ آسان ترین صورت میں، انجن کی ابتدا اس طرح نظر آتی ہے۔

mdb_env_create(env);​
mdb_env_set_map_size(*env, 1024 * 1024 * 512)​
mdb_env_open(*env, path.UTF8String, MDB_NOTLS, 0664);

Mail.ru کلاؤڈ ایپلیکیشن میں، ہم نے صرف دو پیرامیٹرز کی ڈیفالٹ ویلیوز کو تبدیل کیا۔

پہلا ورچوئل ایڈریس اسپیس کا سائز ہے جس پر اسٹوریج فائل میپ کی گئی ہے۔ بدقسمتی سے، یہاں تک کہ ایک ہی ڈیوائس پر، مخصوص قدر رن سے چلانے کے لیے نمایاں طور پر مختلف ہو سکتی ہے۔ iOS کی اس خصوصیت کو مدنظر رکھنے کے لیے، زیادہ سے زیادہ اسٹوریج والیوم کو متحرک طور پر منتخب کیا جاتا ہے۔ ایک خاص قدر سے شروع ہو کر، اسے فنکشن تک ترتیب سے آدھا کر دیا جاتا ہے۔ mdb_env_open سے مختلف نتیجہ واپس نہیں کرے گا۔ ENOMEM. نظریہ میں، اس کے برعکس طریقہ بھی ہے - پہلے انجن کو کم از کم میموری مختص کریں، اور پھر، جب غلطیاں موصول ہوں، MDB_MAP_FULL، اس میں اضافہ کریں۔ تاہم، یہ بہت زیادہ کانٹے دار ہے۔ وجہ یہ ہے کہ فنکشن کا استعمال کرتے ہوئے میموری (ری میپ) کو دوبارہ مختص کرنے کا طریقہ کار ہے۔ mdb_env_set_map_size انجن سے پہلے موصول ہونے والی تمام ہستیوں (کرسر، لین دین، چابیاں اور اقدار) کو باطل کر دیتا ہے۔ کوڈ میں واقعات کے اس موڑ کو مدنظر رکھنا اس کی اہم پیچیدگی کا باعث بنے گا۔ اگر، تاہم، ورچوئل میموری آپ کے لیے بہت اہم ہے، تو یہ اس کانٹے کو قریب سے دیکھنے کی ایک وجہ ہو سکتی ہے جو بہت آگے جا چکا ہے۔ ایم ڈی بی ایکس، جہاں اعلان کردہ خصوصیات میں "آٹومیٹک آن دی فلائی ڈیٹا بیس سائز ایڈجسٹمنٹ" ہے۔

دوسرا پیرامیٹر، جس کی ڈیفالٹ قدر ہمارے مطابق نہیں تھی، دھاگے کی حفاظت کو یقینی بنانے کے میکانکس کو منظم کرتی ہے۔ بدقسمتی سے، کم از کم iOS 10 کو تھریڈ لوکل اسٹوریج کے لیے سپورٹ میں دشواری ہے۔ اس وجہ سے، اوپر کی مثال میں، ذخیرہ کو جھنڈے کے ساتھ کھولا گیا ہے۔ MDB_NOTLS. اس کے علاوہ یہ بھی ضروری تھا۔ کانٹا C++ ریپر lmdbxxاس وصف کے ساتھ اور اس میں متغیرات کو کاٹنا۔

ڈیٹا بیس

ڈیٹا بیس ایک الگ B-tree مثال ہے، جس پر ہم نے اوپر بات کی ہے۔ اس کا افتتاح ایک لین دین کے اندر ہوتا ہے، جو شروع میں تھوڑا سا عجیب لگ سکتا ہے۔

MDB_txn *txn;​
MDB_dbi dbi;​
mdb_txn_begin(env, NULL, MDB_RDONLY, &txn);​
mdb_dbi_open(txn, NULL, MDB_CREATE, &dbi);​
mdb_txn_abort(txn);

درحقیقت، LMDB میں ایک لین دین ایک سٹوریج ادارہ ہے، نہ کہ مخصوص ڈیٹابیس ادارہ۔ یہ تصور آپ کو مختلف ڈیٹا بیس میں موجود اداروں پر جوہری آپریشن کرنے کی اجازت دیتا ہے۔ نظریہ میں، یہ مختلف ڈیٹا بیس کی شکل میں ماڈلنگ ٹیبلز کے امکانات کو کھولتا ہے، لیکن ایک وقت میں میں نے ایک مختلف راستہ اختیار کیا، جس کی تفصیل ذیل میں بیان کی گئی ہے۔

کلیدیں اور اقدار

ساخت MDB_val کلید اور قدر دونوں کا تصور پیش کرتا ہے۔ مخزن کو ان کے الفاظ کے بارے میں کوئی اندازہ نہیں ہے۔ اس کے لیے، کچھ اور صرف ایک دیے گئے سائز کے بائٹس کی ایک صف ہے۔ زیادہ سے زیادہ کلید کا سائز 512 بائٹس ہے۔

typedef struct MDB_val {​
    size_t mv_size;​
    void *mv_data;​
} MDB_val;​​

کمپیریٹر کا استعمال کرتے ہوئے، اسٹور چابیاں کو صعودی ترتیب میں ترتیب دیتا ہے۔ اگر آپ اسے اپنے سے تبدیل نہیں کرتے ہیں، تو پہلے سے طے شدہ کو استعمال کیا جائے گا، جو انہیں لغت کی ترتیب میں بائٹ بائٹ ترتیب دیتا ہے۔

معاملات

لین دین کا ڈھانچہ تفصیل سے بیان کیا گیا ہے۔ پچھلے باب، تو یہاں میں ان کی اہم خصوصیات کو مختصراً دہراؤں گا:

  1. تمام بنیادی خصوصیات کی حمایت کرتا ہے۔ ایسڈ: جوہری، مستقل مزاجی، تنہائی اور وشوسنییتا۔ میں مدد نہیں کر سکتا لیکن نوٹ کر سکتا ہوں کہ macOS اور iOS پر پائیداری کے لحاظ سے ایک بگ ہے جو MDBX میں ٹھیک کر دیا گیا تھا۔ آپ ان میں مزید پڑھ سکتے ہیں۔ پڑھیں.
  2. ملٹی تھریڈنگ کے نقطہ نظر کو "سنگل رائٹر / ایک سے زیادہ قارئین" اسکیم کے ذریعہ بیان کیا گیا ہے۔ لکھنے والے ایک دوسرے کو بلاک کرتے ہیں، لیکن قارئین کو بلاک نہیں کرتے۔ قارئین مصنفین یا ایک دوسرے کو بلاک نہیں کرتے ہیں۔
  3. نیسٹڈ ٹرانزیکشنز کے لیے سپورٹ۔
  4. ملٹی ورشن سپورٹ۔

LMDB میں ملٹی ورشن اتنا اچھا ہے کہ میں اسے عملی طور پر ظاہر کرنا چاہتا ہوں۔ نیچے دیے گئے کوڈ سے آپ دیکھ سکتے ہیں کہ ہر ٹرانزیکشن ڈیٹا بیس کے بالکل اسی ورژن کے ساتھ کام کرتی ہے جو اس وقت موجود تھا جب اسے کھولا گیا تھا، اس کے بعد کی تمام تبدیلیوں سے مکمل طور پر الگ تھلگ رہ کر۔ اسٹوریج کو شروع کرنا اور اس میں ٹیسٹ ریکارڈ شامل کرنا کسی بھی دلچسپ چیز کی نمائندگی نہیں کرتا ہے، اس لیے یہ رسومات بگاڑنے والے کے نیچے رہ جاتی ہیں۔

ٹیسٹ اندراج شامل کرنا

MDB_env *env;
MDB_dbi dbi;
MDB_txn *txn;

mdb_env_create(&env);
mdb_env_open(env, "./testdb", MDB_NOTLS, 0664);

mdb_txn_begin(env, NULL, 0, &txn);
mdb_dbi_open(txn, NULL, 0, &dbi);
mdb_txn_abort(txn);

char k = 'k';
MDB_val key;
key.mv_size = sizeof(k);
key.mv_data = (void *)&k;

int v = 997;
MDB_val value;
value.mv_size = sizeof(v);
value.mv_data = (void *)&v;

mdb_txn_begin(env, NULL, 0, &txn);
mdb_put(txn, dbi, &key, &value, MDB_NOOVERWRITE);
mdb_txn_commit(txn);

MDB_txn *txn1, *txn2, *txn3;
MDB_val val;

// Открываем 2 транзакции, каждая из которых смотрит
// на версию базы данных с одной записью.
mdb_txn_begin(env, NULL, 0, &txn1); // read-write
mdb_txn_begin(env, NULL, MDB_RDONLY, &txn2); // read-only

// В рамках первой транзакции удаляем из базы данных существующую в ней запись.
mdb_del(txn1, dbi, &key, NULL);
// Фиксируем удаление.
mdb_txn_commit(txn1);

// Открываем третью транзакцию, которая смотрит на
// актуальную версию базы данных, где записи уже нет.
mdb_txn_begin(env, NULL, MDB_RDONLY, &txn3);
// Убеждаемся, что запись по искомому ключу уже не существует.
assert(mdb_get(txn3, dbi, &key, &val) == MDB_NOTFOUND);
// Завершаем транзакцию.
mdb_txn_abort(txn3);

// Убеждаемся, что в рамках второй транзакции, открытой на момент
// существования записи в базе данных, её всё ещё можно найти по ключу.
assert(mdb_get(txn2, dbi, &key, &val) == MDB_SUCCESS);
// Проверяем, что по ключу получен не абы какой мусор, а валидные данные.
assert(*(int *)val.mv_data == 997);
// Завершаем транзакцию, работающей хоть и с устаревшей, но консистентной базой данных.
mdb_txn_abort(txn2);

میں تجویز کرتا ہوں کہ آپ SQLite کے ساتھ وہی چال آزمائیں اور دیکھیں کہ کیا ہوتا ہے۔

ملٹی ورشن ایک iOS ڈویلپر کی زندگی میں بہت اچھے فوائد لاتا ہے۔ اس پراپرٹی کو استعمال کرتے ہوئے، آپ صارف کے تجربے کی بنیاد پر اسکرین فارمز کے لیے ڈیٹا سورس کی اپ ڈیٹ کی شرح کو آسانی سے اور قدرتی طور پر ایڈجسٹ کر سکتے ہیں۔ مثال کے طور پر، آئیے Mail.ru کلاؤڈ ایپلیکیشن کی ایک خصوصیت لیتے ہیں جیسے سسٹم میڈیا گیلری سے مواد کو آٹو لوڈ کرنا۔ اچھے کنکشن کے ساتھ، کلائنٹ سرور میں فی سیکنڈ کئی تصاویر شامل کرنے کے قابل ہے۔ اگر آپ ہر ڈاؤن لوڈ کے بعد اپ ڈیٹ کرتے ہیں۔ UICollectionView صارف کے کلاؤڈ میں میڈیا مواد کے ساتھ، آپ اس عمل کے دوران تقریباً 60 fps اور ہموار اسکرولنگ کو بھول سکتے ہیں۔ بار بار اسکرین اپ ڈیٹس کو روکنے کے لیے، آپ کو کسی نہ کسی طرح اس شرح کو محدود کرنے کی ضرورت ہے جس پر ڈیٹا بنیادی میں تبدیل ہوتا ہے۔ UICollectionViewDataSource.

اگر ڈیٹا بیس ملٹی ورژن کو سپورٹ نہیں کرتا ہے اور آپ کو صرف موجودہ موجودہ حالت کے ساتھ کام کرنے کی اجازت دیتا ہے، تو اس ڈیٹا کا ایک وقتی اسٹیبل اسنیپ شاٹ بنانے کے لیے آپ کو اسے یا تو کسی ان میموری ڈیٹا ڈھانچے میں یا کسی عارضی ٹیبل پر کاپی کرنا ہوگا۔ ان طریقوں میں سے کوئی بھی بہت مہنگا ہے۔ ان میموری اسٹوریج کی صورت میں، ہمیں میموری میں لاگت آتی ہے، تعمیر شدہ اشیاء کو ذخیرہ کرنے کی وجہ سے، اور وقت کے ساتھ، فالتو ORM تبدیلیوں سے منسلک۔ جہاں تک عارضی میز کا تعلق ہے، یہ ایک اور بھی مہنگی خوشی ہے، جس کا مطلب صرف غیر معمولی معاملات میں ہوتا ہے۔

LMDB کا ملٹی ورژن حل ایک مستحکم ڈیٹا سورس کو برقرار رکھنے کے مسئلے کو بہت خوبصورت طریقے سے حل کرتا ہے۔ صرف ایک ٹرانزیکشن کھولنے کے لیے کافی ہے اور voila - جب تک ہم اسے مکمل نہیں کر لیتے، ڈیٹا سیٹ کے درست ہونے کی ضمانت ہے۔ اس کی اپ ڈیٹ کی رفتار کی منطق اب مکمل طور پر پریزنٹیشن پرت کے ہاتھ میں ہے، جس میں کوئی اہم وسائل نہیں ہیں۔

کرسر

کرسر B-tree traversal کے ذریعے کلیدی قدر کے جوڑوں پر ترتیب وار تکرار کے لیے ایک طریقہ کار فراہم کرتے ہیں۔ ان کے بغیر، ڈیٹا بیس میں میزوں کو مؤثر طریقے سے ماڈل بنانا ناممکن ہوگا، جس کی طرف ہم اب رجوع کرتے ہیں۔

4.2 ٹیبل ماڈلنگ

کلیدی ترتیب کی خاصیت آپ کو ایک اعلیٰ سطحی تجرید بنانے کی اجازت دیتی ہے جیسے بنیادی تجرید کے اوپر ایک میز۔ آئیے کلاؤڈ کلائنٹ کے مین ٹیبل کی مثال کا استعمال کرتے ہوئے اس عمل پر غور کریں، جو صارف کی تمام فائلوں اور فولڈرز کے بارے میں معلومات کو محفوظ کرتا ہے۔

ٹیبل اسکیما

عام منظرناموں میں سے ایک جس کے لیے فولڈر ٹری کے ساتھ ٹیبل کا ڈھانچہ تیار کیا جانا چاہیے وہ ہے دی گئی ڈائرکٹری کے اندر موجود تمام عناصر کا انتخاب اس قسم کے موثر سوالات کے لیے ایک اچھا ڈیٹا آرگنائزیشن ماڈل ہے۔ ملحقہ فہرست. اسے کلیدی قدر کے اسٹوریج کے اوپر لاگو کرنے کے لیے ضروری ہے کہ فائلوں اور فولڈرز کی کلیدوں کو اس طرح ترتیب دیا جائے کہ وہ پیرنٹ ڈائرکٹری میں ان کی رکنیت کی بنیاد پر گروپ کی جائیں۔ اس کے علاوہ، ڈائرکٹری کے مواد کو ونڈوز کے صارف سے واقف شکل میں ظاہر کرنے کے لیے (پہلے فولڈرز، پھر فائلیں، دونوں کو حروف تہجی کے مطابق ترتیب دیا گیا ہے)، کلید میں متعلقہ اضافی فیلڈز کو شامل کرنا ضروری ہے۔

نیچے دی گئی تصویر دکھاتی ہے کہ ہاتھ میں کام کی بنیاد پر، بائٹ سرنی کی شکل میں کیز کی نمائندگی کیسی نظر آتی ہے۔ پیرنٹ ڈائرکٹری (سرخ) کے شناخت کنندہ کے ساتھ بائٹس پہلے رکھے جاتے ہیں، پھر قسم (سبز) کے ساتھ اور نام (نیلے) کے ساتھ پہلے سے طے شدہ LMDB کمپیریٹر کے ذریعے ترتیب دیے جانے کے بعد، انہیں ترتیب دیا جاتا ہے۔ مطلوبہ طریقہ. یکساں طور پر ایک ہی سرخ سابقے کے ساتھ کلیدوں کو عبور کرنے سے ہمیں ان کی متعلقہ اقدار اس ترتیب میں ملتی ہیں جس ترتیب سے انہیں صارف انٹرفیس (دائیں طرف) میں ظاہر ہونا چاہیے، بغیر کسی اضافی پوسٹ پروسیسنگ کی ضرورت ہوتی ہے۔

iOS ایپلی کیشنز میں کلیدی قدر ڈیٹا بیس LMDB کی چمک اور غربت

کلیدوں اور اقدار کو سیریلائز کرنا

دنیا میں اشیاء کو سیریلائز کرنے کے بہت سے طریقے ایجاد ہو چکے ہیں۔ چونکہ ہمارے پاس رفتار کے علاوہ کوئی اور ضرورت نہیں تھی، اس لیے ہم نے اپنے لیے سب سے تیز رفتار کا انتخاب کیا - C زبان کے ڈھانچے کی ایک مثال کے زیر قبضہ میموری کا ایک ڈمپ اس طرح، ڈائرکٹری عنصر کی کلید کو مندرجہ ذیل ڈھانچے کے ساتھ ماڈل بنایا جا سکتا ہے۔ NodeKey.

typedef struct NodeKey {​
    EntityId parentId;​
    uint8_t type;​
    uint8_t nameBuffer[256];​
} NodeKey;

بچانے کے لیے NodeKey آبجیکٹ میں ذخیرہ کرنے کی ضرورت ہے۔ MDB_val ڈیٹا پوائنٹر کو ڈھانچے کے آغاز کے پتے پر رکھیں، اور فنکشن کے ساتھ ان کے سائز کا حساب لگائیں۔ sizeof.

MDB_val serialize(NodeKey * const key) {
    return MDB_val {
        .mv_size = sizeof(NodeKey),
        .mv_data = (void *)key
    };
}

ڈیٹا بیس کے انتخاب کے معیار کے پہلے باب میں، میں نے CRUD آپریشنز کے اندر متحرک مختص کو ایک اہم انتخابی عنصر کے طور پر کم کرنے کا ذکر کیا۔ فنکشن کوڈ serialize یہ ظاہر کرتا ہے کہ LMDB کے معاملے میں ڈیٹا بیس میں نئے ریکارڈ داخل کرتے وقت ان سے مکمل طور پر گریز کیا جا سکتا ہے۔ سرور سے آنے والی بائٹ سرنی کو پہلے اسٹیک ڈھانچے میں تبدیل کیا جاتا ہے، اور پھر انہیں معمولی طور پر اسٹوریج میں پھینک دیا جاتا ہے۔ اس بات کو مدنظر رکھتے ہوئے کہ LMDB کے اندر کوئی متحرک مختص بھی نہیں ہے، آپ iOS کے معیارات کے مطابق ایک شاندار صورتحال حاصل کر سکتے ہیں - نیٹ ورک سے ڈسک تک پورے راستے پر ڈیٹا کے ساتھ کام کرنے کے لیے صرف اسٹیک میموری کا استعمال کریں!

بائنری کمپیریٹر کے ساتھ چابیاں ترتیب دینا

کلیدی ترتیب کا رشتہ ایک خاص فنکشن کے ذریعہ متعین کیا جاتا ہے جسے کمپیریٹر کہتے ہیں۔ چونکہ انجن ان میں موجود بائٹس کے سیمنٹکس کے بارے میں کچھ نہیں جانتا ہے، اس لیے پہلے سے طے شدہ موازنہ کرنے والے کے پاس بائٹ بائی بائٹ موازنہ کا سہارا لیتے ہوئے کلیدوں کو لغت کی ترتیب میں ترتیب دینے کے سوا کوئی چارہ نہیں ہے۔ ڈھانچے کو منظم کرنے کے لیے اس کا استعمال کلہاڑی سے مونڈنے کے مترادف ہے۔ تاہم، سادہ معاملات میں مجھے یہ طریقہ قابل قبول لگتا ہے۔ متبادل ذیل میں بیان کیا گیا ہے، لیکن یہاں میں اس راستے پر بکھرے ہوئے کچھ ریک نوٹ کروں گا۔

یاد رکھنے کی پہلی چیز قدیم ڈیٹا کی اقسام کی میموری کی نمائندگی ہے۔ اس طرح، تمام ایپل ڈیوائسز پر، انٹیجر متغیر فارمیٹ میں محفوظ ہوتے ہیں۔ لٹل اینڈیان. اس کا مطلب یہ ہے کہ کم سے کم اہم بائٹ بائیں طرف ہو گا، اور بائٹ بائی بائٹ موازنہ کا استعمال کرتے ہوئے عدد کو ترتیب دینا ممکن نہیں ہوگا۔ مثال کے طور پر، 0 سے 511 تک نمبروں کے سیٹ کے ساتھ ایسا کرنے کی کوشش کرنے سے درج ذیل نتیجہ نکلے گا۔

// value (hex dump)
000 (0000)
256 (0001)
001 (0100)
257 (0101)
...
254 (fe00)
510 (fe01)
255 (ff00)
511 (ff01)

اس مسئلے کو حل کرنے کے لیے، انٹیجرز کو کلید میں بائٹ بائٹ کمپیریٹر کے لیے موزوں فارمیٹ میں محفوظ کرنا چاہیے۔ خاندان کے افعال آپ کو ضروری تبدیلی لانے میں مدد کریں گے۔ hton* (خاص طور پر htons مثال سے ڈبل بائٹ نمبرز کے لیے)۔

پروگرامنگ میں سٹرنگز کی نمائندگی کرنے کا فارمیٹ، جیسا کہ آپ جانتے ہیں، مکمل ہے۔ история. اگر سٹرنگز کے سیمنٹکس کے ساتھ ساتھ ان کو میموری میں پیش کرنے کے لیے استعمال ہونے والی انکوڈنگ سے پتہ چلتا ہے کہ فی کریکٹر ایک سے زیادہ بائٹ ہو سکتا ہے، تو بہتر ہے کہ فوری طور پر ڈیفالٹ کمپیریٹر استعمال کرنے کے خیال کو ترک کر دیا جائے۔

دوسری بات ذہن میں رکھنی ہے۔ صف بندی کے اصول ڈھانچہ فیلڈ کمپائلر۔ ان کی وجہ سے، کوڑے کی قدروں کے ساتھ بائٹس فیلڈز کے درمیان میموری میں بن سکتے ہیں، جو یقیناً بائٹ بائٹ کی ترتیب کو توڑ دیتے ہیں۔ کوڑے کو ختم کرنے کے لیے، آپ کو صف بندی کے اصولوں کو ذہن میں رکھتے ہوئے، یا تو قطعات کو سختی سے متعین ترتیب میں اعلان کرنے کی ضرورت ہے، یا ڈھانچے کے اعلان میں وصف کا استعمال کرنا ہوگا۔ packed.

ایک بیرونی موازنہ کے ساتھ چابیاں ترتیب دینا

کلیدی موازنہ منطق بائنری موازنہ کرنے والے کے لیے بہت پیچیدہ ہو سکتی ہے۔ بہت سی وجوہات میں سے ایک ساخت کے اندر تکنیکی شعبوں کی موجودگی ہے۔ میں ڈائرکٹری عنصر کے لیے کلید کی مثال کا استعمال کرتے ہوئے ان کی موجودگی کی وضاحت کروں گا جو ہمارے لیے پہلے سے واقف ہے۔

typedef struct NodeKey {​
    EntityId parentId;​
    uint8_t type;​
    uint8_t nameBuffer[256];​
} NodeKey;

اس کی سادگی کے باوجود، زیادہ تر معاملات میں یہ بہت زیادہ میموری استعمال کرتا ہے۔ نام کا بفر 256 بائٹس لیتا ہے، حالانکہ اوسطاً فائل اور فولڈر کے نام شاذ و نادر ہی 20-30 حروف سے زیادہ ہوتے ہیں۔

ریکارڈ کے سائز کو بہتر بنانے کے لیے معیاری تکنیکوں میں سے ایک یہ ہے کہ اسے اصل سائز تک "تراش" کیا جائے۔ اس کا خلاصہ یہ ہے کہ تمام متغیر کی لمبائی والے فیلڈز کے مواد کو ڈھانچے کے آخر میں ایک بفر میں محفوظ کیا جاتا ہے، اور ان کی لمبائی الگ الگ متغیرات میں محفوظ ہوتی ہے۔ اس نقطہ نظر کے مطابق، کلید NodeKey مندرجہ ذیل کے طور پر تبدیل کیا جاتا ہے.

typedef struct NodeKey {​
    EntityId parentId;​
    uint8_t type;​
    uint8_t nameLength;​
    uint8_t nameBuffer[256];​
} NodeKey;

مزید، سیریلائز کرتے وقت، ڈیٹا کا سائز متعین نہیں کیا جاتا ہے۔ sizeof پوری ساخت، اور تمام فیلڈز کا سائز ایک مقررہ لمبائی کے علاوہ بفر کے اصل استعمال شدہ حصے کا سائز ہے۔

MDB_val serialize(NodeKey * const key) {
    return MDB_val {
        .mv_size = offsetof(NodeKey, nameBuffer) + key->nameLength,
        .mv_data = (void *)key
    };
}

ری فیکٹرنگ کے نتیجے میں، ہمیں کلیدوں کے زیر قبضہ جگہ میں نمایاں بچت ملی۔ تاہم، تکنیکی میدان کی وجہ سے nameLength، پہلے سے طے شدہ بائنری موازنہ کلیدی موازنہ کے لیے اب موزوں نہیں ہے۔ اگر ہم اسے اپنے سے تبدیل نہیں کرتے ہیں، تو نام کی لمبائی خود نام کے مقابلے میں ترتیب دینے میں ایک اعلی ترجیحی عنصر ہوگی۔

LMDB ہر ڈیٹا بیس کو اس کا اپنا کلیدی موازنہ فنکشن رکھنے کی اجازت دیتا ہے۔ یہ فنکشن کا استعمال کرتے ہوئے کیا جاتا ہے۔ mdb_set_compare کھولنے سے پہلے سختی سے. واضح وجوہات کی بناء پر، ڈیٹا بیس کی پوری زندگی میں اسے تبدیل نہیں کیا جا سکتا۔ موازنہ کرنے والے کو بائنری فارمیٹ میں دو کلیدیں بطور ان پٹ موصول ہوتی ہیں، اور آؤٹ پٹ پر یہ موازنہ کا نتیجہ واپس کرتا ہے: (-1) سے کم، (1) سے بڑا یا (0) کے برابر۔ سیڈوکوڈ برائے NodeKey ایسا لگتا ہے.

int compare(MDB_val * const a, MDB_val * const b) {​
    NodeKey * const aKey = (NodeKey * const)a->mv_data;​
    NodeKey * const bKey = (NodeKey * const)b->mv_data;​
    return // ...
}​

جب تک کہ ڈیٹا بیس میں موجود تمام کلیدیں ایک ہی قسم کی ہوں، غیر مشروط طور پر ان کی بائٹ کی نمائندگی کو ایپلیکیشن کلیدی ڈھانچہ کی قسم میں ڈالنا قانونی ہے۔ یہاں ایک نزاکت ہے، لیکن ذیل میں "ریڈنگ ریکارڈز" کے ذیلی حصے میں اس پر بحث کی جائے گی۔

سیریلائزنگ ویلیوز

LMDB ذخیرہ شدہ ریکارڈز کی کلیدوں کے ساتھ انتہائی شدت سے کام کرتا ہے۔ ان کا ایک دوسرے کے ساتھ موازنہ کسی بھی لاگو آپریشن کے فریم ورک کے اندر ہوتا ہے، اور پورے حل کی کارکردگی کا انحصار موازنہ کرنے والے کی رفتار پر ہوتا ہے۔ ایک مثالی دنیا میں، پہلے سے طے شدہ بائنری کمپیریٹر چابیاں کا موازنہ کرنے کے لیے کافی ہونا چاہیے، لیکن اگر آپ کو اپنا استعمال کرنا ہے، تو اس میں کیز کو ڈی سیریلائز کرنے کا طریقہ کار جتنی جلدی ہو سکے ہونا چاہیے۔

ڈیٹا بیس کو ریکارڈ کے ویلیو حصے (قدر) میں خاص دلچسپی نہیں ہے۔ بائٹ کی نمائندگی سے کسی شے میں اس کی تبدیلی صرف اس وقت ہوتی ہے جب ایپلیکیشن کوڈ کے ذریعہ اس کی ضرورت ہوتی ہے، مثال کے طور پر، اسے اسکرین پر ظاہر کرنے کے لیے۔ چونکہ یہ نسبتاً شاذ و نادر ہی ہوتا ہے، اس لیے اس طریقہ کار کے لیے رفتار کے تقاضے اتنے اہم نہیں ہیں، اور اس کے نفاذ میں ہم سہولت پر توجہ مرکوز کرنے کے لیے بہت زیادہ آزاد ہیں، مثال کے طور پر، ان فائلوں کے بارے میں میٹا ڈیٹا کو سیریلائز کرنے کے لیے جو ابھی تک ڈاؤن لوڈ نہیں ہوئی ہیں۔ NSKeyedArchiver.

NSData *data = serialize(object);​
MDB_val value = {​
    .mv_size = data.length,​
    .mv_data = (void *)data.bytes​
};

تاہم، ایسے اوقات ہوتے ہیں جب کارکردگی اب بھی اہمیت رکھتی ہے۔ مثال کے طور پر، صارف کے کلاؤڈ کے فائل ڈھانچے کے بارے میں میٹینفارمیشن کو محفوظ کرتے وقت، ہم آبجیکٹ کے وہی میموری ڈمپ استعمال کرتے ہیں۔ ان کی سیریلائزڈ نمائندگی پیدا کرنے کے کام کی خاص بات یہ ہے کہ ڈائرکٹری کے عناصر کو کلاسوں کے درجہ بندی کے مطابق بنایا گیا ہے۔

iOS ایپلی کیشنز میں کلیدی قدر ڈیٹا بیس LMDB کی چمک اور غربت

اسے C زبان میں لاگو کرنے کے لیے، وارثوں کے مخصوص فیلڈز کو الگ ڈھانچے میں رکھا جاتا ہے، اور ان کا تعلق بنیاد کے ساتھ ٹائپ یونین کے فیلڈ کے ذریعے بیان کیا جاتا ہے۔ یونین کے اصل مشمولات تکنیکی وصف کی قسم کے ذریعے بیان کیے گئے ہیں۔

typedef struct NodeValue {​
    EntityId localId;​
    EntityType type;​
    union {​
        FileInfo file;​
        DirectoryInfo directory;​
    } info;​
    uint8_t nameLength;​
    uint8_t nameBuffer[256];​
} NodeValue;​

ریکارڈز کو شامل کرنا اور اپ ڈیٹ کرنا

سیریلائزڈ کلید اور قدر کو اسٹور میں شامل کیا جا سکتا ہے۔ ایسا کرنے کے لئے، فنکشن کا استعمال کریں mdb_put.

// key и value имеют тип MDB_val​
mdb_put(..., &key, &value, MDB_NOOVERWRITE);

کنفیگریشن کے مرحلے پر، ایک ہی کلید کے ساتھ متعدد ریکارڈز کو ذخیرہ کرنے کی اجازت دی جا سکتی ہے یا منع کیا جا سکتا ہے، اگر چابیاں کی نقل ممنوع ہے، تو ریکارڈ داخل کرتے وقت، آپ یہ تعین کر سکتے ہیں کہ موجودہ ریکارڈ کو اپ ڈیٹ کرنے کی اجازت ہے یا نہیں۔ اگر جھگڑا صرف کوڈ میں غلطی کے نتیجے میں ہوسکتا ہے، تو آپ پرچم کی وضاحت کرکے اس سے خود کو بچا سکتے ہیں۔ NOOVERWRITE.

اندراجات پڑھنا

LMDB میں ریکارڈ پڑھنے کے لیے، فنکشن استعمال کریں۔ mdb_get. اگر کلیدی قدر کے جوڑے کو پہلے سے پھینکے گئے ڈھانچے سے ظاہر کیا جاتا ہے، تو یہ طریقہ کار اس طرح نظر آتا ہے۔

NodeValue * const readNode(..., NodeKey * const key) {​
    MDB_val rawKey = serialize(key);​
    MDB_val rawValue;​
    mdb_get(..., &rawKey, &rawValue);​
    return (NodeValue * const)rawValue.mv_data;​
}

پیش کردہ لسٹنگ سے پتہ چلتا ہے کہ کس طرح سٹرکچر ڈمپ کے ذریعے سیریلائزیشن آپ کو نہ صرف لکھتے وقت بلکہ ڈیٹا پڑھتے وقت متحرک مختص سے چھٹکارا حاصل کرنے کی اجازت دیتی ہے۔ فعل سے ماخوذ mdb_get پوائنٹر بالکل ورچوئل میموری ایڈریس پر نظر آتا ہے جہاں ڈیٹا بیس آبجیکٹ کی بائٹ نمائندگی کو اسٹور کرتا ہے۔ درحقیقت، ہمیں ایک قسم کا ORM ملتا ہے جو بہت زیادہ ڈیٹا پڑھنے کی رفتار تقریباً مفت فراہم کرتا ہے۔ نقطہ نظر کی تمام خوبصورتی کے باوجود، اس سے منسلک کئی خصوصیات کو یاد رکھنا ضروری ہے.

  1. صرف پڑھنے والے لین دین کے لیے، ویلیو سٹرکچر کی طرف اشارہ کرنے والا صرف اس وقت تک درست رہے گا جب تک کہ لین دین بند نہ ہو جائے۔ جیسا کہ پہلے ذکر کیا گیا ہے، B-tree کے صفحات جن پر کوئی چیز واقع ہے، کاپی آن رائٹ کے اصول کی بدولت، اس وقت تک کوئی تبدیلی نہیں ہوتی جب تک کہ ان کا حوالہ کم از کم ایک لین دین سے ہو۔ ایک ہی وقت میں، جیسے ہی ان سے منسلک آخری لین دین مکمل ہوتا ہے، صفحات کو نئے ڈیٹا کے لیے دوبارہ استعمال کیا جا سکتا ہے۔ اگر اشیاء کے لیے ضروری ہے کہ وہ اس لین دین کو زندہ رکھے جس نے انہیں بنایا ہے، تب بھی انہیں کاپی کرنا ہوگا۔
  2. ریڈ رائٹ ٹرانزیکشن کے لیے، نتیجے میں آنے والی ویلیو سٹرکچر کی طرف اشارہ صرف اس وقت تک درست رہے گا جب تک کہ پہلے ترمیمی طریقہ کار (ڈیٹا لکھنا یا حذف کرنا) نہ ہو جائے۔
  3. ساخت اگرچہ NodeValue مکمل نہیں، لیکن تراشی ہوئی (سب سیکشن "بیرونی کمپیریٹر کا استعمال کرتے ہوئے کیز کو ترتیب دینا" دیکھیں)، آپ پوائنٹر کے ذریعے محفوظ طریقے سے اس کے فیلڈز تک رسائی حاصل کر سکتے ہیں۔ اہم بات یہ ہے کہ اس کا احترام نہ کریں!
  4. کسی بھی حالت میں موصولہ پوائنٹر کے ذریعے ساخت میں ترمیم نہیں کی جانی چاہیے۔ تمام تبدیلیاں صرف طریقہ کار کے ذریعے کی جانی چاہئیں mdb_put. تاہم، اس سے کوئی فرق نہیں پڑتا ہے کہ آپ یہ کرنا کتنی ہی مشکل سے چاہتے ہیں، یہ ممکن نہیں ہوگا، کیونکہ میموری کا علاقہ جہاں یہ ڈھانچہ واقع ہے اسے صرف پڑھنے کے موڈ میں نقشہ بنایا گیا ہے۔
  5. مثال کے طور پر، فنکشن کا استعمال کرتے ہوئے زیادہ سے زیادہ سٹوریج کے سائز میں اضافہ کرنے کے مقصد کے لیے ایک فائل کو پراسیس ایڈریس اسپیس میں ری میپ کریں۔ mdb_env_set_map_size عام طور پر تمام لین دین اور متعلقہ اداروں کو مکمل طور پر باطل کر دیتا ہے اور خاص طور پر کچھ چیزوں کی طرف اشارہ کرتا ہے۔

آخر میں، ایک اور خصوصیت اتنی کپٹی ہے کہ اس کے جوہر کو ظاہر کرنا صرف دوسرے پیراگراف میں فٹ نہیں ہوتا ہے۔ B-tree کے باب میں، میں نے ایک خاکہ دیا ہے کہ اس کے صفحات کو یادداشت میں کیسے ترتیب دیا جاتا ہے۔ اس سے یہ معلوم ہوتا ہے کہ سیریلائزڈ ڈیٹا کے ساتھ بفر کے آغاز کا پتہ بالکل من مانی ہو سکتا ہے۔ اس کی وجہ سے، ان کی طرف اشارہ ڈھانچہ میں موصول ہوا MDB_val اور کسی ڈھانچے کی طرف اشارہ کرنے والے کو کم کر کے، یہ عام صورت میں غیر منسلک ہو جاتا ہے۔ ایک ہی وقت میں، کچھ چپس کے آرکیٹیکچرز (iOS کے معاملے میں یہ armv7 ہے) کا تقاضا ہے کہ کسی بھی ڈیٹا کا پتہ مشین کے لفظ کے سائز کا ایک کثیر ہو یا دوسرے لفظوں میں، سسٹم کے بٹ سائز ( armv7 کے لیے یہ 32 بٹس ہے)۔ دوسرے الفاظ میں، ایک آپریشن کی طرح *(int *foo)0x800002 ان پر فرار ہونے کے مترادف ہے اور فیصلے کے ساتھ پھانسی کی طرف جاتا ہے۔ EXC_ARM_DA_ALIGN. ایسے افسوسناک انجام سے بچنے کے دو طریقے ہیں۔

پہلا واضح طور پر منسلک ڈھانچے میں ڈیٹا کی ابتدائی کاپی کرنے پر ابلتا ہے۔ مثال کے طور پر، حسب ضرورت موازنہ کرنے والے پر یہ مندرجہ ذیل طور پر ظاہر ہوگا۔

int compare(MDB_val * const a, MDB_val * const b) {
    NodeKey aKey, bKey;
    memcpy(&aKey, a->mv_data, a->mv_size);
    memcpy(&bKey, b->mv_data, b->mv_size);
    return // ...
}

ایک متبادل طریقہ یہ ہے کہ مرتب کرنے والے کو پہلے سے مطلع کیا جائے کہ کلیدی قدر کے ڈھانچے کو وصف سے منسلک نہیں کیا جا سکتا ہے۔ aligned(1). ARM پر آپ کو بھی ایسا ہی اثر ہو سکتا ہے۔ کے حصول کے لئے اور پیکڈ وصف کا استعمال کرتے ہوئے. اس بات کو مدنظر رکھتے ہوئے کہ یہ ڈھانچے کے زیر قبضہ جگہ کو بہتر بنانے میں بھی مدد کرتا ہے، یہ طریقہ میرے نزدیک افضل معلوم ہوتا ہے، حالانکہ приводит ڈیٹا تک رسائی کے آپریشنز کی لاگت میں اضافہ۔

typedef struct __attribute__((packed)) NodeKey {
    uint8_t parentId;
    uint8_t type;
    uint8_t nameLength;
    uint8_t nameBuffer[256];
} NodeKey;

رینج کے سوالات

ریکارڈ کے ایک گروپ پر اعادہ کرنے کے لیے، LMDB ایک کرسر خلاصہ فراہم کرتا ہے۔ آئیے دیکھتے ہیں کہ صارف کے کلاؤڈ میٹا ڈیٹا کے ساتھ ٹیبل کی مثال کا استعمال کرتے ہوئے اس کے ساتھ کیسے کام کیا جائے جو ہمارے لیے پہلے سے واقف ہے۔

ڈائریکٹری میں فائلوں کی فہرست ظاہر کرنے کے حصے کے طور پر، یہ ضروری ہے کہ وہ تمام کلیدیں تلاش کی جائیں جن کے ساتھ اس کی چائلڈ فائلز اور فولڈرز وابستہ ہیں۔ پچھلے ذیلی حصوں میں ہم نے کیز کو ترتیب دیا تھا۔ NodeKey اس طرح کہ وہ بنیادی طور پر پیرنٹ ڈائرکٹری کی ID کے ذریعہ ترتیب دیے گئے ہیں۔ اس طرح، تکنیکی طور پر، فولڈر کے مواد کو بازیافت کرنے کا کام ایک دیئے گئے سابقہ ​​کے ساتھ کلیدوں کے گروپ کی اوپری باؤنڈری پر کرسر کو رکھنا اور پھر نچلی باؤنڈری پر اعادہ کرنا ہے۔

iOS ایپلی کیشنز میں کلیدی قدر ڈیٹا بیس LMDB کی چمک اور غربت

اوپری باؤنڈ براہ راست ترتیب وار تلاش کے ذریعے پایا جا سکتا ہے۔ ایسا کرنے کے لیے، کرسر کو ڈیٹا بیس میں کلیدوں کی پوری فہرست کے شروع میں رکھا جاتا ہے اور اس میں مزید اضافہ کیا جاتا ہے جب تک کہ پیرنٹ ڈائرکٹری کے شناخت کنندہ کے ساتھ ایک کلید اس کے نیچے ظاہر نہ ہو۔ اس نقطہ نظر کے 2 واضح نقصانات ہیں:

  1. لکیری تلاش کی پیچیدگی، اگرچہ، جیسا کہ جانا جاتا ہے، درختوں میں عام طور پر اور خاص طور پر B-درخت میں اسے لوگاریتھمک وقت میں انجام دیا جا سکتا ہے۔
  2. بیکار میں، مطلوبہ صفحہ سے پہلے کے تمام صفحات کو فائل سے مرکزی میموری میں لے جایا جاتا ہے، جو کہ بہت مہنگا ہے۔

خوش قسمتی سے، LMDB API ابتدائی طور پر کرسر کو پوزیشن میں رکھنے کا ایک مؤثر طریقہ فراہم کرتا ہے، ایسا کرنے کے لیے، آپ کو ایک کلید بنانے کی ضرورت ہے جس کی قدر واضح طور پر وقفہ کی اوپری باؤنڈری پر واقع کلید سے کم یا اس کے برابر ہو۔ مثال کے طور پر، اوپر کے اعداد و شمار میں فہرست کے سلسلے میں، ہم ایک کلید بنا سکتے ہیں جس میں فیلڈ parentId 2 کے برابر ہوگا، اور باقی تمام صفر سے بھرے ہوئے ہیں۔ اس طرح کی جزوی طور پر بھری ہوئی کلید فنکشن ان پٹ کو فراہم کی جاتی ہے۔ mdb_cursor_get آپریشن کا اشارہ MDB_SET_RANGE.

NodeKey upperBoundSearchKey = {​
    .parentId = 2,​
    .type = 0,​
    .nameLength = 0​
};​
MDB_val value, key = serialize(upperBoundSearchKey);​
MDB_cursor *cursor;​
mdb_cursor_open(..., &cursor);​
mdb_cursor_get(cursor, &key, &value, MDB_SET_RANGE);

اگر کلیدوں کے گروپ کی اوپری باؤنڈری پائی جاتی ہے، تو ہم اس پر اعادہ کرتے ہیں یہاں تک کہ یا تو ہم مل جائیں یا کلید کسی دوسرے سے نہ مل جائے۔ parentId، یا چابیاں بالکل ختم نہیں ہوں گی۔

do {​
    rc = mdb_cursor_get(cursor, &key, &value, MDB_NEXT);​
    // processing...​
} while (MDB_NOTFOUND != rc && // check end of table​
         IsTargetKey(key));    // check end of keys group​​

اچھی بات یہ ہے کہ mdb_cursor_get کا استعمال کرتے ہوئے تکرار کے حصے کے طور پر، ہمیں نہ صرف کلید، بلکہ قدر بھی ملتی ہے۔ اگر، نمونے لینے کی شرائط کو پورا کرنے کے لیے، آپ کو دیگر چیزوں کے ساتھ، ریکارڈ کے قدر والے حصے سے فیلڈز کو چیک کرنے کی ضرورت ہے، تو وہ اضافی اشاروں کے بغیر کافی قابل رسائی ہیں۔

4.3 میزوں کے درمیان تعلقات کی ماڈلنگ

اب تک، ہم سنگل ٹیبل ڈیٹا بیس کے ساتھ ڈیزائننگ اور کام کرنے کے تمام پہلوؤں پر غور کرنے میں کامیاب ہو چکے ہیں۔ ہم کہہ سکتے ہیں کہ ایک جدول ترتیب شدہ ریکارڈوں کا ایک مجموعہ ہے جو ایک ہی قسم کے کلیدی قدر کے جوڑوں پر مشتمل ہوتا ہے۔ اگر آپ ایک کلید کو مستطیل کے طور پر اور متعلقہ قدر کو متوازی پائپ کے طور پر ظاہر کرتے ہیں، تو آپ کو ڈیٹا بیس کا ایک بصری خاکہ ملتا ہے۔

iOS ایپلی کیشنز میں کلیدی قدر ڈیٹا بیس LMDB کی چمک اور غربت

تاہم، حقیقی زندگی میں اس قدر کم خونریزی سے گزرنا شاذ و نادر ہی ممکن ہے۔ اکثر ڈیٹابیس میں یہ ضروری ہوتا ہے، سب سے پہلے، کئی ٹیبلز کا ہونا، اور دوم، بنیادی کلید سے مختلف ترتیب میں ان میں انتخاب کرنا۔ یہ آخری حصہ ان کی تخلیق اور باہمی ربط کے مسائل کے لیے مختص ہے۔

انڈیکس ٹیبلز

کلاؤڈ ایپلیکیشن میں "گیلری" سیکشن ہے۔ یہ پورے کلاؤڈ سے میڈیا مواد دکھاتا ہے، تاریخ کے لحاظ سے ترتیب دیا گیا ہے۔ اس طرح کے انتخاب کو بہترین طریقے سے نافذ کرنے کے لیے، مرکزی میز کے آگے آپ کو ایک نئی قسم کی چابیاں کے ساتھ ایک اور بنانا ہوگا۔ ان میں فائل کی تخلیق کی تاریخ کے ساتھ ایک فیلڈ ہو گا، جو ترتیب دینے کے بنیادی معیار کے طور پر کام کرے گا۔ چونکہ نئی کلیدیں مرکزی ٹیبل میں موجود کلیدوں کی طرح ڈیٹا کا حوالہ دیتی ہیں، ان کو انڈیکس کیز کہا جاتا ہے۔ نیچے دی گئی تصویر میں وہ نارنجی رنگ میں نمایاں ہیں۔

iOS ایپلی کیشنز میں کلیدی قدر ڈیٹا بیس LMDB کی چمک اور غربت

ایک ہی ڈیٹا بیس کے اندر مختلف ٹیبلز کی چابیاں ایک دوسرے سے الگ کرنے کے لیے، ان سب میں ایک اضافی ٹیکنیکل فیلڈ ٹیبل آئی ڈی شامل کی گئی۔ چھانٹنے کے لیے اسے سب سے زیادہ ترجیح دے کر، ہم اپنے اصولوں کے مطابق سب سے پہلے ٹیبلز اور ٹیبلز کے اندر کلیدوں کی گروپ بندی حاصل کریں گے۔

انڈیکس کلید بنیادی کلید کے طور پر اسی ڈیٹا کا حوالہ دیتی ہے۔ پرائمری کلید کے ویلیو پارٹ کی ایک کاپی اس کے ساتھ منسلک کرکے اس پراپرٹی کا سیدھا سادا نفاذ کئی نقطہ نظر سے بہتر نہیں ہے:

  1. جگہ کے لحاظ سے، میٹا ڈیٹا کافی امیر ہو سکتا ہے۔
  2. کارکردگی کے نقطہ نظر سے، چونکہ نوڈ کے میٹا ڈیٹا کو اپ ڈیٹ کرتے وقت، آپ کو اسے دو کلیدوں کا استعمال کرکے دوبارہ لکھنا پڑے گا۔
  3. کوڈ سپورٹ کے نقطہ نظر سے، اگر ہم کسی ایک کلید کے لیے ڈیٹا کو اپ ڈیٹ کرنا بھول جاتے ہیں، تو ہمیں سٹوریج میں ڈیٹا کی عدم مطابقت کا ایک پرجوش بگ ملے گا۔

اگلا، ہم ان کوتاہیوں کو دور کرنے کے بارے میں غور کریں گے.

میزوں کے درمیان تعلقات کو منظم کرنا

انڈیکس ٹیبل کو مین ٹیبل سے جوڑنے کے لیے پیٹرن مناسب ہے۔ "قیمت کے طور پر کلید". جیسا کہ اس کے نام سے پتہ چلتا ہے، انڈیکس ریکارڈ کا ویلیو حصہ بنیادی کلیدی قدر کی کاپی ہے۔ یہ نقطہ نظر پرائمری ریکارڈ کے ویلیو حصے کی ایک کاپی کو ذخیرہ کرنے سے منسلک تمام اوپر بیان کردہ نقصانات کو ختم کرتا ہے۔ صرف قیمت یہ ہے کہ انڈیکس کلید کے ذریعے ایک قدر حاصل کرنے کے لیے، آپ کو ڈیٹا بیس میں ایک کے بجائے 2 سوالات کرنے کی ضرورت ہے۔ اسکیماتی طور پر، نتیجے میں ڈیٹا بیس اسکیما اس طرح لگتا ہے۔

iOS ایپلی کیشنز میں کلیدی قدر ڈیٹا بیس LMDB کی چمک اور غربت

میزوں کے درمیان تعلقات کو منظم کرنے کا ایک اور نمونہ ہے۔ "بے کار چابی". اس کا خلاصہ کلید میں اضافی صفات شامل کرنا ہے، جن کی ضرورت چھانٹنے کے لیے نہیں، بلکہ متعلقہ کلید کو دوبارہ بنانے کے لیے Mail.ru کلاؤڈ ایپلی کیشن میں اس کے استعمال کی حقیقی مثالیں موجود ہیں، تاہم، اس میں گہرے غوطے سے بچنے کے لیے۔ مخصوص iOS فریم ورک کے تناظر میں، میں ایک فرضی، لیکن ایک واضح مثال دوں گا۔

کلاؤڈ موبائل کلائنٹس کے پاس ایک صفحہ ہوتا ہے جو وہ تمام فائلیں اور فولڈرز دکھاتا ہے جنہیں صارف نے دوسرے لوگوں کے ساتھ شیئر کیا ہے۔ چونکہ ایسی فائلیں نسبتاً کم ہیں، اور ان سے وابستہ تشہیر کے بارے میں بہت سی مختلف قسم کی مخصوص معلومات موجود ہیں (کس کو رسائی دی گئی ہے، کن حقوق کے ساتھ، وغیرہ)، اس لیے یہ عقلی نہیں ہو گا کہ اس کی قیمت کے حصے پر بوجھ ڈالا جائے۔ اس کے ساتھ مین ٹیبل میں ریکارڈ کریں۔ تاہم، اگر آپ ایسی فائلوں کو آف لائن ڈسپلے کرنا چاہتے ہیں، تب بھی آپ کو اسے کہیں اسٹور کرنے کی ضرورت ہے۔ قدرتی حل یہ ہے کہ اس کے لیے ایک الگ ٹیبل بنایا جائے۔ نیچے دیے گئے خاکے میں، اس کی کلید "P" کے ساتھ لگائی گئی ہے، اور پلیس ہولڈر "propname" کو زیادہ مخصوص قدر "عوامی معلومات" سے تبدیل کیا جا سکتا ہے۔

iOS ایپلی کیشنز میں کلیدی قدر ڈیٹا بیس LMDB کی چمک اور غربت

تمام منفرد میٹا ڈیٹا، ذخیرہ کرنے کی خاطر جسے ایک نیا ٹیبل بنایا گیا تھا، کو ریکارڈ کے ویلیو حصے میں رکھا جاتا ہے۔ ایک ہی وقت میں، آپ ان فائلوں اور فولڈرز کے ڈیٹا کو ڈپلیکیٹ نہیں کرنا چاہتے جو پہلے سے ہی مین ٹیبل میں محفوظ ہیں۔ اس کے بجائے، بے کار ڈیٹا کو "P" کلید میں "نوڈ ID" اور "ٹائم اسٹیمپ" فیلڈز کی شکل میں شامل کیا جاتا ہے۔ ان کا شکریہ، آپ ایک انڈیکس کلید بنا سکتے ہیں، جس سے آپ ایک بنیادی کلید حاصل کر سکتے ہیں، جس سے، آخر میں، آپ نوڈ میٹا ڈیٹا حاصل کر سکتے ہیں۔

نتیجہ

ہم LMDB کے نفاذ کے نتائج کا مثبت اندازہ لگاتے ہیں۔ اس کے بعد، درخواستوں کو منجمد کرنے کی تعداد میں 30 فیصد کمی واقع ہوئی۔

iOS ایپلی کیشنز میں کلیدی قدر ڈیٹا بیس LMDB کی چمک اور غربت

کئے گئے کام کے نتائج iOS ٹیم سے آگے نکل گئے۔ فی الحال، اینڈرائیڈ ایپلی کیشن کے اہم "فائلز" سیکشنز میں سے ایک نے بھی LMDB استعمال کرنا شروع کر دیا ہے، اور دوسرے حصے راستے میں ہیں۔ C زبان، جس میں کلیدی قدر کی دکان کو لاگو کیا جاتا ہے، ابتدائی طور پر C++ میں کراس پلیٹ فارم کے ارد گرد ایک ایپلیکیشن فریم ورک بنانے میں ایک اچھی مدد تھی۔ ایک کوڈ جنریٹر کا استعمال بغیر کسی رکاوٹ کے نتیجے میں آنے والی C++ لائبریری کو Objective-C اور Kotlin میں پلیٹ فارم کوڈ کے ساتھ جوڑنے کے لیے کیا گیا تھا۔ ججن ڈراپ باکس سے، لیکن یہ بالکل مختلف کہانی ہے۔

ماخذ: www.habr.com

نیا تبصرہ شامل کریں