nigakyのブログ

雑多なメモです。

git レポジトリを http で公開するときの注意点

基本的にはgitレポジトリをhttpで公開する -- BONNOH FRACTION 14の通りにやればできます。
ただ、公開したレポジトリに push も出来るようにする場合、push するたびにサーバ側で "git update-server-info" しないと、HTTP経由で最新のリビジョンが見えません。

以下のようにすると、pushされるたびに自動的に "git update-server-info" してくれます。

# cd /path/to/git-repository.git
# mv hooks/post-update.sample hooks/post-update

# この他にもコミット後に自動でメールが飛ぶフックなどのテンプレが用意されてますね。

詳しくはGitに書いてありました。

Python で文字列をN文字ずつに分割する

Pythonの文字列に対する split は、指定したセパレータで分割することはできますが、指定文字数で分割することはできません(と思います)。そこでPythonで(できればPython的に)どう書いたらよいか考えてみました。

1文字ずつたどりながら処理する

ぱっと思いつくのはこの方法です。
指定文字数に達したら結果用のリストに追加し、そのリストを返します。

def splitStr(str, num):
    s = ''
    j = 0
    l = []
    for i in str:
        s += i
        j += 1
        if j == num:
            l.append(s)
            j = 0
            s = ''
    if s:
        l.append(s)
    return l

zip で Python 的に処理する

上の方法はあまり Python的ではありませんでした。
zipを使う方がPython的かつ高速らしいので、zipを使う方法を考えてみました。

def splitStr2(str, num):
    l = []
    for i in range(num):
        l.append(str[i::num])
    l = ["".join(i) for i in zip(*l)]
    rem = len(str) % num  # zip で捨てられた余り
    if rem:
        l.append(str[-rem:])
    return l

もっとうまく書けそうですが、なんとなくPython的な気がします。

性能比較

せっかくなので性能を比較してみました。
timeit を利用して 10 万回呼び出した時間を計測しています。

$ python splitStr.py
splitStr: 3.60764718056    # シンプルな方法
splitStr2: 2.22185182571   # zip を使った方法

結果は上の通り、zipを使った方法が 2.2 秒とシンプルな方法の 1.5 倍くらい高速でした。
zipはうまく使うと強力ですね。


以下は今回の計測に利用したスクリプト全文です。

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys, timeit

def splitStr(str, num):
    s = ''
    j = 0
    l = []
    for i in str:
        s += i
        j += 1
        if j == num:
            l.append(s)
            j = 0
            s = ''
    if s:
        l.append(s)
    return l

def splitStr2(str, num):
    l = []
    for i in range(num):
        l.append(str[i::num])
    l = ["".join(i) for i in zip(*l)]
    rem = len(str) % num  # zip で捨てられた余り
    if rem:
        l.append(str[-rem:])
    return l

if __name__ == '__main__':
    """ "a" 100 文字を 2 文字ずつのリストに分割
    それを 10 万回繰り返して時間を計測"""
    t = timeit.Timer('splitStr("a" * 100, 2)', "from __main__ import splitStr")
    print "splitStr: " + str(t.timeit(number=100000))
    t = timeit.Timer('splitStr2("a" * 100, 2)', "from __main__ import splitStr2")
    print "splitStr2: " + str(t.timeit(number=100000))

Gizzardを試してみた

