Skip to content

PHP extension for interfacing with MySQL Handler Socket

有关于 HandlerSocket 的介绍、性能及其安装,可参考Using SQL as NoSQL。而 PHP extension for interfacing with MySQL Handler Socket,实际上这里php-handlersocket有整体的介绍,包括其安装、使用方法。现在纯粹是因为自己测试时犯了一很基础的错误,所以,罚自己多敲点字。

安装

[root@localhost php-handlersocket]# /usr/local/php/bin/phpize
[root@localhost php-handlersocket]# ./configure --with-php-config=/usr/local/php/bin/php-config
[root@localhost php-handlersocket]# make
[root@localhost php-handlersocket]# make install

说明:
1 编译时需要 libhsclient 库(libhsclient – HandlerSocket client library)。
2 安装成功时,在 PHP 的 extension dir 生成一名为 handlersocket.so,将extension=handlersocket.so加入 php.ini, 重启 PHP 服务。

HandlerSocket Class methods

HandlerSocket::construct

创建一 HandlerSocket Object。

HandlerSocket::__construct ( string $host, string $port [,  array $options ] )

参数:

  • $host MySQL 服务器 host name。
  • $port HandlerSocket 的端口地址。

返回值:
返回 HandlerSocket Object。

HandlerSocket::openIndex

在对数据库表做任何的增删改查操作前,必须先选择一索引。

public bool HandlerSocket::openIndex ( int $id, string $db, string $table, string $index, string $fields )

参数:

  • $id HandlerSocket ID; 1 SELECT, 2 UPDATE, 3 INSERT, 4 DELETE。
  • $db 数据库名
  • $table 表名
  • $index 索引名, 可以是手动创建的索引名。这个参数可为空,一般指定时是用于 SELECT,eg: 指定为主键:HandlerSocket::PRIMARY
  • $fields 字段名(多个字段名,用逗号分隔),可为空。

返回值:
成功时返回 TRUE, 反之亦然。

HandlerSocket::executeSingle

在表上做增删改查操作。

public mixed HandlerSocket::executeSingle ( int $id, string $op, array $fields [, int $limit, int $skip, string $modop, array $values, array $filters, int $invalues_key, array $invalues ] )

参数:

  • $id HandlerSocket ID; 1 SELECT, 2 UPDATE, 3 INSERT, 4 DELETE。
  • $op 操作符,有如下可选项, ‘=’, ‘>=’, ‘<=’, ‘>’, ‘<’, ‘+’。
  • $fields 查询中所用到的字段,数组,其长度必须等于或小于指定的列数。
  • $limit 最多影响的行数(最开始根据这个函数名称有在怀疑这个参数,测试时发现,如果存在满足条件的多条记录时,会根据这个参数指定的值返回记录数)。
  • $skip 在检索记录前忽略掉的行数。
  • $modop 指定修改操作,可选值:’U', ‘D’。
  • $values 数组,用于做 UPDATE 操作时指定修改的值。
  • $filters 过滤的选项。
  • $invalues_key ? (enabled : 0 / disabled : -1).
  • $invalues IN options

返回值:
返回做对应操作时的执行结果。

HandlerSocket::executeMulti

在一次调用中执行多个操作,即多个 HandlerSocket::executeSingle 的合并。

public mixed HandlerSocket::executeMulti ( array $requests )

参数:

  • $requrest 多组 executeSingle 参数,用数组的形式体现。

注意:
等同于:HandlerSocket::executeSingle($requests00, $requests01, ...), HandlerSocket::executeSingle($requests10, ...) ...
返回结果:
返回做对应操作时的执行结果。

HandlerSocket::executeUpdate

To update a record from a table using an index.

public mixed HandlerSocket::executeUpdate ( int $id, string $op, array $fields, array $values [, int $limit, int $skip, array $filters, int $invalues_key, array $invalues ] )

参数:

  • $id HandlerSocket ID; 2 UPDATE 。
  • $op 操作符,有如下可选项, ‘=’, ‘>=’, ‘<=’, ‘>’, ‘<’, ‘+’。
  • $fields 查询中所用到的字段,数组,其长度必须等于或小于指定的列数。
  • $values UPDAET 时指定修改的值。
  • $limit 最多影响的行数。
  • $skip 在检索记录前忽略掉的行数。
  • $filters 过滤的选项。
  • $invalues_key ? (enabled : 0 / disabled : -1).
  • $invalues IN options

