Slide 1

Slide 1 text

自作ストレージエンジンから見る MySQL の内部実装 2020/01/18 @lrf141

Slide 2

Slide 2 text

自己紹介 - けんつ (@lrf141) - DBMS, 分散システム - Go / PHP / C - MySQL はフェチ - 社会性がたりない

Slide 3

Slide 3 text

こっち読むと幸せになれる

Slide 4

Slide 4 text

始める前に

Slide 5

Slide 5 text

No content

Slide 6

Slide 6 text

24 枚 / 10 分

Slide 7

Slide 7 text

38 枚 / 5 分

Slide 8

Slide 8 text

今日話すこと

Slide 9

Slide 9 text

今日話すこと - OSS としての mysql-server コード・リーディング - 既存の SE 実装 - 内部実装を支えるシステムコール - MySQL Internal Manual - Source Code Documentation

Slide 10

Slide 10 text

今日話すこと - OSS としての mysql-server コード・リーディング - 既存の SE 実装 - 内部実装を支えるシステムコール - MySQL Internal Manual - Source Code Documentation

Slide 11

Slide 11 text

今日話すこと - ストレージエンジンを支える仕組み - テーブルファイル作成時の処理 - テーブルファイル読み込み時の処理 - SELECT, INSERT 時の処理

Slide 12

Slide 12 text

資料 - MySQL Internal Manual - MySQL 8.0.18 Source Code Documentation - Connpass に掲載したブログ - Github mysql-server

Slide 13

Slide 13 text

ストレージエンジンを支える仕組み

Slide 14

Slide 14 text

ストレージエンジンを支える仕組み - Pluggable Storage Engine - Handlerton - Handler - Share - Lock

Slide 15

Slide 15 text

Pluggable Storage Engine - MySQL はストレージエンジンをプラグインとして扱う - 共有ライブラリ(.so)形式で /usr/lib/mysql/plugin 以下にあるものが対象 - 動的に設定可能 - mysqld は ha_hoge.cc|.h で宣言、実装されている API を呼び出す

Slide 16

Slide 16 text

No content

Slide 17

Slide 17 text

handlerton - Handler Singleton - 各ストレージエンジンにつき1つのみの生成 - ストレージエンジンの定義を保持 - メタ情報と API を実装したメソッドポインタ

Slide 18

Slide 18 text

No content

Slide 19

Slide 19 text

Handler - テーブル、コネクション毎に作成される - データストレージ、インデックス、行操作 - ロック等、同時実行制御に関する処理も保持 - MySQL Server と実際に通信するのはこれ - SQL 操作以外にも統計情報系もここ

Slide 20

Slide 20 text

No content

Slide 21

Slide 21 text

Share - テーブルのメタデータを保持する - インスタンスはテーブル間で共有される - ロックに関するメンバを持つ - ファイルディスクリプタはここで持つと良い?

Slide 22

Slide 22 text

No content

Slide 23

Slide 23 text

Lock - Share にマスターロック(THR_LOCK)、ハンドラにロックインスタンス (THR_LOCK_DATA) - ロックインスタンスが他のハンドラに対して有効なロックを持つ - Posix Thread ベース - デフォルトで SELECT は共有ロック、INSERT 等は排他ロック - 内部ロックはロックインスタンスを利用

Slide 24

Slide 24 text

class Gambit_share : public Handler_share { public: THR_LOCK lock; const char *name; … } class ha_gambit : public handler { THR_LOCK_DATA lock; ///< MySQL lock Gambit_share *share; ///< Shared lock info Gambit_share * get_share(); ///< Get the share

Slide 25

Slide 25 text

TABLE 作成時の処理

Slide 26

Slide 26 text

Table 作成時の処理 - /var/lib/mysql 以下にデータベース名でディレクトリが存在する前提 - テーブル毎にディレクトリが作成される - ha_hoge::create を実装する - open システムコールのラッパーである my_create を使用する - sdi ファイルも同時に生成される - 作成時にオプションを変更可能

Slide 27

Slide 27 text

int ha_gambit::create (const char *name, TABLE *, HA_CREATE_INFO *, dd::Table *) { DBUG_TRACE; File create_file; DBUG_ENTER("ha_gambit::create" ); if ((create_file= my_create(name, 0, O_RDWR | O_TRUNC, MYF(0))) < 0) DBUG_RETURN(-1); if ((my_close(create_file, MYF(0))) < 0) DBUG_RETURN(-1);

Slide 28

Slide 28 text

TABLE 読み込み時の処理

Slide 29

Slide 29 text

Table 読み込み時の処理 - ha_hoge::open を実装する - SELECT, INSERT, etc… 時に走るためロックが必要 - ファイルディスクリプタは share でもっておくのが良さそう?

Slide 30

Slide 30 text

int ha_gambit::open(const char *name, int, uint, const dd::Table *) { DBUG_TRACE; File open_file; if (!(share = get_share())) return 1; thr_lock_data_init(&share->lock, &lock, NULL); if (!(open_file = my_open(name, O_RDWR, MYF(0)))) return 1; share->table_file = open_file; share->name = name; return 0; }

Slide 31

Slide 31 text

SELECT, INSERT 時の処理

Slide 32

Slide 32 text

共通の前提 - Share(TABLE_SHARE) がテーブルのメタデータを保持 - TABLE_SHARE は各フィールドの情報を持つ Field も保持 - 各フィールドは String(sql_string.h) というバッファを利用 - ロックが走る - 内部フォーマットの先頭はカラム数分の Null ビットマップ

Slide 33

Slide 33 text

for (Field **field = table->field; *field; field++) { const char *p; const char *end; … }

Slide 34

Slide 34 text

INSERT 時の処理 ひたすら Field から String バッファに値を格納して my_write するだけ!!!!

Slide 35

Slide 35 text

SELECT 時の処理 - Field の値を引数である buf に格納 - 値の実体は Field->ptr - buf にコピーするべきだが Field->ptr と buf は参照先が同じ - store メソッドで Field->ptr に値読み取った値を格納する

Slide 36

Slide 36 text

おわりに

Slide 37

Slide 37 text

おわりに - MySQL 内でストレージエンジンが担保する機能は少ない - SE は Handler が肝 - ロックに関することがわかると大体いける - 全て実装依存 - コードはドキュメント