Monday, December 25, 2006

TortoiseSVN 共享文件夹下一样显示图标

虽然是 TortoiseSVN 既有功能,猜想很多人都不知道的。

正常情况下,如果你在一个网络共享文件夹下面 checkout 一个 subversion 控制的项目。这个项目的文件夹并不会像在本地文件夹中一样,以各式各样的图标来表示文件状态。你需要做的是稍许改一下配置:
TortoiseSVN -> Settings -> Look and Feel -> Icon Overlays -> Network Drivers

选中 Network Drivers,就能看到文件状态图标了。

货比三家

时常在网上书店买书,本着货比三家的原则,往返于各书店的价格页面,甚是累人。

也听说过用来比较价格的搜索网站,乘兴而去,败兴而归!

http://www.tejiawang.com/
收录站点少(2),价格信息单一

http://www.uobuy.com/
收录站点多(4),但是没有 china-pub,价格信息单一、滞后

http://www.danawa.com.cn/
不知所云

http://www.souchang.com/
收录站点少(1)


罢罢罢!

自己动手,丰衣足食。
http://sym.noticpan.org/

暂时只收录了当当和卓越,做了简单的消重再确认。

感想,卓越的页面要比当当规整一些,比较容易解析。

Sunday, December 24, 2006

也谈 Google 和百度

“百度更懂中文”,大家都这么说,著名用例:马勒隔壁的。

就当挑刺吧,正好刚才碰到了,举个例子
测试站点:
www.google.cn
www.baidu.com
搜索用例:
site:www.joyo.com Perl语言入门

从结果看,Google 给我的就是我要的;百度?不知道在干什么。

在中国,恐怕 Google 最痛的莫过于“不能用”。不谈 GFW,百度能做到,Google 为什么做不到?一样是企业,Google 确实逊人一筹。不过我没有这个烦恼,至少现在没有,所以我只用 Google。

Sunday, December 10, 2006

小心时区陷阱(二)

测试用例
#!/usr/bin/perl
use strict;
use warnings;
use Time::Piece qw//;
use Date::Simple qw//;
use POSIX qw//;

sub show_info {
my $msg = shift;
my $hour = (localtime)[2];
printf "tz=$ENV{TZ}, tzname=%s:%s, hour=%2d # $msg\n", POSIX::tzname, $hour;
}

$ENV{TZ} = 'JST-9';
print "Date::Simple version is $Date::Simple::VERSION\n";
show_info('start');
my $date = Date::Simple->new;
show_info('after new');
$date->strftime("%Y-%m-%d\n");
show_info('after strftime');
POSIX::tzset;
show_info('after tzset');


输出结果
tz=JST-9, tzname=JST:JST, hour= 8 # start
tz=JST-9, tzname=JST:JST, hour= 8 # after new
tz=JST-9, tzname=UTC:UTC, hour=23 # after strftime
tz=JST-9, tzname=JST:JST, hour= 8 # after tzset


另外,关于 $ENV{TZ},提醒一下。
假设机器的时区设置为 UTC+9,不考虑非法的时区设置,那么根据值的不同,分别会是这样的结果
1.  not exists $ENV{TZ}        UTC+9
2.1 if ( $ENV{TZ} ) {...} UTC+0
2.2 else {...} UTC+9


Patch for Date::Simple 3.02
$ diff -r Date-Simple-3.02.orig Date-Simple-3.02
diff -r Date-Simple-3.02.orig/lib/Date/Simple.pm Date-Simple-3.02/lib/Date/Simple.pm
158a159
>
160,161c161,174
< local $ENV{TZ} = 'UTC+0';
< return POSIX::strftime ($format, _gmtime ($self));
---
> my $exists_env_tz = exists $ENV{TZ};
> my $tz = $ENV{TZ} if $exists_env_tz;
>
> $ENV{TZ} = 'UTC+0';
> my $result = POSIX::strftime ($format, _gmtime ($self));
>
> if ( $exists_env_tz ) {
> $ENV{TZ} = $tz;
> } else {
> delete $ENV{TZ};
> }
> POSIX::tzset();
>
> return $result;

参考链接
rt#23875

Tuesday, December 05, 2006

小心时区陷阱(一)

不知道大家有没有碰到过这样的问题,原本好好的当前时区时间突然变为 0 时区时间。

