clojure recur

clojure是函数是编程语言,本身没有循环的语法。要实现类似循环的效果,需要用递归来实现。比如计算从1加到n的和这样一个函数: (defn addup     ([limit] (addup limit 0 0))     ([limit current sum]         (if (< limit current)             sum             (addup limit (+ 1 current) (+ current sum))))) 调用 (addup 10) 可以得到55 但是调用 (addup 50000) 不出意外,出现了StackOverflowException, 这是递归典型的错误。 为此,需要进行优化。尾递归优化是指如果递归满足一定条件,编译器可以将递归展开,避免出现栈溢出的问题。这里的条件,就是递归的最后一次调用是否是其本身,比如上面的代码,最后一次操作仍然是addup,即满足尾递归的条件,而如果同样的代码写成: (defn [...]

Posted in: 手艺 by Sunng 2 Comments

RPC, Serialization and Schema

The post is brought to you by lekhonee v0.7 糖果项目的后端用Java编写,我负责service gateway的开发(暂且叫sergent),服务以Java接口+Annotation的形式声明,与Spring集成使用,Java对象被序列化为JSON和XML(通过jackson和castor)与外部系统交互。专门的JSON Schema和XML Schema是可选的,系统交互通过简明的文档和人工确认。 RPC框架是跨进程、跨系统交互的重要工具,RPC框架中又包括远程调用、网络传输和序列化反序列化等等部分。流行的工具包括Facebook的thrift,Google的Protobuf和原先Hadoop项目下的avro。其中thrift包含远程调用、反序列化、网络等等全部的功能。Protobuf本身是一个序列化反序列化库,另有很多第三方RPC实现,avro目前除了序列化和反序列化的功能,也包含了ipc的HTTP Server和SocketServer等实现。在序列化的格式方面,Thrift支持JSON和二进制协议,Protobuf本身仅有二进制支持,但已经存在第三方的其他格式实现。 avro原生支持二进制和JSON格式。 从效率上来说,二进制方式的序列化要比文本方式的快。Google Code上(最近迁往了github)有一个tpc项目(thrift-protobuf-compare),根据这个项目的最新的比较结果(与原先不同): protobuf成为了三者中耗时最少的框架,之后是thrift和avro,这次avro的耗时甚至超过了文本方式的jackson(主要在反序列化上)。 但是二进制协议通常都需要定义Schema,thrift / protobuf / avro三者各自定义了Schema的格式,没有类似XSD和Json Schema的统一标准,也就是说,当你需要传输一个对象,就要为它编写一个Schema文件。按照通常的习惯,都是先编写Schema,然后通过命令行工具或者自动构建工具来生成Java source。对于新系统还好说,对旧系统这个改造就比较麻烦了。另外,二进制协议不便于调试,所以各个thrift/protobuf/avro先后也都有JSON的实现,在文本的序列化格式上,JSON对XML的优势是全方位的。 所以综合起来,很难说有一种完美的解决方案。二进制协议的效率高,但是改造、编写Schema的代价并不小,还要面对核心Model被绑架到具体框架的风险。文本协议开发简便,不需要Schema,直接POJO就可以序列化和反序列化,但是在时间和空间上都不如二进制的方式。 补充 从tpc项目的结果上看,kryo在时间、空间上都击败了所有对手,而且,kryo的API非常简洁,不需要Schema文件就可以序列化POJO,听起来太完美了,看来以后sergent要借鉴一下的。 补充 2010-06-14 发现avro现在也有ReflectDatumReader和ReflectDatumWriter,可以通过反射内部自动映射生成Schema,可以尝试一下。

Posted in: 手艺 by Sunng 8 Comments , ,

ibatis infinite loop when getFirstResultSet

前几天上线后老大发现几台负载非常高,dump线程状态后发现多个线程死循环在同一处,于是发现了ibatis的这个bug: https://issues.apache.org/jira/browse/IBATIS-384 https://issues.apache.org/jira/browse/IBATIS-587 在mysql数据库上,没有结果集时,stmt.getUpdateCount()会返回0,而非-1. ibatis 2.4.3   private ResultSet getFirstResultSet(StatementScope scope, Statement stmt) throws SQLException {     ResultSet rs = null;     boolean hasMoreResults = true;     while (hasMoreResults) {       rs = stmt.getResultSet();       if (rs != null) {         break;       [...]

Posted in: 手艺 by Sunng 4 Comments ,

Maven recipe #0

问题: 多个root pom的dependencyManagement有重复的内容,希望统一管理。 解决: 新建一个空pom.xml,在dependencyManagement中指定这些依赖,如 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">     <modelVersion>4.0.0</modelVersion>     <groupId>info.sunng</groupId>     <artifactId>root</artifactId>     <packaging>pom</packaging>     <version>0.0.1-SNAPSHOT</version>     <dependencyManagement>         <dependencies>             <dependency>                 <groupId>info.sunng</groupId>         [...]

Posted in: 手艺 by Sunng 7 Comments , ,

Sunng's Canvas based Heatmap API

Glad to announce my works this morning: A simple heatmap API based on HTML5 canvas. The programming interface is rather simple now. To create such a heatmap, you just new a heatmap object by: <canvas width=”300″ height=”215″ id=”canv”></canvas> heatmap = new HeatMap(“canv”); Then read your dataset and push data into the heatmap: heatmap.push(x, y, value); [...]

Suppressing simple-xml's class attribute

Simple-xml is an object-xml serialization and de-serialization framework. It’s featured by annotation-driven, light-weight and self-contained. In simple-xml, pojos that will be serialized are annotated with @Root, @Element, @Attribute or @Text. The problem is, when handling with inheritance, if the actual type is different from declared type, simple-xml will add a “class” attribute for de-serialization consideration. [...]

Posted in: 手艺 by Sunng 4 Comments ,

OAuth Step by Step

最近琢磨OAuth认证方式。OAuth的优点主要在于 用户不需要直接提供用户名密码给第三方应用,就可以让第三方应用访问受限资源; 资源提供方对第三方应用有更细粒度的控制。 在整个OAuth协议里,生成signature的base string是最容易出错的部分。它由HTTP方法名、URL编码的请求路径和请求的参数表组成。 请求的参数表是除去oauth_signature以外的所有参数,按参数名排序,并进行url转义 def to_signature_key(method, url, data): keys = list(data.keys()) keys.sort() encoded = urllib.quote(“&”.join([key+"="+data[key] for key in keys])) return “&”.join([method, urllib.quote(url, safe="~"), encoded]) 有了这个通用的生成signature base string的方法,以后就可以根据OAuth协议规范按步骤进行。 首先获取Request Token。这一步通常使用资源提供方注册的API Key和API Key Secret def request_token_params(consumer_key, consumer_secret, path, method=’GET’): data={} data['oauth_consumer_key']=consumer_key data['oauth_signature_method']=’HMAC-SHA1′ data['oauth_timestamp']=str(int(time.time())) data['oauth_nonce']=”.join([str(random.randint(0,9)) for i in range(10)]) print data msg = to_signature_key(method, path, data) [...]

Posted in: 手艺 by Sunng 1 Comment , , ,

Java嵌入式数据库的速度对比

Yan的APIKEY一直是用嵌入式的数据库存储的,最初使用的是hsqldb,最近又添加了H2和Derby的支持,基本上囊括了所有开源的Java嵌入式数据库。实现多了自然需要挑选、比较一下。 数据库特性的比较,H2的网站上有很好的Matrix,一目了然 http://www.h2database.com/html/features.html#comparison 关于速度的比较,今天做了一个简单的测试。 分别从derby / H2 / hsqldb中取出10 、100、1000条数据,循环100000次,比较耗时,如下: 三者的速度差距非常明显,hsqldb远快于其他两个。 而在10、100、1000条记录的索引上查询,并取出指定记录呢,同样是100000次,如下: 再索引上查询,速度受记录数量的影响非常微弱了。但是hsqldb还是远快于其他二者,有趣的是derby的速度要略微快于H2. 根据这样的结果,在Yan的应用中,hsqldb还是最理想的实现。

Posted in: 手艺 by Sunng 9 Comments ,

在RHEL4上搭建Python/Lighttpd/FastCGI环境

在一台赤裸裸的RHEL4上部署web.py程序,一切从几乎是从零开始。以下操作均以root用户操作。 1. 安装MySQL数据库 下载安装MySQL wget http://dev.mysql.com/get/Downloads/MySQL-5.1/mysql-5.1.41-linux-i686-glibc23.tar.gz/from/http://mirror.services.wisc.edu/mysql/ 解压,按照INSTALL文件说明进行安装,不多赘述 2. 安装Python环境 下载Python源码 wget http://www.python.org/ftp/python/2.6.4/Python-2.6.4.tar.bz2 解压,编译安装,不需要特殊操作。 下载Easy_install wget http://pypi.python.org/packages/2.6/s/setuptools/setuptools-0.6c11-py2.6.egg 安装 sh setuptools-0.6c11-py2.6.egg 安装相关Packages easy_install DBUtils easy_install flup easy_install web.py 安装mysql-python mysql-python包不能用easy_install安装,手动下载 wget http://downloads.sourceforge.net/project/mysql-python/mysql-python-test/1.2.3b1/MySQL-python-1.2.3b1.tar.gz?use_mirror=softlayer 加压,编辑site.cfg 指定mysql_config的路径,注意是新安装的mysql路径 mysql_config=/usr/local/mysql/bin/mysql_config 编译、安装 python setup.py build python setup.py install 声明libmysqlclient路径 export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/mysql/lib 3. 安装服务器环境 下载安装fastcgi头文件 wget http://www.fastcgi.com/dist/fcgi.tar.gz 解压,默认编译安装 下载安装PCRE wget ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-8.00.tar.bz2 解压,默认编译安装 下载lighttpd wget [...]

Posted in: 手艺 by Sunng 7 Comments , , ,

Nginx HTTP Push

前些天看到一个Nginx的Module,用来是实现Comet,今天简单试了一下功能。作者名叫Leo Ponomarev,项目地址:http://pushmodule.slact.net/ 安装 Module需要在编译时加入nginx,同时下载nginx和nginx-push-module,在nginx configure时增加一个参数: ./configure –add-module=path/to/nginx_http_push_module 使用 编写一个非常基本的nginx配置文件: events{ worker_connections 1024; } http{ server { listen 80; server_name localhost; location /publish { set $push_channel_id $arg_id; push_publisher; push_store_messages on; push_message_timeout 2h; push_max_message_buffer_length 10; push_min_message_recipients 0; } location /subscribe{ push_subscriber; push_subscriber_concurrency broadcast; set $push_channel_id $arg_id; default_type text/plain; } } } 一个简单的Server定义了两个路径分别用于publish和subscribe。所有相关的配置项可以在项目主页找到解释,不作赘述。 启动nginx nginx -c /home/sun/nginxpush/nginx-push.conf 打开一个终端访问subscribe [...]

Posted in: 手艺 by Sunng 2 Comments , ,