kasei_sanのブログ

かせいさんのIT系のおぼえがきです。胡乱の方はnoteとtwitterへ

Rubyで書く! Quineのサンプルと解説

Quine ってなに?

クワイン(英: Quine)は、コンピュータプログラムの一種で、自身のソースコードと完全に同じ文字列を出力するプログラムである。

クワイン (プログラミング) - Wikipedia

基本の Ruby Quine

eval s="puts'eval s='+s.inspect"

解説

  • eval s="..." では、sに文字列を代入して、それが eval される
  • s の中身は "puts'eval s='+s.inspect"
  • なので、s を eval すると、'eval s='+s.inspect が puts される
  • s.inspect"puts'eval s='+s.inspect".inspect なので、 "\"puts'eval s='+s.inspect\"" となる
  • 結果、puts される文字列は、コードと同じ "eval s=\"puts'eval s='+s.inspect\"" となる

感想

  • s が再起っぽい挙動をするのがややこしいけど、理解すると eval すごいってなる

最短(と思われる) Ruby Quine

puts <<2*2,2
puts <<2*2,2
2

解説

  • 1行目の <<2 はヒアドキュメント
    • なので、2行目はすべて文字列
    • 3行目の 2 でヒアドキュメント終了
  • <<2*2 でヒアドキュメントの内容を2倍にしている
  • puts は複数の引数を渡されると改行してそれぞれを出力する
    • そのため、puts <<2*2,2,2 では改行後に2 を出力する
  • 結果として、コードと同一内容の文字列が出力される

f:id:kasei_san:20190501155916j:plain

感想

パッと見なにしているかわからない感がすごい

もっと短い Ruby Quine

$><<IO.read($0)

解説

  • $> は、 $stdout 標準出力
  • <<オブジェクトを出力させる命令
  • $0 は実行時に指定されたファイル名なので、IO.read($0) で、実行しているファイルの文字列を読み出す
  • 結果として、コードと同一内容の文字列が出力される
  • 仕組み上、irbでは実行エラーになる

感想

これはすこしずるいと思う

更に短い Ruby Quine

0

感想

ずるい

参考リンク

stackoverflow.com

PostgreSQL93でのレプリケーション確認方法

プライマリ側

SELECT * FROM pg_stat_replication

psql -x -c "SELECT * FROM pg_stat_replication"

-[ RECORD 1 ]----+------------------------------
pid              | 2167
usesysid         | 42700
usename          | repl_user
application_name | walreceiver
client_addr      | 10.0.2.102
client_hostname  |
client_port      | 33058
backend_start    | 2018-11-07 10:38:31.841085+09
state            | streaming
sent_location    | 12F8/8D0006C8
write_location   | 12F8/8D0006C8
flush_location   | 12F8/8D0006C8
replay_location  | 12F8/8D000400
sync_priority    | 0
sync_state       | async

重要なステータス

  • sync_state: 同期方法
    • sync: 非同期レプリケーション
    • async: 同期レプリケーション
  • state: スタンバイの状態。通常は streaming
  • sent_location: プライマリが送信済みのWALの位置
  • write_location: プライマリがバッファに書き込み済みのWALの位置
  • flush_location: プライマリがディスクに書き込み済みのWALの位置
  • replay_location: スタンバイがディスクに書き込み済みのWALの位置

〜_location がすべて一致していれば、遅延なくレプリケーションが行われている証拠

スタンバイ側

pg_last_xlog_receive_location()pg_stat_replication の位置と大差なければレプリケーションができている

psql -c "select pg_last_xlog_receive_location()"
 pg_last_xlog_receive_location
-------------------------------
 12F8/8D000E88
(1 row)

pg_last_xlog_receive_location は、 ストリーミングレプリケーションにより受信され、ディスクに書き込まれたトランザクションログの最後の位置

なお、PostgreSQL96からは pg_stat_wal_receiver で、pg_stat_replication のような情報が取れるらしいです

参考