这个问题困扰了我很久,原因有二:
1、程序不是个单文件脚本
2、单元测试无法重现错误

后来在同事的帮助下,总算找到了问题所在

localtime(3) calls tzset(3), but localtime_r(3) not.
threaded perl localtime() calls localtime_r(3) instead of localtime(3)

来看一下 Date::Simple 的一段源代码

sub format {
my ($self,$format)=@_;

$format= $fmts{refaddr($self)||''} || $fmts{ref($self)} || $Standard_Format
if @_==1;

return "$self" unless defined ($format);
require POSIX;
local $ENV{TZ} = 'UTC+0';
return POSIX::strftime ($format, _gmtime ($self));
}

POSIX::strftime() 调用 tzset() 时看到的环境变量 $ENV{TZ} 是 UTC+0。在这之后就有问题了,如果使用 localtime(),因为 localtime_r(3) 并不会调用 tzset(),所以即使环境变量 $ENV{TZ} 已经恢复原值,localtime() 查看内部变量的时候,还是之前的 UTC+0。

至于为什么 localtime_r(3) 不像 localtime(3) 一样调用 tzset(3) 根据环境变量重设时区,我理解下来的主要原因是因为,它是线程不安全的。可能会出现下面这种情况

thread1
thread2
tzset()
tzset()
localtime()
localtime()

另外,关于环境变量 $ENV{TZ}存在(exists),但其值为空的时候,也会得到 UTC+0 的结果。

相关链接:
perlbug #26136

Friday, November 03, 2006

AppLocale 和乱码

在安装 AppLocale 之后,微软安装程序包(MSI)的执行就会出现乱码。
网上广为流传的一个方法是把下面这个文件的内容清空,并将属性改为只读。

C:\WINDOWS\AppPatch\AppLoc.tmp


另有说法是直接删除亦可,并不会影响 AppLocale 的正常使用。

Monday, October 30, 2006

不那么成功的 Mozilla Firefox 2.0

在经历了短暂的亲密接触之后,工作和娱乐我都降级成了 1.5.0.7,很遗憾。

我很少降级软件,除非迫不得已。

2.0 的 UI 改进并不大,但是挺漂亮的,我很喜欢。至于把关闭按钮添加到每个标签页上,我倒觉得是个见仁见智的事情。除此以外,对我来说,就没有什么变化了。

工作环境下,2.0 本身并没有什么问题,蛮好的。但是,LiveHTTPHeaders 还没兼容 2.0,而对于我的工作来说,有时候它还真是那么得重要。在没找到替代插件之前,我能做的只能是降级 2.0。

娱乐环境下,出于不知名的原因,2.0 频频死机。好好的就失去响应了,还是缓不过神的那种。我现在用的网络本来就不好,这样一来,简直就是雪上加霜。没辙儿,怎么地我也犯不着跟自己过不去,降!

就这样,恋恋不舍地,我离开了 2.0。

Tuesday, October 24, 2006

外壳程序意外停止,Explorer.exe 被重新启动。

被这个问题困扰了一个星期,症状为:

在某些(我没能归纳出来)情况下,按下 Ctrl 键,Explorer.exe(不是浏览器,是最基础的那个 Explorer) 就崩溃重启了。没有错误报告,只能在事件查看器中发现来源于 Winlogon 的上述信息,事件 ID:1002。对其他程序倒是毫无影响,但是我就完全用不了 Ctrl+C/V 来操作文件了,甚是痛苦。

网上搜索了好几圈,看到有类似的问题,但是都没能解决我的问题。期间还差点弄爆系统,只要一按键盘,鼠标键盘全部失去响应,亏得有系统还原(擦把汗 -_-||)。最后总算撇到一文提到了金山词霸,嘿,还真对上号了!关闭 CB 就 OK。后来装了 CB 2005 的 SP1,就没有问题了。

小记一把,留作备忘。

Friday, October 20, 2006

MySQL 连接 localhost

在使用 mysql 连接 localhost 时,情况并不是表面上看起来的那样子。

举个例子:
$ mysql -u root test

这里没有指定主机,所以连接的是 localhost,若你是用 yum/apt-get/urpmi 等 RPM 管理工具安装了 MySQL 的话,这里称其为数据库 A,那么应该是很顺利地连接上了。然后,再安装一个 MySQL,称之为数据库 B,使用其他端口,比如 3307,再尝试连接。
$ mysql -u root -P 3307 test

