2012年7月15日日曜日

nginx 1.2 のインストール

ユーザの追加


# useradd -s /sbin/nologin nginx

インストール


# ./configure \
--user=nginx \
--group=nginx \
--prefix=/opt/nginx-1.2.2 \
--with-pcre \
--with-http_ssl_module \
--with-http_realip_module \
--with-http_addition_module \
--with-http_xslt_module \
--with-http_sub_module \
--with-http_dav_module \
--with-http_flv_module \
--with-http_gzip_static_module \
--with-http_random_index_module \
--with-http_secure_link_module \
--with-http_stub_status_module
# make
# make install

起動スクリプトの準備


# vi /etc/init.d/nginx

=== ここから
#!/bin/sh
#
# nginx - this script starts and stops the nginx daemon
#
# chkconfig:   - 85 15
# description:  Nginx is an HTTP(S) server, HTTP(S) reverse \
#               proxy and IMAP/POP3 proxy server
# processname: nginx
# config:      /etc/nginx/nginx.conf
# config:      /etc/sysconfig/nginx
# pidfile:     /var/run/nginx.pid

# Source function library.
. /etc/rc.d/init.d/functions

# Source networking configuration.
. /etc/sysconfig/network

# Check that networking is up.
[ "$NETWORKING" = "no" ] && exit 0

#nginx="/usr/sbin/nginx"
nginx="/usr/local/nginx/sbin/nginx"
prog=$(basename $nginx)

#NGINX_CONF_FILE="/etc/nginx/nginx.conf"
NGINX_CONF_FILE="/usr/local/nginx/conf/nginx.conf"

[ -f /etc/sysconfig/nginx ] && . /etc/sysconfig/nginx

lockfile=/var/lock/subsys/nginx

make_dirs() {
   # make required directories
   user=`nginx -V 2>&1 | grep "configure arguments:" | sed 's/[^*]*--user=\([^ ]*\).*/\1/g' -`
   options=`$nginx -V 2>&1 | grep 'configure arguments:'`
   for opt in $options; do
       if [ `echo $opt | grep '.*-temp-path'` ]; then
           value=`echo $opt | cut -d "=" -f 2`
           if [ ! -d "$value" ]; then
               # echo "creating" $value
               mkdir -p $value && chown -R $user $value
           fi
       fi
   done
}

start() {
    [ -x $nginx ] || exit 5
    [ -f $NGINX_CONF_FILE ] || exit 6
    make_dirs
    echo -n $"Starting $prog: "
    daemon $nginx -c $NGINX_CONF_FILE
    retval=$?
    echo
    [ $retval -eq 0 ] && touch $lockfile
    return $retval
}

stop() {
    echo -n $"Stopping $prog: "
    killproc $prog -QUIT
    retval=$?
    echo
    [ $retval -eq 0 ] && rm -f $lockfile
    return $retval
}

restart() {
    configtest || return $?
    stop
    sleep 1
    start
}

reload() {
    configtest || return $?
    echo -n $"Reloading $prog: "
    killproc $nginx -HUP
    RETVAL=$?
    echo
}

force_reload() {
    restart
}

configtest() {
  $nginx -t -c $NGINX_CONF_FILE
}

rh_status() {
    status $prog
}

rh_status_q() {
    rh_status >/dev/null 2>&1
}

case "$1" in
    start)
        rh_status_q && exit 0
        $1
        ;;
    stop)
        rh_status_q || exit 0
        $1
        ;;
    restart|configtest)
        $1
        ;;
    reload)
        rh_status_q || exit 7
        $1
        ;;
    force-reload)
        force_reload
        ;;
    status)
        rh_status
        ;;
    condrestart|try-restart)
        rh_status_q || exit 0
            ;;
    *)
        echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload|configtest}"
        exit 2
esac
=== ここまで

nginx の起動


# /etc/init.d/nginx start

2012年7月7日土曜日

MySQL 5.5.24 をインストールする。

