Warum wurde SQLite in C geschrieben?
(sqlite.org)- SQLite wird seit den Anfängen (2000) in C entwickelt – aus Gründen der Performance, Kompatibilität, geringen Abhängigkeiten und Stabilität
- C kann auf nahezu allen Betriebssystemen und aus fast allen Sprachen heraus genutzt werden und unterstützt insbesondere als Low-Level-Bibliothek eine schnelle Ausführung
- Statt einer objektorientierten Sprache wurde C gewählt – wegen der Erweiterbarkeit, der Aufrufbarkeit aus vielen Sprachen und weil C++ und Java damals noch unreif waren
- SQLite hat eine Einzeldatei-Struktur mit kaum Abhängigkeiten und verwendet nur ein Minimum an Funktionen aus der C-Standardbibliothek
- Es gibt Diskussionen über eine Neuschreibung in „sicheren Sprachen“ wie Rust und Go, doch bei Qualitätskontrolle, Performance und Aufrufbarkeit als Bibliothek liegt C weiterhin vorn
1. Warum C die optimale Wahl ist
- SQLite wird seit der ersten Entwicklung am 29. Mai 2000 bis heute in C gepflegt
- Derzeit gibt es keine Pläne, es in einer anderen Sprache neu zu schreiben
- C bietet hardware-nahe Kontrolle und zugleich hohe Portabilität und wird daher oft als „portable Assemblersprache“ bezeichnet
- Andere Sprachen können behaupten, „so schnell wie C“ zu sein, aber keine behauptet, schneller als C zu sein
1.1. Performance
- Eine Low-Level-Bibliothek wie SQLite wird häufig aufgerufen und muss daher extrem schnell arbeiten
- C eignet sich gut zum Schreiben schneller Programme, ist portabel und erlaubt zugleich einen hardwarenahen Zugriff
- Auch wenn andere moderne Sprachen behaupten, „so schnell wie C“ zu sein, gibt es im allgemeinen Einsatz keine Sprache, die überzeugend als schneller als C gilt
- C erlaubt eine feine Kontrolle über Speicher- und CPU-Ressourcen und erreicht dadurch teils 35 % bessere Performance als das Dateisystem
- Beispiel: Internal vs External BLOBs
1.2. Kompatibilität
- Fast jedes System kann in C geschriebene Bibliotheken aufrufen
- Beispielsweise lässt sich SQLite auch unter Android (Java-basiert) über einen Adapter verwenden
- Wäre SQLite in Java geschrieben worden, könnte es auf dem iPhone (Objective-C, Swift) nicht genutzt werden, was die Universalität stark einschränken würde
1.3. Geringe Abhängigkeiten
- Weil SQLite als C-Bibliothek entwickelt wurde, hat es nur sehr geringe Laufzeitabhängigkeiten
- In der Minimal-Konfiguration werden nur sehr grundlegende Funktionen der C-Standardbibliothek verwendet:
memcmp(),memcpy(),memmove(),memset(),strcmp(),strlen(),strncmp() - Selbst vollständigere Builds haben nur wenige zusätzliche Abhängigkeiten wie
malloc(),free()und Datei-I/O - Moderne Sprachen erfordern oft große Laufzeitumgebungen und tausende Interfaces
1.4. Stabilität
- C ist eine alte, langweilige Sprache mit wenig Veränderung, doch genau das bedeutet Vorhersehbarkeit und Stabilität
- Für eine kleine, schnelle und zuverlässige Datenbank-Engine wie SQLite ist eine Sprache geeignet, deren Spezifikation sich nicht ständig ändert
- Wenn sich Sprachspezifikation oder Implementierung häufig ändern, wirkt sich das nachteilig auf die Stabilität von SQLite aus
2. Warum nicht in einer objektorientierten Sprache?
- Manche Entwickler glauben, ein komplexes System wie SQLite lasse sich ohne Objektorientierung schwer umsetzen, aber Bibliotheken in C++ oder Java sind im Vergleich zu C schwerer aus anderen Sprachen aufzurufen
- Für die Unterstützung vieler Sprachen wie Haskell, Java usw. war die Wahl einer C-Bibliothek sinnvoll
- Objektorientierung ist keine Sprache, sondern ein Entwurfsmuster und daher nicht auf bestimmte Sprachen beschränkt
- Auch in C lassen sich mit Strukturen und Funktionszeigern objektorientierte Muster umsetzen
- Objektorientierung ist nicht immer die beste Struktur; prozeduraler Code kann klarer, leichter wartbar und manchmal auch schneller sein
- In den frühen Jahren der SQLite-Entwicklung (um 2000) galt:
- Java war unreif
- C++ hatte ernste Kompatibilitätsprobleme zwischen Compilern
→ Damals war C die praktischste und sicherste Wahl
- Auch heute gibt es nur wenige Vorteile, die eine Neuschreibung von SQLite rechtfertigen würden
3. Warum nicht in einer „sicheren Sprache“?
- In jüngerer Zeit ist das Interesse an sicheren Programmiersprachen wie Rust und Go gestiegen, aber als SQLite ursprünglich entwickelt wurde (in den ersten zehn Jahren), existierten diese Sprachen noch nicht
- Eine Neuschreibung in Go oder Rust könnte mehr Bugs verursachen oder die Performance verschlechtern
- Diese Sprachen fügen zusätzlichen Verzweigungscode für Speicherprüfungen usw. ein; in der Qualitätsstrategie von SQLite ist jedoch 100% Branch Coverage entscheidend, und dieser Punkt ist nicht erfüllt
- Sichere Sprachen beenden Programme in Out-of-Memory-Situationen meist, SQLite ist dagegen so ausgelegt, dass es sich auch bei Speichermangel erholen kann
- Rust, Go usw. sind weiterhin junge Sprachen und benötigen fortlaufende Weiterentwicklung
- Deshalb begrüßt das SQLite-Entwicklungsteam zwar die Weiterentwicklung sicherer Sprachen, legt für die SQLite-Implementierung aber weiterhin Wert auf die bewährte Stabilität von C
Trotzdem besteht irgendwann die Möglichkeit einer Neuschreibung in Rust. In Go ist das eher unwahrscheinlich, weil Go assert() nicht mag
- Für eine Umsetzung in Rust gäbe es jedoch Voraussetzungen:
- Rust müsste reifer werden und sich langsamer verändern, also zu einer „alten und langweiligen Sprache“ werden
- Es müsste bewiesen sein, dass sich damit eine universell aus vielen Sprachen aufrufbare Bibliothek erstellen lässt
- Es müsste Objektcode erzeugt werden können, der auch auf Geräten ohne Betriebssystem, etwa in Embedded-Systemen, läuft
- Es müssten Werkzeuge für 100% Branch-Coverage-Tests auf kompilierten Binärdateien verfügbar sein
- OOM-Fehler (Speichermangel) müssten recoverbar sein
- Rust müsste alles, was C in SQLite leistet, ohne Performanceverlust erledigen können
- Falls ein Rust-Fan (
rustacean) meint, dass all diese Bedingungen bereits erfüllt sind und SQLite in Rust neu geschrieben werden sollte, wird empfohlen, die SQLite-Entwickler direkt zu kontaktieren und dafür zu argumentieren
2 Kommentare
Hacker-News-Kommentare
if (i >= array_length) panic("index out of bounds")hinzu. Dieser Code selbst ist aber durch den Rust-Compiler gut getestet, daher sollte er kein Problem darstellen. Ich bin mir nicht sicher, ob ich diese Logik richtig versteheget_unchecked()sind auch Zugriffe ohne Bounds Check möglich, was Sicherheit und Performance kombinieren kann get_unchecked-Dokumentationassert()eher unwahrscheinlich ist. Für eine Migration nach Rust wären aus dieser Sicht Bedingungen nötig wie: Rust müsste über längere Zeit stabiler und weniger veränderlich werden, für allgemeine Bibliotheksentwicklung geeignet sein, auch auf Embedded-Systemen ohne OS laufen, Tooling für 100% Branch Coverage bieten, über Mechanismen für OOM-Fehlerbehandlung verfügen und die Rolle von C ohne Performanceverlust ersetzen könnenif condition { panic(err) }wie eine Art Assert-Funktion zu verwenden?Die Formulierung, dass C auch für SQLite ein Sicherheitsrisiko sei – gilt das selbst dann, wenn man ausreichend gute Tests schreibt und selbst als Entwickler ausreichend erfahren ist? Dass Logik und Entwicklungsprozess das Problem sein können, ist nachvollziehbar, aber dass die Sprache selbst eine Sicherheitslücke sein soll, ist für mich schwer zu verstehen. Tatsächlich gibt es doch kaum Programme, die nicht auf in C geschriebene Infrastruktur angewiesen sind.