注意:
等同于:HandlerSocket::executeSingle($id, $op, $fields, $limit, $skip, 'U', $values, $filters, $invalues_key, $invalues)
返回值:
返回做对应操作时的执行结果。

HandlerSocket::executeDelete

To delete a record from a table using an index.

public mixed HandlerSocket::executeDelete ( int $id, string $op, array $fields [, int $limit, int $skip, array $filters, int $invalues_key, array $invalues ] )

参数:

  • $id HandlerSocket ID; 4 DELETE 。
  • $op 操作符,有如下可选项, ‘=’, ‘>=’, ‘<=’, ‘>’, ‘<’, ‘+’。
  • $fields 查询中所用到的字段,数组,其长度必须等于或小于指定的列数。
  • $limit 最多影响的行数。
  • $skip 在检索记录前忽略掉的行数。
  • $filters 过滤的选项。
  • $invalues_key ? (enabled : 0 / disabled : -1).
  • $invalues IN options

注意:
等同于:HandlerSocket::executeSingle($id, $op, $fields, $limit, $skip, 'D', NULL, $filters, $invalues_key, $invalues)
返回值:
返回做对应操作时的执行结果。

HandlerSocket::executeInsert

To insert a record from a table using an index.

public mixed HandlerSocket::executeInsert ( int $id, array $values )

参数:

  • $id HandlerSocket ID; 3 INSERT 。
  • $values HandlerSocket::openIndex 指定的字段参数所对应的值,但是以数组的形式体现。

注意:
等同于:HandlerSocket::executeSingle($id, '+', $values, 0, 0, NULL, NULL, NULL) ,第三个参数中指定的值必须和在此之前调用 HandlerSocket::openIndex 时第五个参数指定的字段对应。
返回值:
返回做对应操作时的执行结果。

HandlerSocket::getError

取得最近一次的错误信息。

public string HandlerSocket::getError ( void )

返回值:
返回最近的错误信息(时间上)。

Example

