<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	>

<channel>
	<title>N.S thoughts</title>
	<atom:link href="http://nightsailer.com/feed" rel="self" type="application/rss+xml" />
	<link>http://nightsailer.com</link>
	<description>...silent is golden...</description>
	<pubDate>Tue, 09 Mar 2010 15:40:17 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.7.1</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>令我发狂IE cookie的问题</title>
		<link>http://nightsailer.com/2010/03/09/685.html</link>
		<comments>http://nightsailer.com/2010/03/09/685.html#comments</comments>
		<pubDate>Tue, 09 Mar 2010 15:40:17 +0000</pubDate>
		<dc:creator>nightsailer</dc:creator>
		
		<category><![CDATA[Technotes]]></category>

		<category><![CDATA[cookie]]></category>

		<category><![CDATA[ie6]]></category>

		<guid isPermaLink="false">http://nightsailer.com/?p=685</guid>
		<description><![CDATA[这个问题基本上可以令人发狂。在 6.0 sp3 091208-2036以后的版本（其他版本也可能有问题）。
如果使用php的set_cookie 如果设置的过期时间比较短，比如180秒后过期，那么cookie将无法创建。
而之前的IE版本以及如Firefox,Chrome,Safari等均没有这个现象。
发现这个原因，是我折腾了一晚上，并且特意弄了台windows，用QQ远程在一个网友的机器上反复折腾，
当临近崩溃的最后一秒发现的。
血泪的教训。 cookie的过期时间最好在1个小时以上，通过将过期时间写入值存入cookie，然后判断，不要依赖浏览器，尤其是
狗屎的IE6. 
听说国外有人给IE6举办了葬礼，什么时候国内能有呢，那对于web开发真是个福音。不过，IE7/8对于网银的支持实在
是糟糕透顶，对于我这种mac用户，IE乃至windows的唯一用途就是上网银。。。所以，我的虚拟机用的还是IE6.。。
天大的讽刺！
还好，招商银行支持iphone，方便多了。
]]></description>
			<content:encoded><![CDATA[<p>这个问题基本上可以令人发狂。在 6.0 sp3 091208-2036以后的版本（其他版本也可能有问题）。<br />
如果使用php的set_cookie 如果设置的过期时间比较短，比如180秒后过期，那么cookie将无法创建。<br />
而之前的IE版本以及如Firefox,Chrome,Safari等均没有这个现象。</p>
<p>发现这个原因，是我折腾了一晚上，并且特意弄了台windows，用QQ远程在一个网友的机器上反复折腾，<br />
当临近崩溃的最后一秒发现的。</p>
<p>血泪的教训。 cookie的过期时间最好在1个小时以上，通过将过期时间写入值存入cookie，然后判断，不要依赖浏览器，尤其是<br />
狗屎的IE6. </p>
<p>听说国外有人给IE6举办了葬礼，什么时候国内能有呢，那对于web开发真是个福音。不过，IE7/8对于网银的支持实在<br />
是糟糕透顶，对于我这种mac用户，IE乃至windows的唯一用途就是上网银。。。所以，我的虚拟机用的还是IE6.。。<br />
天大的讽刺！</p>
<p>还好，招商银行支持iphone，方便多了。</p>
]]></content:encoded>
			<wfw:commentRss>http://nightsailer.com/2010/03/09/685.html/feed</wfw:commentRss>
		</item>
		<item>
		<title>PHP:call_user_func_array 导致的诡异事件</title>
		<link>http://nightsailer.com/2010/03/04/681.html</link>
		<comments>http://nightsailer.com/2010/03/04/681.html#comments</comments>
		<pubDate>Wed, 03 Mar 2010 16:40:01 +0000</pubDate>
		<dc:creator>nightsailer</dc:creator>
		
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://nightsailer.com/?p=681</guid>
		<description><![CDATA[最近，在升级原创榜时，发现了Doggy中Dt模版的一个诡异现象。当访问某些页面时，不定期出现Gateway timeout.
PHP没有报任何错误，也没有任何错误日志或者信息输出。我一度认为是模版的Tag有问题，因为当尝试
删除某些Tag后会解决这个问题。好景不长，更多的页面也冒出此类错误，然而当我把模版内部解析缓存关闭后，则不会出现此类错误。 于是转头跟踪Dt模版的内部调用。Dt模版的设计中，当模版第一次被解析后，将模版转换成Doggy_Dt_NodeList对象，并将它缓存到内部cache中。当模版下次被调用时，如果模版没有变动，则直接调用NodeList的render方法，这样可以减少模版解析的时间。然后，当从缓存中被反序列的Doggy_Dt_NodeList，却无法正确执行filter。看下面的一段代码：
if (isset(Doggy_Dt::$filters[$name])) {
                foreach ($args as $i => $argument) {
                    # name args
       [...]]]></description>
			<content:encoded><![CDATA[<p>最近，在升级原创榜时，发现了Doggy中Dt模版的一个诡异现象。当访问某些页面时，不定期出现Gateway timeout.<br />
PHP没有报任何错误，也没有任何错误日志或者信息输出。我一度认为是模版的Tag有问题，因为当尝试<br />
删除某些Tag后会解决这个问题。好景不长，更多的页面也冒出此类错误，然而当我把模版内部解析缓存关闭后，则不会出现此类错误。 于是转头跟踪Dt模版的内部调用。Dt模版的设计中，当模版第一次被解析后，将模版转换成Doggy_Dt_NodeList对象，并将它缓存到内部cache中。当模版下次被调用时，如果模版没有变动，则直接调用NodeList的render方法，这样可以减少模版解析的时间。然后，当从缓存中被反序列的Doggy_Dt_NodeList，却无法正确执行filter。看下面的一段代码：</p>
<p>if (isset(Doggy_Dt::$filters[$name])) {</p>
<p>                foreach ($args as $i => $argument) {<br />
                    # name args<br />
                    if (is_array($argument)) {<br />
                        foreach ($argument as $n => $arg) {<br />
                            $args[$i][$n] = $this->resolve($arg);<br />
                        }<br />
                    }<br />
                    else {<br />
                    # resolve argument values<br />
                       $args[$i] = $this->resolve($argument);<br />
                    }<br />
                }<br />
                array_unshift($args, $object);<br />
                $object = call_user_func_array(Doggy_Dt::$filters[$name], $args);<br />
            }</p>
<p>罪魁祸首是：call_user_func_array(Doggy_Dt::$filters[$name], $args)。</p>
<p>此处调用的call_user_func_array导致无法autoload class。于是php就悄无声息的挂了。</p>
<p>说是诡异，就是因为，如果不是反序列出来的，则能够正常的调用。<br />
此外，在官方手册中，对于call_user_func_array还有一段注释：</p>
<p>Note: Callbacks registered with functions such as call_user_func() and call_user_func_array() will not be called if there is an uncaught exception thrown in a previous callback.</p>
<p>也就是说，如果之前call_user_func_array()导致了未知的异常，那么后续的call_user_func_array则不会被调用。</p>
<p>后来检查，的确模版中也有错误的filter tag。 但，奇怪的是只有是反序列（unserialize）回来的才会重复此类<br />
现象。 因此，未必是完全如注释所说的原因。<br />
我猜测，有可能是call_user_func_array的错误导致了反序列后的对象无法正确再次调用call_user_func_array，至少在call_user_func_array中无法正确autoload class。</p>
<p>解决方法，其实也是修复上面代码的一个bug，在call_user_func_array前增加is_callable判断。<br />
if (isset(Doggy_Dt::$filters[$name]) &#038;&#038; is_callable(Doggy_Dt::$filters[$name])) {</p>
<p>}<br />
else {<br />
   Doggy_Log_Helper::warn(&#8217;unkown filter:&#8217;.$name);<br />
}</p>
<p>于是，世界就太平了。</p>
]]></content:encoded>
			<wfw:commentRss>http://nightsailer.com/2010/03/04/681.html/feed</wfw:commentRss>
		</item>
		<item>
		<title>MongoDB practice:基于MongoDB的好友消息动态的实现思路（How to build activity-streaming with MongoDb）</title>
		<link>http://nightsailer.com/2010/02/21/675.html</link>
		<comments>http://nightsailer.com/2010/02/21/675.html#comments</comments>
		<pubDate>Sun, 21 Feb 2010 07:50:28 +0000</pubDate>
		<dc:creator>nightsailer</dc:creator>
		
		<category><![CDATA[mongodb]]></category>

		<category><![CDATA[activity-stream]]></category>

		<category><![CDATA[好友动态]]></category>

		<guid isPermaLink="false">http://nightsailer.com/?p=675</guid>
		<description><![CDATA[好友动态是SNS最常见的功能。在设计“视觉中国原创榜”的好友动态时，也遇到如何实现的问题。和普通的SNS不同，
视觉中国原创榜用户不仅仅关注好友的动态，而且也要关注自己的作品和自己曾经关注过的作品的动态。
这样，就需要给用户分别push 3种不同的动态： 我的作品的动态，我关注过的作品（包括收藏过，评论过，评分过）的动态，
以及我关注的人（followed）的动态，未来还有好友的动态。这些动态，用户都应该可以取消关注。如何实现？
使用传统的数据库会面临很多问题，比如如何sharding。 幸运的是，我们用的MongoDB，这给我们解决问题带来了极大的方便。
首先，对每个用户，分别设计以下 collection
//by nightsailer.com
activity_streaming.feed, 属性分别为：
$schema = array(
  _id,  用户id
  followed_art => array(), 用户关注的作品id列表
  followed_people=>array(), 用户关注的人id列表
  my_art => array() 用户的作品id 列表
)
//by nightsailer.com
activity_stream.user:
   _id
   type=> 动态steam的类型（我关注的作品，我的作品，我关注的人）
   stream_target =>  对应动态stream的对象（作品id，人id）
   stream => array()  FIFO数组，存放activity的DBRef
   time => int  最后一次activity的时间戳
activity_stream.site
 [...]]]></description>
			<content:encoded><![CDATA[<p>好友动态是SNS最常见的功能。在设计“<a href="http://czone.chinavisual.com/" onclick="javascript:pageTracker._trackPageview ('/outbound/czone.chinavisual.com');">视觉中国原创榜</a>”的好友动态时，也遇到如何实现的问题。和普通的SNS不同，<br />
视觉中国原创榜用户不仅仅关注好友的动态，而且也要关注自己的作品和自己曾经关注过的作品的动态。<br />
这样，就需要给用户分别push 3种不同的动态： 我的作品的动态，我关注过的作品（包括收藏过，评论过，评分过）的动态，<br />
以及我关注的人（followed）的动态，未来还有好友的动态。这些动态，用户都应该可以取消关注。如何实现？<br />
使用传统的数据库会面临很多问题，比如如何sharding。 幸运的是，我们用的MongoDB，这给我们解决问题带来了极大的方便。</p>
<p>首先，对每个用户，分别设计以下 collection</p>
<p>//by nightsailer.com<br />
activity_streaming.feed, 属性分别为：<br />
$schema = array(<br />
  _id,  用户id<br />
  followed_art => array(), 用户关注的作品id列表<br />
  followed_people=>array(), 用户关注的人id列表<br />
  my_art => array() 用户的作品id 列表<br />
)<br />
//by nightsailer.com<br />
activity_stream.user:<br />
   _id<br />
   type=> 动态steam的类型（我关注的作品，我的作品，我关注的人）<br />
   stream_target =>  对应动态stream的对象（作品id，人id）<br />
   stream => array()  FIFO数组，存放activity的DBRef<br />
   time => int  最后一次activity的时间戳</p>
<p>activity_stream.site<br />
  _id  uuid<br />
  type:  动态类型<br />
  data:  hash 动态数据<br />
  time</p>
<p>activity_stream.queue<br />
 同 activity_stream.site<br />
存放待处理的动态队列</p>
<p>我们使用异步处理方式，按照以下流程：<br />
1. 当用户某些动作产生一个事件后，将事件push到activity_stream.queue， 通知worker进行处理<br />
2. worker 被唤醒，从activity_stream.queue中提取未处理的事件。<br />
3. worker 将事件放入activity_stream.site，作为全站动态广播<br />
4. worker 从activity_streaming.feed中反向查找事件的作品或作者是否有对应的人，如果有，则将此事件id<br />
push到activity_stream.user 的对应fifo数组中。<br />
（这是MongoDB最兴奋的地方，可以直接查询数组中的值，只要对数组进行索引）</p>
<p>这样，用户可以：</p>
<p>－ 从activity_stream.user 中删除某个事件<br />
－ 从activity_stream.feed 中删除某个关注的对象（实现类似忽略这个人的动态，忽略这个作品的动态等等）<br />
－ 当用户关注好友后，将其加入activity_stream.feed<br />
－ 当用户上传作品后，将作品加入activity_stream.feed<br />
－ 当用收藏、评分、评论后，将其作品加入activity_stream.feed</p>
<p>以上是<a href="http://nightsailer.com/category/mongodb">MongoDB实践</a>的第二篇，待续。</p>
]]></content:encoded>
			<wfw:commentRss>http://nightsailer.com/2010/02/21/675.html/feed</wfw:commentRss>
		</item>
		<item>
		<title>MongoDB practice: My Perl GridFS Wrapper</title>
		<link>http://nightsailer.com/2010/02/18/671.html</link>
		<comments>http://nightsailer.com/2010/02/18/671.html#comments</comments>
		<pubDate>Wed, 17 Feb 2010 16:29:42 +0000</pubDate>
		<dc:creator>nightsailer</dc:creator>
		
		<category><![CDATA[Perl]]></category>

		<category><![CDATA[mongodb]]></category>

		<category><![CDATA[gridfs]]></category>

		<category><![CDATA[perl]]></category>

		<guid isPermaLink="false">http://nightsailer.com/?p=671</guid>
		<description><![CDATA[简单写了一个Perl版本的GriFS的wrapper：
package CZone::GridFS;
use strict;
use MongoDB::GridFS;
use Path::Class;
use Digest::file qw(digest_file_hex);
use Digest::MD5 qw(md5_hex);
use IO::File;
use Data::Dumper;
use Any::Moose;
has database => (
    isa => &#8216;MongoDB::Database&#8217;,
    is  => &#8216;ro&#8217;,
    required => 1
    );
has _gridfs => (
    isa => &#8216;MongoDB::GridFS&#8217;,
    is  => &#8216;ro&#8217;,
  [...]]]></description>
			<content:encoded><![CDATA[<p>简单写了一个Perl版本的GriFS的wrapper：</p>
<p>package CZone::GridFS;<br />
use strict;<br />
use MongoDB::GridFS;<br />
use Path::Class;<br />
use Digest::file qw(digest_file_hex);<br />
use Digest::MD5 qw(md5_hex);<br />
use IO::File;<br />
use Data::Dumper;<br />
use Any::Moose;</p>
<p>has database => (<br />
    isa => &#8216;MongoDB::Database&#8217;,<br />
    is  => &#8216;ro&#8217;,<br />
    required => 1<br />
    );</p>
<p>has _gridfs => (<br />
    isa => &#8216;MongoDB::GridFS&#8217;,<br />
    is  => &#8216;ro&#8217;,<br />
    lazy => 1,<br />
    builder  => &#8216;_build__gridfs&#8217;,<br />
    );</p>
<p>has _file_collection => (<br />
    isa => &#8216;MongoDB::Collection&#8217;,<br />
    is  => &#8216;ro&#8217;,<br />
    lazy => 1,<br />
    builder => &#8216;_build__file_collection&#8217;<br />
    );</p>
<p>sub _build__gridfs {<br />
    my $self = shift;<br />
    return $self->database->get_gridfs;<br />
}</p>
<p>sub _build__file_collection {<br />
    my $self = shift;<br />
    return $self->database->get_collection(&#8217;fs.files&#8217;);<br />
}</p>
<p>sub get_bytes {<br />
    my ($self, $id ) = @_;<br />
    my $file = $self->_gridfs->find_one({_id => $id });<br />
    my $bytes;<br />
    my $fh = new IO::File \$bytes,&#8217;>';<br />
    $file->print($fh);<br />
    return $bytes;<br />
}</p>
<p>sub store_file {<br />
    my ($self, $file_path) = @_;<br />
    my $file = file($file_path)->absolute;<br />
    return undef unless -e $file;<br />
    my $md5 = digest_file_hex($file,&#8217;MD5&#8242;);<br />
    my $fh = $file->open(&#8217;r') or return undef;<br />
    return $self->_store_fh($fh,$md5);<br />
}</p>
<p>sub _store_fh {<br />
    my ($self,$fh,$md5) = @_;<br />
    # $grid_file isa MongoDB::GridFS::File<br />
    my $grid_file = $self->_gridfs->find_one({ &#8216;md5&#8242; => $md5});<br />
    if ($grid_file) {<br />
        $self->_inc_refs($grid_file->info->{_id});<br />
        return $grid_file->info->{_id};<br />
    }<br />
    else {<br />
        my $oid = $self->_gridfs->insert($fh,{<br />
            refs => 1,<br />
            md5 => $md5,<br />
        });<br />
        return $oid;<br />
    }<br />
}</p>
<p>sub store_bytes {<br />
    my ($self, $bytes) = @_;<br />
    my $md5 = md5_hex($bytes);<br />
    my $fh = new IO::File \$bytes,&#8217;<';<br />
    # my $fh = FileHandle->new;<br />
    # $fh->open(\$bytes,&#8217;<');<br />
    return $self->_store_fh($fh,$md5);<br />
}</p>
<p>sub unlink {<br />
    my ($self, $id ) = @_;<br />
    $self->_dec_refs(MongoDB::OID->new(value =>&#8221;$id&#8221;));<br />
}</p>
<p>sub _inc_refs {<br />
    my ($self,$id) = @_;<br />
    $self->_file_collection->update({_id => $id },{ &#8216;$inc&#8217; => { refs => 1}});</p>
<p>}</p>
<p>sub _dec_refs {<br />
    my ($self,$id) = @_;<br />
    $self->_file_collection->update({_id => $id },{ &#8216;$inc&#8217; => { refs => -1}});<br />
}</p>
<p>sub gc {<br />
    my $self = shift;<br />
    $self->_gridfs->remove({refs => 0});<br />
}</p>
<p>no Any::Moose;<br />
__PACKAGE__->meta->make_immutable;<br />
1;</p>
<p>__END__</p>
<p>这是从czone项目中的PHP代码移植过来的。<br />
方便将gridfs中的文件读写到scalar中。同时，通过检查存储文件的md5值，并记录相同文件的引用计数，相同文件只存储一个copy，节省空间。（BSON格式对于空间的需求是非常大的）</p>
]]></content:encoded>
			<wfw:commentRss>http://nightsailer.com/2010/02/18/671.html/feed</wfw:commentRss>
		</item>
		<item>
		<title>I&#8217;m back.</title>
		<link>http://nightsailer.com/2010/01/30/659.html</link>
		<comments>http://nightsailer.com/2010/01/30/659.html#comments</comments>
		<pubDate>Sat, 30 Jan 2010 06:58:26 +0000</pubDate>
		<dc:creator>nightsailer</dc:creator>
		
		<category><![CDATA[Misc]]></category>

		<guid isPermaLink="false">http://nightsailer.com/?p=659</guid>
		<description><![CDATA[域名转移完毕. 现在是新域名 nightsailer.com了.
wordpress中需要更新settings中的WordPress address (URL)和Blog URL.
然后使用301将night9.cn 重新定向到 nightsailer.com.
]]></description>
			<content:encoded><![CDATA[<p>域名转移完毕. 现在是新域名 nightsailer.com了.</p>
<p>wordpress中需要更新settings中的WordPress address (URL)和Blog URL.<br />
然后使用301将night9.cn 重新定向到 nightsailer.com.</p>
]]></content:encoded>
			<wfw:commentRss>http://nightsailer.com/2010/01/30/659.html/feed</wfw:commentRss>
		</item>
		<item>
		<title>重新启用nightsailer.com,转移中</title>
		<link>http://nightsailer.com/2010/01/30/653.html</link>
		<comments>http://nightsailer.com/2010/01/30/653.html#comments</comments>
		<pubDate>Sat, 30 Jan 2010 06:02:24 +0000</pubDate>
		<dc:creator>nightsailer</dc:creator>
		
		<category><![CDATA[Misc]]></category>

		<category><![CDATA[godaddy]]></category>

		<guid isPermaLink="false">http://night9.cn/?p=653</guid>
		<description><![CDATA[一直比较纠结要不要转移到godaddy中, 今天看到张宴的godaddy域名转移过程, 痛下决心
重新启用我原来的域名 nightsailer.com
这是我99年-2000年左右使用的个人域名,万网注册的,
当时用的mt3架的blog. 后来工作忙,不知道过期(可见万网的服务),当时连要自己设置ns记录都要收费!
索性就放弃了.
早上找了$7.49 的优惠码,注册2年,用支付宝付款,全部下来105.04RMB, 比起国内,真的很便宜了.
手里的几个cn域名马上也过期了,再也不续费了, .com的域名也准备转移走.
]]></description>
			<content:encoded><![CDATA[<p>一直比较纠结要不要转移到godaddy中, 今天看到张宴的<a href="http://blog.s135.com/domain_transfer/" onclick="javascript:pageTracker._trackPageview ('/outbound/blog.s135.com');">godaddy域名转移过程</a>, 痛下决心<br />
重新启用我原来的域名 nightsailer.com</p>
<p>这是我99年-2000年左右使用的个人域名,万网注册的,<br />
当时用的mt3架的blog. 后来工作忙,不知道过期(可见万网的服务),当时连要自己设置ns记录都要收费!<br />
索性就放弃了.</p>
<p>早上找了$7.49 的优惠码,注册2年,用支付宝付款,全部下来105.04RMB, 比起国内,真的很便宜了.</p>
<p>手里的几个cn域名马上也过期了,再也不续费了, .com的域名也准备转移走.</p>
]]></content:encoded>
			<wfw:commentRss>http://nightsailer.com/2010/01/30/653.html/feed</wfw:commentRss>
		</item>
		<item>
		<title>Notes: CentOS5.4编译Perl IO::Tty的处理</title>
		<link>http://nightsailer.com/2010/01/29/649.html</link>
		<comments>http://nightsailer.com/2010/01/29/649.html#comments</comments>
		<pubDate>Thu, 28 Jan 2010 17:40:59 +0000</pubDate>
		<dc:creator>nightsailer</dc:creator>
		
		<category><![CDATA[Perl]]></category>

		<category><![CDATA[Technotes]]></category>

		<guid isPermaLink="false">http://night9.cn/?p=649</guid>
		<description><![CDATA[直接编译IO::Tty,会导致:
Can&#8217;t load &#8216;/root/.cpan/build/IO-Tty-1.08-PWZkbn/blib/arch/auto/IO/Tty/Tty.so&#8217; for module IO::Tty:
 undefined symbol: strlcpy at &#8230;..
快速修正, 打开Makefile
DEFINE = -DHAVE_DEV_PTMX -DHAVE_GETPT -DHAVE_GRANTPT -DHAVE_OPENPTY -DHAVE_POSIX_OPENPT -DHAVE_PTSNAME -DHAVE_PTSNAME_R -DHAVE_PTY_H -DHAV
E_SIGACTION -DHAVE_STRLCPY -DHAVE_SYS_STROPTS_H -DHAVE_TERMIOS_H -DHAVE_TERMIO_H -DHAVE_TTYNAME -DHAVE_UNLOCKPT -DHAVE__GETPTY
去掉 中间的-DHAVE_STRLCPY和最后的-DHAVE__GETPTY
重新编译, make test.
ok!
]]></description>
			<content:encoded><![CDATA[<p>直接编译IO::Tty,会导致:</p>
<p>Can&#8217;t load &#8216;/root/.cpan/build/IO-Tty-1.08-PWZkbn/blib/arch/auto/IO/Tty/Tty.so&#8217; for module IO::Tty:<br />
 undefined symbol: strlcpy at &#8230;..</p>
<p>快速修正, 打开Makefile<br />
DEFINE = -DHAVE_DEV_PTMX -DHAVE_GETPT -DHAVE_GRANTPT -DHAVE_OPENPTY -DHAVE_POSIX_OPENPT -DHAVE_PTSNAME -DHAVE_PTSNAME_R -DHAVE_PTY_H -DHAV<br />
E_SIGACTION -DHAVE_STRLCPY -DHAVE_SYS_STROPTS_H -DHAVE_TERMIOS_H -DHAVE_TERMIO_H -DHAVE_TTYNAME -DHAVE_UNLOCKPT -DHAVE__GETPTY</p>
<p>去掉 中间的-DHAVE_STRLCPY和最后的-DHAVE__GETPTY</p>
<p>重新编译, make test.</p>
<p>ok!</p>
]]></content:encoded>
			<wfw:commentRss>http://nightsailer.com/2010/01/29/649.html/feed</wfw:commentRss>
		</item>
		<item>
		<title>PHP编写命令行脚本和后台运行程序的注意事项</title>
		<link>http://nightsailer.com/2010/01/29/641.html</link>
		<comments>http://nightsailer.com/2010/01/29/641.html#comments</comments>
		<pubDate>Thu, 28 Jan 2010 17:32:58 +0000</pubDate>
		<dc:creator>nightsailer</dc:creator>
		
		<category><![CDATA[PHP]]></category>

		<category><![CDATA[Thoughts]]></category>

		<category><![CDATA[shell guard]]></category>

		<guid isPermaLink="false">http://night9.cn/?p=641</guid>
		<description><![CDATA[在一些场合(如开发,测试), 可能需要使用PHP编写一些命令行的处理脚本,或者是长时间
后台运行的任务, 需要注意以下准则:
准则1. 尽量避免使用PHP编写后台运行程序, 尤其是类似while(true){&#8230;.} 这种循环的处理脚本.
比如,有时候我们需要定期检查数据库,然后有数据进行处理,没有数据等待.
我强烈建议不要使用PHP编写这样的类似service的脚本. php的gc并不稳定, 当运行到一定时候,
会异常退出. 另外, PHP也不擅长做命令行脚本. 看看Phing, 号称PHP port的Ant, 但是性能
糟糕的一塌糊涂, 远不如使用几个unix工具+shell来的快捷. (更别提windows,那基本是不可用).
使用Perl,Python来完成相应的任务吧, 那会让你很愉快, 或者,Ruby也不错.
准则2 编译特殊版本的php
如果一定要沉迷于PHP解决, 那么首先, 重新编译PHP,去掉所有不实用的模块. 增加PHP的稳定性.
准则3 不要直接使用fork 或者 nohup
不要在PHP中直接使用fork来进入后台运行, 也不要直接使用nohup来运行直接运行php 循环脚本.
准则4 使用 shell guard 来完成PHP的后台循环运行
php的脚本只需要处理一次数据后马上退出,不要使用任何while(true) 这样的脚本来挂起等待.
相反的, 可以使用以下的shell gurad 来完成上述工作:
night9.cn# cat guard.sh
DIR=`pwd`
while true; do
    echo &#8220;start php script ..&#8221;
    php $DIR/thumbnail_worker.php
    [...]]]></description>
			<content:encoded><![CDATA[<p>在一些场合(如开发,测试), 可能需要使用PHP编写一些命令行的处理脚本,或者是长时间<br />
后台运行的任务, 需要注意以下准则:</p>
<p>准则1. 尽量避免使用PHP编写后台运行程序, 尤其是类似while(true){&#8230;.} 这种循环的处理脚本.</p>
<p>比如,有时候我们需要定期检查数据库,然后有数据进行处理,没有数据等待.<br />
我强烈建议不要使用PHP编写这样的类似service的脚本. php的gc并不稳定, 当运行到一定时候,<br />
会异常退出. 另外, PHP也不擅长做命令行脚本. 看看Phing, 号称PHP port的Ant, 但是性能<br />
糟糕的一塌糊涂, 远不如使用几个unix工具+shell来的快捷. (更别提windows,那基本是不可用).</p>
<p>使用Perl,Python来完成相应的任务吧, 那会让你很愉快, 或者,Ruby也不错.</p>
<p>准则2 编译特殊版本的php<br />
如果一定要沉迷于PHP解决, 那么首先, 重新编译PHP,去掉所有不实用的模块. 增加PHP的稳定性.</p>
<p>准则3 不要直接使用fork 或者 nohup<br />
不要在PHP中直接使用fork来进入后台运行, 也不要直接使用nohup来运行直接运行php 循环脚本.</p>
<p>准则4 使用 shell guard 来完成PHP的后台循环运行<br />
php的脚本只需要处理一次数据后马上退出,不要使用任何while(true) 这样的脚本来挂起等待.<br />
相反的, 可以使用以下的shell gurad 来完成上述工作:<br />
night9.cn# cat guard.sh<br />
DIR=`pwd`<br />
while true; do<br />
    echo &#8220;start php script ..&#8221;<br />
    php $DIR/thumbnail_worker.php<br />
    echo &#8220;respawn the worker&#8230;&#8221; </p>
<p>上面这种脚本我称之为shell guard.这样的好处是你的后台脚本永远可以可靠的运行,一旦因为php自身出现问题(如内存溢出),那么马上就可以立即重新执行.<br />
对于检查,执行,休眠模式,可以使用和以下类似的:<br />
while true; do<br />
    php ./realtime_data_worker.php<br />
    echo &#8220;paused 10s&#8221;<br />
    sleep 10<br />
done</p>
<p>上述shell guard的另一个好处就是一旦你更新了Php文件, 下次运行时就是新的了. 而无须kill掉在重启.<br />
特别适合频繁变更的情况,减少你的工作量.</p>
<p>准则5 可以在你PHP脚本中监控执行的情况, 当执行了一定次数或者内存消耗到一定,则exit, 释放占用的内存,<br />
防止内存泄露.<br />
这条一定要和shell guard来配合.</p>
<p>如果你用windows, 抱歉, 这不在我考虑的范围之内.</p>
<p>准则6 如果以上仍然无法解决一些问题, 那么请参考第一条,使用Perl/Python重写. 立刻会药到病除 <img src='http://nightsailer.com/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> </p>
<p>PS: 某些copy &#038; paste的人儿, 转载我的笔记麻烦给个出处. 我现在知道某些人为何使用我不称我,而使用类似night9.cn认为这样的第三人称说法, 都是某些热衷把转载当自己原创使用的人害得,但每次我看到这样的第三人称总会稀稀拉拉掉一地鸡皮疙瘩.</p>
<p>我写的所有笔记和心得都是自己实践, 主要是为自己备忘使用,都是原创,无须声明.<br />
有时候很纳闷, 转载有必要么?<br />
google可以告诉你一切. 减少点碳排放吧.</p>
]]></content:encoded>
			<wfw:commentRss>http://nightsailer.com/2010/01/29/641.html/feed</wfw:commentRss>
		</item>
		<item>
		<title>Mouse,Moose和MooseX::Declare</title>
		<link>http://nightsailer.com/2010/01/28/637.html</link>
		<comments>http://nightsailer.com/2010/01/28/637.html#comments</comments>
		<pubDate>Wed, 27 Jan 2010 18:56:05 +0000</pubDate>
		<dc:creator>nightsailer</dc:creator>
		
		<category><![CDATA[Perl]]></category>

		<category><![CDATA[moose]]></category>

		<category><![CDATA[moosex::delcare]]></category>

		<guid isPermaLink="false">http://night9.cn/?p=637</guid>
		<description><![CDATA[如果你是一个Perl的开发者, 现在还不知道Moose那么你对Perl的了解基本上还停留在10年前了.
虽然国内Perl的开发者寥寥无几, 但Perl的强大远远超越一般人的想象空间.
我使用Perl是让自己更愉快,因为很多事情变得很简单.
Perl的OO一般人很难理解, 但是却用了最简单和巧妙的方式实现了,想想, 一个bless搞定, 再看看
PHP之类的,多么臃肿.
有了Moose,你会发现, 不仅仅OO,AOP这些东西实现起来是多么的轻松.
当看到MooseX::Declare, 你更会惊叹, &#8220;这还是Perl么?&#8221;.
use MooseX::Declare;
class BankAccount {
    has &#8216;balance&#8217; => ( isa => &#8216;Num&#8217;, is => &#8216;rw&#8217;, default => 0 );
    method deposit (Num $amount) {
        $self->balance( $self->balance + $amount );
    }
   [...]]]></description>
			<content:encoded><![CDATA[<p>如果你是一个Perl的开发者, 现在还不知道Moose那么你对Perl的了解基本上还停留在10年前了.<br />
虽然国内Perl的开发者寥寥无几, 但Perl的强大远远超越一般人的想象空间.</p>
<p>我使用Perl是让自己更愉快,因为很多事情变得很简单.</p>
<p>Perl的OO一般人很难理解, 但是却用了最简单和巧妙的方式实现了,想想, 一个bless搞定, 再看看<br />
PHP之类的,多么臃肿.</p>
<p>有了Moose,你会发现, 不仅仅OO,AOP这些东西实现起来是多么的轻松.<br />
当看到MooseX::Declare, 你更会惊叹, &#8220;这还是Perl么?&#8221;.</p>
<p>use MooseX::Declare;</p>
<p>class BankAccount {<br />
    has &#8216;balance&#8217; => ( isa => &#8216;Num&#8217;, is => &#8216;rw&#8217;, default => 0 );</p>
<p>    method deposit (Num $amount) {<br />
        $self->balance( $self->balance + $amount );<br />
    }</p>
<p>    method withdraw (Num $amount) {<br />
        my $current_balance = $self->balance();<br />
        ( $current_balance >= $amount )<br />
            || confess &#8220;Account overdrawn&#8221;;<br />
        $self->balance( $current_balance - $amount );<br />
    }<br />
}</p>
<p>和教条的Python相比我喜欢Perl的哲学, 同样的结果可以有不同的选择, 如何做,取决你自己.</p>
]]></content:encoded>
			<wfw:commentRss>http://nightsailer.com/2010/01/28/637.html/feed</wfw:commentRss>
		</item>
		<item>
		<title>几个很有用的TextMate bundle</title>
		<link>http://nightsailer.com/2010/01/26/631.html</link>
		<comments>http://nightsailer.com/2010/01/26/631.html#comments</comments>
		<pubDate>Tue, 26 Jan 2010 14:22:51 +0000</pubDate>
		<dc:creator>nightsailer</dc:creator>
		
		<category><![CDATA[Misc]]></category>

		<category><![CDATA[Util]]></category>

		<category><![CDATA[ctags]]></category>

		<category><![CDATA[perl]]></category>

		<category><![CDATA[perl-completion]]></category>

		<category><![CDATA[Textmate]]></category>

		<guid isPermaLink="false">http://night9.cn/?p=631</guid>
		<description><![CDATA[TextMate的这几个bundle对我来说非常有用:
1. CTags
和vim中的类似,可以ctrl+] 可以快速列出和跳转到symbol所在的文件位置. 有点遗憾的是不能想vim那样返回.
适合多数的编程语言.
2. Devel::IntelliPerl
Perl的自动解析和语法提示,能够根据指定变量的上下文给出语法提示,主要是列出可以调用的方法. 很cool.
除了TextMate,还支持vim. 由于使用Moose进行反射分析,可以显示出继承的方法. 比单纯的正则分析
要准确的多.
3. Act
可以使用正则表达式快速搜索项目中的文件. 使用Perl编写, 是一个快速和强大的grep 替代品.
TextMate中的search in project可以休息了. 如果你用TextMate,就知道在大的项目中使用search in project是
一种煎熬. 我很多次不长记性的调用,看着高起的CPU和风扇声,被迫kill掉textmate. 使用Act可以省去find+grep
的诸多不便. 而且, 由于是Perl编写,你可以使用完整的PCRE, 而不是GNU的精简版, 甚至你可以只搜索某种
编程语言的.很不错的.
其他如project plus,git bundle这些都是标配了.
]]></description>
			<content:encoded><![CDATA[<p>TextMate的这几个bundle对我来说非常有用:</p>
<p>1. <a href="http://github.com/textmate/ctags.tmbundle" onclick="javascript:pageTracker._trackPageview ('/outbound/github.com');">CTags</a><br />
和vim中的类似,可以ctrl+] 可以快速列出和跳转到symbol所在的文件位置. 有点遗憾的是不能想vim那样返回.<br />
适合多数的编程语言.</p>
<p>2. <a href="http://search.cpan.org/dist/Devel-IntelliPerl/" target="_blank" onclick="javascript:pageTracker._trackPageview ('/outbound/search.cpan.org');">Devel::IntelliPerl</a><br />
Perl的自动解析和语法提示,能够根据指定变量的上下文给出语法提示,主要是列出可以调用的方法. 很cool.<br />
除了TextMate,还支持vim. 由于使用Moose进行反射分析,可以显示出继承的方法. 比单纯的正则分析<br />
要准确的多.</p>
<p>3. <a href="http://search.cpan.org/perldoc?App%3A%3AAck" target="_blank" onclick="javascript:pageTracker._trackPageview ('/outbound/search.cpan.org');">Act</a><br />
可以使用正则表达式快速搜索项目中的文件. 使用Perl编写, 是一个快速和强大的grep 替代品.<br />
TextMate中的search in project可以休息了. 如果你用TextMate,就知道在大的项目中使用search in project是<br />
一种煎熬. 我很多次不长记性的调用,看着高起的CPU和风扇声,被迫kill掉textmate. 使用Act可以省去find+grep<br />
的诸多不便. 而且, 由于是Perl编写,你可以使用完整的PCRE, 而不是GNU的精简版, 甚至你可以只搜索某种<br />
编程语言的.很不错的.</p>
<p>其他如project plus,git bundle这些都是标配了.</p>
]]></content:encoded>
			<wfw:commentRss>http://nightsailer.com/2010/01/26/631.html/feed</wfw:commentRss>
		</item>
	</channel>
</rss>
