Hatena::ブログ(Diary)

ユーウツな雨がふりつづいても雪がハートを曇らせてもドアの中で待っていた君に魔法をかけたいのさ RSSフィード

2009-07-13

[]次回勉強会は「MySQLハッキングの手引き」

宣伝です。

次回のオープンソーステクノロジー勉強会は松信嘉範さんをお迎えして

MySQLハッキングの手引き」というテーマお話を伺います。

講師を紹介していただいた、いちいさんに感謝です!!

MySQLハッキングの手引き」

日本MySQLユーザー会 松信 嘉範 (MATSUNOBU Yoshinori)

MySQLオープンソースなので、必要に応じてMySQLソースコードを改変して、自分好みの機能を追加することができます。またストレージエンジンなどプラグイン形式になっている部分もあり、場合によってはMySQL本体を改変することなくお望みの機能を用意することもできます。このセッションでは、いくつかの例を挙げながら、具体的なMySQLハッキングデモをお見せします。またMySQL本家へのコントリビューションの方法も紹介します。

第18回 オープンソーステクノロジー勉強会 - GREE Labs

みなさま、よろしくおねがいします。


第18回オープンソーステクノロジー勉強会 −開催のご報告− - GREE Labs

2009-07-02

[]PHPでlibdrizzleを使うときのメモ

peclにlibdrizzleが登録されたのでメモ

http://pecl.php.net/package/drizzle/

<?php
$drizzle = new drizzle();

$db = 'information_schema';
$query = 'SELECT * FROM character_sets';

$host = 'localhost';
$port = '3306';
$user = 'root';
$password = NULL;
$options = DRIZZLE_CON_MYSQL;

$concurrent_queries = 5;

for ($i=0; $i<$concurrent_queries; $i++) {
    $con = $drizzle->addTcp($host, $port, $user, $password, $db, $options);
    $drizzle->queryAdd($con, $query, 0, $i);
}

while ($q = $drizzle->run()) {
    $data = $q->data();
    $result = $q->result();
    while (($column = $result->columnNext()) != NULL) {
        print $column->name() . ':';
    }
    print "\n";

    while (($row = $result->rowNext()) != NULL) {
        print "$data " . implode(':', $row) . "\n";
    }
    print "\n";
}

if ($drizzle->returnCode() != DRIZZLE_RETURN_OK) {
      exit(0);
}

とりあえずあとで。

2008-12-10

[] memcachedのdecrementコマンドバイトサイズがresizeされないのは仕様でした

memcachedにはincrementとdecrementコマンドというのがあって、

incr <key> <value>

もしくは

decr <key> <value>

とやると<key>に入ってる値から<value>を足したり、引いたりします。


increment

memcachedの1.2.6を使って、

incrementで9から10に変更し、getのレスポンスを見るとバイト数も1から2に変更されます。

getのレスポンスフォーマット

VALUE <key> <flags> <bytes>

<data>

です。

set key 0 0 1
9
STORED

get key
VALUE key 0 1
9
END

incr key 1
10

get key
VALUE key 0 2
10
END

decrement

同様にmemcachedの1.2.6を使って、

decrementで10から9に変えてみると、getしたときのサイズが2のままです。

set key 0 0 2
10
STORED

get key
VALUE key 0 2
10
END

decr key 1   
9

get key
VALUE key 0 2
9 
END

偉いひとに聞いたら、これは仕様らしくて実際にmemcachedプロトコルドキュメントに書いてありました。

Note also that decrementing a number such that it loses length isn't

guaranteed to decrement its returned length. The number MAY be

space-padded at the end, but this is purely an implementation

optimization, so you also shouldn't rely on that.

http://code.sixapart.com/svn/memcached/trunk/server/doc/protocol.txt

memcachedの実装をみてみると、

memcached-1.2.6/memcached.c

