Documentation
¶
Overview ¶
Package pluginstore gives each plugin its own PostgreSQL schema (#2481).
なぜ schema を分けるのか ¶
mk-go の migration は連番 (`000074_...`) で、プラグインをこの列に載せられない。 2 つのプラグインが同時に次の番号を要求して衝突する。schema を分ければ、各 プラグインが本体の連番と干渉せず独立した migration を持てる。
手法は #2450 でテスト用に導入したものと同じ (`search_path` を DSN に張る)。 pgx は未知の keyword を runtime parameter として送るので、接続ごとに適用され、 pool が新しい接続を張っても schema が変わらない。
分離の強さについて ¶
`search_path` は**事故を防ぐ仕組みであって、権限による強制ではない**。 プラグインが `public.note` のように明示的に修飾すれば mk-go のテーブルに 到達できる。プラグインは同一プロセスの Go コードで、そもそも設定ファイルから 認証情報を読めるため、ここを権限で塞いでも意味は薄い。
重要なのは「素直に書いたら本体のテーブルに触れない」ことで、これは満たす。 **ノートの可視性判定はアプリケーション側の 4 箇所にあり DB には無い**ので、 `SELECT * FROM note` が通ってしまうと非公開ノートが混ざる。
Index ¶
- Constants
- func Apply(ctx context.Context, db Executor, migrations []Migration) error
- func ListSchemas(ctx context.Context, baseDSN string) ([]string, error)
- func OrphanSchemas(present []string, known []string) []string
- func SchemaName(name string) (string, error)
- type Executor
- type Migration
- type Store
Constants ¶
const SchemaPrefix = "plugin_"
SchemaPrefix namespaces plugin schemas so they never collide with mk-go's own objects (which live in `public`).
Variables ¶
This section is empty.
Functions ¶
func Apply ¶
Apply runs the migrations that have not been applied yet against db.
Store.Migrate はロックを取ってからこれを呼ぶ。**plugin/plugintest も同じ 関数を使う** — フェイクが本番と違う挙動をすると、テストが通ったのに本番で 落ちる (実際 plugintest が素朴に実行していて、2 回目で 「already exists」になった)。
func ListSchemas ¶
ListSchemas returns the plugin schemas that exist in the database.
func OrphanSchemas ¶
OrphanSchemas returns the schemas that belong to no currently built-in plugin.
**プラグインを消してもデータは自動では消さない。** カウンタと違って削除した 行は復元できないので、一時的に外しただけの運用 (更新・切り分け) でデータが 飛ぶ方が損害が大きい (fsck が孤児行を報告に留めているのと同じ理由、#2473)。
代わりに「残っていること」を見えるようにする。黙って残ると、運営者は自分の DB に何があるか把握できなくなる。
突き合わせは**プラグイン名から schema 名を作る向き**で行う。schema 名から プラグイン名へ戻すと、`plugin_game_info` が `game-info` と `game_info` の どちらだったか判別できない (SchemaName が `-` を `_` に倒すため)。
func SchemaName ¶
SchemaName maps a plugin name to its schema, validating the identifier.
identifier は SQL の placeholder にできないため文字列として埋め込むしかない。 plugin.Definition 側でも名前を検証しているが、**ここでも検証する**: 埋め込みの 直前で確かめないと、呼び出し経路が増えたときに検証の無い経路ができる。
Types ¶
type Executor ¶
type Executor interface {
ExecContext(ctx context.Context, query string, args ...any) (sql.Result, error)
QueryContext(ctx context.Context, query string, args ...any) (*sql.Rows, error)
BeginTx(ctx context.Context, opts *sql.TxOptions) (*sql.Tx, error)
}
Executor is the subset of *sql.DB / *sql.Conn that applying migrations needs.
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store is one plugin's storage handle.
func Open ¶
Open creates the plugin's schema if needed and returns a pool pinned to it.
baseDSN は mk-go 本体と同じ接続文字列 (config.Config.DSN())。