Sunday, 11 March 2007

Handle the XML Data by Serialising in PHP

前段时间,接手一个PHP Web Application。在这个程序中,当新用户Login之后,都需要从配置文件中读入数据,进行初始化。配置文件,采用的是XML格式,大小20KB~30KB。初始化的过程,包含了XML解析,和数据对象的建立。XML解析,使用DOM XML扩展来完成。

在调试的过程中发现,整个程序在运行的时候,初始化过程占用了大部分时间,使得用户在Login之后,有明显地反映迟钝的感觉。如何提供初始化的速度?Inspection的结果,经过初始化后的XML数据,最后都变成了PHP中的对象,并且对不同用户来讲,并没有什么特别的不同。非常幸运,PHP提供了串行化(Serialisng)这一功能。通过serialise处理,把初始化后的XML数据对象,以串行化的形式直接存储到文件中。这样处理的结果是,用户Login之后,仅仅只需要从文件中“反串行化”数据对象即可,从而初始化过程得以大大加快。

接下来的问题是,运行过程中是反串行化数据对象,那么谁来完成XML数据串行化?一旦XML数据有所改变,又该如何?在最后实现的程序中,是通过监控XML文件和串行化数据文件,来决定应该如何操作。如果没有串行化数据文件,那就进行XML解析、创建对象、串行化和文件保存,这一完整的初始化处理;如果发现XML文件比串行化数据文件“新”,说明XML文已有所更动,需要再重新进行一次完整的初始化处理;如果串行化数据文件,比XML文件“新”,说明这两个文件是对应的,这时直接从串行化数据文件中,反串行化出数据对象,就完成初始化过程。XML数据的每一次更新,串行化数据文件都会随之自动更新。如此这般,程序最终实现了对XML数据自动进行串行化处理、自动更新和自动载入。

这样的处理方式,让人有似曾相识的感觉。如果把XML文件看成*.c,串行化数据文件看成*.o,那么“串行化”操作实际就是一个编译的过程,只是这里“编译”的不是程序,而是XML数据。比较XML文件和串行化数据文件的新旧,来确定是否重新初始化,这根本就是一个make的自动过程。

编译过的东西,跑起来就是快。

Saturday, 10 March 2007

RELEASE: mod_scgi 1.12 for Apache 2 (Windows)

The mod_scgi for Apache 2 has been upgraded to SCGI 1.12.

You can download it from http://bigonez.googlepages.com/.

Friday, 9 March 2007

Using AUTO_INCREMENT field in MySQL

AUTO_INCREMENT,是MySQL数据库中,字段定义当中的一个可选属性,可以用来对每个纪录产生唯一标识符。简单的说,就是“自增加”数字字段。当我们不断地往数据表中写入数据的时候,auto increment字段的数值会不断地增加,并且这种增加是连续的。

前些日,James说,在他的那个数据收集程序中,使用了auto increment字段作为记录的ID。但他遇到问题是,该字段出现了“间隔”,ID号并不是我们认为的那样是连续的,出现了gap。他的程序是Python写的一个多线程、多路数据输入的数据收集程序,MySQL数据库接口当然就是那个MySQLdb。这里,就不去探讨James是如何发现和解决问题的。最后的结果,是在某一个线程中,虽然发出了insert指令,但是却没有commit。补上commit,就解决问题了。( 显然,他在这里使用了支持transaction的table,也没有打开数据库连接的“自动commit”。)

仔细想想,这个问题还是蛮有意思的。在我以前的认识中,insert指令在没有commit之前,不应该对DB有任何影响。但是在这里,一旦发出的insert指令,是针对一个包含了auto increment字段的表,那么MySQL就会立即“预先”将latest ID分配给该纪录,即使还没有commit该insert指令。之后的其它insert指令,则会获得后续更新的ID。如果有insert语句最终并没有commit,就会造成auto increment字段的不连续。

这样的结果表明,auto increment字段在MySQL收到insert语句的时候,就已经修改了内部的计数器,而不是等到commit的时候才动作,并且这个动作不可逆。