APUE 3rd Editionの写経の準備メモ

Advanced Programming in the UNIX Environment, 3rd Editionの写経のための準備メモ。

環境

OS X

$ gcc -v
Configured with: --prefix=/Library/Developer/CommandLineTools/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 6.0 (clang-600.0.56) (based on LLVM 3.5svn)
Target: x86_64-apple-darwin14.0.0
Thread model: posix

Ubuntu

$ gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/4.9/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 4.9.1-16ubuntu6' --with-bugurl=file:///usr/share/doc/gcc-4.9/README.Bugs --enable-languages=c,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.9 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.9 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --disable-vtable-verify --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-4.9-amd64/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-4.9-amd64 --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-4.9-amd64 --with-arch-directory=amd64 --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-gc --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 4.9.1 (Ubuntu 4.9.1-16ubuntu6)

ソースコード

http://www.apuebook.com/code3e.html からダウンロード

コンパイル

OS X

makeコンパイルエラーを抜粋。

gcc -R. -o t4 t4.o -L../lib -L. -lapue_db -lapue
clang: error: unknown argument: '-R.'
make[1]: *** [t4] Error 1
make: *** [all] Error 1

-R.のRの後のドットを取れば解決できるっぽい*1

--- db/Makefile.orig 2015-03-08 05:45:46.000000000 +0900
+++ db/Makefile   2015-03-08 05:46:00.000000000 +0900
@@ -15,7 +15,7 @@
   EXTRALD=-Wl,-rpath=.
 endif
 ifeq "$(PLATFORM)" "freebsd"
-  EXTRALD=-R.
+  EXTRALD=-R
 endif
 ifeq "$(PLATFORM)" "macos"
   EXTRALD=-R

Ubuntu

makeコンパイルエラーを抜粋。

gcc -ansi -I../include -Wall -DLINUX -D_GNU_SOURCE  badexit2.c -o badexit2  -L../lib -lapue -pthread -lrt -lbsd
/usr/bin/ld: cannot find -lbsd
collect2: error: ld returned 1 exit status
Makefile:31: recipe for target 'badexit2' failed
make[1]: *** [badexit2] Error 1

libbsdをインストールすればコンパイルできる*2

$ sudo apt-get install libbsd-dev

ヘッダとライブラリ

makeした後にヘッダとライブラリをコピー*3

$ sudo cp include/apue.h /usr/local/include
$ sudo cp lib/libapue.a /usr/local/lib

コンパイル時にオプションでライブラリを指定する。

$ gcc ls.c -lapue

サイボウズのLT大会で発表してきた

サイボウズが社内で開いているLT大会「技術Bar」に参加してLTしてきました。
「まだ黒い画面で消耗してるの?」というタイトルで、主にlsコマンドの出力を色付きにして見やすくする方法について話しました。

スライドを作ってから気がついたのですが、スライド作成時のkコマンドは少しバージョンが古いもので、現在ではオプションがついたりと少しバージョンアップしていました。

技術Barについて

技術Barについては以下の記事で解説されています。

