プログラミング
クエリ可能な実行可能ファイル
Queryable Executables (fzakaria.com)
要約
この記事では、実行可能ファイル自体をSQLiteデータベースとして扱う「SELF」という新しいフォーマットを紹介しています。これにより、プログラムのコード、ウェブサイトのアセット、ルーティング情報、さらには実行時の状態ログまで、すべてを単一のデータベースファイルに格納し、SQLクエリでアクセス・操作することが可能になります。このアプローチは、従来のファイルシステムへの依存を減らし、デプロイメントと状態管理を劇的に簡素化する可能性を秘めています。
全文翻訳
私の記事「Your executable is a SQLite database」が多くの人に反響を呼んだことを知り、大変嬉しく思っています。これは私が以前から考えていたフォーマットであり、そのアイデアは他の人々の共感を呼んだようです。簡単に振り返ると、SELFはプログラムがSQLiteデータベースであるフォーマットです。binfmt_miscを使用してカスタムインタープリタをトリガーし、segmentsテーブルの行をマッピングしてエントリーポイントにジャンプさせることができます。これにより、バイナリツールの多くのクラスがSQLに集約されます。
ファイルフォーマットがSQLiteデータベースであることで、すべてがSQLに集約されていくことに驚かされます。私自身やコメントで他の人々がすぐに気づいたアイデアがあります。もし実行可能ファイルがデータベースであり、データベースは書き込み可能なものであるなら、実行中のプログラムは状態を保存するためにもそれを使用できるのでしょうか? 🤔 はい! 🤯 完全なディストリビューションだけでなく、すべてのアプリケーションの状態を単一のファイルに集約でき、/var/ や /tmp/、/home/ やその他のファイルシステムへの依存をなくすことができます。プログラムは、実行しているのと同じファイルに自身の状態を保存でき、トランザクション的に行うことができます。
self-httpd は、まさにそれを実現するプルーフ・オブ・コンセプトのウェブサーバーです。これは単一ファイルのプログラムで、データベースから実行されます。ファイルには、プログラム、ウェブサイト、ルート、そしてすべてのビジターログが含まれています。すべての状態は、プログラム自体と同じSQLiteファイルに更新されます。
# 私たちのサーバーは単一ファイルであり、SQLiteデータベースです
$ file server
server: SQLite 3.x database, application id 1397050438, ...
$ ./server --journal wal 8080
self-httpd: serving 3 routes out of /srv/self/server
self-httpd: listening on http://0.0.0.0:8080 with 4 workers
$ curl -s localhost:8080 | head -1
<!doctype html>
# まだ誰もそのページでボタンを押していません
$ sqlite3 server 'SELECT count(*) FROM presses'
0
$ curl -s -X POST -d press localhost:8080/api/press
{"presses":1,"button":"press"}
# アプリケーションデータは同じデータベース内にあります
$ sqlite3 server 'SELECT id, at, button FROM presses'
1|2026-08-25 03:11:28|press
# ページを取得したGETリクエストも同様でした
$ sqlite3 server 'SELECT count(*) AS n, path FROM visits GROUP BY path'
1|/
1|/api/press
このウェブサーバーは https://selfdb.exe.xyz でライブ公開されています。サイトが動作しない場合は申し訳ありません。彼らの最小ティアにデプロイしました。後世のために、念のためサイトのスクリーンショットを添付しました!それは単一のファイル、SQLiteデータベースであり、サーバーでもあります。ウェブサイトであり、プログラムであり、ビジターログと状態でもあります。
§すべては私の悪魔のミューズ
Justine Tunney の作品には多大な敬意を払っています。彼女の先行技術である redbean は、自己解凍ZIPアーカイブとして構築された Actually Portable Executable で、単一ファイルのウェブサーバーであり、このアイデアにインスピレーションを与えました。SELF は多くの点でそれほど brililant ではありません。非常に似たことを達成するために、よりシンプルなツールに依存していますが、すべてが単一のドメイン、SQLに集約されていくことに驚かされます。redbean がアーカイブフォーマット(ZIP)を含める必要があるのに対し、SELF ではハンドラーテーブルに新しい行を追加するのが同等です。
INSERT INTO handlers VALUES ('/api/busiest', 'SELECT path, count(*) FROM visits GROUP BY path ORDER BY 2 DESC LIMIT 5');
redbean が Actually Portable Executable なら、これは Actually Queryable Executable です。一方はどこでも実行でき、もう一方は SELECT できます。
§必要なのは argv[0] だけ
プロセスはどのようにして自分自身にアクセスできるのでしょうか? 🤔 現在のところ、/proc/self/exe は使用できません。
22面白いことに、VFS Linuxメンテナーは最近カーネルに透過的なbinfmt_miscサポートを導入しました。これにより、/proc/self/exe が元のファイルを指すようになります。私はここでそれについて書きました。binfmt_miscが一致すると、カーネルはファイルをexecveせず、インタープリタをexecし、パスを渡します。self-execはargv + 1をプログラムに渡すため、プログラムのargv[0]は実行可能ファイルへのパスになります。インタープリタは、エントリーポイントにジャンプする前にSQLite接続を解放するため、プログラムは自身のファイルを開いてクエリできます。
int main(int argc, char **argv) {
sqlite3 *db;
/* カーネルが実行したファイル */
sqlite3_open(argv[0], &db);
...
}
これは非常に制限がなく、魔法のようです。自身のセグメントテーブルや、その隣にある新しいテーブルを読み取ることができます。書き込みは呼び出し間で永続します。✨
§self-httpd
例のウェブサーバーは3つのテーブルで構成されています:routes、visits、presses。すべてのビジターとすべてのボタンプレスを記録します。
-- コンパイルとリンク後に実行可能ファイルに追加されるコンテンツ --
CREATE TABLE routes (path TEXT PRIMARY KEY, mime TEXT, body BLOB);
-- 実行中に実行可能ファイルに書き戻される、サイトが収集するもの --
CREATE TABLE visits (id INTEGER PRIMARY KEY, at TEXT, ua TEXT, path TEXT);
CREATE TABLE presses (id INTEGER PRIMARY KEY, at TEXT, button TEXT);
アプリケーションのビルドは非常に平凡で、見慣れたものです。アプリケーションスキーマを作成するためにDDLを実行し、ウェブサイトをINSERTします。
# 現時点では通常のELF
$ cc -O2 server.c -o server.elf $(pkg-config --libs sqlite3)
# 同じプログラムを、行として
$ elf2self server.elf server
$ sqlite3 server < site/schema.sql
$ sqlite3 server "INSERT INTO routes VALUES ('/index.html', 'text/html', readfile('site/index.html'))"
アセットパイプラインは、「通常のウェブサーバー」のように見えますが、コンテンツのためにSQLで自身にクエリしていることに気づくまでです。ああ、そして「自身」とはSQLiteデータベースです。
cluster_file server — 同じファイル!
req GET /
proc running server
req->proc
krn execve()
binfmt_misc
se
self-exec
krn->se
se->proc
map, jump
seg segments (the program)
se->seg SELECT content
rsp 200 OK
proc->rsp
rt routes (the website)
proc->rt SELECT body
vis visits (the log)
proc->vis INSERT
https://selfdb.exe.xyz のページには、ビジターログやボタンプレスに加えて、多くの楽しい追加情報が表示されています。セグメント、シンボル、リロケーションも含まれています。これらはビルド時に組み込まれるのではなく、実行中に自身からクエリされます。
§ライブサイトの編集はトランザクション
ACIDトランザクションの機能があれば、興味深いことが可能になります。ウェブサーバーは実行中に自身のコンテンツを編集でき、編集はトランザクション的です。UPDATEはプログラムと同じファイルにコミットされ、ROLLBACKで元に戻されます。
# 実行中のサイトを変更。再起動、リロード、デプロイ不要
$ sqlite3 server "UPDATE routes SET body = readfile('new.html') WHERE path = '/index.html'"
$ curl -s localhost:8080
<!doctype html>
<h1>edited in place</h1>
ファイルフォーマットがSQLiteであるため、存在するツールの豊富な選択肢も活用できます。sqldiffは、「デプロイが何をしたか」を正確に教えてくれるため、プログラムの2つのバージョン間の変更を監査および特定できます。
$ sqldiff --summary yesterday.server server
routes: 1 changes, 0 inserts, 0 deletes, 2 unchanged
segments: 0 changes, 0 inserts, 0 deletes, 13 unchanged
symbols: 0 changes, 0 inserts, 0 deletes, 174 unchanged
relocations: 0 changes, 0 inserts, 0 deletes, 99 unchanged
全文検索はどうでしょうか? FTS5はCREATE VIRTUAL TABLEの距離にあり、ウェブサーバーは自身のページを内部でインデックス化でき、その後もウェブサーバーであり続けることができます。
$ sqlite3 server "CREATE VIRTUAL TABLE search USING fts5(path, body); INSERT INTO search SELECT path, body FROM routes WHERE mime LIKE 'text/%'"
$ sqlite3 server "SELECT path, snippet(search, 1, '[', ']', '...', 6) FROM search WHERE search MATCH 'transaction'"
/index.html|...Editing is a [transaction].</h2>
# まだ実行中。単に自身を認識しただけです
$ ./server 8080
これらの機能は私が書いたものではありません。SQLiteが既に持っている機能であり、プログラムがデータベースであることによって無料で継承するものです。静的サイトジェネレーターが流行していましたが、未来は実際にクエリ可能な実行可能ファイルです。
§デプロイは単一ファイルのscp
exe.devのような製品が支持するシンプルさに、私は本当に魅力を感じています。人々はしばしば、単一ファイルをデプロイするためにscpやsshの「古き良き時代」に戻りたいと切望しており、SELFはそのようなことが再び可能になるフォーマットです。