测试表 schema:

 CREATE TABLE `hstesttbl` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `k` char(6) DEFAULT NULL,
  `v` char(6) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_hstesttbl_k` (`k`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
$host       = 'localhost';
$port       = 9998;
$port_wr    = 9999;
$dbname     = 'hstestdb';
$table      = 'hstesttbl';

//GET
$hs = new HandlerSocket($host, $port);
if (!($hs->openIndex(1, $dbname, $table, HandlerSocket::PRIMARY, 'k,v'))) {
    echo $hs->getError(), PHP_EOL;
    die();
}

$retval = $hs->executeSingle(1, '=', array('k1'), 1, 0);
var_dump($retval);

$retval = $hs->executeMulti(
    array(
        array(1, '=', array('k1'), 1, 0),
        array(1, '=', array('k2'), 1, 0)
    )
);
var_dump($retval);
unset($hs);

//UPDATE
$hs = new HandlerSocket($host, $port_wr);
if (!($hs->openIndex(2, $dbname, $table, '', 'v'))) {
    echo $hs->getError(), PHP_EOL;
    die();
}

if ($hs->executeUpdate(2, '=', array('k1'), array('V1'), 1, 0) === false) {
    echo $hs->getError(), PHP_EOL;
    die();
}

unset($hs);

//INSERT
$hs = new HandlerSocket($host, $port_wr);
if (!($hs->openIndex(3, $dbname, $table, '', 'k,v'))) {
    echo $hs->getError(), PHP_EOL;
    die();
}

if ($hs->executeInsert(3, array('k2', 'v2')) === false) {
    echo $hs->getError(), PHP_EOL;
}
if ($hs->executeInsert(3, array('k3', 'v3')) === false) {
    echo 'A', $hs->getError(), PHP_EOL;
}
if ($hs->executeInsert(3, array('k4', 'v4')) === false) {
    echo 'B', $hs->getError(), PHP_EOL;
}

unset($hs);

//DELETE
$hs = new HandlerSocket($host, $port_wr);
if (!($hs->openIndex(4, $dbname, $table, '', ''))) {
    echo $hs->getError(), PHP_EOL;
    die();
}

if ($hs->executeDelete(4, '=', array('k2')) === false) {
    echo $hs->getError(), PHP_EOL;
    die();
}

PS: 因为建立测试表时忘记指定存储引擎为 InnoDB, 测试 INSERT 操作时,怎样都是失败。后面为了验证问题的出处,用 perl 的 API 做同样的测试操作,结果也是失败。查看表结构后,修改储存引擎为 InnoDB,才成功。只是这个问题的错误信息太难理解,就几个数字,在没找到答案之前,害我还去查看了下 HandlerSocket 的源代码,当然,没有从中得到任何的提示。

Tagged , , ,

推荐《探索推荐引擎的秘密》系列

FROM: 推荐《探索推荐引擎的秘密》系列

最近推荐引擎成为显学,主要原因应该是电子商务的蓬勃发展。头些日子和图灵的两位老师吃饭,我甚至了解到因为推荐引擎以及机器学习领域的日渐火爆,图灵出的线性代数最近销量都很好,更别提大家现在到处都可以看到这个领域相关的招聘。我最近的创业项目iApp4Me其实也是一个推荐引擎的应用,我关注这个领域有很长一段时间了。这个领域还很新,还有很多未知的可能性,非常有意思。

不过在我关注的过程中,我发现很多人其实对什么是推荐引擎一知半解,这有点像5-6年前的技术界对搜索引擎的理解一样,那时候有人曾在CSDN言之凿凿的说Google其实用的就是Mysql无非是服务器多,而且管理员水平高而已。虽然大多数的高校的计算机专业都有信息检索课程,但是很多甚至是名校的毕业生也说不清楚搜索引擎是怎么回事儿。

事实上技术界开始对搜索引擎技术大规模的扫盲是从lucene这个开源软件的出现以后开始的,在这个问题上某Cutting同学居功至伟。后来也是在他组织下Lucene项目组开发孵化出来了Google的MapRuduce架构的开源实现Hadoop。在Yahoo、在阿里巴巴以及全世界很多公司和组织中Hadoop都起到了很大的作用。后来,lucene项目组还孵化了Mahout,一个基于Hadoop和Lucene的机器学习、推荐引擎项目。现在推荐引擎的实践中,这个Mahout这个项目也起到了很大的作用。值得推荐的相关开源项目还有weka,Javaml,numpy等。

当然光有这些开源项目也是不够的,如果你完全不理解推荐引擎的理论,你也很难玩转它。今天我发现了IBM开发者社区近期出现了一组文章《探索推荐引擎的秘密》,写的很好,可以算作非常好的这个领域的综述的文章,非常适合给不了解或者一知半解的人建立概念,所以在这里推荐给大家。

PS:
前几日,titan 推荐我看这篇日志,当然,重点还是文中提到的 IBM 开发者社区推出的关于推荐引擎的系列文章。推荐系统,去年有一阵子看过一些文章,但到此刻,基本上都已归还给作者,so, 现在将其转载过来,以备自己“捡”起来时资料的查找。

还有这篇文章 智能推荐系统 ,很值得一看。

Tagged

Web 开发人员速查卡

FROM: Web开发人员速查卡

无论你是多牛的程序员,你都无法记住所有的东西。而很多时候,查找某些知识又比较费事。所以,网上有很多Cheat Sheets,翻译成小抄也好 ,速查卡也好,总之就是帮你节省 时间的。之前给大家介绍过Web设计的速查卡25个jQuery的编程小抄,还有程序员小抄大全,今天转一篇开发人员的速查卡,源文在这里。下面的文章我就不翻译了。

HTML Cheat Sheet

CSS Cheat Sheets

Adobe Flash Cheat Sheets

ASP Cheat Sheets

PHP Cheat Sheets

MySQL Cheat Sheets

JavaScript Cheat Sheets

jQuery Cheat Sheets

Unicode Cheat Sheets

XML Cheat Sheets

mod_rewrite and .htaccess Cheat Sheets

Tagged

Super Smack

Super Smack 是一个强大的压力测试工具,支持 MySQL, PostgreSQL, Oracle。最开始的版本是由Sasha Pachev写成,由Jeremy Zawodny在维护,而现在,是
Tony Bourke
在维护,根据 Tony Bourke 的 开发 log 来看,2005-08-30 后,super smack 就已经停止发布新的版本,但这并不妨碍我们现在继续使用它(这个工具的开发者和维护者很伟大)。

安装

安装有点点麻烦,主要是编译时会出现一些问题。

[root@localhost tmp]# wget http://vegan.net/tony/supersmack/super-smack-1.3.tar.gz
[root@localhost tmp]# tar xvzf super-smack-1.3.tar.gz
[root@localhost super-smack-1.3]# ./configure  --prefix=/usr/local/super-smack --with-mysql --with-mysql-lib=/usr/local/mysql/lib/mysql --with-mysql-include=/usr/local/mysql/include/mysql
[root@localhost super-smack-1.3]# make
[root@localhost super-smack-1.3]# make install
说明

1 编译时,必须指定它所支持的数据库管理系统,否则会报如下错误。

......
configure: error:

You should include support for at least one database!

Reconfigure with one or more of:
  --with-mysql
  --with-pgsql
  --with-oracle

2 选择支持 MySQL 后, 在 MySQL 编译安装的情况下时, 也需要在编译参数中指定 MySQL 的 lib。
3 编译时,dictionary.h 和 super-smack.cc 报错:

......
dictionary.h:93: error: ‘strlen’ was not declared in this scope
super-smack.cc:126: error: ‘strlen’ was not declared in this scope

在 super smack 源代码的 src 目录,找到 dictionary.h, super-smack.cc,分别加上#include <string.h>
4 编译时,query.cc 报错

query.cc:200: error: cast from ‘char*’ to ‘unsigned int’ loses precision
query.cc:200: error: cast from ‘char*’ to ‘unsigned int’ loses precision
query.cc:219: error: cast from ‘char*’ to ‘unsigned int’ loses precision
query.cc:219: error: cast from ‘char*’ to ‘unsigned int’ loses precision

在 super smack 源代码的 src 目录, 找到 query.cc文件,将上面指定的 200, 219 行中的unsigned int改为unsigned long

用其测试 MySQL 之前奏

1 看 Makefile 才知道, smack 文件是放在 /usr/share/smacks 这个目录下(开始并不知道源代码中有一份), 产生的数据文件是在/var/smack-data目录下

...
SMACKS_DIR = /usr/share/smacks
DATADIR = /var/smack-data
...

2 根据 MySQL 的参数对应修改 /usr/share/smacks 目录下的 select-key.smack 和 update-select.smack 文件。包括 user, host, db, pass, 还有,最重要的 socket 路径。

3 未将 super smack 的 bin 目录加入 PATH 时,则还需:

gen_data_file "gen-data -n 90000 -f %12-12s%n,%25-25s,%n,%d";
#改为
gen_data_file "./gen-data -n 90000 -f %12-12s%n,%25-25s,%n,%d";
#或者直接
gen_data_file "/usr/local/super-smack/bin/gen-data -n 90000 -f %12-12s%n,%25-25s,%n,%d";

4 因为在 select-key.smack 和 update-select.smack 文件中指定的数据文件是 words.dat, 而安装默认情况下 words.dat 为空文件:

[root@localhost smack-data]# ls -al
total 5320
drwxr-xr-x  2 root root    4096 May 26 18:12 .
drwxr-xr-x 24 root root    4096 May 26 17:25 ..
-rw-r--r--  1 root root 5421337 May 26 17:25 ..  http_auth.dat
-rw-r--r--  1 root root       0 May 26 17:25 ..  words.dat

所以,需将 select-key.smack 和 update-select.smack 文件中指定的数据 words.dat 改为 http_auth.dat(其实为了统一,最好也是 http_auth.dat,因为文件中指定测试的表名是 http_atuh)。

当然,为了不修改,也可以在开始先执行如下命令:

[root@localhost bin]# /usr/local/super-smack/bin/gen-data -n 90000 -f %12-12s%n,%25-25s,%n,%d > /var/smack-data/words.dat

5 将 /usr/share/smacks 下文件 copy 到 /usr/local/super-smack/bin/ 目录下:

[root@localhost super-smack]# cp /usr/share/smacks/*  bin/

运行

[root@localhost bin]# ./super-smack -d mysql select-key.smack 20 1000
Query Barrel Report for client smacker1
connect: max=2204ms  min=1ms avg= 221ms from 20 clients
Query_type      num_queries     max_time        min_time        q_per_s
select_index    40000   0       0       5017.26

参数:

  • -d 指定测试的数据库管理系统的类型。
  • 20 20 个线程
  • 1000 每个线程 1000 个查询

实际上,还有-D参数来指定数据文件,默认路径如前面提到是 /var/smack-data, 这个路径需跟 select-key.smack 和 update-select.smack 指定的一致。

返回结果:

  • max=2204ms min=1ms avg= 221ms from 20 clients 连接的最大、最小及平均花费时间。
  • q_per_s|5017.26 QPS,每秒请求处理数
  • 40000, 脚本中,对查询次数做了翻倍处理, 所以, 20 × 1000 x 2 = 40,000.
Tagged ,

Install PHP 5.3 using source code

compile configuration

 ./configure  \
 --prefix=/usr/local/php --with-config-file-path=/usr/local/php/etc \
 --with-mysql=/usr/local/mysql --with-mysqli=/usr/local/mysql/bin/mysql_config  \
 --with-freetype-dir \
 --with-jpeg-dir \
 --with-png-dir \
 --with-zlib \
 --with-libxml-dir \
 --enable-xml \
 --disable-debug \
 --disable-rpath \
 --enable-safe-mode \
 --enable-bcmath \
 --enable-shmop \
 --enable-sysvsem \
 --enable-inline-optimization \
 --without-sqlite \
 --with-curlwrappers \
 --enable-mbregex \
 --enable-mbstring \
 --with-mcrypt \
 --enable-cgi \
 --enable-fpm --with-fpm-user=www --with-fpm-group=www
 
Tagged

Libtool library used but `LIBTOOL’ is undefined