mysql ユーザの作成

$ groupadd mysql
$ useradd -g mysql -d /home/mysql mysql

すでに mysql ユーザが存在している場合は,useradd の代わりに usermod を使用する。
これは,自分の環境が /home 配下へのディスク割り当てが多かったため。

$ usermod -g mysql -d /home/mysql -m mysql

-m オプションは,既存のユーザディレクトリを -d で指定した場所へ変更する。

cmake のインストール

$ yum install cmake

mysql のインストール

5.5 からは,configure ではなく,cmake にてビルドする方法になったようなので,以下のようにオプションを指定して実行する。

$ cmake . -DCMAKE_INSTALL_PREFIX=/home/mysql/5.5.24/master \ 
-DMYSQL_DATADIR=/home/mysql/5.5.24/master/data \
-DDEFAULT_CHARSET=utf8 \ 
-DDEFAULT_COLLATION=utf8_general_ci \ 
-DENABLED_LOCAL_INFILE=true \ 
-DWITH_EXTRA_CHARSETS=all \ 
-DWITH_INNOBASE_STORAGE_ENGINE=1 \ 
-DWITH_READLINE=ON \ 
-DSYSCONFDIR=/home/mysql/5.5.24/master

あとは,いつもの通り。

$ make
# make install

インストールが済んだら,データベースの初期化を行う。

/home/mysql/scripts/mysql_install_db \
  --user=mysql \
  --basedir=/home/mysql \
  --datadir=/home/mysql/data


参考:
UbuntuでMySQL5.5を再インストールする方法と複数起動させる方法 http://namakesugi.blog42.fc2.com/blog-entry-120.html

[DB] CentOS に MySQL をソースコードからインストール
http://codenote.net/db/mysql/229.html

2012年3月25日日曜日

[ruby] ruby, rubygems, rails のインストールメモ

ruby をソースからインストールする際に若干ハマってしまったので,手順を残しておきます。

環境は,次の通りです。
  • fedora 15
  • ruby 1.9.3-p125
  • rubygems 1.8.21
  • rails 3.2.2
  • sqlite3 1.3.5

libyaml のインストール

yaml のパーサが変更されたとかで,そのままインストール作業を進めていたら,こんな警告が出ました。
It seems your ruby installation is missing psych (for YAML output). To eliminate this warning, please install libyaml and reinstall your ruby.
そのための対応として,libyaml をインストールします。

$ wget http://pyyaml.org/download/libyaml/yaml-0.1.4.tar.gz
$ tar xvzf yaml-0.1.4.tar.gz
$ cd yaml-0.1.4
$ ./configure
$ make
# make install

ruby のインストール

上記のインストールが済んだら,次は ruby です。
$ wget ftp://ftp.ruby-lang.org/pub/ruby/1.9/ruby-1.9.3-p125.tar.gz
$ tar xvzf ruby-1.9.3-p125.tar.gz
$ cd ruby-1.9.3-p125
$ ./configure --prefix=/opt/ruby-1.9.3 \
  --with-opt-dir=/usr/local/lib \
  --enable-shared \
  --enable-option-checking
$ make
# make install


rubygem のインストール

続いて,rubygem を入れます。
$ wget http://production.cf.rubygems.org/rubygems/rubygems-1.8.21.tgz
$ tar xvzf rubygems-1.8.21.tgz
$ cd rubygems-1.8.21
$ ./configure
$ make
# make install


さてこれで,あとはすんなりと rails を入れてアプリを作れるかなと思っていたら,途中で幾つかエラーが出たので,事前準備をしておきます。

openssl のインストール

# yum install openssl-devel
# cd ruby_src_dir/ext/openssl
# ruby extconf.rb
# make
# make install

sqlite3 のインストール

# yum install sqlite-devel
# gem install sqlite3 -v '1.3.5'

これであとは,rails のインストールを行います。

ruby on rails のインストール

# gem install rails

gem list を叩いて,rails (3.2.2) が表示されればOKです。
準備ができたので,アプリを作成して起動します。

