2015年10月15日木曜日

Dockerfile ビルド時間短縮 tips

ubuntu や centos などの dockerhub イメージを使って Dockerfile を書くとき、大抵の場合 apt-get update や yum update を先頭に書きます。

FROM ubuntu:latest
RUN apt-get update && apt-get -y upgrade && apt-get clean

毎回たくさんのダウンロードが実行される時間を省略するために以下をやっておきます。

ホストOS 上で docker run
$ docker run -it --name t1 ubuntu:latest 
コンテナで apt-get update など実行して exit
# apt-get update && apt-get -y upgrade && apt-get clean
# exit
同じ名前でイメージ作成
$ docker commit t1 ubuntu:latest ← 同じ名前でイメージ更新
$ docker rm t1 ← 仮コンテナを削除
これで Dockerfile の FROM はいじらずにビルド時間を短縮できます。

2015年4月22日水曜日

技術ネタは Qiita とここで 2重投稿してみる

mysql の procedure(プロシージャ)で add partition

サンプルテーブル log。主キーは id 一つ。
create table log (
    id              bigint          not null auto_increment,
    message         text            ,
    created_at      int             not null,
    primary key (id)
) engine = InnoDB;
このままだとパーティション作成できないので主キーをいじる
alter table log
    modify id bigint not null,
    drop primary key;
alter table log
    add primary key (id, created_at),
    modify id bigint not null auto_increment;
パーティションを 1つ追加しとく。
alter table log partition by range (created_at) (
    partition pmin values less than (0)
);
プロシージャを作って 3年分のパーティション追加。
drop procedure if exists add_monthly_partition;
delimiter //
create procedure add_monthly_partition(
    in table_name text,
    in date_func text,
    in years int)
begin
    select now() into @d;
    select date_add(@d, interval years year) into @last;

    while @d < @last do
        select concat(
            'alter table ', table_name,
            ' add partition (partition p',
            date_format(@d, '%Y%m'),
            ' values less than (', date_func, '(''',
            date_format(@d, '%Y-%m-01'), ''')))'
        ) into @ddl;
        select @ddl;
        prepare stmt from @ddl;
        execute stmt;
        deallocate prepare stmt;
        select date_add(@d, interval 1 month) into @d;
    end while;
end //
delimiter ;

call add_monthly_partition('log', 'unix_timestamp', 3);

2014年9月4日木曜日

Java クラスパスを再帰的に設定

昔は こんな スクリプトを使っていましたが、今はコレ1行。

CLASSPATH=.`find lib -name "*.jar" -exec echo -n :{} \;`

2013年8月8日木曜日

UTF-8 BOM ファイルを探す

メモメモ find ./tmpl -name "*.html" -type f | grep -v .svn | xargs file | grep BOM とか。

2011年9月3日土曜日

perl のマルチスレッド

ども。ある案件で perl の マルチスレッドを使うことになりました。

use threads;
my @ts;
for (1..5) {
   my $t = threads->create(sub {
       # some code
       …
       # 1つのスレッド処理完了 *1

   });
   push(@ts, $t);
}
eval { $_->join } for @ts;


# 終了処理 *2

このようなコードを書いたのですが、どれかのスレッドの「# 1つのスレッド処理完了 *1」のタイミング「Scalars leaked: 1」が発生します。
このエラーが発生するとまだ「# 終了処理 *2」は実行されず、メインプロセスごと落ちてしまいます。
まだ実行中のスレッドもメインプロセスとともに落ちます。

再現率は 100%ではないのですが、スレッドでやる仕事時間が長ければ長いほど「Scalars leaked: 1」は 100%に近い状態で発生していました。

スレッドの呼び出し方法が悪いのかと思い 事前に関数定義したり
my $runnable = sub {
   # some coe
};

my @ts;
for (1..5) {
   my $t = threads->create($runnable);
   push(@ts, $t);
}

eval { $_->join } for @ts;


こんなことしたり
my @ts;
for (1..5) {
   my $t = threads->create(\&runnable);
   push(@ts, $t);
}
eval { $_->join } for @ts;

sub runnable {
   # some coe
};


こんなことしたり、色々試しましたが症状は改善しません。
my @ts;
for (1..5) {
   my $t = threads->create('runnable');
   push(@ts, $t);
}
eval { $_->join } for @ts;

sub runnable {
   # some coe
};


perl 5.8.8 を使っていたので perl 5.14.1 にもしてみましたが、「Scalars leaked: 1」の代わりに「Segmentation fault」が発生するようになりました。


最終的に以下の方法でひとまず解決しました。perl 5.10.x あたりから登場する threads::shared を使います。

use threads;
use threads::shared;

my %alive :shared;
my $keepalive :shared;

$keepalive = 1;
for my $i (1..5) {
   $alive{$i} = time();
   my $t = threads->create(sub {
       my $ii = shift;
       # some code
       $alive{$ii} = time(); # この時間にまだ生きいることを知らせる
       # some code
       $alive{$ii} = time(); # この時間にまだ生きいることを知らせる
       # some code
       delete $alive{$ii}; # このスレッドの処理が終わったので %alive を消す
       while (1) {
           last unless $keepalive; # 他のすべてのスレッドが終了し、メインスレッドの「# 終了処理 *2」が終わるまで待機
           sleep(2);
       }
   }, $i);
   $t->detach; # join しない
}


# join の代わりに %alive が全部なくなるまで待つ

while (1) {
   my @keys = keys %alive;
   last if @keys == 0; # %alive が無くなったら終了
   my $now = time();
   for my $key (@keys) {
       my $a = $alive{$key} or next;
       if ($now - $a > 30) {
            # %alive 処理ができずに落ちたスレッドがいるかも知れないので、最後の生存通知から 30秒以上たってる場合は以後処理しない。
           warn "timeout $key";
           delete $alive{$key};
       }
   }
   sleep(5);
}

# 終了処理 *2
# some code

$keepalive = 0; # すべてのスレッドに関数を終了して良いことを知らせる。このあとどこかで Segmentation fault が発生するかも知れないが、構わないものとする。


たぶん、大丈夫だと思う。美しくはないですが。。
あやうく Java で書きなおそうかと思いました。

2011年8月23日火曜日

memcached でキーの列挙 (3)

前回のエントリ memcached でキーの列挙 (2)

こんなん作りました。memcached-tool ぽく。既にあったらすません~。
http://code.google.com/p/memcached-keys/