DateTime::Format::Strptime にパッチを送った話 #Perl
CPAN モジュールの DateTime::Format::Strptime は DateTime と同じ Dave Rolsky さんが開発しているもので、日付時刻を含む文字列のパースによく使われているのではないかと思います。
このモジュールの挙動が v1.58 から変わっていました。
#!perl use feature qw(say); use DateTime::Format::Strptime; my $strp = DateTime::Format::Strptime->new( pattern => '%Y%m%d', ); for my $str (qw/20160330 access_log.20160330/) { my $dt = $strp->parse_datetime($str); say "$str => undef " and next unless $dt; say "$str => " . $strp->format_datetime($dt); }
これを実行すると、下のようになりました。
# v1.57 以前 20160330 => 20160330 access_log.20160330 => 20160330 # v1.58 以降 20160330 => 20160330 access_log.20160330 => undef
そう。
日付時刻を表す文字列の前に、別の文字列があるようなものはパースできなくなっていたのです。
Changes や差分を見ていたところ、どうやら v1.57 〜 v1.60 の間に互換性を崩す大幅な変更があったようです。
ので、仕様変更かなーと同僚の間で話していたのですが、作者に聞くのが確実だろうと思ったので、GitHub の Issued で聞いてみました。
なんとバグだったようです。
せっかくなので、直せるかどうか手元でやってみることにしました。
GitHub で fork して、まずはテストを書いて再現させてみました。
テストを書いたところ、どうやら 20160330.log
のように、後ろに文字列があるケースはパースできるということに気がつきました。
…で、試行錯誤した結果、正規表現を数文字変えれば問題の挙動が直り、既存のテストも通るということがわかりました。
ので、Pull Request を送りました。
取り込まれる過程で少し修正されていましたが、めでたく修正版の v1.67 がリリースされました。
めでたしめでたし。
Gotanda.pm #8 で memcached-cli について喋ってきた #gotandapm #memcached
既に2回このブログで紹介している memcached-cli について、昨日開催された第8回 Gotanda.pm で LT してきました。
資料はこちらです。今回は Speaker Deck に上げてみました。
Speaker Deck だとスライド中のリンクが無効になる(?)ようなので、いくつか貼っておきます:
- https://github.com/key-amb/perl5-App-Memcached-CLI
- https://github.com/memcached/memcached
- https://metacpan.org/pod/Term::ReadLine
残念ながら時間が足りず、デモが幻に終わってしまいました。
デモでは、Memcached の slab reassign, lru_crawler 辺りの機能を memcached-cli で触ってみるつもりでした。
せっかく準備していたので、Qiita に手順と結果をアップしておきました。
ご興味のある方はご覧ください。
感想など
いろいろありましたが、特に DBIx::Class の深い話を聞けたのが面白かったです。
あと、そういえばサイボウズさんの yrmcds は Memcached のテキストプロトコルにも対応しているのでした、というのを思い出しました。
ので、後で memcached-cli で操作してみるというのをやってみたいなと思いました。
今回、LT 枠が埋まった後の、遅いめの参加表明でしたが、柔軟に対処していただきました。
ありがとうございました!
Ruby コード中の "=" や "=>" を整列してくれる "ruby-align" というツールを作った
こちらになります。
使い方・動作例
ruby-align [-f] ファイル
で結果を標準出力に吐きます。
README には vim の設定例を書いてますが、エディタから呼んでその場でコード整形すると捗るかと。
動作例としては、README に挙げたものをこちらにも貼っておきます:
## before a = 1 dddd ||= (1..3) bb -= 20 e = { foo: 1, bar: 'Bar' } stash = { foo: 123, 'bar' => 'Bar', "bazz" => %w[ x y z ] } ## after a = 1 dddd ||= (1..3) bb -= 20 e = { foo: 1, bar: 'Bar' } stash = { foo: 123, 'bar' => 'Bar', "bazz" => %w[ x y z ] }
一応、ネストしたハッシュや制御構文でのインデント変更も、テストケースに書いたものは対応できているはずです。(CI も通っています。)
これを作ったきっかけ
Perl でコードを書く場合、私はフォーマットのツールとして Perltidy を使っています。
この記事で紹介されているような Vim の設定をして、ハッシュ定義の =>
等を揃えるのに多用しています。
…で、Ruby でそういうの無いの、と思って探したところ、どうも RuboCop に行き着くようです。*1
が、実際に試してもみたのですが、どうも思った通りに動いてくれない*2し、求めてもいない警告をたくさん出してくれます。
で、ついカッとなって作ってしまった感じです。
最初は VimScript で書こうとしてみたのですが、初心者すぎてつらかったのと、perltidy のようなインタフェースのものを作った方が他のエディタにも組み込みやすかろうということで Ruby に方向転換しました。*3
また、Ruby で書くにあたっては、始め RuboCop でも使われている whitequark/parser を使おうとしました。 が、求めている機能に対して牛刀感がして、やめてしまいました。
…で、結局ゴリゴリと正規表現を書いてます。
これはこれで、やはりつらみはある*4のですが、ある程度のパターンについてはテストを書いたので、ぶっ壊れることはそんなに無いかと思います。
自分のために作ったという部分が大きいですが、もしお気に召しましたらご自由にお使いくださいというところです。
(ただし、コードが壊れても責任は負えませんので、バックアップはお忘れなく。。)
参考
Vim で使える汎用の整列ツールとしては、昔から Align を使っているのですが、調べ直してみたところ Alignta や vim-easy-align というのが見つかりました。
こういう整列ツールでも、だいたいやりたいことはできそうだなと思いました。
key: "value"
形式のエントリと "key" => "value"
のものが混ざってるとつらそうですが、まあ、両者が混ざったハッシュってそんなに無い(?)のかなと思ったりもします。
memcached-cli の v0.9.4 までの追加機能の紹介
3/24 の記事で、最近作った memcached-cli というツールの紹介をしました。
別に困ってはいないのですが、もっと便利にしたので、Changes から抜粋して追加機能を紹介しておきます。
昨日か一昨日に手元に入れて試してみた、という方はぜひアップデートしてみてください。
gets, add, replace, append, prepend, cas, touch, incr, decr の実装
v0.6.0 以前は get/set/delete しかできませんでしたが、これで memcached/doc/protocol.txt に書かれている Retrieval, Storage コマンド + α のデータ操作が全てできるようになりました。
なんとなくコマンドの解説:
- add は該当キーのデータが無いときのみ成功します。
- replace は該当キーのデータが有るときのみ成功します。
- cas は gets で取得した cas 値に基いて更新を試み、cas 値が異なっていたら更新しません。
append, prepend はこんな感じですね:
memcached@127.0.0.1:11211> add foo Foo memcached@127.0.0.1:11211> append foo .extension memcached@127.0.0.1:11211> prepend foo prefix- memcached@127.0.0.1:11211> get foo key: foo value: prefix-Foo.extension length: 20B flags: 0
get, gets で複数キーの同時取得に対応
元々 get, gets は複数キーを渡せたので、 memcached-cli
でもできるようにしました。
で、複数データ取得した時には下のように LTSV で表示するようにしました。
memcached@SERVER:PORT> gets foo bar Key:foo Value:Foo Length:3B Flags:0 Cas:219 Key:bar Value:Bar Length:3B Flags:0 Cas:220
cachedump コマンドで VALUE も取得して表示
以前の cachedump
コマンドは stats cachedump
の結果をそのまま出力していましたが、上のような LTSV にして、かつデータの中身も合わせて表示できたら便利だな、と思ったので、実装しました。
memcached@SERVER:PORT> cachedump 1 Key:foo Value:Foo Length:3B Expire:2016-03-26 00:30:27 Flags:0 Cas:219 Key:bar Value:Bar Length:3B Expire:2016-03-26 09:53:19 Flags:0 Cas:220 Key:baz Value:Baz Length:3B Expire:2016-03-26 10:49:05 Flags:123 Cas:221
実運用だと、 display
でざっと全体の様子をつかんで、気になるスラブ・クラスを cachedump してみて、場合によっては中身を見る、という調査の流れがよくあるかと思いますが、そんなときにこれを使うとすごく捗りそうです。
stats
, settings
の結果を正規表現でフィルタ可能に
小ネタですが、よく見る指標がある人にはちょっと便利かと。
memcached@127.0.0.1:11211> stats (get|set) # stats # Field Value cmd_get 248 cmd_set 515 get_hits 46 get_misses 202 memcached@127.0.0.1:11211> settings ^lru # stats settings # Field Value lru_crawler no lru_crawler_sleep 100 lru_crawler_tocrawl 0
ランダムデータ生成機能を実装しました
> randomset [<NUMBER> [<MAX_LENGTH> [<MIN_LENGTH> [<NAMESPACE>]]]] > randomset # 100 個生成 > randomset 50 # 50 個生成 > randomset 50 1024 # データ長 1-1024B の範囲で生成 > randomset 50 1024 256 # データ長 256-1024B の範囲で生成 > randomset 50 1024 256 sample1 # キーの prefix を 'sample1:' にする
これを使って、前回も話題に触れたネームスペースごとの統計取得・表示を簡単に試すことができます。
memcached@127.0.0.1:11211> settings detail # 設定を絞込み表示 # stats settings # Field Value detail_enabled no memcached@127.0.0.1:11211> detail on OK - Enabled stats collection for detail dump. memcached@127.0.0.1:11211> settings detail # stats settings # Field Value detail_enabled yes memcached@127.0.0.1:11211> \dd # まだデータが無い memcached@127.0.0.1:11211> detail on OK - Enabled stats collection for detail dump. memcached@127.0.0.1:11211> randomset 1000 0 0 sample1 Random Generate. [....................] Complete. memcached@127.0.0.1:11211> randomset 1000 0 0 sample2 Random Generate. [....................] Complete. memcached@127.0.0.1:11211> randomset 1000 0 0 sample3 Random Generate. [....................] Complete. memcached@127.0.0.1:11211> \dd PREFIX sample3 get 0 hit 0 set 1000 del 0 PREFIX sample2 get 0 hit 0 set 1000 del 0 PREFIX sample1 get 0 hit 0 set 1000 del 0
(これで、別に作っていたデータ生成ツールは要らなくなりました。)
memcached-tool の "dump" コマンドをインポート
memcached-cli dump_all
というコマンドにしました。
memcached-tool の "dump" は expire 0 のデータが正しく dump できない不具合があるのですが、こちらでは直しました。*1
ついでに dump から restore できるようにした
restore_dump <dumpファイル>
でできます。
cat <dumpファイル> | telnet SERVER PORT
で行けるかなと思ったのですが、やってみたら CLIENT_ERROR の嵐になってしまいましたので、このコマンドを使うといいと思います。
実運用上も、Memcached サーバを再起動しないといけないときに dump して別サーバに restore して IP アドレスを付け替える、みたいな使い方ができるかもしれません。
実装していないコマンドも実行できるようにしました。
call <command> [<arguments>...]
という形式で、任意のコマンドを直接 Memcached サーバに投げれるようにしました。
これで、まだ実装していない stats conns
や slabs reassign <src class> <dest class>
のようなコマンドも実行できます。
memcached-tool の sizes
コマンドも実装していませんが、 call stats sizes
で OK です。
今後 memcached に新しいコマンドが追加されてもなんとかなりそうです。
終りに
memcached 初心者の学習用にも良いかもなー、とも思いました。
もうたぶん、あまりいじることはないと思いますが、何かあれば GitHub のイシューなりでお知らせください。
それでは、Have fun!
*1:本家では修正 PR が出ていますが、まだ取り込まれていません。
Memcached に対話的にコマンドを実行できる "memcached-cli" を作った
Redis*1 には redis-cli
というツールがあって、Redis サーバに接続して対話的にコマンドを発行して、結果を得ることができます。
Memcached*2 の場合、いい感じに使えるツールがなくて*3、必要なときはいつも TELNET でつないでコマンドを実行していました。
それもたまにしかやらないので、 set
コマンドの打ち方とか、よく忘れて調べていました。(難易度高い)
…というわけで、そういう操作を簡単に対話的に実行できるものを作りました。
CPAN にも公開していますので、 cpanm App::Memcached::CLI
でインストールできます。
これに script/memcached-cli
というスクリプトを同梱しています。
まだすべてのコマンドを網羅できたわけではないですが((執筆時点の App-Memcached-CLI のバージョンは v0.5.3
))、現時点でも、特にサーバ運用管理者にとってはそこそこ便利なものになっているのではないかと思います。
以下、memcached-cli
の使い方の紹介です。
対話モード
接続
接続先を -a|--addr
オプションか、第1引数で渡してください。
% memcached-cli memd.foo.local:11211 % memcached-cli -a memd.foo.local # デフォルト 11211 ポート % memcached-cli # localhost に接続
接続すると下のように対話モードに移行します。
memcached@127.0.0.1:11211>
get/set
特に違和感なく使えるかと思います。
memcached@127.0.0.1:11211> get foo Not found - foo memcached@127.0.0.1:11211> set foo WHAAH!!! OK memcached@127.0.0.1:11211> get foo key: foo value: WHAAH!!! flags: 0 length: 8
expire (exptime)を指定する場合、value の後に秒数で渡してください。 デフォルトでは expire 0 で set するので、 expire しません。
memcached@127.0.0.1:11211> set short WRYYY!!! 5 OK memcached@127.0.0.1:11211> get short key: short value: WRYYY!!! flags: 0 length: 8 # 5秒後 memcached@127.0.0.1:11211> get short Not found - short
expire の後ろに flags
(任意の非負整数)を渡すこともできます。
delete
KEY 指定で delete できます。
memcached@127.0.0.1:11211> delete foo OK memcached@127.0.0.1:11211> get foo Not found - foo
memcached-tool からの移植機能
Memcached 付属の memcached-tool
*4はスラブのクラスごとの統計情報表示など、運用管理者にとって便利な機能を備えています。
一部を除いて memcached-cli
に移植しましたので、対話的に実行することができます。
memcached@127.0.0.1:11211> display # Item_Size Max_age Pages Count Full? Evicted Evict_Time OOM 1 96B 0s 1 0 yes 0 0 0 18 4.4K 0s 1 0 yes 0 0 0 20 6.9K 6s 1 2 yes 0 0 0 22 10.8K 6s 1 1 yes 0 0 0 24 16.9K 6s 1 1 yes 0 0 0 26 26.5K 0s 1 0 yes 0 0 0 : memcached@127.0.0.1:11211> \d # 同じ
display
はよく打ちそうだなと思ったので、 \d
というエイリアスを作ってみました。
対話モードの終了
\q
または quit
または exit
で終了します。
その他の機能
help
または \h
で実装されているコマンドが表示されます。
\h <command>
で一部のコマンドは、より詳しい情報が見れます。
memcached@127.0.0.1:11211> \h [Available Commands] \h, help Show help (this) \v, version Show server version \q, quit, exit Exit \d, display Display slabs info \s, stats Show stats \c, settings, config Show settings \cd, cachedump, dump Show cachedump of specified slab \dd, detaildump Show detail dump detail Enable/Disable detail dump get Get data of KEY set Set data with KEY, VALUE delete Delete data of KEY flush, flush_all Invalidate whole data Type \h <command> for each. memcached@127.0.0.1:11211> \h cachedump (略)
memcached-tool
から移植したのは display
に加えて stats
, settings
あたりですね。
その他、運用管理向けの機能として、cachedump
を実装しました。 cachedump <CLASS> [<SIZE>]
で特定スラブのアイテムのキーと expire を <SIZE>
の個数だけ一覧できます。デフォルトの <SIZE>
は20にしました。
また、下の記事で紹介されていたネームスペースごとの統計も detaildump
で表示できるようにしました。
Cache::Memcached(::Fast) のネームスペースは最後に区切り文字をいれた方が良い話とネームスペース毎に統計を取る方法 - blog.nomadscafe.jp
この統計情報を起動時に有効化してない場合、有効化するには stats detail on
を叩かないといけません。
ので、それも detail on
で、できるようにしました。
ついでに detail off
で無効化できるようにしました。
バッチモード
更に、これらを対話モードだけでなく、バッチで実行できたら、より便利だなと思ったので、 v0.4
でできるようにしました。
redis-cli
もバッチ実行できますし。
これによって、 memcached-tool
から移植した機能については memcached-tool
と同じようにコマンドラインから実行できるようになりました。
$ memcached-cli localhost display # Item_Size Max_age Pages Count Full? Evicted Evict_Time OOM 1 96B 0s 1 0 yes 0 0 0 18 4.4K 164s 1 1 yes 0 0 0 24 16.9K 164s 1 2 yes 0 0 0 # ※ `\` で始まるエイリアスは適当にエスケープなりしてあげる必要があります。 $ memcached-cli localhost \\cd 18 ITEM memcached-roaster:random-generate1:data54 [3724 b; 1458806126 s]
flush_all
または flush
を実行すると、全てのデータが無効化される(次回GET時に expired 扱いになる)ので、気をつけて下さいね。
$ memcached-cli localhost flush_all OK
実装したコマンドは全て、対話モードでもバッチモードでも、どちらでも実行できます。
今後
もうあまり困ってはいないのですが、Memcached のその他のコマンドも少しずつ追加していこうかなと思っています。
あと、ランダムにデータ生成するようなコマンドも作ろうかなと思っていたりします。*5
何かあれば GitHub 上で Issue や PR をいただければ、歓迎いたします。
余談
もっと早くこれを作っておけば良かったという感はあります。
なんで Perl なのかというと、memcached-tool が Perl で書かれていて、それを参考にしながら移植したからです。*6
脚注
*3:最近探したところ、いくつか見つかりましたが、ほしい感じのはなかったです。
*4:memcached/memcached-tool at master · memcached/memcached · GitHub
*5:テスト用に https://github.com/key-amb/perl5-App-Memcached-Roaster というチープなツールを作りました。
*6:https://github.com/key-amb/perl5-App-Memcached-Tool という memcached-tool のポーティングも作りました。