月に1回やっていて学生なら無料で参加できるようなので、学生の人は是非参加すると良いと思います!(ステマ
働いているエンジニアと話せたり、社内の雰囲気を知れたりする良い機会になりました。
facebookページなどで開催のお知らせがあると思います。

サイボウズはもう16卒の新卒採用の選考が始まってますね。早くエントリーしなきゃ。

MySQLでTPC-Hベンチマークを実行する

DSS (Decision Support System) のベンチマークであるTPC-HMySQLで実行してみます。

HammerDB というTPC-Hを実行できるベンチマークツールも存在するのですが、今回は公式に配布されるデータロードプログラムのDBGENとクエリ作成プログラムのQGENを使用します。

環境

前提

  • MySQLがインストールされていること
  • mysqldが動いてること

手順

TPC-H用のデータベースとユーザの作成

TPC-H用のデータベースtpchとクエリを実行するユーザーtpchを作成します。 わかりやすさのためtpchとしていますが、別に何でもいいと思います。
ユーザーtpchにはデータベースtpchの権限を与えておきます。

$ mysql -u root -p

mysql> CREATE DATABASE tpch;
Query OK, 1 row affected (0.00 sec)

mysql> CREATE USER 'tpch'@'localhost';
Query OK, 0 rows affected (0.00 sec)

mysql> GRANT ALL ON tpch.* to 'tpch'@'localhost';
Query OK, 0 rows affected (0.00 sec)

DBGEN, QGENのセットアップ

DBGENとQGENは公式ページ TPC-H - Homepage の右のリンクからダウンロードできますが、MySQLで実行するには何点かの修正パッチが必要です。
ダウンロードとパッチの適用などをしてくれるスクリプトinstall-dbgen.shを書いたので、それを用います。 install-dbgen.shが行うことは以下の通りです。

  • DBGENのダウンロードと展開
  • dss.ddl, dss.ri, tpcd.hに対してパッチを適用し、その後dbgen, qgenコンパイル
  • dbgen, qgenのラッパースクリプトの設置

DBGENのダンロード先とラッパースクリプトの設置先はそれぞれシェル変数SRC_DIRBIN_DIRで指定します。
今回はSRC_DIR~/srcBIN_DIR~/binを指定します。

$ cd ~/src
$ git clone git://github.com/itiut/tpch-mysql
$ BIN_DIR=~/bin SRC_DIR=~/src ./tpch-mysql/install-dbgen.sh

install-dbgen.shのソースはこちらから。itiut/tpch-mysql
修正点は以下の通りです。

  • データベース名とテーブル名を大文字から小文字に変更 (dss.ddl, dss.ri)
  • コメントの文法を修正 (dss.ri)
  • 外部キー作成クエリに参照先のカラム名を追加 (dss.ri)
  • MySQL用のヘッダ定義を追加 (tpcd.h)
  • クエリのテンプレートをMySQLの文法に修正 (queries/*.sql)

通常dbgenqgenを実行するときには辞書ファイルやクエリテンプレートを指定しなければいけないのですが、ラッパースクリプトではその辺の指定をしなくても済むようにしています。 tpch-mysql/queriesにあるクエリテンプレートとSRC_DIRにダウンロードしたDBGENをそのまま使うので、変更や削除はしないで下さい。

テーブルの作成

dbgenと同じディレクトリにある、テーブル作成用のクエリdss.ddlを実行してテーブルを作成します。

$ cd ~/src/tpch_2_17_0/dbgen
$ mysql -u tpch -D tpch < dss.ddl

dbgenを用いてデータを作成

BIN_DIRに指定したディレクトリが環境変数PATH中にあれば、dbgenが使えます。
dbgenの基本的な使い方としては、-sオプションでScale Factorというデータのサイズの指標を変更します。Scale Factorが大きいときには、データを分割して作成することもできます。
データは拡張子.tblのファイルとして作成されます。

$ dbgen -s 1
$ ls *.tbl
customer.tbl  lineitem.tbl  nation.tbl  orders.tbl  partsupp.tbl  part.tbl  region.tbl  supplier.tbl

データベースにデータをロード

作成したデータのファイル名から拡張子を除いたものが同じ名前のテーブルに対応しているので、対応するテーブルにデータをロードします。

$ for tbl_file in *.tbl; do mysql -u tpch -D tpch -e "LOAD DATA LOCAL INFILE '$tbl_file' INTO TABLE $(basename $tbl_file .tbl) FIELDS TERMINATED by '|' LINES TERMINATED BY '\n';"; done

インデックスを作成

dbgenと同じディレクトリにある、インデックス作成用のクエリdss.riを実行してインデックスを作成します。

$ mysql -u tpch -D tpch < dss.ri

qgenを用いてクエリを作成

qgen-sオプションでScale Factorを指定します。
1~22のクエリ番号を指定してクエリを個別に作成できます。

$ for i in $(seq 1 22); do qgen -s 1 $i > $i.sql; done
$ ls *.sql
10.sql  11.sql  12.sql  13.sql  14.sql  15.sql  16.sql  17.sql  18.sql  19.sql  1.sql  20.sql  21.sql  22.sql  2.sql  3.sql  4.sql  5.sql  6.sql  7.sql  8.sql  9.sql

後はこれらのクエリを

$ mysql -u tpch -D tpch < 1.sql

などで実行するだけです。

平成26年度データベーススペシャリスト試験に合格した

やったぜ。

f:id:itiut:20140620125007p:plain

とはいえ準備不足だったためあまり点数は高くないので、これからもっと精進します。

研究室の同期向けにターミナルの勉強会を開いた

4月から新しい研究室に変わってリモートで作業する機会が増えたので、自分自身の復習も兼ねてターミナルにあまり慣れてないであろう研究室の同期向けにターミナルの勉強会を開きました。
参加者は私を含めてM1とM2合わせて9人で、内容はbashとtmuxの基本操作・設定をデモを交えつつやり、最後に~/.ssh/configを使うとsshコマンドが楽になるということを説明しました。

スライドはこちら。
黒い画面入門

f:id:itiut:20140619155102p:plain

勉強会中の質問とか感想とか

  • 意外とbashの行頭・行末移動のC-aC-eのコマンドが覚えられない
    • キーボード上でaが左、eが右にあるのを行頭・行末と対応させると覚えやすい
  • whatis emacsは哲学
  • コマンドの実行回数ランキングの上位が1文字になっててウケる
  • rm -iにしてても結局確認せずにy押してEnterしちゃう
    • ファイルの内容確認して重要そうだったら警告してくれるコマンドがあったら幸せになれそう
  • tmuxの|でペイン縦に分割、-でペインを横に分割は直感的でわかりやすい
  • 多段sshは全然知られてなかった
  • tmuxの発音は「ティーマックス」だった?
    • 今までずっと「ティーミュックス」と呼んでた

スライドの作成環境

PowerPointを窓から投げ捨てたいのですが、良さそうな移行先が見つかってません。

前に使ったglide.soというgist上のmarkdownをスライドショーにしてくれるサービスがダウンしてて使えなかったので、今回のスライドはRemarkを使って作ったのですが、結構使いやすかったです。

$ python -m SimpleHTTPServerすればローカル環境だけでプレビューできてとても楽です。
ただしテンプレートらしきものはないのでcssを少しカスタマイズしないといけないし、htmlの<textarea>にmarkdownを直書きするのは少しキモいです。

しばらくはRemarkを使ってみようと思います。

InnoDBの共有テーブルスペースにrawデバイスを使う

すごくハマったのでメモ。 公式ドキュメントに手順が載っているが、これだけではできなかった。

MySQL :: MySQL 5.6 Reference Manual :: 14.5.8 Using Raw Disk Partitions for the Shared Tablespace

環境

  • MySQL 5.6.19
    • ソースからインストール
    • basedir: /opt/mysql
    • datadir: /var/lib/mysql
  • 使うデバイス: /dev/sdb1
  • mysqldを動かすユーザー: mysql

手順

1. innodb_file_per_tableを無効に

5.6.6 以降はデフォルトでinnodb_file_per_tableが有効になっていて、テーブルごとにファイルを作ってしまう。 /etc/my.cnfを開いて[mysqld]セクションに無効にする設定を追加しておく。

またこの時点ではinnodb_data_file_pathはデフォルト値に設定しておく。 rawデバイス用の設定にするとmysql_install_dbでデータディレクトリを初期化したときにエラーが生じ、rootパスワードが勝手に設定されてmysqlにログインできなかった。

[mysqld]
innodb_file_per_table=OFF
innodb_data_file_path=ibdata1:12M:autoextend

2. mysql_install_dbでデータディレクトリの初期化

$ sudo /opt/mysql/scripts/mysql_install_db --user=mysql --datadir=/var/lib/mysql

必要に応じて--datadirオプションを付けてデータディレクトリを指定する。

3. mysqlデータベース中のテーブルのダンプと削除

ibdata1中にはmysqlデータベース中のいくつかのテーブルが含まれている。5.6 以前ではibdata1が削除されるとそれらのテーブルは再び作られるが、5.6 では再び作られないらしい。
innodb - Cannot open table mysql/innodb_index_stats - Database Administrators Stack Exchange

なのでこれらのテーブルをダンプしておいて、後でリストアする。 これらのテーブルを復元しないでおくとInnoDB: Error: Table "mysql"."innodb_table_stats" not found.というようなエラーが大量に出ていた。

mysqldを起動してテーブルをダンプして削除。その後mysqldを停止。

$ sudo service mysql.server start

$ mysqldump -u root mysql \
innodb_index_stats \
innodb_table_stats \
slave_master_info \
slave_relay_log_info \
slave_worker_info \
> mysql_innodb_tables.sql

$ mysql -u root -D mysql -e "DROP TABLE innodb_index_stats, innodb_table_stats, slave_master_info, slave_relay_log_info, slave_worker_info"

$ sudo service mysql.server stop

4. ログファイルの削除

ドキュメントには書かれていなかったが、ib_logfile0などのログファイルが存在するとログが書き込めないというエラーが生じた。

$ sudo rm /var/lib/mysql/ib_logfile*

5. rawデバイスの初期化のための設定

ここからやっとドキュメントの手順開始。
/etc/my.cnfを開いてinnodb_data_home_dirinnodb_data_file_pathを設定する。

[mysqld]
innodb_data_home_dir=
innodb_data_file_path=/dev/sdb1:300Gnewraw

使うデバイスの所有者がmysqldを動かすユーザーと同じでないとデバイスを開けないので、所有者を変更しておく。

$ sudo chown mysql:mysql /dev/sdb1

6. rawデバイスの初期化

mysqldを起動するとrawデバイスの初期化が始まる。大きい容量を指定していると長い時間がかかる。
初期化が終わったら何もせずにmysqlを停止させる。

$ sudo service mysql.server start && sudo service mysql.server stop

7. rawデバイス用の設定

/etc/my.cnfを開いてinnodb_data_file_pathの値がnewrawであったところをrawに変更する。

[mysqld]
innodb_data_home_dir=
innodb_data_file_path=/dev/sdb1:300Graw

8. ダンプしたテーブルのリストア

mysqldを起動してさっきダンプしたテーブルをリストアする。

$ sudo service mysql.server start

$ mysql -u root -D mysql < mysql_innodb_tables.sql

以上で完了。

KVM上のVirtIOを使うWindowsでディスクアクセス速度を測定してみた

前回に引き続きKVMの準仮想ドライバVirtIOを使って、KVM上のWindowsでディスクアクセス速度を測定しました。 比較対象としては網羅性は無いですが、KVM上でVirtIOを使わずデフォルトのドライバを使った場合と、VirtualBox上のWindowsと、ローカルのUbuntuとで速度を測定して比較しました。

環境

ホスト環境

ハードウェア

  • CPU
  • RAM
    • DDR3 1067MHz 4GB x 2
  • HDD
    • Hitachi HTS547550A9E384 500GB 5400RPM

ソフトウェア

ゲスト環境

共通

  • 割り当てCPUコア数
    • 2
  • 割り当てメモリサイズ
    • 4096MB
  • 割り当てストレージサイズ
    • 96GB
  • ゲストOS

比較対象

  • VBox-dynamic
    • VirtualBox上で、ストレージは動的割り当て
    • AHCIタイプのストレージコントローラを使用 (デフォルト仕様)
    • ホストI/Oキャッシュは使用しない (デフォルト仕様)
  • VBox-fixed
    • VirtualBox上で、ストレージは固定割り当て
    • それ以外はVBox-dynamicと同じ
  • KVM-IDE
    • KVM上で、ストレージ固定割り当て (デフォルト仕様)
    • Disk busはIDE (デフォルト仕様)
    • I/Oキャッシュはデフォルト (有効?)
  • KVM-VirtIO
    • Disk busはVirtIO
    • それ以外はKVM-IDEと同じ
  • Local
    • ホストのローカルで測定

測定結果

KVM-VirtIOの値が非常に大きくなったので、他の値を見やすくするためKVM-VirtIOがグラフの右端で見切れるようにしてます。

考察

まずKVM-IDEKVM-VirtIOも明らかにおかしい大きな値が出ています。ローカルとゲストとで測定方法が厳密には同じではないので正確な比較ではないですが、ローカルよりもKVM-IDEKVM-VirtIOの方が大きな値を取るのは普通考えられないことです。 あまり確証はないですが、考えられる理由は2点あります。

  • KVMのホストI/Oのキャッシュがデフォルトだとオンになっていて、メモリを読み書きしていた
  • KVM (のドライバ) がものすごく頭が良くて、無意味な処理を無視していた?

一方VirtualBoxでの値はローカルの値とほぼ同等で、個人的見解としては仮想化した時のディスクアクセスのオーバーヘッドは実用上無視できると思います。

今回の測定は、デスクトップやノートPCでホストOSのWindowsを使うときにハイパーバイザとしてKVMを使うかどうかの調査も兼ねてたのですが、VirtualBoxのディスクアクセスは遅いのではないかという疑念は晴れて、VirtualBoxの使用をやめる消極的な理由はなくなりました。

KVMを使ってみた感想

  • ゲストの解像度をウィンドウサイズに合わせて変更できなかった (やり方を知らないだけかも)
  • ホストではxmodmapを使ってCapsLockを左Ctrlに変更していたのに、ゲストには反映されなかった

ディスクアクセス速度よりも使いにくさが目立ったので、KVMWindowsを仮想化するのはやめておきます。

結論

  • KVMのディスクアクセス速度はなんか悪さされて正確に測れなかった
  • VirtualBoxのディスクアクセスのオーバーヘッドは実用上無視できる (個人的見解)
  • 引き続きVirtualBoxWindowsを仮想化して使う