你会发现,连上的还是数据库 A,而不是 B。

为啥乜?
因为连的是 localhost。

这种情况下,mysql 是通过 unix socket 而不是 tcp/ip 连接数据库的。所以,在本地有多个数据库的时候,用 -S 参数连接能保证 DWIM。举个例子:
$ mysql -u root -S /tmp/mysql_another.sock test

当然,也可以这样:
$ mysql -u root -h 192.168.0.1 -P 3307 test

只是 unix socket 方式可以获得更高的效率,闻得一说有 30% 之多,啧啧。

Thursday, October 19, 2006

MySQL 的 Control-C

Changes in release 5.0.25 (15 September 2006)

For the mysql client, typing Control-C causes mysql to attempt to kill the current statement. If this cannot be done, or Control-C is typed again before the statement is killed, mysql exits. Previously, Control-C caused mysql to exit in all cases. (Bug#17926; see also Bug#1989)

MySQL 总算解决这个问题了,放弃执行正在运行的 SQL 指令。

以往如果误执行了一个巨慢的 SQL 指令,通常的做法是 Control-C 退出并重新进入 MySQL 命令行环境,列出所有执行线程,找出那个慢郎中并杀之。现在好了,直接 Control-C 就能搞定了。

5.1 系在较早之前就加入了此功能,4.1 系至今没有同步此更新的迹象,遗憾……

Bug#1989 was submitted at 1 Dec 2003 12:51

忍不住牢骚一句,这个改进未免也来得太慢了一些啊!

Friday, October 06, 2006

heartbeat 学习笔记(二)

在 IP 的 failover 搞定之后,其他资源的添加就简单多了。
我这里要做的是把 Pound 挂到 heartbeat 下面去。需要添加的是一个支持 start & stop 的脚本,这里是个最简单的例子:
$ cat /etc/ha.d/resource.d/pound

#!/bin/sh

start() {
pound -f /etc/pound.cfg -p /var/run/pound.pid
}

stop() {
kill `cat /var/run/pound.pid`
rm -f /var/run/pound.pid
}

case "$1" in
start)
start
;;

stop)
stop
;;

*)
echo $"Usage: $0 {start|stop}"
;;
esac

然后把它添加到 haresources 中去:
$ cat /etc/ha.d/haresources

master_node 192.168.1.100 pound

至于 Pound 的设置,这里就略过不表了,搞定收工。

Thursday, October 05, 2006

heartbeat 学习笔记(一)

测试环境:
OS: CentOS 4.3
heartbeat: 1.2.3.cvs.20050927-1.c
两个节点,捆绑资源为 ipfail

/etc/ha.d/ha.cf 和 /etc/ha.d/haresources 基本上是照猫画虎,两个节点完全相同。认证模式为 crc,使用以太网接口、UDP单播方式通信。条件限制,没用使用串口。可用性测试为第三台主机不间断 ping virtual ip。auto_failback 设为 on。

下面我将主节点称为 A 节点,从节点称为 B 节点。
首先启动 A 节点的 heartbeat 服务,若不启动 B 节点的 heartbeat 服务,那么只有经过 initdead 时间后,A 节点才会启用本地资源;否则,在节点间发生通信后,根据设置文件及各节点的状态,A 节点会立即启用本地资源,这里指的是 virtual ip。

在 heartbeat 的文档中提到,ipfail 需要指定普通节点以外的 Ping 节点,以帮助各节点判断网络状况。Ping 节点一般可以是可用性比较高的网关路由器等。在实际测试中,从效果来看,有没有 Ping 节点并不影响效果。没有做更进一步的分析,跳过。

在启动各节点的 heartbeat 后,virtual ip 在 A 节点上正常启用了。然后关闭 A 节点的 heartbeat 来模拟 A 节点不可用的情况,B 节点顺利接过了 virtual ip。再启动 A 节点的 heartbeat,因为 auto_failback 为 on,所以 A 节点又重新接管 virtual ip。两次切换都没有影响第三台主机 ping 的结果,一直处于可用状态。

参考资料:
Linux HA
Linux 上的高可用中间件

Wednesday, October 04, 2006

NotiCPAN 正式上线

虽然功能不全,不过站点看起来已经不是那么得简陋了,接下来就是逐步完善功能了。

当前状态:
用户数:19
订阅数:318

