2011/10/31


node.jsのスライドを見てて、プラットフォームの違いを吸収するnode.jsの核でもある非同期通信ライブラリuvを今日知ったので試してみた。
joyent/libuv - GitHub

platform layer for node.js

https://github.com/joyent/libuv
libev/libeventをwindowsでもちゃんと使いたいという所から出てきたライブラリ。
#include <iostream>
#include <uv/uv.h>

int
main() {
  int r;
  uv_tcp_t tcp;
  struct sockaddr_in server_addr;

  server_addr = uv_ip4_addr("127.0.0.1"80);
  r = uv_tcp_init(uv_default_loop(), &tcp);
  uv_connect_t connect_req;

  r = uv_tcp_connect(&connect_req, &tcp, server_addr,
    [](uv_connect_t *req, int status) {
      std::cout << "connected" << std::endl;

      int r;
      uv_buf_t buf[1];
      uv_stream_t* tcp = req->handle;
      char *req_message = "GET / HTTP/1.0\r\n\r\n";

      buf[0].len = strlen(req_message);
      buf[0].base = req_message;

      uv_write_t write_req;
      r = uv_write(&write_req, tcp, buf, 1,
        [](uv_write_t* req, int status) {
          int r;
          uv_stream_t* tcp = req->handle;

          std::cout << "written" << std::endl;
          r = uv_read_start((uv_stream_t*)tcp,
            [](uv_handle_t* handle, size_t size) -> uv_buf_t {
              std::cout << "alloc " << size << std::endl;
              uv_buf_t buf;
              buf.base = (char*)malloc(size);
              buf.len = size;
              return buf;
            },
            [](uv_stream_t* tcp, ssize_t nread, uv_buf_t buf) {
              std::cout << "read" << std::endl;

              if (nread < 0) {
                if (buf.base) {
                  free(buf.base);
                }
                uv_close((uv_handle_t*) tcp,
                  [](uv_handle_t* handle) {
                    std::cout << "closed" << std::endl;
                  }
                );
                return;
              }
              std::cout << buf.base << std::endl;
               
              free(buf.base);
              return;
            }
          );
        }
      );
    }
  );

  std::cout << "main" << std::endl;
  uv_run(uv_default_loop());
}
コールバック関数用意するのがめんどくさくなったのでlambdaで。 g++ -std=c++0x foo.cxx -lws2_32
みたいにしてビルドします。
ポート80のサーバに接続して応答を貰うだけ。コールバックベースなので、イベントループで処理待機する事になる。よって結果は main
connected
written
alloc 65536
read
HTTP/1.1 200 OK
Date: Mon, 31 Oct 2011 04:19:52 GMT
Server: Apache/2.2.17 (Win32) mod_fcgid/2.3.6
Last-Modified: Sat, 20 Nov 2004 06:16:26 GMT
ETag: "2000000011333-2c-3e94a902f4280"
Accept-Ranges: bytes
Content-Length: 44
Connection: close
Content-Type: text/html

<html><body><h1>It works!</h1></body></html>
alloc 65536
read
closed

こんな感じになります。1リクエストに対して1つのコールバックが必要になる訳で、若干手間な気がしたのはきっと僕がオッサンになったせいだと思う。まぁWindows特有の手続きやハックが要らないのは良いと思う。

あと、これを実際に生かそうと思うと、処理部もストリーミングに対応する必要があり、例えばリクエストの断片を受信したとしても完了部が来るまで蓄え続ける必要がある点はuvを使っても変わらない訳で、libcurlで良くね?と思ってしまったのも、きっと僕がオッサンになったせいだと思う。


追記
サーバ処理書くならlibcurlでは出来ないので、libuvやpicoev使うといいですね。
Posted at by



2011/09/30


※ネタです

※UDFです

Vimテクニックバイブル ~作業効率をカイゼンする150の技 Vimテクニックバイブル ~作業効率をカイゼンする150の技
Vimサポーターズ
技術評論社 単行本(ソフトカバー) / ¥364 (2011年09月23日)
 
発送可能時間:


正誤表を書くのにしばらくこの本をちょっと眺めてみたら、SQLiteのUDFって簡単に作れるんだなー、と思った && そういやV8ってライブラリとして簡単にリンクできるはずだな、と思い出した ので、ついカッとなって作った。

sqlite3udf-jseval - GitHub

http://github.com/mattn/sqlite3udf-jseval

UDFうんぬn

ほとんど↑の本、全然関係ないと思ってたけど、やっぱりSQLiteのUDFについて全然書いてなかった。しょうがないので軽く紹介しておくと

UDFを追加する場合、SQLiteの再コンパイルは必要ない (しかるべき所に.soがおいてあればいい)
UDFはこの辺読んどけばだいたい分かる。

例えば文字列っぽいものを返すmyfuncっていうUDFを作りたい場合
SQLITE_EXTENSION_INIT1 static void js_eval_func(sqlite3_context *context, int argc, sqlite3_value **argv);
int sqlite3_extension_init(sqlite3 *db, char **errmsg, const sqlite3_api_routines *api);
の二つの関数を実装したmyfunc.cっていうコードを用意してあげて gcc -o myfunc.so myfunc.c `sqlite_config --cflags` -shared という風にコンパイルして(これはLinuxの場合)、しかるべき場所(LD_LIBRARY_PATHが通る場所)に置いた後、sqliteのシェルで > select load_extension("myfunc.so"); とやればいきなり使える。

