Archive for April, 2013

ThinkPHP cofigure (配置文件)

April 25th, 2013

* 在首页定义 define(‘APP_DEBUG’, TRUE); 的情况下:
在Application/Conf/config.php中 定义 ‘APP_STATUS’ => ‘debug’, 或者 ‘APP_STATUS’ => ‘production’, 会加载Application/Conf/debug.php 或者 在Application/Conf/production.php. 在这两个文件中可以定义配置覆盖config.php中的配置。

* 在首页定义 define(‘APP_DEBUG’, FALSE); 的情况下:
Application/Conf/config.php中定义’APP_STATUS’无效, 因此debug.php和production.php都不会加载.
系统只会将config.php编译至 Application/Runtime/~runtime.php 中.

PHP Hash Chinese Character or String

April 22nd, 2013

Hash a Chinese character or string into a integer number. This might be useful when one wants to split a huge table which is indexed by Chinese strings horizontally into many tables.

	/**
	 * Hash a chinese charactor into an int number.
	 * @param string $c A chinese character
	 * @return number
	 */
	public static function hashZhChar($c) {
		return (ord(substr($c, 0 , 1)) -176)*94 + ord(substr($c, 1, 1)) - 161;
	}
	/**
	 * Hash a chinese string into an integer number.
	 *
	 * @param string $s A chinese string.
	 * @return number
	 */
	static function hashZh($s) {
		$first = mb_substr($s, 0, 1, 'UTF-8');
		$last = mb_substr($s, -1, 1, 'UTF-8');
		$middle = mb_substr($s, intval(mb_strlen($s, 'UTF-8')/2), 1, 'UTF-8');
		return self::hashZhChar($first) + self::hashZhChar($last) + self::hashZhChar($middle);
	}
	

Mysql replication set up and error fix

April 17th, 2013

Section 1: set up replication

1.1 on master:

* change my.cnf
* create slave user and grant proper privileges
* restart server

2.2 on slave

* change my.cnf with the created msater user
* restart server

Section 2: fix error on replication

2.1 on master:

* check master status:
mysql> show master status \G
* check processlist:
mysql> SHOW PROCESSLIST \G;

2.2 on slave

* check slave status and you will find the problem.
mysql> SHOW SLAVE STATUS \G
* check processlist:
mysql> SHOW PROCESSLIST \G;
* identify the problem
root> grep mysql /var/log/syslog

2.3 fix problems

* way 1: use SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 1 to tell the slave to skip one query (which is the invalid one that caused the replication to stop). If you’d like to skip two queries, you’d use SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 2; instead and so on.
mysql> STOP SLAVE;
mysql> SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 1;
mysql> START SLAVE;

* way 2: edit my.cnf and add ‘slave-skip-errors = NNN,NNN,NNN’ the numbers should be the errno(s) you found in /var/log/syslog.
root> vi /etc/mysql.my.cnf
and add the line ‘slave-skip-errors = NNN,NNN,NNN’ in the slave section.
root> /etc/init.d/mysql restart

Thinkphp memory leak? ThinkPHP内存泄露?

April 8th, 2013

Recently I encountered a problem with writing scripts with ThinkPHP framework. My scripts usually take long time to finish and have lots of communication with Mysql. However I find with ThinkPHP it’s very easy to come across with problem of out of memory, even if I’ve set the memory limit for each script to 256MB, which is quiet high!

Today I finally decided to carefully check this problem. The first thing came into my mind was that this must have something to do with db operations since I’m have heavy mysql operations. So I write a small piece of code to test whether I was right. Here is the code:

public function test() {
$mdl = M('t3');
$i = 0;
while(++$i < 300) {
$mdl->where('id=1')->select();
if($i % 50 == 0) {
echo number_format(memory_get_usage()) . "
\n";
}
}
}

I run this code and found this memory usage kept increasing which indicates there really exists a memory leak. Here is a sample output:

4,125,264 
4,146,688 
4,169,136 
4,189,536 
4,211,984

And then I replaced select() with buildSql() which only builds the sql instead of querying the db, I found that the memory stopped increasing. So the problem locates in the db operations!

After diving a bit in the source code, I found that the cause is the function Db::debug() which utilizes function trace(). Here is the Db::debug() definition:

    protected function debug() {
        $this->modelSql[$this->model]   =  $this->queryStr;
        $this->model  =   '_think_';
        if (C('DB_SQL_LOG')) {
            G('queryEndTime');
            trace($this->queryStr.' [ RunTime:'.G('queryStartTime','queryEndTime',6).'s ]','','SQL');
        }
    }

I realized that at the moment my application is still in the debug mode, which by default set the DB_SQL_LOG true. So now the solution is obvious: simply switch off the sql log, either by defining it in the config file such as Conf/debug.php or set it dynamically like this C(‘DB_SQL_LOG’, false). Because my website is still under development thus I need it on. So I choose the latter to set it dynamically in my script file.

But how the memory leak happens still remains uncovered. I’ll check it later.