Friday, September 29, 2006

MySQL 不能启动一例

现象为,启动、长时间等待,最后失败。
查看错误日志,没有任何有效信息。
060929 12:14:36 mysqld started
060929 12:14:36 mysqld ended

查看系统日志 /var/log/messages,能看到形如
Sep 29 11:51:46 localhost kernel: audit(1159498306.605:23): avc: denied { append } for pid=17579 comm="mysqld" name="mysql.err" dev=hda3 ino=4212878 scontext=root:system_r:mysqld_t tcontext=root:objec
t_r:var_lib_t tclass=file
Sep 29 11:51:46 localhost kernel: audit(1159498306.605:24): avc: denied { append } for pid=17579 comm="mysqld" name="mysql.err" dev=hda3 ino=4212878 scontext=root:system_r:mysqld_t tcontext=root:objec
t_r:var_lib_t tclass=file
Sep 29 11:51:46 localhost kernel: audit(1159498306.674:25): avc: denied { create } for pid=17579 comm="mysqld" name="mysql.sock" scontext=root:system_r:mysqld_t tcontext=root:object_r:var_lib_t tclass=sock
_file

排查后,发现为 selinux 所不容,关闭之,解决。

Tuesday, September 26, 2006

MySQL 的选项和变量

不得不说,MySQL 对于开发者是越来越友好。
关于可用的选项和变量,在参考手册中已经有了专门的章节,很好用。

Sunday, September 17, 2006

MySQL Replication 浅尝

虽然 RAID 1 可以避免硬盘的物理损坏带来的损失,但是如果整机发生故障,单节点的数据库(相信一般的中小型站点都是)依然会造成服务陷入较长时间不可用的状态。所以需要导入其他高可用方案,于是我认识了 MySQL Replication。

MySQL Replication 从 MySQL 3.23.15 开始被引入,包含于标准的 MySQL 发行版,可以实现完全复制另一个数据库,而且配置方法很简单,主要有以下几点。

一、主(被复制方)从(复制方)数据库使用相同版本,或者从数据库可以高于主数据库。反之则有较大风险,因为复制(replication)是基于操作(statement)的,而不是基于数据行(row)的,所以高版本的某些操作可能无法被低版本正确执行。MySQL 5.1 开始会引入基于数据行的复制(replication),是个很值得期待的新特性。

二、主从双方的初始数据状态要严格一致,即从库的初始数据要和主库二进制日志(binary log)指定的复制起始点所在时刻的数据要一致。如果备份方案是计划的一部分,那么这不算是个问题,一切都从零开始。但若是要对一个正在运行的数据库实施复制(replication),就不是件那么令人愉快的事情了,烫手山芋就是如何取得一个某时刻下完整的数据拷贝,MySQL 并没有提供一个像样的热备解决方案。如果是个纯 innodb 数据库的话,还能从 InnoDB 的提供商 Innobase Oy 那里获取一个热备工具,当然,价格不菲。除此以外,停机备份几乎是不可避免的,代价取决于数据量。

三、主库需要开启二进制日志,以及创建一个特权用户。从库则相应地在配置文件中指定使用该用户,另外可按需设置复制(replication)数据库(schema)的黑名单或白名单,一般来说,可以把 mysql 和 test 加入黑名单,即在复制时忽略这两个数据库的一切操作。

准备就绪后,只需要启动从数据库,实施备份就开始了。从库上有两个工作线程,其一负责从主数据库读取日志,写入本地中继日志(relay log),其一负责根据中继日志进行数据操作,两者交错工作。

主从数据库中的表类型(Engine)可以是不同的,这一特性可以带来多少效益完全取决于你的创意。简单点的例如,主库中表 A 使用 InnoDB 来满足较大量的并发读写操作,而从库的表 A 则使用 MyISAM 来创建全文索引实现全文检索,或者从库全部使用 ARCHIVE 来节省硬盘空间等等。

MySQL Replication 是单向的,但是从数据库同时可以扮演主数据库的角色,所以双向备份是可以有条件地实现的。主要障碍是数据同步存在延时(虽然正常情况下是毫秒级别的)所以无法保证数据库群任意时刻都拥有相同的数据,一定程度上可以通过全局性的读写规划和设置复制(replication)黑白名单来减轻这个问题,但总的来说是个比较冒险的做法。