バックグラウンドジョブおぼえがき

概要

job を用いて複数のコマンドを1つのシェルで平行して実行することができる

普通にコマンドを実行すると始まって、入力を受け付けるのが フォアグラウンドジョブ

入力を受け付けずに、CUIの後ろで実行されるのが バックグラウンドジョブ

バックグラウンドジョブを活用すると、時間のかかる処理を、1つのコンソールで並列で処理できて便利

バックグラウンドでジョブを実行する方法

& をつけると、最初からバックグラウンドで実行される

${コマンド} &

フォアグラウンドジョブをバックグラウンドに移動する方法

^z で現在実行中のジョブがバックグラウンドに移動

ただし、停止状態になるため、 bg ${job id} で再開する必要がある

バックグラウンドジョブの一覧を表示するコマンド

jobs

バックグラウンドジョブをフォアグラウンドに持ってくる方法

バックグラウンドジョブは、標準入力が必要になると停止状態になるので、 fg コマンドでフォアグラウンドに持ってくる必要がある

fg ${jobsで出てきたjob id}

(やや番外) ログアウトしてもコマンドを停止させない方法

nohup を先頭につける

  • 重い処理をリモートで実行するときに & と併用して、バックグラウンドジョブにして exit することが多い
nohup ${コマンド} &

MySQL でテーブルをロックせずに index を貼る方法いろいろ

indexを張った場合の処理の基本的な流れ

ALTER TABLE でindexを追加すると、indexを貼り終わるまでテーブルがロックされる

  • 内部的には テーブルをロック→テーブルをコピー→コピーしたテーブルにindexを貼る→元のテーブルと入れ替える→ロック解除 という処理が行われる

そのため、普通にindexを追加すると長時間DBが使い物にならなくなる

どうしたら良いの?

InnoDBの場合 online alter table という超スペシャルな機能があって、条件さえ満たしていればロックやテーブルコピーなしにindexが貼れる

MySQL :: MySQL 5.6 リファレンスマニュアル :: 14.11 InnoDB とオンライン DDL

online alter table の制約

MySQL 5.6 以前に作られた日時カラムを持つテーブルの場合、最低1回はコピーが必要

  • MySQL 5.6にて、日時カラムに浮動小数点が追加されたため

InnoDBじゃない場合は?

古来より、ロックなしに ALTER TABLE するためのオンラインDDLツールが作られており、それに頼るのが良い

pt-online-schema-change

昔からよく使われていた(と思われる)オンラインDDL

使用例も多く見つかる

ameblo.jp

gh-ost

Goで書かれている最近っぽいアーキテクチャのオンラインDDL

参考リンク

takatoshiono.hatenablog.com

InnoDBのバッフアプールとMyISAMのキーバッファについて

概要

  • InnoDBとMyISAMの違いについて解説
  • その上で、それぞれのキャッシュの取り扱いと、キャッシュに関する値の最適化について解説

そもそも、InnoDBとMyISAMの違い

どちらも ストレージエンジン

MySQLは、リクエストから以下のような流れで、データのread/writeが行われる

コネクションプール
    ↓
   パーサー(SQLをパース)
    ↓
ストレージエンジン(SQLを元にストレージを読み書きする)
    ↓
  ストレージ

MySQLではこの ストレージエンジン を MyISAMとInnoDBの2つから選ぶことができる

で、InnoDBとMyISAMどっちが良いの?

以前はMyISAMとInnoDBの棲み分けがあったが、今は概ねInnoDB

MySQL 5.5.5 からは、InnoDBがデフォルト

公式でもInnoDBの利点がいろいろ書かれて推奨されている

dev.mysql.com

InnoDBとMyISAMのキャッシュの取り扱い

InnoDBとMyISAMのおおきな違いの一つ

MyISAMの場合