sqlite3_value_textはアロケートした文字列を渡して、最終引数に開放関数を渡すというのがUDFのお作法らしい。strdupで確保したポインタは最終引数の関数でfreeする、みたいな。

動かす手順

で、今回作ったのはV8とリンクして、JSの文字列をevalしてくれるjs_evalというUDF。
多分試す人はいないと思うけど、動かすための手順を書くと

V8のビルド

V8を落としてきてビルドする。ただし、SQLiteのUDFは別に-fPICを付けなくてもおk。

js_eval.cppをコンパイル

V8をビルドしたディレクトリにもっていって
g++ -o js_eval.so js_eval.cpp `sqlite_config --cflags` -shared -Iinclude libv8.a -lpthread
そうすると、js_eval.soができるので、これをLD_LIBRARY_PATHが通ったディレクトリに置く

読み込むる

シェルに入って
> select load_extension("myfunc.so"); (※このUDF、食わせるものによってはSQLiteごと落ちるかもしれないので良い子のみんなは注意だ)

キターーーッ

すごい。
sqlite3udf1

全然
sqlite3udf2
役に立つ気がしない。
sqlite3udf3
というかSQLite力が低すぎてどうしたら面白くなるか思いつかない。これを発展させていってTEXTとかに突っ込んだJSONの中身を効率よく検索とか出来たら面白い&実用的なんだけど、道は遠そうだ。


参考
やったーJavaScriptの動くMySQLできたよー - 愛と勇気と缶ビール

しばらく 積ん読 していたこの本をちょっと眺めてみたら、 MySQL のUDFって簡単に作れるんだなー、と思った && そういや V8 って ライブラリ として簡単にリンクできるはずだな、と思い出した...

http://d.hatena.ne.jp/zentoo/20110925/1316961032
Posted at by



2011/08/04


最近はクラウドサーバ等、割と色んな所で見かける様になったuWSGIですが...
uWSGI

uWSGI is a fast, self-healing and developer/sysadmin-friendly application container server coded in pure C.

http://projects.unbit.it/uwsgi/
Perlだとhirataraさんが書いた記事や
Hokkaido.pmでuWSGIについてLTした - a geek born in Tomakomai

uWSGI はデフォルトではhttpではなくuwsgiプロトコルを喋るので、uwsgiプロトコルを喋れるフロントエンドを立ち上げます...

http://d.hatena.ne.jp/hiratara/20110718/1310950381
Plack::App::uWSGIが参考になります。
hiratara/p5-Plack-App-uWSGI - GitHub

Plack::App::uWSGI - a PSGI frontend of uwsgi.

https://github.com/hiratara/p5-Plack-App-uWSGI
こちらはuwsgiに付属のpsgiプラグインを使っています。なお、uwsgiのcontribフォルダにはPlack::Handler::Uwsgiが同梱されているので、例えばnginx.confに server {
  listen 8082;
  location / {
    include uwsgi_params;
    uwsgi_pass 127.0.0.1:9999;
  }
}
と書いておき use Plack::Handler::Uwsgi;

my $app = sub {
    return [ 200, [ 'Content-Type' => 'text/plain' ], [ 'Hello World' ] ];
};
Plack::Handler::Uwsgi->new(host=>'127.0.0.1'port=>9999)->run($app)
こんな感じに走らせると、"http://server:8082/" で"Hello World"が表示されます。もちろんフロントエンドであるnginxの設定を弄ればキャッシュやタイムアウトも変更出来るという仕組みです。

ちなみにcontribフォルダにはrubyやjavaのコードも置いてあります。つまりuWSGIプロトコルを実装すれば、言語を問わずフロントエンドをnginxとしたワーカーが作れるって事ですかね。

Go言語も仲間に入れてよ!って事でuWSGIリスナを書いてみました。
mattn/go-uwsgi - GitHub

uwsgi implement for go

https://github.com/mattn/go-uwsgi
あくまでリスナという位置づけなので、unixドメインソケットのファイルや、tcpソケットなど、goでnet.Listenerとして扱える物であれば何でもokです。これを使うとファイルサーバがほんの数行で書けてしまいます。

nginx.confが server {
  listen 8081;
  location / {
    include uwsgi_params;
    uwsgi_pass unix:///var/run/go-uwsgi/socket;
  }
}
であれば package main

import (
    "net"
    "http"
    "github.com/mattn/go-uwsgi"
    "os"
)

func main() {
    s := "/var/run/go-uwsgi/socket"
    os.Remove(s)
    l, e := net.Listen("unix", s)
    if e != nil { panic(e.String()) }
    http.Serve(&uwsgi.Listener{l}, http.FileServer(http.Dir(".")))
}
これだけですね。簡単です。
初めてのPerl 第5版 初めてのPerl 第5版
Randal L. Schwartz, Tom Phoenix, brian d foy, 近藤 嘉雪
オライリージャパン 大型本 / ¥670 (2009年10月26日)
 
発送可能時間:

Posted at by