$ rails new myapp
--- 途中で以下のように促されるので,パスワードを入力する。
Enter your password to install the bundled RubyGems to your system:
$ cd myapp
$ rails server

あとは,http://localhost:3000 でアプリにアクセスできます。

[scala]scala でリトライ処理

http://d.hatena.ne.jp/Yoshiori/20120315/1331825419 の記事を読んで,
scala でリトライ処理を書いてみました。
例外処理は,Option に翻訳しており,処理に失敗したときは,None になります。

object Retry {

  def run[A](f: => A)(count: Int, interval: Int = 3000): Option[A] = { 
    exec(f) match {
      case result: Some[_] => result
      case None if count >= 1 => Thread.sleep(interval); run(f)(count - 1, interval)
      case None => None
    }   
  }
                                                                                                                                                                       
  private def exec[A](f: => A): Option[A] = { 
    try {
      Some(f)
    } catch {
      case _ => None
    }   
  }

}

使い方は,次のような感じで。

import org.scalatest.FunSpec

class RetrySpec extends FunSpec {

  describe("Usage") {
    it("通常呼び出し") {
      val result = Retry.run {
        1 + 2
      }(1)
      assert(result === Some(3))
    }
                                                                                                                                                                       
    it("1秒間隔で3回リトライ") {
      val result = Retry.run {
        "some error occured"(999)
      }(3, 1000)
      assert(result === None)
    }
  }
}

ソースコードはこちら。
https://github.com/dnoguchi/retry-handler

2012年1月8日日曜日

[scala][play2.0] Anorm のサンプル(1)

playframework に付いてくるDBアクセスモジュール(ORマッパーではない) Anorm を使ってみました。
よくわかっていなところが多いですが、メモ書きしておきます。

テストプロジェクトの構築


今回使用した環境は、play2.0 になります。インストール手順については省きますので、他のサイトをご覧になって、各自準備してください。
リポジトリは、こちらです。HEADを使用しています。
https://github.com/playframework/Play20

はじめに、動作確認用のテストプロジェクトを作成します。
$ play new anorm-sample

テーブルとモデルの準備


使用したテーブルは次の通り。
CREATE TABLE user (
    id bigint NOT NULL AUTO_INCREMENT, 
    email varchar(255) NOT NULL, 
    password varchar(255) NOT NULL, 
    fullname varchar(255) NOT NULL, 
    isAdmin boolean NOT NULL, 
    PRIMARY KEY (id)
);

ファイル名は 1.sql として、arnom-sample/db/evolutions/default/1.sql に配置します。
テスト時にはこのテーブルを使うことになります。
(完全な内容は、github においておきます)

CREATE TABLE user (
    id bigint NOT NULL AUTO_INCREMENT, 
    email varchar(255) NOT NULL, 
    password varchar(255) NOT NULL, 
    fullname varchar(255) NOT NULL, 
    isAdmin boolean NOT NULL, 
    PRIMARY KEY (id)
);


テーブルに対応するモデルを実装します。

まずは、caseクラスです。Models.scala ファイルに定義しました。
import anorm._

case class User(
  id: Pk[Long] = NotAssigned, 
  email: String, password: String, fullname: String, isAdmin: Boolean)


ここで、Pk[Long] とありますが、これは、anorm パッケージに定義されている抽象クラスで、Option のようなものみたいです。
id が存在するかしないかを表現しています。実際に値が存在する場合(DBから取得したデータなど)は、
case class Id[ID](id: ID) extends Pk[ID] 
となり、
値が存在しない場合(DBに登録前のデータなど)は、
case object NotAssigned extends Pk[Nothing] 
として扱います(IDは型パラメータ)。
上記では、デフォルト値として、NotAssigned を割り当てています。