1562 char *do_add_delta(conn *c, item *it, const bool incr, const int64_t delta, char *buf) {
略
1584     sprintf(buf, "%llu", value);
1585     res = strlen(buf);
1586     if (res + 2 > it->nbytes) { /* need to realloc */
1587         item *new_it;
1588         new_it = do_item_alloc(ITEM_key(it), it->nkey, atoi(ITEM_suffix(it) + 1), it->exptime, res + 2 );
1589         if (new_it == 0) {
1590             return "SERVER_ERROR out of memory in incr/decr";
1591         }
1592         memcpy(ITEM_data(new_it), buf, res);
1593         memcpy(ITEM_data(new_it) + res, "\r\n", 2);
1594         do_item_replace(it, new_it);
1595         do_item_remove(new_it);       /* release our reference */
1596     } else { /* replace in-place */
1597         memcpy(ITEM_data(it), buf, res);
1598         memset(ITEM_data(it) + res, ' ', it->nbytes - res - 2);
1599     }

1586行目でincrementもしくはdecrement後の値のサイズがもとのバイト数よりも大きい場合は、バイト数の置き換えも伴うデータの置き換えが行われてます、

そうでない場合、同じか小さくなった場合は変更後の値のみ置き換わり(1597行目)、小さくなった場合の余りのバイトにはスペースがパディングされてます(1598行目)。


きっとこのぐらいの変更で解消されそう。

diff --git a/memcached.c b/memcached.c
index 3b7a187..15b32b0 100644
--- a/memcached.c
+++ b/memcached.c
@@ -1583,7 +1583,7 @@ char *do_add_delta(conn *c, item *it, const bool incr, const int64_t delta, char
     }
     sprintf(buf, "%llu", value);
     res = strlen(buf);
-    if (res + 2 > it->nbytes) { /* need to realloc */
+    if (res + 2 != it->nbytes) { /* need to realloc */
         item *new_it;
         new_it = do_item_alloc(ITEM_key(it), it->nkey, atoi(ITEM_suffix(it) + 1), it->exptime, res + 2 );
         if (new_it == 0) {

2008-12-05

[] PHP 5.3 でlambda!

PHP: rfc:closures [PHP Wiki]

5.3 alpha1から使えるclosureの機能をつかってみたよ!

php-5.3.0alpha3/Zend/tests$ ls closure_*
closure_001.phpt  closure_006.phpt  closure_011.phpt  closure_016.phpt  closure_021.phpt  closure_026.phpt  closure_031.phpt
closure_002.phpt  closure_007.phpt  closure_012.phpt  closure_017.phpt  closure_022.phpt  closure_027.phpt  closure_032.phpt
closure_003.phpt  closure_008.phpt  closure_013.phpt  closure_018.phpt  closure_023.phpt  closure_028.phpt
closure_004.phpt  closure_009.phpt  closure_014.phpt  closure_019.phpt  closure_024.phpt  closure_029.phpt
closure_005.phpt  closure_010.phpt  closure_015.phpt  closure_020.phpt  closure_025.phpt  closure_030.phpt
  • closure_003.phpt
--TEST--
Closure 003: Lambda with lexical variables (local scope)
--FILE--
<?php

function run () {
        $x = 4;

        $lambda1 = function () use ($x) {
                echo "$x\n";
        };

        $lambda2 = function () use (&$x) {
                echo "$x\n";
        };

        $lambda1();
        $lambda2();
        $x++;
        $lambda1();
        $lambda2();
}

run();

echo "Done\n";
?>
--EXPECT--
4
4
4
5
Done
$ php closure_003.phpt 
--TEST--
Closure 003: Lambda with lexical variables (local scope)
--FILE--
4
4
4
5
Done
--EXPECT--
4
4
4
5
Done

[] PHP 5.3 alpha3 released!

PHP 5.3 alpha3 released!したのを

PHP5.3.0α3が来る - Do You PHP はてなを見て知りました!

$ php -v
PHP 5.3.0alpha3 (cli) (built: Dec  5 2008 16:06:48)
Copyright (c) 1997-2008 The PHP Group
Zend Engine v2.3.0, Copyright (c) 1998-2008 Zend Technologies

$ php -r 'namespace A::B;'

Parse error: syntax error, unexpected T_PAAMAYIM_NEKUDOTAYIM, expecting T_NS_SEPARATOR or ';' or '{' in Command line code on line 1

$ php -r 'namespace A\B; var_dump(__NAMESPACE__);'
string(3) "A\B"

2008-12-02

[]PHPのarray_mergeと+演算子が気になったから

array_merge と + は key がぶつかると、value は片方残る。array_merge は後勝ち。+ は早いもの勝ち。

PHP 配列の + 演算子が便利な件 - yoyaのメモ

が気になったので。


+演算子の処理はphp-5.2.6/Zend/zend_operators.cのadd_function()にあって、

ZEND_API int add_function(zval *result, zval *op1, zval *op2 TSRMLS_DC)
{   
    zval op1_copy, op2_copy;

    if (op1->type == IS_ARRAY && op2->type == IS_ARRAY) {
        zval *tmp;

        if ((result == op1) && (result == op2)) {
            /* $a += $a */
            return SUCCESS;
        }
        if (result != op1) {
            *result = *op1;
            zval_copy_ctor(result);
        }
        zend_hash_merge(result->value.ht, op2->value.ht, (void (*)(void *pData)) zval_add_ref, (void *) &tmp, sizeof(zval *), 0);
        return SUCCESS;
    }

両方ともarrayだとzend_hash_mergeがよばれます。

  • php-5.2.6/Zend/zend_hash.c
 801 ZEND_API void _zend_hash_merge(HashTable *target, HashTable *source, copy_ctor_func_t pCopyConstructor, void *tmp, uint size, int overwrite ZEND_FILE_LINE_DC)
 805     int mode = (overwrite?HASH_UPDATE:HASH_ADD);
 813             if (_zend_hash_quick_add_or_update(target, p->arKey, p->nKeyLength, p->h, p->pData, size, &t, mode ZEND_FILE_LINE_RELAY_CC)==SUCCESS && pCopyConstructor) {

zend_hash_merge()をみると、

int overwriteは0が来てるので,805行目のmodeはHASH_ADDになります。

で、このmodeが813行目の_zend_hash_quick_add_or_updateの引数としてつかわれます。


  • php-5.2.6/Zend/zend_hash.c
 270 ZEND_API int _zend_hash_quick_add_or_update(HashTable *ht, char *arKey, uint nKeyLength, ulong h, void *pData, uint nDataSize, v     oid **pDest, int flag ZEND_FILE_LINE_DC)
 285         if ((p->h == h) && (p->nKeyLength == nKeyLength)) {
 286             if (!memcmp(p->arKey, arKey, nKeyLength)) {
 287                 if (flag & HASH_ADD) {
 288                     return FAILURE;
 289                 }

_zend_hash_quick_add_or_updateをみると、さきほどのmodeはflagという変数名でつかわれてて中身はHASH_ADDです。

286行目以降にmemcmpで比較してkeyが同じ場合の処理が書かれてるんですが、

そのまえに287行目のif文でHASH_ADDだと処理を中断してます。

なので、値の上書きはおこなわれません


つぎにarray_mergeは、

  • php-5.2.6/ext/standard/array.c
2293 PHPAPI int php_array_merge(HashTable *dest, HashTable *src, int recursive TSRMLS_DC) /* {{{ */
2342                     zend_hash_update(dest, string_key, string_key_len,
2343                                      src_entry, sizeof(zval *), NULL);

zend_hash_updateがよばれて配列マージがおこなわれます。


zend_hash_updateはphp-5.2.6/Zend/zend_hash.hにかかれてて、

102 #define zend_hash_update(ht, arKey, nKeyLength, pData, nDataSize, pDest) \
103         _zend_hash_add_or_update(ht, arKey, nKeyLength, pData, nDataSize, pDest, HASH_UPDATE ZEND_FILE_LINE_CC)
104 #define zend_hash_add(ht, arKey, nKeyLength, pData, nDataSize, pDest) \
105         _zend_hash_add_or_update(ht, arKey, nKeyLength, pData, nDataSize, pDest, HASH_ADD ZEND_FILE_LINE_CC)

大事なのは7番目の引数でHASH_UPDATEが入ってるところです。

HASH_UPDATEだと、さっきのzend_hash.cの287行目の条件にマッチしないので,

そのまま処理が続いて値の上書きがおこなわれてます。

_zend_hash_add_or_update()と_zend_hash_quick_add_or_update()の違いってkeyがemptyだったときの処理のちがいくらいでした。