qyb的博客

前两天碰到 greader/gmail 暴慢的故障

前一分钟还好好的,突然 gmail 和 greader 就同时慢了下来

故障现象是加载页面(包括 js)速度还算可以接受,但 Ajax 开始运行后就没有数据返回了。在这个期间内其它同事的应用都很正常,可见不是网络问题。被迫用 gmail 的 BasicHTML 模式——不过也是很慢。持续了大约一天的时间,然后突然又同时恢复。

猜测在请求个人的数据的时候(mail & feed),google 的前端 web 服务器收到 request 后,首先要和某个服务交互一下,然后才能继续请求其它服务。好比以前 gmail 的 addressbook 服务故障后导致所有人登录不了邮箱一样,这次又是 reader 和 mail 同时依赖的一个服务出了故障.

下回再碰到这种情况应该就有经验了,耐心等待就是

Topic: 技术

奇怪的休止符

在小步舞曲里面除了波音之外,还出现了一种诡异的休止符(五线谱外的休止符),见下:

From blog 配图

从右手谱来看这里明明是3/4拍的曲子,可左手谱...数一数居然是5/4拍了

搜索到一个达人解释,但看得还是稀里糊涂。不过天才qyb终于最后想明白了这里该怎么弹,就是:左手可以视为在弹两组音。第一小节的一组(一指弹奏)是一个1/4休止符+1/2的 Re,另一组(三指弹奏)是1/2的 Si + 1/4的Si;第二小节同样是(一指弹奏)1/4休止+1/2 Mi,以及 (二指弹奏)1/2 Do + 1/4 Do

详细说第一小节的指法是,左手三指首先弹 Si, 1/4 拍后一指弹 Re, 再 1/4 拍后三指抬起,再落下,1/4拍后小节结束..

详细曲谱在http://www.free-scores.com/download-sheet-music.php?pdf=239

PS: 我的练琴现在完全是自学。女儿还是继续她的汤普森+拜厄教程,我则是按照随电钢琴带的 60 首曲子的难度从低到高练习——难度分A/B/C三档。A档大概是8首曲子,而经典到恶俗的《致爱丽丝》被列入B档,估计要到明年中才开始练习了。电钢琴+Youbute,我觉得是互联网时代的新潮组合,比看什么教学DVD有趣多了

Topic: 音乐

today

1. 第一次一个人开车.
2. 小步舞曲勉勉强强能弹完整了
3. 把内部wiki路径整理了一遍

4. 发现搜狐内部原来有一个 cygwin 的镜像,同时被维护的还有一个 CPAN 镜像.

Topic: 生活

佩措尔德 G大调小步舞曲

《快乐的农夫》早就练好了,现在的目标是 Minuet in G major。

这首曲子听起来是相当的耳熟,以前一直传闻是巴赫的,后来考证出乃 Christian Petzold 的作品。现在右手已经很熟练了,左手的第一部分也很熟了。但在双手合练时碰到一个障碍——有一个小节是右手弹1/4音符,左手弹1/8音符——对右撇子来说,让左手弹得比右手快还保持节奏是挺不习惯的;而且紧跟这一小节后右手是一个波音左手有一个指位的变化,就更增加了偶这种菜鸟的心理畏惧感。

最近几个小时的练琴都是在攻克这个难关,争取本周能搞定,这个月把这首曲子练过去,08年结束之前再学一首新曲子

Topic: 音乐

关于 "#include"

我想写C程序都通常是把系统头文件放在最上面,然后是第三方库的,最后是我自己的,比如下面这样

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3.  
  4. #include <mysql.h>
  5.  
  6. #include <my_foo.h>
  7. ...

