Gömülü sistemler genellikle tam veritabanı sunucularının tepesi olmadan yerel veri yönetimi gerektirir. C'deki hafif bir veritabanı motoru uygulama geliştiricileri hafıza, performans ve depolama üzerinde doğrudan kontrol sağlar. Bu makale basit bir gömülü veritabanı motorun tasarımı ve uygulanması ile yürür, veri yapıları, CRUD işlemleri, indeksleme ve kalıcı ortamlar için.

Bir Gömülü Veritabanı Motoru için Temel Gereksinimler

Bir gömülü veritabanı, RAM, flash ve işleme hızı üzerinde sıkı sınırlar içinde çalışmalıdır. Tipik gereksinimler, EEPROM, SPI flash veya SD kartlar gibi doğrusal olmayan hafızalarda da veri depolamalıdır.

Doğru veri yapısını seçmek ilk tasarım kararıdır. Diziler basit ama statik boyutlarda sınırlıdır. Linked listeleri dinamik büyüme sağlar ancak puanlayıcı bir ek. dengeli performans için, sabit boyutlu rekor havuzları ücretsiz olarak kullanarak kullanan bir hibrit yaklaşım iyi çalışabilir. ”ENGT:0SQLite'in tasarım ilkeleri).

Record Storage Katmanı Tasarımı

Depolama katmanı, kayıtların hafızada veya diskte nasıl yapıldığını yönetir. Ortak bir model her kaydı belirli bir uzunluk yapısı olarak basit bir noktaya kadar basit bir dizi yapı olarak tedavi etmektir ve doğrudan indeksleme sağlar. Değişken uzunlukta rekorlar karmaşık parçalama gerektirir ve hafıza yöneticisi gerektirir.

Bir Rekor Havuzla Sabit-Length Records

Bir kayıt silindiğinde, bu yaklaşım dinamik tahsis ve O'nun tahsis süresinden kaçınır.A bitmap veya boş listeler kullanılır.Bir kayıt silindiğinde, slot dinamik tahsis ve O'nun tahsis süresinden kaçınır.

#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];

Kalıcı depolama için havuz bir dosya veya flaş bölgesi tarafından desteklenebilir.Başlangıçta, motor RAM'a olmayan hafızadan havuzu okur ve kapatma (veya periyodik olarak) geri yazıyor.

Data Integrity Checks

Yolsuzluk tespit etmek için her kayıt için basit bir çek alanı ekleyin.ETHFLT:0)CRC-32) gömülü sistemler için iyi bir seçimdir, hata algılama gücü ile denge dengelemek.

Temel CRUD Operasyonları Uygulamayın

Kayıt havuzu ile tanımlanan, ekleme, bulmak, güncelleme ve kayıtları silmek için işlevleri uygulayın. Arama işlemleri genellikle performans şişesi, bu yüzden naif lineer arama sadece küçük veri tabanları için kabul edilebilir ( birkaç yüz kayıt).

Free-List Management ile birlikte

Ücretsiz endeksler listesini koruyun.In insert, pop a index from the free-list, record doldur ve aktif olarak işaretleyin. Ücretsiz liste kendisi bir dizi tamsayı kullanarak basit bir yığın olabilir.

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;
}

Arama ve Update

Havuzda basit bir arama, sadece aktif kayıtları kontrol edin. Güncellemeler için, kayıt, değişiklik alanları bulmak ve kayıt silinirse ücretsiz listeyi yeniden kontrol edin.

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;
}

Gelişmiş Kavramlar: Indexing and Persistence

Kayıt sayısı büyüdükçe, lineer arama pahalı hale gelir. Basit bir indeks eklemek - anahtar noktalı veya ikili arama ağacı gibi - gömülü sistemler için yeniden beslenme zamanı.

Sorted Index with Two Search

Arama anahtarı tarafından sıralanan bir kayıt indeksi kullanın (örneğin, ID). Yeni bir kayıt eklerken, indeksini ikili bir eklenti kullanarak sıralanan diziye ekleyin. Sonra arama Olog n) ikili arama yoluyla Olog n) olur.Deletions, indeksleme için bu kabul edilebilir.

Kalıcı Depolama File I /Okullanım

Bir dosya sistemi olmadan mikro kontroller üzerinde, ham flaş bellek yaygındır. Linux tabanlı gömülü sistemler, standart POSIXİLETİŞİM: 4) /) iyi bir dosya formatı kullanın: bir başlık yazın (sihirli sayı, sürüm, kayıt sayısı) ham havuz tarafından takip edilen.Demirlik için, bir yazı-açıklık için bir dosya sistemi, ancak temel motorlar için tek bir flaş sayfası için.

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;
 }
}

