というわけで
reizou.coというドメインが取れたようなので、冷蔵庫関連のWebサービスをやりたい。
written by shn, on Jul 21, 2010 1:33:00 PM.
すいません。早とちりでした。 GoDaddyの作業がつまってたみたいで、先程ドメインが承認されました。
GoDaddy
@shn It can take time for the domains to be registered and to be available in your Domain Manager. Please allow 24 to 48 hours. ^Al
http://twitter.com/GoDaddy/status/19085967761
dominioamigoが一時的に抑えてたってことなんだろうか。下請けかなんかなのかな。
.coドメインのコロンビア外一般登録が開始されたわけですけど、僕がGoDaddyで事前予約したドメインは二つともdominioamigo.comとかいうレジストラに取られてしまいました…
adachin.coなんて僕以外に欲しい奴がいるとは思えないので、本当にフェアだったのか疑ってしまう…
.coのwhoisはwhois.coからできるようです。
written by shn, on Mar 25, 2010 8:01:00 PM.
思いついたら随時更新していきます。 これも追加しろ!とか、間違ってるぞ!とかあったらコメントください。
参照カウンタについて、呼び出し側が責任を持ってreleaseする必要があるのはinit系かcopy系を呼んだ時のみ。
これ以外は、呼び出され側(なんていうんだ?)が参照カウンタを持っている(か、例えばautoreleaseしてある)
リリースする前に必ずBuild And Analyze(Shift+Cmd+A)をしよう。メモリリークやらなにやらを指摘してくれる。
[NSDictionary dictionaryWithObejctsAndKeys]ではセンチネルとしてnilを使うが、nilを値として設定したい時もある。 その場合は代わりに印として[NSNull null]を使う。 nilの場合はNull Object Pattern的に、全てのセレクタ呼びだしは無視されるが、NSNullに何か呼びだすと例外が出るので注意。
hogehoge.mmとかにすればObjective-C++としてコンパイルしてくれるので、stlも使えるよ。
自作ViewControllerのxibを作って「あれれーロードされないぞ」って事になったら、File's OwnerがNSObjectのままになっていないかチェック
subviewはviewが参照カウンタをもっているのでretainにする必要はない(retainにした場合、明示的にreleaseする事)
オーガナイザーが糞重くなったり、ビルドしたけど謎のエラーで実行できなくなったりしたらとりあえずXCodeを再起動させてから考えると良いと思う。
変数名などをOption+Clickするとヘルプが出てきます。
UIに関する操作(例えばpushViewControllerとか)はmain threadで行うのが無難(詳しく追ってないので、経験上、としか言えないけど…)
別スレッドから操作したい時は、performSelectorOnMainThreadを呼べば楽。
Tagged as: Objective-C, iPhone | 1 comment
written by shn, on Mar 21, 2010 7:06:00 PM.
「Cassandraというものがなんだかよく分からない」 〜 NoSQLについて、鳩山由紀夫
週末プロジェクトになりつつあるCassandra修行ですが、しょっぱなから躓いている。 (経験から言えば、躓いたらほっておいて先進めばいいだけなので、躓くのを言い訳に止まっている)
さて、
あるユーザーサービスを考えてみる。ユーザー毎にページをもたせたい(http://hogehoge.com/shn/ みたいに) また認証はパスワードとか面倒なのでOpenIDにしてみよう。
というのをCassandra(とLazyboy)でやるにはどうしたらいいのかしら。
MySQLでやるならこんな感じのテーブルを用意しているはずだ。
CREATE TABLE Accounts (
account_id INTEGER NOT NULL PRIMARY KEY AUTO INCREMENT,
account VARCHAR(64) NOT NULL UNIQUE,
openid_identifier VARCHAR(255) NOT NULL UNIQUE
);
アカウント情報について、「アカウントから」と「OpenIDから」の2系統からアクセスされるので、その二つをUNIQUE INDEXにした。
Cassandraの場合はひとつのColumnFamilyについて一つの順序しか持てない。今回のアプリの場合、http://hogehoge.com/shn/からshnを引っ張ってくるケースが多そうなので、とりあえずアカウント名でソートされたColumnFamilyを用意するのか
<Keyspace Name="UserData">
<ColumnFamily CompareWith="BytesType" Name="Accounts"/>
</Keyspace>
{ // Accounts
"shn" : {
"openid_identifier": "http://glucose.jp/shn"
}, ...
}
て感じだろうか。さてOpenIDからアカウントを引っ張ってくる場合はどうするのだろう。新しくColumnFamilyを定義するか、
<Keyspace Name="UserData">
<ColumnFamily CompareWith="BytesType" Name="Accounts"/>
<ColumnFamily CompareWith="BytesType" Name="Identifiers"/>
</Keyspace>
{ // Identifiers
"http://glucose.jp/shn" : {
"account": "shn"
}, ...
}
Accountsの中に特殊なRow Key(__identifiers__的な)を定義してその中に突っ込むかの2通りが思いつく。
{ // Accounts
"shn" : {
"openid_identifier": "http://glucose.jp/shn"
},
"__identifiers__" : {
"http://glucose.jp/shn": "shn"
}, ...
}
どっちが良いのかな。API的にはどっちもgetを2回呼ぶ事になるのだと思うけど、データはどのノードに配置されるのだろうか。
他のものを見てみるとtwissandraの場合前者の方法だ。こっちのBlogの例題の場合後者に近い(ちょっと用途違うけど)。 Delicious clone in cassandraの例はどうやってデータひっぱってくるのかさっぱりわからない。
DataModel - Cassandraw Wikiによると
The row key is what determines what machine data is stored on. Thus, for each key you can have data from multiple column families associated with it. However, these are logically distinct, which is why the Thrift interface is oriented around accessing one ColumnFamily per key at a time. (TODO given this, is the following JSON more confusing than helpful?)
keyによってどのノードにデータが保持されるか決まるそうなので、後者の方法だと特定のマシンにOpenIDのindex情報が固まる事になる。ここらへん、例えば「インデックス用のCFは全ノードに配置したい!」とか邪な事を考えた場合に、カスタマイズしたReplicationStorategyを書けば良さそうなところがCassandraの強みかもしれん。
PythonのCassandra高級インタフェースであるところのLazyboyさんはViewという仕組みがあるようだ。
Lazyboy's view classes provide a way to build secondary indexes into a column family. For example, you might create a view that has only Lazyboy authors from the Users table:
というわけで、IdentifiersというViewを定義してそこのappendしたら良いかな?とやってみたら
{ // Identifiers
"shn": "shn"
}
というCFができて泣いた。ViewのKeyを決定する関数が
def _record_key(self, record=None):
"""Return the column name for a given record."""
return record.key.key if record else str(uuid.uuid1())
となっているため、User(key=shn)を突っ込むとViewのkeyもshnになっちゃう… ソース読んでて思ったのだけど、このViewはタイムライン的な奴を実装するためにあるようなので、僕のやりたい事とはちょっとずれているな。
というわけで、玉虫色のエントリになったCassandra修行二回目。 その他参考にしたりしたページ
Tagged as: Cassandra, Python | 0 comments
written by shn, on Mar 15, 2010 11:10:00 PM.
日曜大工はPython3kにしようか > Python3kはMySQLドライバ無いのか > じゃあCassandra使ってみるか > thriftもPython3k無いじゃん > じゃあ2.6でCassandraか、という経路によりCassandraにトライしてみることにしました。
修行中の身である故、情報の正確性は無担保。 ためしたCassandraは0.5.1
Cassandraとは、もともとFacebookが開発して、現在はApacheでホスティングされている分散データベース。最近、TwitterがMySQLから移行したことで話題になった。
いわゆるNoSQL(この呼び方は好きじゃないけど)のジャンルに属するデータベースで、データモデルの表現力的には DataStore(GAE) > Cassandra > Key-Value Storeぐらいのものなんじゃないのかなと思う。
DLしてみたらJavaだった。Javaなんて大学のレポートいらいですね。あれもJythonで書いてJavaコードにコンパイルして出した気がする。とりあえずシングルノードで動かしてみようと思って
bin/cassandra -f
してみたら、いくつかライブラリが足りなかった(主にログ関係?)。 slf4j-log4j12-1.5.11.jar, slf4j-api-1.5.11.jar, commons-collections-3.2.1.jar, google-collect-1.0.jar, log4j-1.2.15.jarを足してもっかい起動。拍子抜け
。-fはフォアグラウンドで起動するオプション。
CassandraのデータモデルはプロジェクトWikiの他に、PythonのライブラリであるLazyboyや、その作者のブログに詳しい。
特に三つ目のがわかりやすいので、いいんじゃないでしょうか。
CassandraのDataModelはKeyspace > (Super)ColumnFamily > Columnという構成になっている。
RDBMSで言うと、Keyspaceは"データベース"、ColumnFamilyは"テーブル"ってぐらいのポジションではないかと。
Columは最小のデータ単位。name, value, timestampのタプル。
{
"name": "emailAddress",
"value": "foo@bar.com",
"timestamp": 123456789
}
timestampはとりあえずスルーしておいていいらしい。name, valueについてはバイト列として扱う。
ColumnFamilyは、keyで識別されるRowの固まり。各Rowの中身はColumnのマップになっている。Rowは常にソート済みで保持されている。 ColumnFamilyの定義 - Row keyの評価法(バイト列として評価するか、utf8文字列として評価するか)や、レプリケーション - はstorage-conf.xmlで定義する。
インデックスが無い代わりに、ColumnFamilyが常にソートされているっていうのがCassandraのユニークな点ではないだろうか。RSS Reader/SNS/Blogのような、昨今のウェブサービス市場を占める「なんかのタイムラインを表示する」アプリケーションに特化している(まだ実際にさわってないからようわからんけど)
ColumnFamilyのソート順はBytesType, UTF8Type, LexicalUUIDType, TimeUUIDType, AsciiType, LongTypeがある模様。 BytesTypeとAsciiTypeの違いは後で調べる。 LongTypeは64bit integerと扱うようだ。64bit以上の値とかを入れたらどうなるんだろう。バイト列としてセットするのだろうか。
LexicalUUIDTypeは128bitのUUIDとして評価するのかな。多分、想像だけどLazyboyなんかのライブラリがオブジェクトを追加するときにUUIDを自動生成したりして、keyを決めるのがめんどいときに便利なんじゃないだろうか。
TimeUUIDTypeはTime UUID(ver1のUUIDのことかしら。ようわからん)として評価する? LongTypeと比べたときの利点は、timestampが被っても大丈夫ってあたりなんだろうか? 上にあげたブログ記事に、ブログ記事のタグごとのタイムラインをTimeUUIDTypeで管理する例が載っている。
SuperColumnFamilyはColumnFamilyのSuperColumn版。SuperColumnとはValueの代わりにColumnのリストが入っている。
だんだん書いていて飽きてきた。ただ、書くと再確認になってよいですね。ColumnFamilyのどこがソートされているのかについてアヤフヤだったのがわかった。
日本語の情報あまりないなーと思っていたら、id:dannさんが書いていた。幅広く解説してある。紹介されていた、Twitterのデータ構造をCassandraでやってみる例(Twissandra)は後で見よう。
TODOとしては
あたりだろうか
Tagged as: Cassandra, Python | 0 comments
written by shn, on Feb 27, 2010 10:53:00 PM.
ビルドツールをwafに代えたのだが、そこにあるテキトーなautomatic buildコードが、FreeBSDで使えるFAM系?のライブラリのgaimに対応していなかったので書き散らかした。 せっかくなのでアップします。
./waf daemonでイケルと思う。_famはうまく動かなかったのでイロイロやってみたけど諦めた。
Tagged as: Python, waf | 0 comments
written by shn, on Feb 7, 2010 12:15:00 AM.
ハルヒ見に行こうと思ったら満席で予約取れなかった。 そこで、私のもう一つの願望である、Dr.HOUSEの透明のホワイトボードを手に入れるべくグーグルとの対話を始めたのであった。
同じ事考えている人発見 → 知的なホワイトボード?? 関係ないけどlive.comのblogのURLは酷いな。愛がなさ過ぎる。
言及されているYahooの質問の回答にあるメーカーだと、20〜30万程するようだ。
見たこと無いのだけどCSIでも透明なボードが出てくるそうで似たような質問があった、それによると、ガラス黒板、チェインジングボードという名前で似たような物があるけどちょっと違う。イーゼルタイプの物が欲しいのだ。
ライト黒板製作所の透明黒板はかなり近い。もっと透明であるとうれしいんだけど、お値段もいいかんじ。
アクリル、ガラスの板を買ってきて自分で作ればいいのかもしれない。この質問によると、アクリルだと使っていくと傷がついて字が消えなくなっていくので、ホワイトボード用の透明シートを貼るのが良いのではないかとのこと。 透明シートはここらへんだろうか。ダイナカル、モウカル
ううむ。東急ハンズ行けば教えてくれるような気もしてきた。
written by shn, on Jan 29, 2010 2:14:00 PM.
先日のAppleのイベント用にこんなのを作って、動かしたりしてたいました。
中身はテキトーに書いたeventletベースCometサーバをFreeBSDで動かしてるのですが、eventletはkqueueのhubが無いのでちょっと負荷が心配になった。ので、kqueueのhubをでっち上げた。例によってテストは無いけど、一晩動いてたのでこの方向でいいのかしら。
kqueueバージンだったので、誰か優しく手ほどきしてください。
Tagged as: Python, eventlet, kqueue | 2 comments
written by shn, on Jan 18, 2010 4:47:00 PM.
嫁の人がタダ券をもらったので、いまさら2012を見てきました。
3分に一回つっこみどころ(ニュートリノが核粒子?に変化する!、とか)がある面白い映画でした。 嫁の人が本編前の予告編だと思って「うわぁ ひでぇなこの映画」とか言ってたら、本編だったという感じです。
ネタバレなんですが、僕が一番気に入ったつっこみどころは、方舟のチケットに一席10億ドル(ユーロです、といいつつドルだったりする。相手によって値段が違う)といいつつ、後半ででてきた「船の建設費用は数10億ドル…」というセリフ。世界が終わるっていうのにぼろ儲けしてる奴がいるよ!と楽しかったです。
AVATARもそうなんですが、ハッピーエンドっぽいラストなんですけど、あの後本当の地獄が始まると思います。
written by shn, on Jan 17, 2010 6:05:00 PM.
eventletづいてるので、Cometサーバを書いてみたよ。
tinycomet.py at master from shnjp's tinycomet - GitHub
eventlet.wsgiを使って、200行ぐらいで簡単なのが書けました。楽しいですね。
python tinycomet.pyで起動して、 /update/<UUID>にPOSTするとデータを作成
% curl -v 'http://127.0.0.1:8090/update/hogehoge' -d mogemoge
...
< HTTP/1.1 201 Created
< X-Tc-Timestamp: 2
< Content-Length: 0
...
受け取るには、/wait/<UUID>
% curl -v 'http://127.0.0.1:8090/wait/hogehoge'
...
< HTTP/1.1 200 OK
< Content-Type: application/octet-stream
< X-Tc-Timestamp: 4
< Content-Length: 7
...
mogemoge
waitにsince=<timestamp>をつけると、その時間になるまで待ちます。
各レスポンスのヘッダにあるX-TC-Timestampが、そのデータの最終更新時刻になります。
timestampは論理時間なので、実世界の時刻とは関係ありません
% curl 'http://127.0.0.1:8090/wait/hogehoge?since=4' &
[1] 97027
# waitに入る
% curl -v 'http://127.0.0.1:8090/update/hogeoge' -d fugafuga
fugafuga[1] + done ....
ほかに、waitにtimeout=[timeout:float]を与えると、timeout秒待って408 Request Timeoutを返します。
また、updateにfinished=1を与えると、次のwaitが終わった後にデータを消します。またcontent_type=[mimetype]でContent-Typeを指定できます。デフォルトはapplication/octet-stream
eventletのdefault hubからthread safeじゃないという理由でpyeventが外されていたのだけど、今回はsingle threadなので試してみた。 しかしうまくimport出来ないので諦め。trunkも、配布バージョン(2007年!!)もだめじゃった。
python2.6からkqueueが使えるそうなので、自分でHubを書くのがよいのかな。eventlet自体もtrunkは結構変わっているので見ないといけなさげ
waitのところは、グローバルなConditionを作って
# wait側
with _update_lock:
while data.last_update <= since:
_update_lock.wait(timeout)
# update側
with _update_lock:
_update_lock.notify_all()
とやっているので、捌くdataの数が増えると破綻すると思う。dataごとにイベントを持たせて、WaitForMultipleObjects()的なことがしたいのだけど、この枠組みではどうやるんだろう。オシエテエライヒト
/wait_multiはmultipart/*を吐くコードを書くのが面倒なので実装していない。
Tagged as: Python, comet, eventlet | 0 comments
Proudly powered by Zine.