Table of Contents
سیستم های جاسازی شده اغلب نیاز به مدیریت داده های محلی بدون سربار سرورهای پایگاه داده کامل دارند. پیاده سازی یک موتور پایگاه داده سبک در C به توسعه دهندگان کنترل مستقیم بر حافظه، عملکرد و ذخیره سازی می دهد.این مقاله از طریق طراحی و پیاده سازی یک موتور پایگاه داده ساده جاسازی شده، پوشش ساختارهای داده، عملیات CRUD، نمایه سازی و استراتژی های پایداری برای محیط های منابع آموزش دیده می شود.
الزامات اصلی برای یک موتور پایگاه داده جاسازی شده
یک موتور پایگاه داده جاسازی شده باید در محدوده تنگ رم، فلش و سرعت پردازش عمل کند. الزامات معمول شامل رفتار تعیین کننده، حداقل رد پای کد و بدون وابستگی خارجی است. موتور باید از عملیات اساسی پشتیبانی کند: وارد کردن، به روز رسانی، حذف و جستجو. بسیاری از پایگاه داده ها نیز نیاز به بقا قدرت و ذخیره اطلاعات در حافظه غیر ولتاژ مانند EEPROM، فلش، و یا کارت های SD.
انتخاب ساختار داده مناسب اولین تصمیم طراحی است. آرایه ها ساده اما محدود با اندازه های استاتیک. لیست لینک شده اجازه رشد پویا اما اضافه کردن سربار اشاره کننده برای عملکرد متعادل، یک رویکرد ترکیبی با استفاده از استخرهای رکورد ثابت با یک لیست آزاد می تواند به خوبی کار کند. SQLite اصول طراحی ارائه بینش های مفید حتی برای موتورهای ساده تر.
طراحی لایه ذخیره سازی رکورد
لایه ذخیره سازی مدیریت می کند که چگونه سوابق در حافظه یا بر روی دیسک قرار می گیرد.یک الگوی مشترک این است که هر رکورد را به عنوان یک ساختار ثابت برای ساده سازی محاسبات اشاره کننده و اجازه می دهد تا نمایه سازی مستقیم پیچیده شود و نیاز به یک مدیر حافظه دارد.
رکورد ثابت با یک Pool
حداکثر تعداد رکوردها (به عنوان مثال، را تعریف کنید و یک آرایه استاتیک را اختصاص دهید. a bitmap یا آهنگ های رایگان لیست که از اسلات ها استفاده می شود.هنگامی که یک رکورد حذف می شود، اسلات آن به استخر باز می گردد.این رویکرد از تخصیص پویا و تضمین O (1) زمان تخصیص اجتناب می کند.
#define MAX_RECORDS 256
typedef struct {
int id;
char name[32];
float value;
int active; // 1 if slot in use
} Record;
Record pool[MAX_RECORDS];
برای ذخیره سازی مداوم، استخر می تواند توسط یک فایل یا منطقه فلش پشتیبانی شود.در شروع، موتور استخر را از حافظه غیر ارادی به رم می خواند و در خاموش کردن (یا به صورت دوره ای) آن را می نویسد.
بررسی های Data Integrity
یک فیلد چکه ساده را به هر رکورد اضافه کنید تا فساد را تشخیص دهید. )CRC-32 یک انتخاب خوب برای سیستم های جاسازی شده است، تعادل پیچیدگی با قدرت تشخیص خطا.
اجرای عملیات CRUD Basic
با تعریف استخر رکورد، پیاده سازی توابع برای وارد کردن، پیدا کردن، به روز رسانی و حذف سوابق جستجو اغلب تنگنا عملکرد هستند، بنابراین جستجوی ساده لوحانه تنها برای پایگاه های داده کوچک (چند صد رکورد) قابل قبول است.
با مدیریت آزاد-List
یک لیست رایگان از شاخص ها را نگه دارید، یک شاخص را از لیست آزاد، پر کردن رکورد، و علامت گذاری آن فعال است.خود لیست آزاد می تواند یک پشته ساده با استفاده از آرایه ای از اعداد صحیح باشد.
int free_list[MAX_RECORDS];
int free_count = MAX_RECORDS;
for (int i = 0; i < MAX_RECORDS; i++) free_list[i] = i;
int db_insert(int id, const char* name, float value) {
if (free_count == 0) return -1; // no space
int idx = free_list[--free_count];
pool[idx].id = id;
strncpy(pool[idx].name, name, sizeof(pool[idx].name)-1);
pool[idx].value = value;
pool[idx].active = 1;
return idx;
}
جستجو و به روز رسانی
یک جستجوی ساده بر روی استخر، چک کردن تنها پرونده های فعال برای به روز رسانی، پیدا کردن رکورد، تغییر زمینه ها و اختیاری چک کردن لیست آزاد اگر رکورد حذف شده است.
int db_find_by_id(int id) {
for (int i = 0; i < MAX_RECORDS; i++) {
if (pool[i].active && pool[i].id == id) return i;
}
return -1;
}
void db_update(int idx, float new_value) {
if (idx >= 0 && idx < MAX_RECORDS && pool[idx].active)
pool[idx].value = new_value;
}
مفاهیم پیشرفته: شاخص و اصرار
همانطور که تعداد رکوردها رشد می کند، جستجوی خطی گران می شود و یک شاخص ساده را اضافه می کند - مانند یک آرایه مرتب از نقاط کلیدی یا یک درخت جستجوی باینری - زمان بازیابی را بهبود می بخشد.برای سیستم های جاسازی شده، یک آرایه استاتیک که در کلید با جستجوی باینری مرتب شده است، اغلب کافی است اگر واردها بی نظیر هستند.
فهرست بندی شده با جستجوی باینری
یک آرایه موازی از شاخص های رکورد را که توسط کلید جستجو (به عنوان مثال، ID) تنظیم شده است، هنگام قرار دادن یک رکورد جدید، فهرست آن را به آرایه مرتب شده با استفاده از یک قرار دودویی قرار دهید، سپس جستجو از طریق جستجوی باینری O(log n) می شود.
ذخیره سازی مداوم با استفاده از File I/O
در میکروکنترلرها بدون سیستم فایل، حافظه فلش خام می نویسد رایج است. [۱] در سیستم های جاسازی شده مبتنی بر لینوکس، استاندارد POSIX / [FLT: ۱.۶] به خوبی از یک فایل ساده استفاده کنید: نوشتن یک هدر (شماره جادویی، نسخه، رکورد) و سپس توسط آرایه خام برای سقوط، یک فایل ساده (F-F) است که می تواند به اندازه کافی کمک کند.
void db_save(const char* filename) {
FILE* fp = fopen(filename, "wb");
if (!fp) return;
fwrite(pool, sizeof(pool), 1, fp);
fclose(fp);
}
void db_load(const char* filename) {
FILE* fp = fopen(filename, "rb");
if (!fp) return;
fread(pool, sizeof(pool), 1, fp);
fclose(fp);
// Rebuild free-list from pool
free_count = 0;
for (int i = 0; i < MAX_RECORDS; i++) {
if (!pool[i].active) free_list[free_count++] = i;
}
}
مدیریت محدودیت ها و اخراج های تجاری
موتورهای پایگاه داده جاسازی شده با یک معامله مداوم بین ویژگی ها و استفاده از منابع مواجه هستند.انتخاب که ویژگی های آن شامل بستگی به برنامه دارد:
- انطباق - معمولا لازم نیست.
- Indexing - اضافه هزینه وارد اما سرعت خواندن.
- Concurrency - اکثر سیستم های جاسازی شده یک رشته را اجرا می کنند.
- [[۱] [۱۰] [۱۰] [۱]] [۱۰] [۱]] [۱۰]] [۱]] [۱۰] [۱]] [۱]] [۱۰] [۱]] [۱۰] [۳]] [۳] [۱]] [۳] [۱] [۱۰] [۱] [۳] [۳] [۱] [۱] [۳] [۱] [۳] [۱] [۶] [۱] [۱] [۱] [۱] [۱] [۱] [۱] [۱] [۱] [۱] [۱] [۱] [۱] [۱] [۱] [۱] [۱] [۳] [۳] [۳] [۳] [۱] [۳] [۳] [۱] [۳] [۳] [۱] [۱] [۳] [۳] [۳] [۳] [۳] [۱] [۳] [۳] [۳] [۱] [۱] [۱] [۱] [۳] [۳] [۳] [۳] [۳] [۳] [۳] [۳] [۳] [۳]
- از دست دادن قدرت - برای ذخیره سازی فلش، اجتناب از به روز رسانی های مکرر کوچک و استفاده از یک طرح دو بار.
مثال عملی: A Temperature loger Database
یک سنسور دمای IoT را در نظر بگیرید که هر دقیقه خواندن را ثبت می کند و آنها را به صورت محلی برای 24 ساعت ذخیره می کند. موتور پایگاه داده باید 14 رکورد (یک بار در دقیقه) را اداره کند (یک رکورد ممکن است شامل یک نوار زمان (دورهUnix)، یک دما ( فلورات)، و یک سنسور ID.12.
موتور می تواند داده ها را در یک مد حلقه ذخیره کند: هنگامی که استخر پر است، قدیمی ترین رکورد بیش از حد نوشته شده است. پیاده سازی یک نقطه "head" برای اسلات بعدی نوشتن و "tail" برای قدیمی ترین رکورد فعال است.این اجتناب از منطق لیست آزاد و ارائه O (1) جستجو می تواند با جستجوی باینری در زمان های زمانی که سوابق زمانی ذخیره شده در دستور ذخیره شده است بهینه سازی شود.
typedef struct {
uint32_t timestamp;
float temp_c;
uint8_t sensor_id;
uint8_t active; // not needed if using ring buffer
} TemperatureRecord;
#define MAX_LOGS 1440
TemperatureRecord logs[MAX_LOGS];
uint16_t head = 0; // next write position
uint16_t count = 0; // number of valid records
در این کتاب بخوانید: در این باره بخوانید: به ، [[FLT13]]، [[FLT14]]، ، [[FLT16]]، [[FLT16]]، [[FLTAGEREF:S]]، [[F]]، [[F]] و [[F]]، [[F]]، [[رده:Toc3992]]، [[رده:Toc3992]] و [[S]]، [[رده:Toc3992]]، [[رده:Toc3992|Toc39910]]، [[Toc399107 01:2|Toc399107 01:56|Toc399107 01:2|T|T|T|T|T|T|T|T|T|T|T|T|T|T|T|T|T|T|T|T|T|T|T|T|T|T|T|T|T|Toc399107 01:56|T|T|T|T|T|T|T|T|T|T|T|T|Toc399107 01:2|T|T|T|T|Toc399107 01:2|T|T|T|
تست و بهینه سازی در مورد سخت افزار Target
همیشه موتور پایگاه داده را در سخت افزار های جاسازی شده واقعی تست کنید، شبیه سازی ها محدودیت های زمانی را از دست می دهند، به ویژه برای چرخه های نوشتن فلش و سناریوهای از دست دادن قدرت، نظارت بر رم استفاده از یک ابزار پروفایل و بررسی موارد لبه: ذخیره سازی کامل، داده های فاسد، تنظیم مجدد تست ساده هزاران ورودی تصادفی، جستجو و حذف در حالی که مقایسه با یک مدل طلایی.
- {\displaystyle {FLT:1} - اگر نوشتن به EEPROM یا فلش NOR، کل را به چند صد هزار بافر دایره ای با لایه ای که طول عمر را گسترش می دهد محدود کنید.
- قدرت و خطا امن [FLT 1] - استفاده از علامت متعهد: نوشتن پرچم پس از یک دسته کامل از رکوردها، در شروع مجدد، پرچم را بررسی کنید؛ اگر از دست رفته، آخرین دسته را دور بیندازید و به حالت قبلی بازگردید.
- استخر حافظه - اجتناب از بازگشت عمیق.
نتیجه گیری
ساخت یک موتور پایگاه داده پایه در C برای سیستم های جاسازی شده یک رویکرد عملی برای مدیریت داده ها در دستگاه های محدود منابع است.با تمرکز بر ساختارهای داده ساده مانند استخر های ثابت و بافرهای حلقه، توسعه دهندگان به عملیات CRUD کارآمد با حداقل سربار اضافه کردن نمایه اختیاری و پایداری پایه، یک آرایه ساده را به یک طبقه داده های محلی قابل اعتماد تبدیل می کند. تکنیک های توصیف شده در اینجا از logger کوچک برای ارائه سیستم های پیچیده تر و پیچیده تر،