MyISAMでは、indexのキャッシュはMySQLが管理。データのキャッシュはOSに任せている

  • MyISAMは1テーブル1ファイル
  • それにより、頻繁にアクセスされるファイルは、OSのキャッシュメモリに乗る
  • そのため、全テーブルがキャッシュメモリに乗るようにメモリサイズを調整する必要がある

インデックスの情報は MySQL 側の key_buffer に格納

key_buffer のサイズは key_buffer_size で設定。最適な値について公式ドキュメントでは、以下のように書かれている

  • マシンの合計メモリーの 25% 程度の値を推奨(残りはOSのキャッシュメモリに使わせる)
  • SHOW STATUS して Key_reads/Key_read_requests > 0.01 or Key_writes/Key_write_requests < 1 ならば、インデックスが効率よくキャッシュされていないので、値を増やす

dev.mysql.com

InnoDBの場合

InnoDBでは、indexのキャッシュも、データのキャッシュもMySQLが管理

もうちょっと厳密に話すと、InnoDBではストレージの読み書きの前に バッファプール を経由する

  • readのとき バッファプール にデータがあれば、読み込みはメモリ上で完結する
  • writeのときも バッファプール のデータを更新して、非同期でストレージを更新する

そのため、バッファプールが小さいと頻繁にディスクアクセスが発生して処理が遅くなる

バッファプールは、innodb_buffer_pool_size でキャッシュサイズを設定可能

公式ドキュメントでは、innodb_buffer_pool_size はマシンのメモリの80%を推奨

dev.mysql.com

まとめ

  • MyISAMでは、indexのキャッシュはMySQLが key_buffer で管理。データのキャッシュはOSに任せている
    • key_buffer_size の最適値はマシンの合計メモリーの 25%
  • InnoDBでは、indexのキャッシュも、データのキャッシュもMySQLが innodb_buffer_pool_size で管理
    • innodb_buffer_pool_size の最適値はマシンのメモリの 80%

Rubyでは真偽とtrue/falseは別物だよ! というお話

今日は、Rubyの true, false と、真偽は別物だよというお話をします

これは何?

会社blogで公開しようとした直前に、上位互換の記事が出てお蔵入りしてしまった可愛そうなblog記事です

techracho.bpsinc.jp

供養と自分の学習記録も兼ねて、個人ブログにupいたします

🙏🙏🙏🙏🙏🙏🙏🙏🙏🙏🙏🙏🙏🙏🙏🙏🙏🙏🙏🙏

真偽とは

Rubyにおいては、 真偽は以下のように定義されてます

  • 偽 : false または nil
  • 真 : 偽値でないすべて

Ruby では false または nil だけが偽で、それ以外は 0 や空文字列も含め全て真です。

制御構造 (Ruby 2.6.0)

true, false とは

真偽を代表するオブジェクトであって、これ以外の値も、上記で説明したように真偽を取ります

  • なお、true, false とも、あるclassのシングルトンのインスタンスです

true は TrueClass クラスの唯一のインスタンスです。 true は真を表す代表のオブジェクトです

class TrueClass (Ruby 2.6.0)

false は FalseClass クラスの唯一のインスタンスです。 false は nil オブジェクトとともに偽を表し、 その他の全てのオブジェクトは真です。

class FalseClass (Ruby 2.6.0)

末尾が ? のメソッドは true, false を返すべきなの? 真偽を返せばよいの?

さて、ここまで true, false と真偽値の違いを説明したのは、上記の疑問のためです

具体的には if hoge? == false という実装をコードレビュー中に見かけて、これが正しいのか正しくないのか論理的に説明が出来なかったために調べ始めました

先に自分なりの結論

末尾が ? のメソッドは true, false を返すべき
ただし、それ利用する側は、true, false 以外の真偽が帰ってくる可能性を考慮して実装すべき

その理由

Rubyのドキュメントでは、? が末尾につくメソッドは慣用的に 真偽値 を返せと言われているためです

ドキュメントを探す限り真偽値の定義は見つかりませんでしたが、おそらくは true/falseのことでしょう

  • 真偽だと全てのオブジェクトを指すことになるため、わざわざ明記する理由もないと思うので