前天动手把我们的 apache module 移植到 nginx 上,里面自然是要 include 一堆 nginx 自己的头文件的。但它需要调 openssl 的库,那把 openssl 的头文件放哪里呢?我想了一下,觉得 openssl-devel 是系统自己 yum 安装上的,应该比 nginx 有更高的优先级,于是就是这么一个顺序

  1. #include <openssl/rsa.h>
  2. #include <openssl/pem.h>
  3.  
  4. #include <ngx_config.h>
  5. #include <ngx_core.h>
  6. #include <ngx_http.h>

(你看,我还是相当注重长幼尊卑的,正统思想啊~~)

这样程序似乎也没有问题,可就一个麻烦事情——调用 nginx 的 log 功能时就会 crash!用 gdb 跟踪,发现是使用 request->connection->log 的指针为空...

但就在 nginx 的代码里,向我的 handler 传入 request 之前,r->c->log 还是一个合法的指针,只要一进我的函数,这个就成了 NULL,而且一旦 handler 结束,指针值又非空了..

写到这里,聪明的读者就应该知道这是由于头文件预处理,导致两边结构体定义不一致。connection 这个结构体是如此定义的:

  1. struct ngx_connection_s {
  2. ...
  3. #if (NGX_SSL)
  4.     ngx_ssl_connection_t  *ssl;
  5. #endif
  6. ...
  7. };

就这么一个小小的 bug,足足花了2个小时才找到原因。

获得什么教训呢?

  1. 下回再用 gdb 跟踪到这种情况,应该能第一时间意识到结构体错误
  2. 如果要提供开发接口给第三方,那第三方可能直接使用的结构体里千万不要包括预处理代码
  3. 只要小心,是可以避免预处理的。但人总有大意的时候,那就养成一个好习惯,把预处理部分都放在结构体的最后,这就考验第三方开发者的人品了

最后是一篇新鲜热辣刚出炉的Nginx模块开发备忘:http://www.dup2.org/files/nginx_module_development.html
nginx 的中文 wiki 上有人写了一篇很好的翻译,我的备忘和其比起来,多了一些数据结构的分析。

Topic: 技术

发现 PyCrypto 不如 ctypes 来得方便

至少对于一个C程序员来说是这样..

有一段RSA签名的程序,原本是用 C 调 libcrypto 包装成 jni 由 java 使用的,现在打算在 python 里面实现一个类似的功能,这段 C 代码大概是这样:

int rsa_sign(char *private_keyfile, char *message, int message_len, char *buf, int buf_size)
{
RSA *key;
int malloc_size, rsa_size;

unsigned char *rsa;

BIO *bio;

bio = BIO_new_file(private_keyfile, "r");
if (NULL == bio) {
return 0;
}
key = (RSA *)PEM_read_bio_RSAPrivateKey(bio, NULL, NULL, NULL);
BIO_free(bio);
if (NULL == key) {
return 0;

}

malloc_size = RSA_size(key);
rsa = (unsigned char *)malloc(malloc_size);
if (NULL == rsa) {
RSA_free(key);
return 0;

}

if (0 == RSA_sign(NID_md5, message, message_len, rsa, &rsa_size, key)) {
free(rsa);
RSA_free(key);
return 0;
}

RSA_free(key);

if (rsa_size/3 * 4 >= buf_size) { /* 结果的 Base64 编码后长度大于 buf_size, 等于也错误(后面需要放 '\0' 的位置) */
free(rsa);
return 0;

}

b64_encode(rsa, rsa_size, buf);

free(rsa);
return 1;
}

可是找遍 PyCrypto, 楞是没有看到怎么实现 PEM_read_bio_RSAPrivateKey 这样从一个 PEM 格式的私钥文件里加载的功能。然后去看哪些基于 PyCrypto 包装的其他的包,比如 ezPyCrypto, Keyczar(这还是 google 发布的),包括 mail-list 上提供的 patch.... 这些似乎倒是可以 load key 了,可缺省好像也并没有对 NID_MD5 的支持, 绝望~~~~

