2018年1月18日木曜日

MySQLのVALUES関数の(今のところ)唯一の使い道

TL;DR

PostgreSQLの VALUES は引数の表リテラル(行リテラルや列リテラルを含む)をテーブルリファレンスにして返してくれる関数だけれど、MySQLの VALUES は残念ながらそんなことはない。

MySQLのINSERTにおけるVALUESはただのキーワードでVALUES関数ではない。
なのでPostgreSQLみたいに表リテラルからテーブルリファレンスを組み立てる用途には使えない(´・ω・`) < よく言われるやーつだ
ところがどっこい、そのVALUESキーワードとは に、VALUES関数 があって、コイツがまたフツーのVALUES関数ではなくて
INSERT … ON DUPLICATE KEY UPDATE ステートメントでは、UPDATE 句の VALUES(col_name) 関数を使用すると、ステートメントの INSERT 部分からカラム値を参照できます。
というニッチな関数になっている。
つまり、
INSERT INTO t1 (num, val, dt) VALUES (1, 'one', '2018-01-18 12:40:00') ON DUPLICATE KEY UPDATE dt = '2018-01-18 12:40:00';
INSERT INTO t1 (num, val, dt) VALUES (1, 'one', '2018-01-18 12:40:00') ON DUPLICATE KEY UPDATE dt = VALUES(dt);
が等価として扱えるというだけの関数である。
もうちょっと他の名前はなかったのか…。

2018年1月10日水曜日

pfs_example_plugin_employee.so is 何

プラグインディレクトリーを覗いてたら pfs_example_plugin_employee.so なるファイルがあって知らないものなので調べてみた。
知らないプラグインを見つけた時の身元調査用に使えるかも知れないのでメモ。

まずはビルドしたディレクトリーの中で find 、MySQL(に限らないのかもだけど)ではコンパイルした時にソースコードのすぐとなりにバイナリーが出来上がるので、変に名前の一部からディレクトリーの名前を類推するよりもこっちの方が楽だったりする。
$ find -name "pfs_example_plugin_employee.so"
./plugin/pfs_table_plugin/CMakeFiles/CMakeRelink.dir/pfs_example_plugin_employee.so
./plugin_output_directory/pfs_example_plugin_employee.so
という訳でソースは plugin/pfs_table_plugin の近くにありそう。
$ ll plugin/pfs_table_plugin/
total 124
drwxrwxr-x 4 yoku0825 yoku0825   125 Jan  9 13:47 CMakeFiles
-rw-rw-r-- 1 yoku0825 yoku0825  2274 Jan  9 13:47 cmake_install.cmake
-rw-r--r-- 1 yoku0825 yoku0825  1175 Sep 19 20:33 CMakeLists.txt
-rw-rw-r-- 1 yoku0825 yoku0825   319 Sep 21 22:29 CTestTestfile.cmake
-rw-rw-r-- 1 yoku0825 yoku0825 15021 Sep 21 22:29 Makefile
-rw-r--r-- 1 yoku0825 yoku0825 13276 Sep 19 20:33 pfs_example_employee_name.cc
-rw-r--r-- 1 yoku0825 yoku0825  5220 Sep 19 20:33 pfs_example_employee_name.h
-rw-r--r-- 1 yoku0825 yoku0825 10242 Sep 19 20:33 pfs_example_employee_salary.cc
-rw-r--r-- 1 yoku0825 yoku0825  4404 Sep 19 20:33 pfs_example_employee_salary.h
-rw-r--r-- 1 yoku0825 yoku0825 10271 Sep 19 20:33 pfs_example_machine.cc
-rw-r--r-- 1 yoku0825 yoku0825  4482 Sep 19 20:33 pfs_example_machine.h
-rw-r--r-- 1 yoku0825 yoku0825  8236 Sep 19 20:33 pfs_example_machines_by_emp_by_mtype.cc
-rw-r--r-- 1 yoku0825 yoku0825  5235 Sep 19 20:33 pfs_example_machines_by_emp_by_mtype.h
-rw-r--r-- 1 yoku0825 yoku0825 11821 Sep 19 20:33 pfs_example_plugin_employee.cc
本体はきっと pfs_example_plugin_employee.cc だなあと思いつつ中身を覗く。
MySQLのプラグインのソースを読むときは mysql_declare_plugin を探すと良い気がしていて、そこに SHOW PLUGINS で表示される情報や INSTALL PLUGIN, UNINSTALL PLUGIN の時に走る関数が指定されている。ちなみに INSTALL PLUGIN で指定するプラグインの名前は mysql_declare_plugin の引数になっている。これ豆。
…限りなく情報はゼロに近かった。 そんなに長くもないコードなのでゆっくり読むけれど、何をどう考えてもPerformance Schemaプラグインのサンプルコード。そもそも名前からそう。しかし MYSQL_DAEMON_PLUGIN なのか。RCだから取り敢えずなのかどうかわからないけれど。
取り敢えず有効化してみようか。
mysql80 7> INSTALL PLUGIN pfs_example_plugin_employee SONAME 'pfs_example_plugin_employee.so';
Query OK, 0 rows affected (0.01 sec)

mysql80 7> SHOW PLUGINS\G
..
*************************** 42. row ***************************
   Name: pfs_example_plugin_employee
 Status: ACTIVE
   Type: DAEMON
Library: pfs_example_plugin_employee.so
License: GPL
できた。 これできっとp_sのテーブルができているはず。
mysql80 7> use performance_schema
Database changed

mysql80 7> SHOW TABLES LIKE '%example%';
+------------------------------------------+
| Tables_in_performance_schema (%example%) |
+------------------------------------------+
| pfs_example_employee_name                |
| pfs_example_employee_salary              |
| pfs_example_machine                      |
| pfs_example_machine_by_employee_by_type  |
+------------------------------------------+
4 rows in set (0.00 sec)

mysql80 7> SHOW CREATE TABLE pfs_example_employee_name\G
*************************** 1. row ***************************
       Table: pfs_example_employee_name
Create Table: CREATE TABLE `pfs_example_employee_name` (
  `EMPLOYEE_NUMBER` int(11) NOT NULL,
  `FIRST_NAME` char(20) DEFAULT NULL,
  `LAST_NAME` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`EMPLOYEE_NUMBER`),
  KEY `FIRST_NAME` (`FIRST_NAME`)
) ENGINE=PERFORMANCE_SCHEMA DEFAULT CHARSET=utf8
1 row in set (0.01 sec)
☆―(ノ゚Д゚)八(゚Д゚ )ノイエ―イ
しかしこれ
mysql80 7> SELECT * FROM pfs_example_employee_name;
Empty set (0.00 sec)

mysql80 7> SELECT * FROM pfs_example_employee_salary;
Empty set (0.00 sec)

mysql80 7> SELECT * FROM pfs_example_machine;
Empty set (0.00 sec)

mysql80 7> SELECT * FROM pfs_example_machine_by_employee_by_type;
Empty set (0.00 sec)
中身が軒並み空なのは、想定した通りなんだろうか…( INSTALL PLUGIN した時に いかにも固定値で値を詰め込むような処理 を通るんだけれども…)
取り敢えずまあ、information_schemaプラグインのようにPerformance Schemaプラグインを書ける時代が来る鴨ってことですね。
取り敢えずPerformance Schemaプラグインに関する記述は(Daemonプラグインのところにも)まだ記述がない。
リリースノートにはなんか、8.0.2でその辺のインターフェイスが作られたようなことが書いてあった。
To support dynamic Performance Schema table manipulation, a new component service named pfs_table_service is now available.
MySQL :: MySQL 8.0 Release Notes :: Changes in MySQL 8.0.2 (2017-07-17, Development Milestone)

【2018/01/10 18:07】
rpmで mysql-community-test を入れるとこの pfs_example_plugin_employee プラグインが入っているわけですが、こっちで試すとちゃんとレコードが入ってた。


$ yum install --enablerepo="mysql80-community" mysql-community-test
$ mysqld --initialize-insecure --user=mysql
$ /etc/init.d/mysqld start

mysql> INSTALL PLUGIN pfs_example_plugin_employee SONAME 'pfs_example_plugin_employee.so';
Query OK, 0 rows affected (0.09 sec)

mysql> SELECT * FROM pfs_example_employee_name;
+-----------------+------------+-----------+
| EMPLOYEE_NUMBER | FIRST_NAME | LAST_NAME |
+-----------------+------------+-----------+
|               1 | foo1       | bar1      |
|               2 | foo2       | bar2      |
|               3 | foo3       | bar3      |
+-----------------+------------+-----------+
3 rows in set (0.01 sec)

mysql> SELECT * FROM pfs_example_employee_salary;
+-----------------+-----------------+---------------+---------------+
| EMPLOYEE_NUMBER | EMPLOYEE_SALARY | DATE_OF_BIRTH | TIME_OF_BIRTH |
+-----------------+-----------------+---------------+---------------+
|               1 |            1000 | 2013-11-12    | 12:02:34      |
|               2 |            2000 | 2016-02-29    | 12:12:30      |
|               3 |            3000 | 2017-03-24    | 11:12:50      |
+-----------------+-----------------+---------------+---------------+
3 rows in set (0.07 sec)

mysql> SELECT * FROM pfs_example_machine;
+-------------------+--------------+--------------+-----------------+
| MACHINE_SL_NUMBER | MACHINE_TYPE | MACHINE_MADE | EMPLOYEE_NUMBER |
+-------------------+--------------+--------------+-----------------+
|                 1 | DESKTOP      | Lenovo       |               1 |
|                 2 | LAPTOP       | Dell         |               2 |
|                 3 | MOBILE       | Apple        |               1 |
|                 4 | MOBILE       | Samsung      |               1 |
|                 5 | LAPTOP       | Lenovo       |               2 |
|                 6 | MOBILE       | Nokia        |               2 |
|                 7 | LAPTOP       | Apple        |               1 |
|                 8 | LAPTOP       | HP           |               3 |
|                 9 | DESKTOP      | Apple        |               3 |
+-------------------+--------------+--------------+-----------------+
9 rows in set (0.00 sec)

mysql> SELECT * FROM pfs_example_machine_by_employee_by_type;
+------------+-----------+--------------+-------+
| FIRST_NAME | LAST_NAME | MACHINE_TYPE | COUNT |
+------------+-----------+--------------+-------+
| foo1       | bar1      | LAPTOP       |     1 |
| foo1       | bar1      | DESKTOP      |     1 |
| foo1       | bar1      | MOBILE       |     2 |
| foo2       | bar2      | LAPTOP       |     2 |
| foo2       | bar2      | MOBILE       |     1 |
| foo3       | bar3      | LAPTOP       |     1 |
| foo3       | bar3      | DESKTOP      |     1 |
+------------+-----------+--------------+-------+
7 rows in set (0.00 sec)




2017年12月19日火曜日

MySQLジャンキーにngx_mrubyを与えた結果

この記事は mod_mruby ngx_mruby Advent Calendar 2017 の18日目の記事です。
時間オーバーしてますごめんなさい。
本題に入る前に、この記事をご覧の方の中に “MySQL HTTP Plugin” をご存知の方はいらっしゃるでしょうか? (MySQL Casualな方々はこの辺でオチの予想がついたはず)
MySQL HTTP Pluginは2014年ころに MySQL Labs で公開されていた「実験室版」として配布されていて、 MySQLがHTTPをしゃべるようになるプラグイン です。
何言ってるのかよくわからないとか、誰得? とか思うかも知れませんが、そんな細かいことを気にしてはいけません。とにかく、MySQL(mysqld)がHTTPをしゃべったんです。
かつての面影(?)はこのあたりの記事とか資料に見て取ることができます。
MySQL Labsは「α前のステータスのプロダクトを取り敢えず出してみる場」らしいので(要出典)、 GAになってから1度もメジャーバージョンアップできずに最短ライフタイムサイクルで消えた ナントカ とは違い、まあそういうものだし当時は俺も「誰得wwww」とか言ってたんですが、
俺が遊び始めて「あー面白いかも」と思った途端に消える
という
いつもの流れになって寂しく思っていたところです。
「そこで ngx_mruby ですよ」
誰かの声が聞こえた気がしたので試してみました。 やってること自体は単なるHello, Worldです。

ngx_mrubyのインストールには nginxにngx_mrubyをインストールする - Qiita を大変参考にさせていただきました。 2014年のアドベントカレンダーの記事が3年経ってMySQLジャンキーを救う(?)、インターネッツですね。
あとはペパボの中の人にパッケージをビルドするヤーツも教えてもらいました。最終的にはこれで作ったrpmをインストールしています。便利!
ngx_mruby/build_config.rbconf.gem :github => 'mattn/mruby-mysql' だけ追加しました。
MySQLに接続しないソフトウェアに興味が持てなううんなんでもない。
/etc/nginx/conf.d/default.conf によしなにこんな記述を追加。 /query をエンドポイントにして後ろに渡されたクエリーをそのままローカルのmysqldに受け渡してJSONで戻す(えっ)
    location /query {
      mruby_content_handler_code '
        req = Nginx::Request.new
        sql = req.uri.gsub(/\/query\//, "")

        conn = MySQL::Database.new("127.0.0.1", "root", "", "world", 64057)
        ret= []

        conn.execute(sql) do |row, field|
          one_row= []
          for n in 0..field.count - 1 do
            one_row.push({field[n] => row[n]})
          end
          ret.push(one_row)
        end

        req.content_type = "application/json"
        Nginx.rputs JSON::stringify(ret)
      ';
    }
こんな感じ。
たったこれだけのものを書くのに結構長い時間がかかった。プログラム力の衰えを感じる。。
で、出来上がったMySQL HTTP Pluginごっこはこんな感じ。
$ http localhost/query/SELECT%20%2A%20FROM%20city%20LIMIT%203
HTTP/1.1 200 OK
Connection: keep-alive
Content-Length: 287
Content-Type: application/json
Date: Tue, 19 Dec 2017 06:24:38 GMT
Server: nginx/1.13.7

[
    [
        {
            "ID": 1
        },
        {
            "Name": "Kabul"
        },
        {
            "CountryCode": "AFG"
        },
        {
            "District": "Kabol"
        },
        {
            "Population": 1780000
        }
    ],
    [
        {
            "ID": 2
        },
        {
            "Name": "Qandahar"
        },
        {
            "CountryCode": "AFG"
        },
        {
            "District": "Qandahar"
        },
        {
            "Population": 237500
        }
    ],
    [
        {
            "ID": 3
        },
        {
            "Name": "Herat"
        },
        {
            "CountryCode": "AFG"
        },
        {
            "District": "Herat"
        },
        {
            "Population": 186800
        }
    ]
]
おおなんかMySQL HTTP Pluginっぽい! ちなみに本家MySQL HTTP Pluginの出力結果はこんな感じでした。結構違う。
ってか実データとメタデータが分離されてた。それでよかったのか。。
$ http http://a:b@localhost:8080/sql/world/SELECT+%2A+FROM+city+LIMIT+3
HTTP/1.1 200 OK
Cache-control: must-revalidate
Connection: Keep-Alive
Content-Length: 1078
Content-Type: application/json
Pragma: no-cache
Server: MyHTTP 1.0.0-alpha

[
    {
        "data": [
            [
                "1",
                "Kabul",
                "AFG",
                "Kabol",
                "1780000"
            ],
            [
                "2",
                "Qandahar",
                "AFG",
                "Qandahar",
                "237500"
            ],
            [
                "3",
                "Herat",
                "AFG",
                "Herat",
                "186800"
            ]
        ],
        "meta": [
            {
                "catalog": "def",
                "charset": 63,
                "column": "ID",
                "database": "world",
                "decimals": 0,
                "flags": 16899,
                "length": 11,
                "org_column": "ID",
                "org_table": "city",
                "table": "city",
                "type": 3
            },
            {
                "catalog": "def",
                "charset": 33,
                "column": "Name",
                "database": "world",
                "decimals": 0,
                "flags": 1,
                "length": 105,
                "org_column": "Name",
                "org_table": "city",
                "table": "city",
                "type": 254
            },
            {
                "catalog": "def",
                "charset": 33,
                "column": "CountryCode",
                "database": "world",
                "decimals": 0,
                "flags": 16393,
                "length": 9,
                "org_column": "CountryCode",
                "org_table": "city",
                "table": "city",
                "type": 254
            },
            {
                "catalog": "def",
                "charset": 33,
                "column": "District",
                "database": "world",
                "decimals": 0,
                "flags": 1,
                "length": 60,
                "org_column": "District",
                "org_table": "city",
                "table": "city",
                "type": 254
            },
            {
                "catalog": "def",
                "charset": 63,
                "column": "Population",
                "database": "world",
                "decimals": 0,
                "flags": 1,
                "length": 11,
                "org_column": "Population",
                "org_table": "city",
                "table": "city",
                "type": 3
            }
        ],
        "status": [
            {
                "server_status": 34,
                "warning_count": 0
            }
        ]
    }
]



まあなんかよしなに楽しんでみました。実際のところ(MySQL的な文脈では)何に使えるだろう。。

2017年12月18日月曜日

InnoDB: Fatal : Cannot initialize AIO sub-system でmysqldが起動しない…だと…

1サーバーにゴツゴツmysqldを詰め込んでいる環境で、ふとこんなエラーでmysqldが起動しなかった。
2017-12-18 17:50:38 12256 [Note] InnoDB: Using Linux native AIO
2017-12-18 17:50:38 12256 [Note] InnoDB: Using CPU crc32 instructions
2017-12-18 17:50:38 7f2b86333740 InnoDB: Warning: io_setup() failed with EAGAIN. Will make 5 attempts before giving up.
InnoDB: Warning: io_setup() attempt 1 failed.
InnoDB: Warning: io_setup() attempt 2 failed.
InnoDB: Warning: io_setup() attempt 3 failed.
InnoDB: Warning: io_setup() attempt 4 failed.
InnoDB: Warning: io_setup() attempt 5 failed.
2017-12-18 17:50:40 7f2b86333740 InnoDB: Error: io_setup() failed with EAGAIN after 5 attempts.
InnoDB: You can disable Linux Native AIO by setting innodb_use_native_aio = 0 in my.cnf
2017-12-18 17:50:40 12256 [ERROR] InnoDB: Fatal : Cannot initialize AIO sub-system
2017-12-18 17:50:40 12256 [ERROR] Plugin 'InnoDB' init function returned error.
2017-12-18 17:50:40 12256 [ERROR] Plugin 'InnoDB' registration as a STORAGE ENGINE failed.
2017-12-18 17:50:40 12256 [ERROR] Unknown/unsupported storage engine: InnoDB
2017-12-18 17:50:40 12256 [ERROR] Aborting

2017-12-18 17:50:40 12256 [Note] Binlog end
2017-12-18 17:50:40 12256 [Note] /usr/local/mysql5626/bin/mysqld: Shutdown complete
珍しい。
AIO関連のエラーなんてMySQL 5.5がGAになってしばらくの時代に、 変なファイルシステム(なんだか忘れた)の上にtmpdirを作ろうとして「そのファイルシステムはAIOに対応していない!」と怒られて以来な気がする。
そういえば最近見ないなアレ。CentOS 5.xがいかんかったのか。
取り敢えずファイルシステムを見てみるに、
# grep vg_00-lv_root /proc/mounts
/dev/mapper/vg_00-lv_root / xfs rw,relatime,attr2,inode64,logbsize=256k,sunit=512,swidth=3584,noquota 0 0
xfsであってAIO非対応な変なファイルシステムではない。 というか他のmysqldは元気でゴリゴリ動いているので、この1プロセスだけAIOがどうこう言われるのがそもそもおかしい。
ググると innodb_use_native_aio = 0 にすればいいよ! とか結構出てくる(というかエラーログもそういってる)けれど、Linux AIOが使えないはずはないんだからそれじゃ気持ちが悪い。
結局、ぐるぐる回って @yoheiaさん のところにたどり着いた。
libaio の aio コンテキスト数を調べる - ablog
# cat /proc/sys/fs/aio-max-nr
65536

# cat /proc/sys/fs/aio-nr
63056
うわーい、ぴっちぴち。
というわけで aio-max-nr を増やしたら無事起動するようになりました。
# echo 131072 > /proc/sys/fs/aio-max-nr
# cat /proc/sys/fs/aio-max-nr
131072
ibdファイルかなりオープンされてるのね…。ちょっと意外。
# lsof | grep mysqld | grep -c ibd
75451

2017年12月8日金曜日

mikasafabric for MySQLのつらいところ

この記事は MySQL Casual Advent Calendar 2017 の8日目の記事です!
1週間前の記事、 日々の覚書: これが多分最後の「MySQL Fabricつらい」 でお焚き上げをしたMySQL Fabricですが、 世の中の物好きな会社 がMySQL Fabricをフォークして mikasafabric for MySQL として使っています。
今日はそのmikasafabric つらい つらくない話をします。ハンカチの用意はよろしいでしょうか。

取り敢えずぶっちゃけた話をするとPythonつらい。
  • どこにクローズ漏れがあるのか ファイルディスクリプターをリーク する
    • max_open_files の値まで突っ込む
    • 監視が Too many open files で転ける
    • フェイルオーバーしようとする
    • フェイルオーバー操作も Too many open files で転ける
    • しかもタイミングによっては open_files に空きができるのでフェイルオーバー操作が 一部だけ成功する という
_人人人人人人人人人人人_
> 控えめに言って地獄 <
 ̄Y^Y^Y^Y^Y^Y^Y^Y^ ̄
接続しているMySQL Routerの数にある程度依存しているような気がしたので、 MySQL Procotolをしゃべっているところ をゴニョゴニョしているものの改善せず…。ボスけて。

↑のバグを踏んだ時、 Too many open files で処理が中途半端に転けたがためにクラスターとして変な状態になっちゃって、「バッキングストアのレコードを直接書き換えることによってフェイルオーバー」させる実績を解除した。つらい。
誰の役にも立たないと思いますが、 servers.modeservers.status をUPDATEするだけでは足りなくて、 groups.master_uuid もUPDATEしてあげないと promote がAssertion Failureで転けます。 しかもバッキングストアに永続化されているので何度再起動しても転けます。これを知らずにこの状態に陥った場合、大した台数でなければ teardown して再登録した方が速いかも知れません。
mysql> SELECT * FROM servers;
+--------------------------------------+-----------------+------+--------+--------+----------+
| server_uuid                          | server_address  | mode | status | weight | group_id |
+--------------------------------------+-----------------+------+--------+--------+----------+
| a95d3771-d667-11e7-acc6-0242ac110002 | 172.17.0.2:3306 |    3 |      3 |      1 | myfabric |
| ab07f0b9-d667-11e7-abd0-0242ac110003 | 172.17.0.3:3306 |    1 |      2 |      1 | myfabric |
| ae8c0955-d667-11e7-ad65-0242ac110004 | 172.17.0.4:3306 |    1 |      2 |      1 | myfabric |
+--------------------------------------+-----------------+------+--------+--------+----------+
3 rows in set (0.00 sec)

mysql> SELECT * FROM groups;
+----------+-------------+--------------------------------------+----------------------------+--------+
| group_id | description | master_uuid                          | master_defined             | status |
+----------+-------------+--------------------------------------+----------------------------+--------+
| myfabric | NULL        | a95d3771-d667-11e7-acc6-0242ac110002 | 2017-12-01 07:17:18.000000 |       |
+----------+-------------+--------------------------------------+----------------------------+--------+
1 row in set (0.01 sec)
あと、 groups.status は実はBIT型なので↑では NULL でもないのに表示がおかしいとか
mysql> desc groups;
+----------------+--------------+------+-----+---------+-------+
| Field          | Type         | Null | Key | Default | Extra |
+----------------+--------------+------+-----+---------+-------+
| group_id       | varchar(64)  | NO   | PRI | NULL    |       |
| description    | varchar(256) | YES  |     | NULL    |       |
| master_uuid    | varchar(40)  | YES  | MUL | NULL    |       |
| master_defined | timestamp(6) | YES  |     | NULL    |       |
| status         | bit(1)       | NO   |     | NULL    |       |
+----------------+--------------+------+-----+---------+-------+
5 rows in set (0.00 sec)

mysql> SELECT CAST(status AS signed) FROM groups;
+------------------------+
| CAST(status AS signed) |
+------------------------+
|                      1 |
+------------------------+
1 row in set (0.00 sec)
暗黙のキャストに期待して UPDATE groups SET status = '0' とかやると
mysql> UPDATE groups SET status = '0' WHERE group_id = 'myfabric';
ERROR 1406 (22001): Data too long for column 'status' at row 1

mysql> UPDATE groups SET status = 0 WHERE group_id = 'myfabric';
Query OK, 1 row affected (0.02 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> UPDATE groups SET status = b'1' WHERE group_id = 'myfabric';
Query OK, 1 row affected (0.02 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> UPDATE groups SET status = 0b0 WHERE group_id = 'myfabric';
Query OK, 1 row affected (0.02 sec)
Rows matched: 1  Changed: 1  Warnings: 0
「あーINTからBITのキャストは出来るけど文字列だと直接BITにキャストできないのかー」とか「そういえば b'010111' みたいな記法あったよね」とか知ることができて新鮮です。

あとはMySQL Routerさんが
MySQL Fabric support was removed.
サポートやめちゃったので、今後MySQL Router 2.1以降に追随していくためにはこっちにもパッチを当てないといけない。 ( そもそもコンフィグパーサーから fabric+cache:// のハンドルが削り取られているので、シンタックスエラーとして扱われる。かなしい)
あー、課題は山積みだわー、つらいわー、mikasafabricほんとつらいわー(棒)
明日は @atsuizoさん で 「SELECT文をタイムアウト強制終了させる「MAX_EXECUTION_TIME」使ってる?」です!

2017年12月4日月曜日

ConoHaの上でひたすらMySQLをビルドする簡単なお仕事

この記事は ConoHa Advent Calendar 2017 の4日目の記事です。
「ConoHaの上で」と銘打ってはいますが、俺の普段使いのLinux環境がConoHaだからというだけで、VirtualBoxだろうとEC2だろうとCentOS 7.4なら全部似たような結果になると思います
というわけでまずは吊るしのConoHaのVPSインスタンスを作ります。
最近のMySQLはビルドに結構メモリーを食うのでメモリーは1GBのものを選びました(512MBだと、途中でOOM Killerに殺されるかまたは永遠にビルドが終わらないと思います。5.7とそれ以降)
WEBからポチポチしてSSHでログインできたら、さっさとビルドを開始します。
まずは 5.0からいきましょう。
2017/12/04現在、サポートが継続されているMySQLは5.5, 5.6, 5.7の3系統です。
サポートが切れているMySQLのソースコードも MySQL :: MySQL Product Archives から手に入れることができます。
(が、ここでもMySQL Fabricは存在しません。 泣かない
というわけでMySQL 5.0系の最終バージョンである5.0.96を取ってきてさっくりビルドしてみます。

$ wget https://downloads.mysql.com/archives/get/file/mysql-5.0.96.tar.gz
$ tar xf mysql-5.0.96.tar.gz 
$ cd mysql-5.0.96/
$ ll
なんかパーミッションがスゴいことになっていて、時代のせいなのかパッケージングが出鱈目だったのか気になります。
MySQL 5.1とそれ以前のバージョンでは configure スクリプトを使って下準備をします。

$ ./configure --prefix=/opt/mysql/5.0.96
..
configure: error: in `/root/mysql-5.0.96':
configure: error: no acceptable C compiler found in $PATH
See `config.log' for more details.
あ、エラった。流石に gcc とかデフォで入っていない様子。
$ sudo yum install -y gcc
$ ./configure --prefix=/opt/mysql/5.0.96
..
checking for termcap functions library... configure: error: No curses/termcap library found
今度は別のエラー。cursesライブラリーがないって言われるけれどこれ ncurses-libs のことではなくて ncurses-devel のことなので注意(数年前にハマったなあ)
$ sudo yum install -y ncurses-devel
$ ./configure --prefix=/opt/mysql/5.0.96

..
Thank you for choosing MySQL!

Remember to check the platform specific part of the reference manual
for hints about installing MySQL on your platform.
Also have a look at the files in the Docs directory.
無事に終わったぽいので make
$ make
..
DEPDIR=.deps depmode=none /bin/sh ../depcomp \
g++ -DDEFAULT_BASEDIR=\"/opt/mysql/5.0.96\" -DMYSQL_DATADIR="\"/opt/mysql/5.0.96/var\"" -DDEFAULT_CHARSET_HOME="\"/opt/mysql/5.0.96\"" -DSHAREDIR="\"/opt/mysql/5.0.96/share/mysql\"" -DDEFAULT_HOME_ENV=MYSQL_HOME -DDEFAULT_GROUP_SUFFIX_ENV=MYSQL_GROUP_SUFFIX -DDEFAULT_SYSCONFDIR="\"/opt/mysql/5.0.96/etc\"" -DHAVE_CONFIG_H -I. -I../include -I../zlib -I../include -I../include -I.    -O -DDBUG_OFF    -fno-implicit-templates -fno-exceptions -fno-rtti -c -o my_new.o my_new.cc
../depcomp: line 571: exec: g++: not found
make[2]: *** [my_new.o] Error 127
make[2]: Leaving directory `/root/mysql-5.0.96/mysys'
make[1]: *** [all-recursive] Error 1
make[1]: Leaving directory `/root/mysql-5.0.96'
make: *** [all] Error 2
C++コンパイラーの g++ が要るって(´・ω・`) だったら configure の段階で言ってよ!
$ sudo yum install -y gcc-c++
$ ./configure --prefix=/opt/mysql/5.0.96