Twitterから新しい分散フレームワークのGizzardというものがOSSで公開されたようです [http://github.com/twitter/gizzard)。Sharding? とかよく分からないのでとりあえず試してみることにしました(が、結局うまくいきませんでした)。

gizzard のビルド

github でソースコードが公開されているのでまずは git で取得

$ git clone git://github.com/twitter/gizzard.git

まずは何も考えずビルド

$ cd gizzard
$ ant
   :
compile-thrift:
    [mkdir] Created dir: /home/nigaky/git/gizzard/target/gen-java

BUILD FAILED
/home/nigaky/git/gizzard/ant/compile.xml:44: The following error occurred while executing this line:
/home/nigaky/git/gizzard/ant/compile.xml:18: Execute failed: java.io.IOException: Cannot run program "thrift": java.io.IOException: error=2, No such file or directory

どうも thrift ってやつを入れないとだめっぽい。しかも github の Issues を見ると、古い thrift を要求するようで、thrift のソースコードが丸ごと公開されていた (http://github.com/twitter/thrift)。

$ git clone git://github.com/twitter/thrift.git
$ cd thrift
$ sh ./bootstrap.sh
$ ./configure
$ make
$ make install

インストールできた。
この libthrift.jar を使いたいけど、クラスパスの設定がよく分からなかったので ivy の jar を上書きする。

$ cp lib/java/libthrift.jar ~/.ivy2/cache/thrift/libthrift/jars/libthrift-0.2.0.jar

再度ビルドしてみる。

$ ant
     :
compile-scala:
   [scalac] Compiling 58 source files to /home/atsji/git/gizzard/target/classes
   [scalac] /home/atsji/git/gizzard/src/main/scala/com/twitter/gizzard/thrift/TSelectorServer.scala:10: error: value thrift is not a member of package org.apache
   [scalac] import org.apache.thrift._
   [scalac]                   ^
     :
BUILD FAILED
/home/nigaky/git/gizzard/ant/compile.xml:89: Compile failed with 4 errors; see the compiler error output for details.

まだダメだ。どうもパッケージの指定がおかしいような気がするので無理矢理修正。

diff --git a/src/main/scala/com/twitter/gizzard/thrift/TSelectorServer.scala b/src/main/scala/com/twitter/gizzard/thrift/TSelecto
rServer.scala
index ee1d90b..ac6a9a0 100644
--- a/src/main/scala/com/twitter/gizzard/thrift/TSelectorServer.scala
+++ b/src/main/scala/com/twitter/gizzard/thrift/TSelectorServer.scala
@@ -7,10 +7,10 @@ import java.util.concurrent.{ConcurrentLinkedQueue, LinkedBlockingQueue, ThreadP   TimeoutException, TimeUnit}
 import scala.collection.jcl
 import scala.collection.mutable
-import org.apache.thrift._
-import org.apache.thrift.protocol._
-import org.apache.thrift.transport._
-import org.apache.thrift.server._
+import com.facebook.thrift._
+import com.facebook.thrift.protocol._
+import com.facebook.thrift.transport._
+import com.facebook.thrift.server._
 import com.twitter.ostrich.Stats
 import com.twitter.xrayspecs.{Duration, Time}
 import com.twitter.xrayspecs.TimeConversions._

再度ビルド。テストを通すため DB_USERNAME, DB_PASSWORD を設定しておく。

$ ant -DDB_USERNAME=hoge -DDB_PASSWORD=fuga
     :
package:
      [tar] Building tar: /home/nigaky/git/gizzard/dist/gizzard-a62ff4a3.tar.bz2
[ivy:publish] :: publishing :: com.twitter#gizzard
[ivy:publish]   published gizzard to /home/nigaky/git/gizzard/dist/repo/com/twitter/gizzard/1.0/gizzard-1.0.jar
[ivy:publish]   published gizzard to /home/nigaky/git/gizzard/dist/repo/com/twitter/gizzard/1.0/gizzard-1.0.pom
[ivy:publish]   published ivy to /home/nigaky/git/gizzard/dist/repo/com/twitter/gizzard/1.0/ivy-1.0.xml

BUILD SUCCESSFUL

なにか間違っているかもしれないが一応ビルドはできた。
使ってみるのはまた後ほど。

Rowz (サンプルプログラム) のビルド

サンプルアプリケーションの Rowz (http://github.com/nkallen/Rowz)。
最初からこちらだけビルドすればよかった。

こちらも同じく thrift 関係でビルド失敗。私の知識ではこれ以上無理なので諦めた。