于是抱着试试的心态用 ctypes 直接去调 libcrypto——以前只是在 PyS60 上玩票似的用过 ctypes,以及在 Win32 下用过,而且那时候 ctypes 还不太成熟——结果发现 python2.5 的 ctypes 竟如此的好用:

import ctypes

import base64

crypto_handler = ctypes.cdll.LoadLibrary("/usr/lib/libcrypto.so")
BIO_new_file = crypto_handler.BIO_new_file
PEM_read_bio_RSAPrivateKey = crypto_handler.PEM_read_bio_RSAPrivateKey
RSA_size = crypto_handler.RSA_size
RSA_sign = crypto_handler.RSA_sign
BIO_free = crypto_handler.BIO_free
RSA_free = crypto_handler.RSA_free

NID_md5 = 4

bio = BIO_new_file("/yourpathfile.key", "r")
key = PEM_read_bio_RSAPrivateKey(bio, 0, 0, 0)
r = BIO_free(bio)
if r != 1:
# break here

print 'BIO_free error'

rsa_size = RSA_size(key)
rsa = ctypes.create_string_buffer(rsa_size)

sign_size = ctypes.create_string_buffer(4)

message = "foobar"
if 1 != RSA_sign(NID_md5, message, len(message), rsa, sign_size, key):
print 'RSA_sign error'

RSA_free(key)

print base64.urlsafe_b64encode(rsa.raw)

Topic: 技术

Apache Module 之在各个 request 之间共享数据(资源)的方法

不论是1.3还是2.x,apache 的模式都包括一个进程服务好多次请求后再退出。现在有一个需求,在每个 request handler 里面希望保存一些数据,这些数据在以后该进程处理其他的 request 中可能还要用到。

最开始我从 request->server->process->pool 顺藤摸瓜看到一个貌似是和进程有关系的资源池。于是仿照 RUN_INIT_ONCE 的apr_pool_userdata_get/apr_pool_userdata_set 来访问资源。这样做的确可以在 request handler 之间共享数据,可是进程退出(apachectl stop)的时候不会去调 cleanup,非常之讨厌。

google 了半天,并参考 apache 自己的 LDAP 模块,发现官方解决方案好像是这样的:

  • 定义module_config结构体的时候,增加一个资源指针
  • 注册child_init的hook函数,从传入的第一个参数(pool指针)里面申请资源
  • 用apr_pool_cleanup_register注册cleanup函数在这个 pool 上(这个是cleanup的核心步骤,我感觉理论上完全可以自己重新创建一个pool,或哪怕是自己malloc,但关键是把cleanup函数注册到这个pool上。因为在进程退出的时候apache只会去销毁这个pool上的资源,而cleanup函数是"资源"之一)
  • ap_get_module_config, 把申请到的资源挂到自己定义的config结构体里

这样在进程退出的时候就自动 cleanup 了。这也是为什么到了 apache 2.0 后就不再提供 child_exit hook 的原因,因为开发者觉得由于有 cleanup 注册的机制,对应 child_init 的 child_exit 就不再有存在的必要。

唯一的疑问就是,request->server->process->pool 和在 child_init 时传入的 pool 是什么关系..... 不过懒得再去寻根究底了,先把需求实现了再说。


2008/11/25 UPDATE:上述的过程有一些问题,就是用 module_config 放资源指针,这样会导致虚拟主机的访问可能取不到 config。最简单粗暴的方法可能也是最有效的方法是用全局变量,当然别忘了 static 修饰。

Topic: 技术

取本机所有的 IP