在实际应用中我遇到过这样的问题,对于受 DATABASE CHARSET 影响的 LOAD DATA 操作(statement),从数据库并不能正确地复制(replication)这一操作(statement),效果等同于从数据库的 DATABASE CHARSET = latin1,是否是 bug 有待于 MySQL 开发者的验证。

更新:
06-10-23 已被确认为 bug,并被判与 15126 重复,后者提交日为 05-11-22。
07-05-01 MySQL Community Server 5.0.41 发布,bug fixed。

其他的,更多的,可以参阅 MySQL 参考手册第六章

Tuesday, September 12, 2006

noticpan.org update 060912

毛坯房在 perlchina 广告了一下,应者寥寥。也是,过分粗糙了,各方各面都是。同时,如期开始了装修工程。到现在为止,第一期简装已经完毕,还是很丑?多多包涵,多多包涵。期间自己在使用中发现了几个 BUG,都一一予以修正。还有部分功能缺失,如注销、忘记/更改密码等,也会于近日慢慢补上。
出乎意料的是,我自己订阅了 10+ 个模块,竟然两个多星期来没有受到一个更新通知,搞笑了,受打击了。但是不能气馁,要相信这个服务肯定是有用的,嗯嗯。
天色不早了,该休息了,各位晚安。

Wednesday, September 06, 2006

noticpan.org online

从想法到实施,花了三个周末,昨晚 noticpan.org 上线了。
最基础的邮件提醒功能已经可用,其他一切都处于史前文明水平,留待日后慢慢开化。
不容易啊,在虚拟主机上搭建 Catalyst 的应用程序。Catalyst 本身已经做得很好了,还有详细的教程说明如何在虚拟主机搭建站点。
革命尚未成功,同志还需努力!

Wednesday, August 30, 2006

DreamHost promo codes

正在筹划个站点,于是满地图找空间,最后决定买 Dreamhost 的虚拟主机。
最初是在 Catalyst 的 wiki 上看到它的广告的,那么想当然地以为它是支持 Catalyst 的,买了之后发现不是这样的,这是后话。
L1: Crazy Domain Insane (20GB disk, 1TB bw, $9.95/month)

咋一看,价格和内容都还不错;再一瞅,跟咱电信一样,包年免初装费,按月付费的话要额外追加一项
$49.95 set up fee

那一年就一年吧,$119.4,也还好吧。那么,最后掏钱之前 Google 一下,这 Dreamhost 到底怎么样,好不好,恕我孤陋寡闻,一搜就搜出了 promo codes 这个东西,大把大把的。使用促销代码注册,最多可以获得$97的优惠,然后$22.4就出手了。
回到上面的话题,原来 Catalyst 需要自己安装的,好就好在 Dreamhost 提供了 ssh/telnet 权限,可以在自己的目录下自行安装。当前正在摸索中……
既然 promo codes 利人又利己,那么我也来弄个玩玩
Code: NOTICPAN
PlanCostThis Code's Discount
L1 Monthly$59.90$50.00
L1 Yearly$119.40$97.00
L1 Two years$190.80$97.00
L2 Monthly$69.90$60.00
L2 Yearly$239.40$97.00
L2 Two years$382.80$97.00
L3 Monthly$89.90$80.00
L3 Yearly$479.40$97.00
L3 Two years$766.80$97.00
L4 Monthly$129.90$97.00
L4 Yearly$959.40$97.00
L4 Two years$1534.80$97.00
While L3 is at L2's price, L2's discount will be used for L3.

Thursday, August 24, 2006

Pound前端下Catalyst的https重定向问题

如果你使用Pound作为前端,那么不可避免地,必须使用Pound作为你的https wrapper,因为Pound和后端只用http通讯。然后说那个Catalyst的重定向,常规情况下,你可以使用这样的代码来做重定向
$c->res->redirect('/foo');

对于大多数现代浏览器,这个响应返回的头部是可以被正常解析的,所以如果你是从一个https入口进的话,这个重定向会正确地被浏览器解析成
https://example.com/foo

但是,根据RFC某某某号的描述,重定向的目标路径应该是全路径,这样的话就有问题了,首先,你必须借助uri_for这个函数来产生你的全路径
$c->res->redirect( $c->uri_for('/foo') )

然后,问题就来了,由于Catalyst只接受到了http的请求,它并不知道外面的世界是上海还是广州,于是,得到了
http://example.com/foo