Kıtlamalar ve Ticaret-offlar

Gömülü veritabanı motorları özellikler ve kaynak kullanımı arasında sürekli bir ticaretle karşı karşıyadır. Hangi özelliklerin dahil edilmesi uygulamaya bağlıdır:

  • [FONT=0)ACID uyumluluğu[[[Dönetici: 1) Genellikle gerekli değildir. Basit atom çoğu sensör veri girişi için yeterli yazar.
  • [FONT=0)Indexing[[DÜT:1] – Adds insert maliyeti ama hızlar okur.Yazar iş yükleri için, indeksleri atlar.
  • [FONT:0)Koncurrency[[Dönetici: 1) - Çoğu gömülü sistem tek bir iplik çalıştırır. bir RTOS kullanarak mutexes kullanın.
  • [FONT=0)Memory ayak izi[[Dönetici: 1 ) – Statik tahsis dinamik ) tarafından daha güvenlidir.UseENFLT:9).Buffer boyutlar için sabitler.
  • [FONT:0)Power kaybı[DÜT:1] – flaş depolama için, sık sık küçük yazarlardan kaçının. Batch güncellemeler ve çift ekranlı bir program kullanın.

Pratik Örnek: Bir Sıcaklık Logger Database

Her dakikayı okuyan bir IoT sıcaklık sensörü düşünün ve onları 24 saat boyunca yerel olarak depolar. Veritabanı motoru 1440 kaydı (bir dakika içinde) her kayıt bir kez bir saat (altınlık) içerebilir ve bir sıcaklık (flot) ve 256 slotlu sabit havuz kullanmak çok küçük; burada kayıt başına 28 tane (4+4+4+4+4 $) gerekir, havuz yaklaşık 40 KB RAM ile kullanılabilir.

Motor bir ring-buffer modada verileri depolayabilir: havuz tam olarak, en eski kayıt yazılmamışsa "head" bir sonraki yazı slotu ve en eski aktif kayıt için "tail" bir "ayak" .Bu kaçınır ücretsiz liste mantığı ve O(1) eklemek. Arama, kronolojik bir sırayla depolanırsa, ikili arama ile optimize edilebilir.

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

Bir okuma girin: belirli bir süre için yazın: sayı = MAXT:12, arter.(wrap)) Sanal başlangıçtan sonra ikili arama kullanın.(kablok sistemlerde son derece hafif ve yaygın olarak kullanılır.)Testing:0)Ring temelleri[Dönemli:[Döneticileri değiştir][Dönemli bir uygulama seçeneği sunar.

Test ve Optimizasyon Hedef Donanımı

Her zaman veritabanı motoru gerçek gömülü donanım üzerinde test edin. Emulators, zamanlama kısıtlamaları kaçırıyor, özellikle flaş yaz döngüleri ve güç kaybı senaryoları için. bir profilleme aracı ve kenar vakaları ile RAM kullanımı: tam depolama, yozlaşmış veriler, orta yazlık bir test kullanımı binlerce rastgele ekleme, aramalar ve altın bir modelle karşılaştırırken siliniyor.

  • [FONT=0]Flash, seviyeleme seviyesi[[DÜT:1) – EEPROM veya NOR flaşa yazsa, toplam birkaç yüz bin yazar.Bir giyim katmanı ile bir delik ömür boyu uzatılır.
  • [FONT:0]Power-fail güvenli[Dönetici: Bir taahhüt işareti kullanın: tam bir kayıttan sonra bir bayrak yazın.Başlangıçta, bayrak kontrol edin; eğer eksikse, son resmi iptal et ve önceki duruma geri dönün.
  • [FONT=0)Memory havuzlama[Dönetici: Derin recursion'dan kaçının.Imory function call stacks sığ. Use statik buffers for file I/O.

Sonuç Sonuç Sonuç Sonuç Sonuç Sonuç Sonuç Sonuç

C'de temel bir veritabanı motoru inşa etmek, veri sınırlı cihazlardaki verileri yönetmek için pratik bir yaklaşımdır. Sabit kayıt havuzu ve ring tamponları gibi basit veri yapıları üzerine odaklanarak, geliştiriciler SQLite veya Berkeley DB gibi daha az yükleyici işlemleri elde ederler.Addifiering and maintain basicence returns a simple array into a reliable local datastore.