Install HandlerSocket 时,报如下错误:

handlersocket/Makefile.am:3: Libtool library used but `LIBTOOL' is undefined

(Solution) Libtool library used but `LIBTOOL’ is undefined这里有提到类似的问题,解决办法很简单,合并文件后,删除多余的,然后创建一符号链接。

This is caused because FreeBSD renames the default tools, like aclocal to aclocal19. When aclocal is run, it looks for files in its FreeBSD set directory,
/usr/local/share/aclocal19 but most normal apps, like libtool, install to /usr/local/share/aclocal. The solution? Simple! Just merge the contents into one
directory, delete the other, and create a symlink!

当然,也可以直接:

cp -R /usr/local/share/aclocal /usr/share/
Tagged ,

vim 正则匹配

:%s/(\d\+,//gc 匹配 (123, , (1,
:%s/test=\(\d\+\)/test=\1/gc \1 匹配第一个 \( \) 的部分 \2 以此类推

Tagged

jQuery Tab

FROM: jQuery idTabs

推荐一 jQuery 实现 Tab 的插件,代码很简短,而且调用也非常简单。head 加上:

<script type="text/javascript" src="jquery.idTabs.min.js"></script>

class="idTabs" element 中,任何<a href="#tabs">以这种形式调用,被点击时都会显示对应 id="tab" element 中的内容。如下:

<ul class="idTabs">
  <li><a href="#jquery">jQuery</a></li>
  <li><a href="#official">Tabs 3</a></li>
</ul>
<div id="jquery">If you haven't checked out ...</div>
<div id="official">idTabs is only a simple ...</div>

demo

Tagged

PHP proxy

$requestUrl = 'http://request-url.com';
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $requestUrl);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_TIMEOUT, '300');
curl_setopt($curl, CURLOPT_PROXY, 'proxy-ip:proxy:port');
curl_exec($curl);
curl_close($curl);
Tagged , ,

跳出.each()

$.each(objs, function(i, n) {
    if(n.attr('checked') == true) {
        return false;
    }
});

return false 跳出 jQuery .each().

换到新的公司后,有专门的前端工程师,以至于之前知道的 JS 也都忘记。而最近做内部沟通系统时,一切需要自己实现,才又捡起来。

Tagged