次に、Userオブジェクトを定義します。
object User {
  // 変数名は何でも構いません。
  val simple = {
    get[Pk[Long]]("user.id") ~
    get[String]("user.email") ~
    get[String]("user.password") ~
    get[String]("user.fullname") ~
    get[Boolean]("user.isAdmin") map {
      case id ~ email ~ password ~ fullname ~ isAdmin => User(id, email, password, fullname, isAdmin)
    }
  }
}


ここで、simple という変数を定義しましたが、これを用いて、SQL実行結果をパースすることになります(取得された値をcaseクラスに割り当てる)。
メソッドが何もないので、登録と検索を行う処理を定義します。
import play.api.db._
import play.api.Play.current

object User {
  
  def insert(user: User) = {
    DB.withConnection { implicit connection =>
      SQL(
        """
          insert into user(email, password, fullname, isAdmin) 
          values ({email}, {password}, {fullname}, {isAdmin})
        """
      ).on(
        'email -> user.email, 
        'password -> user.password, 
        'fullname -> user.fullname, 
        'isAdmin -> user.isAdmin
      ).executeUpdate()
    }
  }

  def findById(id: Long): Option[User] = {
    DB.withConnection { implicit connection =>
      SQL("select * from user where id = {id}").on('id -> id).as(User.simple.singleOpt)
    }
  }

  def findAll(): Seq[User] = {
    DB.withConnection { implicit connection =>
      SQL("select * from user").as(User.simple *) 
    }
  }
  
}

ソースを見れば何となく分かりそうな感じもすると思いますが、個別に補足していきます。

各メソッドは DB.withConnection で始まっていますが、これがお決まりの書き方で、java.sql.Connection を必要とするような処理ブロックを受け取ります。
このブロックの中で、発行するSQL文を組み立てて、実行することになります。
また、一連の処理をトランザクション切って実行したい場合は、DB.withTransaction を利用することになります(今回は使用しませんでしたが、そのうち書こうと思います)。

メソッド内にて発行したいsql文は anorm.SQL を使用して組み立てることになり、プレースホルダー部分は '{' と '}' で囲みます。
プレースホルダーに割り当てたい値は、on メソッドを呼び出した中でマッピングを列挙していくことになります。
基本的には、プレースホルダーの文字列に相当する scala.Symbol と、メソッドの引数で受け取った値などを組みとしてタプルを構成すればよいです。
ちなみに、anorm のソースを見てみると、scala.Symbol でなくてもよいようで、別のオブジェクトの場合は、toString の結果を使用してタプルを構成するみたいですね。
とはいっても、通常は常套手段に則り、シンボルを使用するのがいいのではないでしょうか(シンボルではない値を使用する場合があるとすれば、条件により更新対象のカラム名を変えるときとか?)

組み立てたクエリを実行するには、登録・更新系の場合であれば executeUpdateメソッドを、参照系の場合であれば asメソッドを呼び出すことになります。
それぞれ最終的には、java.sql.PreparedStatement の executeUpdateメソッドや executeQueryメソッドを呼び出しているようです。

登録・更新系の処理であれば実行結果の行数をそのまま返せばよいと思いますが、参照系の場合は最初に定義した simple を利用して、java.sql.ResultSet の内容を適切なオブジェクトに変換して返す必要があります。上記のサンプルでいうと、id を指定してデータを取得する findById においては、User.simple.singleOpt メソッドを呼び出して、Option でラップして1件返すようにしています。また、登録済みのデータすべてを取得する findAll においては、User.simple.* メソッドを呼び出して、Seq[User] を返すようにしています(実際には、List)。

ちょっと長くなってきましたので、テストケースの説明などは省略します。今回作成したサンプルコードは以下においておきます。
https://github.com/dnoguchi/anorm-sample

参考URL:
playframework 2.0 のリポジトリ
https://github.com/playframework/Play20
Play で Scala を使う方法 ー データモデルの最初のイテレーション.
http://playscalaja.appspot.com/documentation/0.9.1/guide2
※play1.x系のscalaモジュールを使用した記事なので、本当に参考までと考えたほうがよいです。