诚然,也许你要的只是某个区域永远安全,那么简单的解决方法就是这样
my $uri = 'https://' . $c->req->header('host') . '/foo';
$c->res->redirect( $uri );

显然,我们要得更多,又要马儿好,又要马儿不吃草。所以呢,在很多站点的入口都能看到一个醒目的“安全登录”的标签。让你自己选,要安全就给你安全,不要?呵呵,我乐得省下这些开销。这样的话,情况就要复杂一些了,首先,为了让Catalyst知道你的来路,Pound必须履行告知的义务,比如这样

ListenHTTPS
AddHeader "secure: 1"
End

接着,就可以根据这个头部来分情况选择重定向的协议(schema)了,我比较倾向于自己写个插件
package Catalyst::Plugin::Secure;

use strict;
use warnings;

sub uri_for {
my ( $c, $path, @args ) = @_;

my $uri = $c->NEXT::uri_for($path, @args);
if ( $c->req->header('secure') ) {
my $str = $uri->as_string;
$str =~ s/^http/https/;
$uri = new URI( $str )->canonical;
}

return $uri;
}

1;

好,圆满了,多谢观赏!

Wednesday, August 16, 2006

正则表达式的写法和效率一例

#!/usr/bin/perl
use strict;
use warnings;
use Benchmark qw(:all);

my $b = cmpthese( -1,
{
pa => qq("It's a fine day today." =~ /a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z/g),
pb => qq("It's a fine day today." =~ /[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ]/g ),
pc => qq("It's a fine day today." =~ /[a-zA-Z]/g ),
}
);

上面的这个例子我一直跑不出个相对稳定的结果,只能随便拿个结果来说明一下:
        Rate   pa   pb   pc
pa 848885/s -- -61% -65%
pb 2204237/s 160% -- -9%
pc 2427045/s 186% 10% --

可以看到,从“或(|)”模式到“类([])”模式,正则匹配的效率可以得到大幅度的提高,如果在“类”中能利用“范围(-)”符的话,还可以有小幅度提升。粗糙地结论就是,正则愈短,效率愈高。

因而在处理特定字符集的情况下,可以将其浓缩成一个精简的字符类描述的话,在执行效率上应该是很有帮助的。

Monday, August 14, 2006

MySQL可靠吗?

由于工作的原因,一直用着MySQL,一来是免费,二来简单易用。
但是随着应用的扩展,对于功能和稳定性的要求也越来越高。最近遇到了一件事情,让我觉得很是不爽,MySQL究竟可不可靠?

事情是这样的,安装完MySQL之后,在简单配置了my.cnf和启动测试之后,就清掉了binlog打算投入使用了。由于经验不足,没有删除ib_logfileX,又因为在第一次启动后修改了配置文件,已创建的ib_logfileX的文件大小和配置文件中的innodb_log_file_size不一致,导致了接下来的问题。
启动MySQL,OK。导入预先准备好的SQL脚本,OK。然后,发现了原来显式声明了Engine=InnoDB的表全部创建成了MyISAM模式。
SHOW ENGINES;后看到InnoDB的状态为DISABLE,很是莫名……最后在hostname.err里面看到,因为innodb_log_file_size的问题,导致了:
1)InnoDB被自动禁用了
2)创建InnoDB模式的表的时候,自动转成了MyISAM

我觉得不满的是,InnoDB被禁用只是在日志里这么一笔带过,终端上没有任何警告信息。据说*nix程序的普识原则是没有输出就是没有错误,难道MySQL认为这只是个小问题,并不会影响用户使用?!之后的自动转换模式就是个衍生问题了,虽然有WARNING,不过在批处理模式下显然是没有任何帮助的了。

问题虽然很好解决,删除innodb-log,重启MySQL,ALTER TABLE,就可以了。但是如果问题发现的晚,或者系统不能轻易下线,那损失就不好估算了。

Saturday, June 24, 2006

Config::General

前面在Catalyst的ML中就配置文件采用哪个模块处理讨论得不亦乐乎,感觉很多人对YMAL都颇有微辞,比如不能使用Tab之类的,最后达成的比较一致的意见是使用Config::General。第一次听说这模块。
正好给朋友写了个脚本,尝试了一下。格式定义和Apache的配置文件格式很相似,就是同一层次的Hash引用和Array引用在配置文件中看起来是不同层的,稍稍有些不爽。例:
<hash>
 foo = bar
