DBICでcreate_relatedをoverrideする
DBICを使っています。
User has_many Histories
っていう関係のテーブルUserとHistoryがあった時に、
Userの行それぞれに対して、最新のHistoryをUserの行の中にキャッシュしておくと便利なときがあります。
そんな時に、$user->add_to_histories ってやった時に $userもupdateしたい、という話です。
PLAIN TEXT
PERL:
CREATE TABLE user (id unsigned not null auto_increment, **中略**, history unsigned not null);
CREATE TABLE history (id unsigned not null auto_increment, user unsigned not null, **中略**, created_date datetime not null);
UserのRowクラスは
PLAIN TEXT
PERL:
package Schema::Row::User;
中略
__PACKAGE__->has_many( histories => 'Schema::Row::History', 'user' );
HistoryのRowクラスは
PLAIN TEXT
PERL:
package Schema::Row::History;
中略
__PACKAGE__->belongs_to( user => 'Schema::Row::User' );
UserのRowクラスに追加されるadd_to_$relを使って
PLAIN TEXT
PERL:
$user->add_to_histories({ action => 'marriage' }); [...]
[perl]32bit/64bitでメモリ使用量違うけど
同じperlのコードを、2台の違うサーバで動かした時に、やたらメモリ量が違うなぁと。
サーバ1: 50MBくらい
サーバ2: 200MBくらい
なんでだろと調べる
サーバ1で
PLAIN TEXT
CODE:
perl -V
Summary of my perl5 (revision 5 version 10 subversion 0) configuration:
Platform:
osname=linux, osvers=2.6.26-1-686, archname=i486-linux-gnu-thread-multi
...
use64bitint=undef, use64bitall=undef, uselongdouble=undef
...
Compiler:
cc='cc', ccflags ='-D_REENTRANT -D_GNU_SOURCE -DDEBIAN -fno-strict-aliasing -pipe -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64',
optimize='-O2 -g',
cppflags='-D_REENTRANT -D_GNU_SOURCE -DDEBIAN -fno-strict-aliasing -pipe -I/usr/local/include'
ccversion='', gccversion='4.3.2', gccosandvers=''
intsize=4, longsize=4, ptrsize=4, doublesize=8, [...]
IO::AIOお試し
AnyEvent/Coro期がわたしにもやってきましたよ。
ファイル書き込みを非同期でやりたいのでIO::AIO試してみました。
Coro::AIO使えばcallback形式ではなく綺麗に書けるようだけれどとりあえずIO::AIOの書き方で。
結果は、↓とかってなるから非同期的な感じだなぁっていうのはわかるんですが、
AnyEventの $cv->send , $cv->recv をとっぱらっても同じように動く。
なぜ?
Event loop integrationっていうのはそれが無い状態に対して、何してくれるの?
PLAIN TEXT
CODE:
perl try/anyevent_aio.pl
[pre] at try/anyevent_aio.pl line 5.
[aft] at try/anyevent_aio.pl line 13.
[opened]0
[opened]1
[opened]2
[opened]3
[opened]4
[opened]5
[opened]6
[opened]7
[opened]8
[opened]9
[wrote]0
[wrote]1
[wrote]2
[wrote]4
[wrote]6
[wrote]3
[wrote]7
[wrote]5
[wrote]8
[closed]9:0
[closed]8:1
[closed]7:2
[closed]6:4
[closed]5:6
[closed]4:3
[closed]3:7
[closed]2:5
[wrote]9
[closed]1:8
[closed]0:9
Hoppyいいよ
Hoppyいい
シリコンバレー行った時に参加した Flash Game Summit とかでも、FITC Toronto 2009でも、マルチプレーヤーFlash熱そうだったので自分の周りではきてる。
汎用的なXMLSocketサーバを書いた
POEとか使ったシングルプロセスシングルスレッドのデーモンでデータベース扱う時はどうするのがいいんだろう?
裏にDB扱うためだけにhttpサーバ置いてデーモンからはそれに非同期でhttpリクエストするという方法がある。
ということでまずはauthを非同期にしてみました。
http://github.com/mash/Hoppy/tree/master
$c->handlerってtcp周りのイベントのハンドラってことでいいのかな。
PLAIN TEXT
PERL:
$c->regist_service(
auth => 'MyApp::Auth',
);
ってやると $c->handler->{auth} に入るのは気のせいかと思いたかったので
s/handler/service/ してみました。めっちゃコアっぽいけどまぁいいか。
ごめんねColinちゃん。
yokohama.pm 4回目行ってきた&DI
いいまとめはこちら
http://d.hatena.ne.jp/hiratara/20090417/1239946298
DIがよくわからなかったなぁ
Bread::Boardの感じだと結局コンストラクタに引数与えるのを書き方かえるだけに見えるけど
外部のxmlファイルに記述したくない、って牧さんは言ってたけど、
フォーマットがxmlかどうかは別として、javaをちょいちょい使ってる時の認識では、
別ファイルであることがDIの本質なんじゃないのかなぁと思っていた。
javaはコンパイルの必要な言語で、
xmlを変えてもリコンパイルが必要無い、
ってメリットがjavaではある
使うときにオブジェクトを渡して、使う側ではインターフェースしか使ってない、
こういうのもDIっていうかな
これをいい感じに書けるのがBread::Boardなのかな
PLAIN TEXT
PERL:
package A;
use Moose;
has cache => ( isa => 'Cache::Cache', is => 'rw', required => 1, default => sub { new Cache::FileCache } );
sub fetch_something {
my ($self, $key) = @_;
my $ret = $self->cache->get($key);
if ( ! defined($ret) ) {
$ret = fetch($key);
$self->cache->set( $key, [...]
preventing cache stampedes
webサイトとかで、重いSQLを使ったページを快適に表示するために、重いSQLの結果をキャッシュするためにmemcachedとかをよく使います。
キャッシュの有効期限が切れた後に、大量のリクエストに対応して大量の重いSQLが走ると困るので、どうしよう。
これをthundering herd 問題といったり、cache stampede, database stampedeというそうです。
キャッシュ切れた後にががっとくるやつ、です。
A. キャッシュの有効期限が切れる
B. SQL発行
C. SQLの結果を受け取る
D. キャッシュにつっこむ
A-D.の間に大量のリクエストが来ると、重いSQLが走るので困ります。
Kazuhookuさんが書いています。
キャッシュシステムの Thundering Herd 問題
対策としては、以下の2種類の手段があります。
* バックエンドへの同一リクエストを束ねるような仕組みを実装する
* エクスパイヤ以前の残存時間が一定以下となった段階で、キャッシュエントリのアップデートを開始する
昨日memcachedの勉強をしている時のFAQの資料にもいろいろ書いてあったのですが、
いくつか対策方法があるようです。
How to prevent clobbering updates, stampeding requests
The easiest answer is to avoid the problem. Don't set caches to expire, and update them via cron, or as data is updated. This does not eliminate [...]
Catalyst::Plugin::DumpRequired
fastcgi(Catalyst,perl)+lighttpdでよくウェブアプリをつくるのですが
Copy on Writeの恩恵を受け、メモリを節約するために、
fastcgiの親プロセスで網羅的にperlモジュールを読み込んでおき、
子プロセスの親プロセスとで共有するメモリを増やしたくなります。
子プロセスでどんなモジュールをrequireしてるのか?
がわかればMyApp.pmでuseしておくことで親プロセスで読み込めます。
それをわかりやすくするためのCatalystプラグインを作りました。
MyApp.pmで
PLAIN TEXT
PERL:
__PACKAGE__->setup(do {
my @plugins;
push @plugins, 'StackTrace', 'DumpRequired' if $ENV{CATALYST_DEBUG};
@plugins;
});
とかするといいと思います。
いろんなパスを通るようにrequest投げると $c->log->debug にrequireしたモジュールが出てきます。
以下参考にさせていただきました。
mod_perlで親プロセスとのCopy on Writeな共有メモリを増やす方法
Template-Plugin-AddTimeというのをつくった
codereposに置きました
Template::Plugin::AddTime - TT filter plugin to add file modified time
# 正直あまり自信はないのですが
jsとかcssとか、あまり変化しないのでブラウザにしっかりキャッシュしてほしいけど、
ファイルを更新した時には再読み込みしてほしいって時に、
expiresヘッダをつけないと、ブラウザの実装によってリクエストが来たり来なかったりして
cssを更新したのに読み込まないクライアントは表示が崩れたりします。
なのでexpiresヘッダをつけてしっかりブラウザにキャッシュして欲しいって時に、
ファイルの更新時刻をくっつけたりバージョン番号をくっつけたりすることがあります。
これはファイルの更新時刻をくっつけるためのTT Filterプラグインです。
こんなふうに使います。
# or with a base path
[% USE AddTime('tmpl/static') -%]
[% '/js/prototype\.js' | addtime -%]
# adds modified time of tmpl/static/js/prototype\.js
/js/prototype\.js\?1231163490
こうしておいて、lighttpdの設定で
expire.url = (
"/js/" => "access 1 years",
)
とかってすれば
Expires: Fri, 01 Jan 2010 00:42:29 GMT
Cache-Control: max-age=31104000
こんなヘッダがくっついてくる。
svnでソース管理してる時には [...]
cpan authorになりました
mashあいてたー
CPAN Recent Changesに自分の名前のるのうれしいなー
意外に簡単でびびる。PAUSEも2日くらいで来たなぁ。
最初からshipitのお世話になりました。いい。
最初のモジュールは
http://search.cpan.org/~mash/Lingua-JA-Yomi-0.01/lib/Lingua/JA/Yomi.pm
http://svn.coderepos.org/share/lang/perl/Lingua-JA-Yomi/trunk/
ちょいちょいつくったものをupしてみますよ。
誰かが便利になるといいですなぁ。
よろしくお願いいたしますm(._.)m
Lingua::JA::Yomi 日本語読みモジュールをつくった
英語を手軽に日本語にしたいと思ってつくった。
今あるモジュールだと、Lingua::JA::Kanaっていうのがあってローマ字→ひらがな変換はできる。
PLAIN TEXT
PERL:
#!/usr/bin/env perl
use strict;
use warnings;
use Lingua::JA::Kana;
use utf8;
use Encode;
my $hiragana = romaji2hiragana('aerosmith');
print 'hiragana: '.Encode::encode('utf8',$hiragana)."\n";
# hiragana: あえろsみth
でもローマ字にあてはまらないのは上記のように残念な感じになるので、
Lingua::JA::Yomi ってのをつくった。
http://coderepos.org/share/browser/lang/perl/Lingua-JA-Yomi/trunk
PLAIN TEXT
PERL:
#!/usr/bin/env perl
use strict;
use warnings;
use Test::More qw/no_plan/;
use utf8;
use Lingua::JA::Yomi;
my $converter = new Lingua::JA::Yomi;
is( $converter->convert('aerosmith'), 'エアロウスミス','aerosmith');
ルー語インスパイアなので辞書は
Bilingual Emacspeak Project
のを使わせていただいております。
今、あの紫の本を読んでるので、再帰処理で少しずつ変換していくとこを実装するのがたのしかったー
PLAIN TEXT
PERL:
# pass in utf8 flagged string
sub convert {
my ($self, $roman, $remainder) = @_;
$remainder ||= '';
print [...]
[perl]TheSchwartzのWorkerにIDをつける
こういうときはどうやってやるのがいいのかなぁ
・なんか限れられた数のリソース(例えば、DISPLAYとか?、)があって、リソースにはTheSchwartzのWorkerを1対1対応させて、Workerを動かしたい
・Jobをinsertする方はどのWorkerに仕事させるか意識したくない
Jobをinsertする方はこんな
feeder.pl
PLAIN TEXT
PERL:
#!/usr/bin/env perl
use strict;
use warnings;
use FindBin;
use File::Spec;
use YAML::Syck;
use TheSchwartz;
my $conf = LoadFile( File::Spec->catfile($FindBin::Bin, '..', 'myapp.yml') );
my $pool = TheSchwartz->new( %{ $conf->{TheSchwartz}{args} } );
$pool->insert('MyApp::SleepWorker');
1;
0~9秒間の間でランダムな秒数寝るだけのWorkerを起動させるpl。
こいつを複数プロセス動かして、それぞれは自分に割り当てられてるリソースを知っている、っていう状態をつくりたい。
workの引数になんか入れてもだめっぽいので、、
worker.pl
PLAIN TEXT
PERL:
#!/usr/bin/env perl
use strict;
use warnings;
use FindBin;
use File::Spec;
use lib File::Spec->catfile( $FindBin::Bin, '..', 'lib' );
use YAML::Syck;
use TheSchwartz;
use MyApp::SleepWorker;
my $conf = LoadFile( File::Spec->catfile($FindBin::Bin, '..', 'myapp.yml') );
my $worker = TheSchwartz->new( %{ $conf->{TheSchwartz}{args} } );
$worker->can_do('MyApp::SleepWorker');
$worker->work;
1;
環境変数なのかなぁ
PLAIN TEXT
PERL:
package [...]
[git]gitに入門してみた
svn使ってます
myappの下には、trunk, tags, branches がある状態
PLAIN TEXT
CODE:
git svn init -s https://path/to/myapp/ myapp
cd myapp
git svn fetch
これに時間かかる
PLAIN TEXT
CODE:
git checkout trunk
これがちょっぱやでびびるなぁ
編集した後、
PLAIN TEXT
CODE:
git add file1 file2 file3
git commit -m"[edited file1,2,3]"
ローカルへのコミットは気軽にしていいみたい
perlのcatalystアプリで、myapp_local.yml とかもろもろローカルで変更しているのがあるので、
そいつらがある状態で
svnにコミットしようとすると、
PLAIN TEXT
CODE:
Cannot dcommit with a dirty index. Commit your changes first, or stash them with `git stash'.
って怒られる
PLAIN TEXT
CODE:
git stash
ってやるとmyapp_local.ymlとかdirtyなファイル達がどっかに退避されるみたい
そこで
PLAIN TEXT
CODE:
git svn dcommit
するとsvnにコミットできる
PLAIN TEXT
CODE:
git stash apply [...]
hilight2skype irssiのhilightをSkypeへ通知
みんなircで呼ばれた時、どうやって気づいてるんだろう?
mash:
って呼ばれてもputtyは3つのディスプレイの1つに表示されてるだけなので気づけないです。
http://im.kayac.com/
をtypesterが使ってるの見てて、やっぱデスクトップでぴこーんってされるのはいいな、と思ってたんだけど
GoogleTalk使ってないしなぁ、Skype版つくるべ、ってことでつくりました。
Skype4IRCってのもありますが、
こちらは、Skypeに届いたチャットメッセージをircに転送するもの。
hilight2skypeとは逆ですね。
■動かし方
skype for linuxインストール
skype4py(skypeAPIのpythonラッパー)インストール
以下をチェックアウト
http://coderepos.org/share/browser/lang/perl/irssi/scripts/hilight2skype.pl
http://coderepos.org/share/browser/lang/perl/irssi/scripts/hilight2skype/send_chat_message.py
$HOME/.irssi/scripts/autorun に入れる
hilight2skype.pl のskype名を自分のに修正
linuxでskypeを立ち上げるんですが、skypeを立ち上げるのにDISPLAY環境変数が必要なので、
PLAIN TEXT
CODE:
Xvnc -query localhost -geometry 1024x768 -depth 16 -fp /usr/share/fonts/X11/100dpi/,/usr/share/fonts/X11/misc securitytypes=none
vncサーバ立ち上げる
一度つないでシェルから
PLAIN TEXT
CODE:
echo $DISPLAY
ってすると、
うちは
127.0.0.1:0.0
になってたので、
vncクライアントは落として、コンソールから
PLAIN TEXT
CODE:
export DISPLAY=127.0.0.1:0.0
./skype-2.0.0.6/skype
ってやるとskype立ち上がる
準備OK
irssi起動すると hilight2skype ってscriptを自動でロードしてくれる
hilight指定されてるメッセージが流れてくると、
skypeがぴこーん!
PLAIN TEXT
CODE:
[irssi #チャンネル名] <送ってきた人> ircのメッセージ
って感じのメッセージがSkypeに届きます。
初めてちょっとだけpython書いたー
vncサーバとDISPLAY環境変数付きでSkype起動できればいいので、
daemontoolsで監視できそう。
なんかサービスつくる?
snmp/mrtgでプロセスの開いているファイルディスクリプタ数を監視
してみる
PLAIN TEXT
PERL:
#!/usr/bin/perl
use strict;
use warnings;
use Unix::Lsof;
use Unix::PID;
my $pid = Unix::PID->new();
my $red5_pid = $pid->get_pidof('search for a process by this string');
unless ( $red5_pid ) {
print '0';
exit;
}
my ( $output, $error ) = lsof( '-p', $red5_pid, '-w' );
my @vals = values %{$output};
print scalar @{ $vals[0]{files} };
snmpd.conf に
PLAIN TEXT
CODE:
exec fd_mon /path/to/fd_mon.pl
mrtg.cfg に
PLAIN TEXT
CODE:
Target[fd]: .1.3.6.1.4.1.2021.8.1.101.1&.1.3.6.1.4.1.2021.8.1.101.1:public@localhost
MaxBytes[fd]: 2000
YLegend[fd]: File Descriptors
ShortLegend[fd]:
LegendI[fd]: [...]
dbicadminの使い方memo
DBIx::Class::ResultSetのdelete_allを使って消してくれるから使うべし
memo
dbicadmin --op=delete --schema=MyClass::Schema --class=MyClass::Schema::TableName --connect='["dbi:mysql:dbname","username","password",{"on_connect_do":["SET NAMES utf8"]}]' --where='{"me.id":"338"}'
何行消すかconfirmしてくれる
そのまんまだと依存モジュールが代わっちゃったのか、--op=selectの時にみれないから
/usr/local/bin/dbicadmin
の99行目とかをコメントアウトして自分でダンプしてみる
use YAML;
print Dump(\@fields)."|n";