Journal InTime


2015-05-14 (Thu) [長年日記]

_ MySQL/MariaDBの準同期レプリケーションの改善

MySQL 5.5/5.6、MariaDB 10.0の準同期レプリケーションでは、マスタ側でcommitした直後にスレーブからのバイナリログの受信完了通知を待つ仕組みになっているため、commitされたデータが他のセッションからreadされた後でスレーブにフェイルオーバーした際にそのデータが欠損する可能性があり、MySQL 5.7でloss-less semi-synchronous replicationという、commit前に受信完了通知を待つ仕組みが導入されている。

MariaDBの方には同様の修正が入ってないのかなと思ったら、10.1にEnhanced semisync replicationという名前で入っているようだ(この記事を見るとこちらの名前の方が由緒正しい?)。

MySQL 5.6向けのパッチはあるようだが、MariaDB 10.0向けのパッチは見当たらなかった。Googleさんのパッチ袋とかに入ってないだろうか。


2015-04-14 (Tue) [長年日記]

_ Ruby 2.2.2

opensslライブラリの脆弱性が修正されたようなので、Ruby 2.2.2にアップデートしておいた。

リリースに関係されたみなさんに感謝。

Tags: Ruby

2014-12-15 (Mon) [長年日記]

_ Intel mapからポータル名をコピーする

Intel map上でポータル名をコピーしようとするとドラッグ操作になってしまってポータル名を選択できない*1ので、HTML5のclipboard APIを使って簡単なブックマークレットを書いてみた。

使い方

  1. 以下のリンクをブックマークバーにドラッグ&ドロックして登録する
  2. Intel mapを開く
  3. ブックマークバーから1で登録したブックマークレットを実行する
  4. ポータルをクリックする
  5. Ctrl+Cを押す

一度3を実行すれば、4〜5は繰り返し実行できる。

Tags: Ingress

*1  IITCならできるかもしれないけど使ってない。


2014-07-31 (Thu) [長年日記]

_ SECDマシンにおける再帰

先日のICFPCに会社のチームで参加して、コンパイラの実装を少しだけ手伝った。

後でわかったが、ICFPCの仮想マシンの仕様LispKitをベースにしていて、SECDマシンという有名なものらしい。

SECDマシンはスタックマシンで、データスタック、制御スタック(関数呼び出しや条件分岐時に復帰するための情報が積まれる)、環境フレーム(変数が格納される)という三つのスタックを持っている(環境フレームは親フレームへのポインタを持っていて、単純にpopされる代りに参照されなくなったらGCされるので、厳密にはスタックではない)。

Stack/Environment/Control/Dumpという4つのレジスタを持つのがSECDマシンという名前の由来。

例えば、((lambda (x) (+ x x)) 21)のようなプログラムは以下のように表現される。

LDC  21       ; 定数21をスタックにpushする。
LDF  body     ; bodyを本体とするクロージャを生成してスタックにpushする。
AP   1        ; 新しい環境フレームを生成して、21に関数を適用する。
RTN           ; 呼び出し元に戻る。
body:
LD   0 0      ; 0番目の環境フレームの0番目の変数(x)の値をスタックにpushする。
LD   0 0      ; 0番目の環境フレームの0番目の変数(x)の値をスタックにpushする。
ADD           ; スタックから二つの値をpopし、加算した結果をスタックにpushする。
RTN           ; 呼び出し元に戻る。

APは新しい環境フレームを生成して関数を適用するが、APと似た命令に環境フレームを生成しないRAPというものがあり、空の環境フレームを生成するDUMという命令とセットで利用する。

例えば、(letrec ((loop (lambda () (loop)))) (loop))のような再帰的なプログラムは以下のように表現される。

DUM 1         ; 空の環境フレームを生成する。
LDF loop      ; loopを本体とするクロージャを生成してスタックにpushする。
LDF main      ; mainを本体とするクロージャを生成してスタックにpushする。
RAP 1         ; DUMで生成した環境フレームを使用してloopにmainを適用する。
RTN
main:
LD 0 0        ; 0番目の環境フレームの0番目の変数(loop)の値をスタックにpushする。
AP 0          ; 関数を適用する
RTN           ; 呼び出し元に戻る。
loop:
LD 1 0        ; 1番目の環境フレームの0番目の変数(loop)の値をスタックにpushする。
AP 0
RTN           ; 呼び出し元に戻る。

DUMで生成した環境フレームがLDF loopで生成されるクロージャによって捕捉されるところがポイントで、これによってloop内のLD 1 0(loopの適用で環境フレームが積まれるのでLDの第1オペランドは1とする)でloop自身を参照できる。

上記の例でDUM/RAPの代りにAPを使うと、letrecの代りにletを使った場合のように、loop内でloop自身を参照できない。


2014-06-30 (Mon) [長年日記]

_ InfluxDBの古いデータの削除

InfluxDBを試しているが、InfluxDBには今のところ古いデータを自動で削除する機能がない(対応予定はあるようだ)。

古いshardを丸ごと削除するのが効率がよいらしい(InfluxDBでは一定期間ごとにshardが作成される)ので、以下のようなcron用スクリプトを書いてみた。

require "influxdb"

USER = "root"
PASS = "root"
TTL = "1d"

def parse_ttl(ttl)
  case ttl
  when /\A(\d+)s\z/
    return $1.to_i
  when /\A(\d+)m\z/
    return 60 * $1.to_i
  when /\A(\d+)h\z/
    return 60 * 60 * $1.to_i
  when /\A(\d+)d\z/
    return 24 * 60 * 60 * $1.to_i
  else
    raise "invalid TTL - #{ttl}"
  end
end

secs_to_live = parse_ttl(TTL)
influxdb = InfluxDB::Client.new

for shard in influxdb.get_shard_list["shortTerm"]
  end_time = Time.at(shard["endTime"])
  if Time.now - end_time > secs_to_live
    influxdb.delete_shard(shard["id"], shard["serverIds"], USER, PASS)
  end
end

InfluxDBでは小文字で始まる名前のseriesは短期間(short term)、大文字で始まる名前のseriesは長期間(long term)と決まっているが、上記のスクリプトでは短期間のshardだけ削除するようにしている。

ただ、デフォルトでは各shardの期間が7日間になっているので、それよりも短い期間でshardを削除する場合は/opt/influxdb/shared/config.tomlの設定を以下のように変更しておく必要がある(この例では6時間に設定している)。

[sharding.short-term]
duration = "6h"

/opt/influxdb/current/config.tomlの方を変更しても反映されないので注意。

Tags: Ruby InfluxDB