$ make
gcc-c++を入れたら再 configure して(しないと make が通らなかった)もっかい makemake が終わったら make install--prefix で指定したパスにファイルをコピー。
$ sudo make install
はい5.0終わり。次5.1。
MySQL 5.1は5.0とそんなに変わらないので、同じくアーカイブのページから5.1系の最終バージョンである5.1.73を…あれ?
「いや、そのりくつはおかしい」と言いたくなるけれども取り敢えずアーカイブページには5.1.72までしかない。 特に切羽詰まっている(?)わけでもないので、今回は5.1.72でビルドすることにしよう。
$ wget https://downloads.mysql.com/archives/get/file/mysql-5.1.72.tar.gz
$ tar xf mysql-5.1.72.tar.gz
$ cd mysql-5.1.72
$ ./configure --prefix=/opt/mysql/5.1.72
$ make
$ sudo make install
特に詰まることもなく(5.0から追加で何か入れることもなく)5.1も終了。はい次5.5。
ここから現在サポートされているバージョンになるので、最新のマイナーバージョンであれば MySQL :: Download MySQL Community Server から、それ以前のマイナーバージョンであればまたアーカイブから取ってくることになる。
ダウンロードページでは5.7が全面に押し出されているけれども、「Looking for previous GA versions?」とか書いてあるのを探すと5.5と5.6へのリンクがあるのでそれを選んでダウンロード。
$ wget https://dev.mysql.com/get/Downloads/MySQL-5.5/mysql-5.5.58.tar.gz
$ tar xf mysql-5.5.58.tar.gz 
$ cd mysql-5.5.58/
$ cmake -DCMAKE_INSTALL_PREFIX=/usopt/mysql/5.5.58
-bash: cmake: command not found
MySQL 5.5とそれ以降では cmake を使って下準備をする。入ってなかったのでインストール。
$ sudo yum install -y cmake
$ cmake -DCMAKE_INSTALL_PREFIX=/usopt/mysql/5.5.58
..
-- Configuring done
-- Generating done
-- Build files have been written to: /root/mysql-5.5.58

