Upgrade to Pro — share decks privately, control downloads, hide ads and more …

full scratch mysql storage engine

kentsu
January 18, 2020

full scratch mysql storage engine

kentsu

January 18, 2020
Tweet

More Decks by kentsu

Other Decks in Technology

Transcript

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

    View Slide

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

    View Slide

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

    View Slide

  4. 始める前に

    View Slide

  5. View Slide

  6. 24 枚 / 10 分

    View Slide

  7. 38 枚 / 5 分

    View Slide

  8. 今日話すこと

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  16. View Slide

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

    View Slide

  18. View Slide

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

    View Slide

  20. View Slide

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

    View Slide

  22. View Slide

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

    View Slide

  24. 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

    View Slide

  25. TABLE 作成時の処理

    View Slide

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

    View Slide

  27. 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);

    View Slide

  28. TABLE 読み込み時の処理

    View Slide

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

    View Slide

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

    View Slide

  31. SELECT, INSERT 時の処理

    View Slide

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

    View Slide

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

    }

    View Slide

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

    View Slide

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

    View Slide

  36. おわりに

    View Slide

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

    View Slide