慣用的に、真偽値を返すタイプのメソッドを示すために使われます。

Rubyで使われる記号の意味(正規表現の複雑な記号は除く) (Ruby 2.6.0)

ただし、「慣用」なので使う側は、安全側に倒したほうがよいと考えています

  • 実装者によっては偽のつもりで nil を返したり、真のつもりで true 以外の値を返すことも十分にありえるので

まとめ

  • true / false と真偽は別物
  • 偽は、falsenil。真はそれ以外のオブジェクトすべて
  • 末尾に ? がつくメソッドは真偽ではなく true / false を返すべきだけれど、それを期待しすぎないほうが安全

以上になります

おまけ

Rubyの真偽の設計思想については、以下の記事が読み応えがありオススメです

qiita.com

いまさら MacBook Air mid 2011 をサクサクにするためにやった3つのこと

これはなに

やたら重くなった MacBook Air mid 2011 (memory 4GB, strage 250GB) をサクサクにするまでの苦闘の記録です

古いMacBookに発生した、つらみあふれる現象

  • ログイン画面を開いてからパスワードを入力するまで1分ほど待たされる
  • 起動してからブラウザを開くまでやたら時間がかかる
  • 何もしていなくてもメモリを3GBくらい専有されている

上記を解決し、ネットサーフィンくらいなら何も支障がない状態になりました!

そのために、いろいろチューニングした結果をまとめます

MacBook Air mid 2011をサクサクにするためにやったこと

以下の3つです

  • ストレージの空き容量確保
  • CPUを無駄に食うプロセスの整理
  • memoryを無駄に食うプロセスの整理(主にChrome)

ストレージの空き容量確保

なぜ空き容量確保が必要か?

もし、ストレージの空きが1GBを切っている場合、メモリ不足時に使用する仮想メモリ(swap)が確保できず、処理が遅くなったり、アプリが強制終了してしまう場合があります

そのため、空き容量を程度確保して、仮想メモリに余裕をもたせておいたほうが良いです

そうでなくても250GBってあんまり余裕ありませんしね...

空き容量を確保するためにやったこと

以下の3つです

  • 写真をgoogleフォトに移動
  • 音楽をgoogle play musicに移動
  • (エンジニア向け) brew cleanup -s を実行

google様にデータを握られるのは好き嫌いはあると思いますが、私はストレージの空き容量の確保と、スマホと複数マシンで写真/音楽が共有されるメリットを取りました

写真をgoogleフォトに移動

googleフォトヘルプに従って操作すれば何も難しいことはありません

support.google.com

しかし、写真アプリで写真を削除した後も、ユーザーディレクトリのピクチャに 写真 Library.photoslibrary というファイルが残る場合があります

これが数GBの容量を食っていることがあるので、こちらも削除しておきましょう

f:id:kasei_san:20190217133659p:plain
写真 Library.photoslibraryはここにあります

音楽をgoogle play musicに移動

こちらも写真と同様にヘルプに従えば移行できます

support.google.com

brew cleanup -s を実行

homebrew のキャッシュファイルをクリアするコマンドです

私の環境では約50MBしか削減されませんでしたが、環境によっては数十GBほどキャッシュされている場合があるようです

CPUを無駄に食うプロセスの整理

効果の高い順に以下の4つを実施しました

  • SMCをリセットする
  • Spotlight関係のプロセスのCPU負荷を下げる
  • windowServerのCPU負荷を下げる
  • spindumpの無効化

SMCをリセットする

SMCとは「システム管理コントローラ」というPCのローレベルの機能のコントローラーです

SMCには、CPUの温度が上がると自動的にCPUの性能を下げて熱暴走を抑える機能があります

しかし、誤動作でCPUの温度が高くないにもかかわらず、CPUの性能を下げてしまう場合があるようです

公式サポートでは、その場合SMCをリセットすることが推奨されています

support.apple.com