$ make
$ sudo make install
あれ、意外とさっくり通ってしまった。まあいいや、5.5終わったので5.6。
$ wget https://dev.mysql.com/get/Downloads/MySQL-5.6/mysql-5.6.38.tar.gz
$ tar xf mysql-5.6.38.tar.gz
$ cd mysql-5.6.38/
$ cmake -DCMAKE_INSTALL_PREFIX=/opt/mysql/5.6.38
$ make
$ sudo make install
このへんからビルドに時間がかかるようになってくる(´・ω・`)
が、特にエラーもなく終わったので次5.7。
MySQL 5.7から先は、同じようにダウンロードページからソースの.tar.gzを探すと「Compressed TAR Archive」と「Compressed TAR Archive, Includes Boost Headers」というのが見つかる。
これは MySQLは5.7.5からBoostを使うようになった からで、別で自分でBoostを入れているような人はBoost同梱版を選ぶ必要は特にない(けれど、バージョン決め打ちでBoostを欲しがるようなので、同梱版の方が絶対に楽だと思う)
$ wget https://dev.mysql.com/get/Downloads/MySQL-5.7/mysql-boost-5.7.20.tar.gz
$ tar xf mysql-boost-5.7.20.tar.gz
$ cd mysql-5.7.20
$ cmake -DCMAKE_INSTALL_PREFIX=/opt/mysql/5.7.20 -DWITH_BOOST=./boost
$ make
$ sudo make install
さて、5.7も案外何事もなく終わったので開発中の最新版8.0に行きましょう。
MySQL 8.0(2017/12/04現在、8.0.3-rc)も MySQL :: Download MySQL Community Server のページの中で「Development Releases」を探すと出てきます。
$ wget https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-boost-8.0.3-rc.tar.gz
$ tar xf mysql-boost-8.0.3-rc.tar.gz
$ cd mysql-8.0.3-rc
$ cmake -DCMAKE_INSTALL_PREFIX=/opt/mysql/8.0.3 -DWITH_BOOST=./boost
$ make
$ sudo make install
:(;゙゚’ω゚’): あらフツーに通った…
もうちょっとなんかライブラリー要求されるかと思いましたが、意外とオプションなしなら通るものですね。
ちなみに、
$ du -sh /opt/mysql/*
66M     /opt/mysql/5.0.96
228M    /opt/mysql/5.1.72
342M    /opt/mysql/5.5.58
998M    /opt/mysql/5.6.38
1.9G    /opt/mysql/5.7.20
1.5G    /opt/mysql/8.0.3
5シリーズビルドするのに大体6時間くらいでした!
それでは楽しい MySQL on ConoHa ライフを!