代码修改自 qmail 的 ipme.c , 要点是对于 struct ifreq 里定义了 ifr_addr.sa_len 的系统(比如 FreeBSD),是和 Linux 不太一样的。
在 CentOS 3 和 FreeBSD 4.7 上测试通过

  1. /* ipme.c from qmail */
  2. #include "sys/types.h"
  3. #include "sys/ioctl.h"
  4. #include "sys/socket.h"
  5. #include "netinet/in.h"
  6. #include "net/if.h"
  7.  
  8. int main(int argc, char *argv[])
  9. {
  10.     struct ifconf ifc;
  11.     int sockfd;
  12.     char buf[20000];
  13.     char *ptr;
  14.  
  15.     if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
  16.         return -1;
  17.     }
  18.  
  19.     ifc.ifc_buf = buf;
  20.     ifc.ifc_len = sizeof(buf);
  21.     if (ioctl(sockfd, SIOCGIFCONF, &ifc) == -1) {
  22.         return -1;
  23.     }
  24.  
  25.     ptr = buf;
  26.     while (ptr < buf + ifc.ifc_len) {
  27.         struct ifreq *ifr;
  28.         struct sockaddr_in *sin;
  29.         int len;
  30.  
  31.         ifr = (struct ifreq *)ptr;
  32. #ifdef __FreeBSD__
  33.         len = sizeof(ifr->ifr_name) + ifr->ifr_addr.sa_len;
  34.  
  35.         if (ifr->ifr_addr.sa_family == AF_INET) {
  36.             printf("%s", ifr->ifr_name);
  37.             sin = (struct sockaddr_in *)&ifr->ifr_addr;
  38.             printf("\t%s", inet_ntoa(sin->sin_addr));
  39.             if (ioctl(sockfd, SIOCGIFFLAGS, ifr) == 0) {
  40.                 if (ifr->ifr_flags & IFF_UP) {
  41.                     printf("\tUP\n");
  42.                 } else {
  43.                     printf("\tDOWN\n");
  44.                 }
  45.             }
  46.         }
  47.  
  48.         // 这段代码来自 qmail 的 ipme.c, 在 FreeBSD 上实测中没有出现过 len 小的情况
  49.         if (len < sizeof(struct ifreq))
  50. #else
  51.         if (ioctl(sockfd, SIOCGIFFLAGS, ifr) == 0) {
  52.             if (ifr->ifr_flags & IFF_UP) {
  53.                 if (ioctl(sockfd, SIOCGIFADDR, ifr) == 0) {
  54.                     if (ifr->ifr_addr.sa_family == AF_INET) {
  55.                         sin = (struct sockaddr_in *)&ifr->ifr_addr;
  56.                         printf("%s\t%s\n", ifr->ifr_name, inet_ntoa(sin->sin_addr));
  57.                     }
  58.                 }
  59.             }
  60.         }
  61. #endif
  62.         len = sizeof(struct ifreq);
  63.         ptr += len;
  64.     }
  65. }
Topic: 技术

昨天终于把《快乐的农夫》的右手弹得像模像样了

"Joyous Farmer" Robert Schumann

左手好几个月前就能弹了,但右手怎么也不行... 后来挺忙的,就一直没有练这个曲子。

前天晚上练极简单的 Ode to Joy 以后,突然想着去把这首舒曼右手再练一下,没想到就很感觉很熟练了,:)

昨天反反复复弹到大拇指下某根筋隐隐作痛;今年的目标是把两手合起来...... 主要是缺练琴的时间,难啊~~~

自己弹没有感觉,看人家的演奏发现弹起来手的表演性还真强。

Topic: 生活 音乐

方刚的"三个容器"

见:http://fangzl.blog.sohu.com/102159550.html

昨天在一个小会上听方刚提到这三个容器,现在我觉得我可以帮着解读一下这三个代表的意思了....

第一个容器,是搜狐博客
第二个容器,搜狐空间... 搜狐空间只是起了一个 Space 的名

第三个容器,是....一张白纸. 用毛主席的话,就是好画最新最美的图画

核心是,这三个容器,在方刚看来,是...完全不兼容的。

但有总线把这三个容器串在一起...

但为什么方刚没有把privacy和 profile/relationship 归一处。而是和 APP 放在一个总线里面呢? 这个可得再问问他

Topic: 商业
订阅 RSS - qyb的博客