電源をOFFにした状態で shift + control + option と電源キーを10秒間押しましょう

電源キーを押しますが、電源が入ることはありません。何も起こらないな? と不安にならなくて大丈夫です

Spotlight関係のプロセスのCPU負荷を下げる

アクティビティモニタの「CPU」タブを見ていたところ、mds_stores というプロセスがCPUを占拠していました(常に25%くらい)

調べたところ、Spotlightで使用するプロセスのようです

私の環境ではAlfredを使用しており、Spotlightは未使用のため、おとなしくしてもらいました

Spotlightでは、検索対象のディレクトリを常にチェックするプロセスが走っています

それを黙らせるには、検索対象をゼロにする必要があります

システム環境設定 -> Spotlight から、それぞれ設定します

f:id:kasei_san:20190217135306p:plain
検索結果のすべてのチェックを外す

f:id:kasei_san:20190217135341p:plain
Spotlightの検索から除外する場所 に Macintosh HD を追加

windowServerのCPU負荷を下げる

windowServerは、画面に表示されるウインドウを管理するプロセスです

MacなのにwindowServer?ってなりますよね...

システム環境設定から、windowServerにてCPUを食う処理を無効化することで、CPU負荷を下げることができます

無効化の方法は以下をご参考ください(Yosemite時代の記録ですが、現行のOSでも設定は大差ありませんでした)

ringosuki.hateblo.jp

spindumpの無効化

spindumpもCPUを占拠していることがあったので、こちらに従い停止しました

blog.monophile.net

spindumpは実行中のアプリケーションの低レイヤ情報を書き出すためのソフトウェアだが、 得られる情報は一般的な利用目的(ソフトウェア開発以外)では役に立たないことが多いと思う。

とのことです

memoryを無駄に食うプロセスの整理

不要なプロセスは起動しないようにしたのと、一番メモリを食うgoogle Chromeの整理を行いました

未使用のアプリをログイン時に起動しないようにする

システム環境設定->ユーザーとグループ->ログイン項目 から、ログイン時に起動するアプリを設定できます

f:id:kasei_san:20190217150758p:plain
未使用のアプリは起動しないようにしましょう

google Chromeの使用メモリ削減

タスクマネージャーを使用して、メモリを食う機能拡張を特定しました

また、広告ブロッカーを導入することで、広告に使われるメモリを無くすことに成功しました

タスクマネージャーの起動方法

画面右上のメニューから その他のツール -> タスクマネージャー でタスクマネージャーを起動させることができます

これにより、メモリやCPUを食う機能拡張やサブフレームを探すことができます

メモリを食う割に使っていない機能拡張は削除しましょう

f:id:kasei_san:20190217151137p:plain
タスクマネージャーの起動方法

f:id:kasei_san:20190217151223p:plain
メモリを食う割に使っていない機能拡張は削除しましょう

Adblock plusの導入

機能拡張 Adblock plusを導入することで、広告やトラッキングのに使われるiframeの起動が抑制され、結果使用メモリが削減されます

広告ブロックは賛否ありますが、自分環境ではブロックしないと文化的なネットサーフィンが難しいそうでしたので導入しました...

chrome.google.com

広告やトラッキングに使用されるiframeは意外にメモリを食っており、例えばニコニコ大百科の場合、 Adblock plusを導入するとで使用メモリが200MBほど削減されます

(ここで表示されている「サブフレーム」というのがiframeのことですね)

f:id:kasei_san:20190217151700p:plain
Adblock plus導入前

f:id:kasei_san:20190217151714p:plain
Adblock plus導入後

まとめ

適切なチューニングをしたところ MacBook Air mid 2011 でも普通に動作するようになりました...!

MacBook Airを購入してから、日が経つごとにどんどん重くなっていって、OSアップデートごとに無駄に重くして買い替えを促進するAppleの陰謀か...などと思っていたのですが...

みなさんも定期的なチューニングで快適なMacBookAirライフをお過ごしください!