</hash>
array = 1
array = 2

好处就是通俗易懂,适用性比较广,毕竟更多人对Apache的配置文件格式比较熟悉。不过如果只是我个人使用,还是会选择YAML的,简洁明了,我喜欢。
---
hash:
 foo: bar
array:
 - 1
 - 2

Sunday, May 07, 2006

Catalyst项目组裂变

核心开发者sri宣布离开Catalyst项目组,另起炉灶Mojo。在我印象里,sri是最活跃的核心之一,感觉上想法也比较多。不知道这次人事变动会给Catalyst带来怎样的变化,拭目以待。

Thursday, April 20, 2006

DBIx::Class和DBI

今天在更新安装DBIx::Class 0.06001的时候,make test在测试关于cache的地方失败了。
究其原因,是因为测试cache是依赖于DBI的Trace Output的。而DBI 1.40在TraceLevel 1下,输出的内容有些问题,并且在DBI 1.43中得到了修正:
- Changes in DBI 1.43 (svn rev 377), 2nd July 2004
* Changed TraceLevel 1 to not show recursive/nested calls.

奇怪的是,在比较DBI 1.40的TraceLevel 1和TraceLevel 2的输出文件后,发现在TraceLevel 1下,输出的是recursive/nested calls的最后一句,不过这一点并没有在Changes中被提到。但是在逐版本安装测试1.42和1.43后,我确认这个问题是在1.43中修正了的。
已经把问题提交到了Dbix-class ML了,估计应该会在下一版本修正。

Saturday, April 01, 2006

如何正确设置svn仓库权限

在多用户环境下,如果你使用的是Berkeley DB作为后端,那么你多半遇到过这样的错误:
Berkeley DB error while opening environment for filesystem ...
DB_RUNRECOVERY: Fatal error, run database recovery

为了解决这个问题还是费了我不少功夫,所以这里小小地归纳一下。
首先每一个用户都需要有BDB文件的读写权限,所以通常情况下我们会创建一个用户组G,然后把所有用户都加入到G中,并且会把整个仓库的组设为G。但是,因为用户在操作BDB的时候会创建新文件,而这时使用的umask一般是022,即组用户没有写权限。此后,当其他用户试图操作该文件的时候就会发生上面的错误。
在svn的How-to文档中建议尽量避免多用户访问仓库,但是如果使用的是file:///或者svn+ssh://的话就完全没办法绕开了。于是《Version Control with Subversion》一书的第6章第5节中另外提供了一个解决方案:
$ cat /usr/local/bin/svn

#!/bin/sh

umask 002
/usr/local/subversion/bin/svn "$@"

即手动包装一下svn,在执行命令之前将umask改为002,问题就这样解决了。
svn作为新一代的版本控制系统,对于这样一个显然客观存在的问题竟然没有一个较好的解决方案,实在是令我吃惊不小。

Friday, March 31, 2006

《Learning Perl》

在国内很久没见过Perl的新书了,总算来了一本。《Perl语言入门(第4版)》,可惜是影印版。很多人都觉得影印版才好,原汁原味。不过我比较偏爱中文版,图个方便,翻看起来利索。
手头有中文的第3版,也是我Perl的启蒙老师,确实不错。第4版估摸着也差不多,差别是更加与时俱进,要不要也买一本呢,呵呵~

Friday, March 17, 2006

Moose

昨天看到的新模块,自我描述是Perl5 OO系统的一个扩展。
注目点
1、在类定义中可以很方便地声明属性的读写权限
2、在子类中可以定义父类方法的绑定方法
例:after 'a' => sub {}
意为在执行方法a之后,绑定执行sub {}。和NEXT有那么点像。
看着会是个挺有意思的东东,关注。

Thursday, March 16, 2006

《Intermediate Perl》

《Learning Perl Objects, References, and Modules》 的第二版,主要是增加了一些关于测试和CPAN的章节。
虽然连第一版都没好好看过,不过对Perl的新书还是很感兴趣的,最想看到的就是中文版。看着省力,就算翻译质量一般般。
不过回想想,手头有的不少是对折书,中文版看起来是比较难了……

其实我是一个程序员

俗话说,好记性不如烂笔头,所以,占块地儿,动动手。
懂的,不懂的,都写下来;想到的,悟到的,都记下来。
^_^