More servicesWindows Live
HomeHotmailSpacesOneCare
 
MSN
Sign in
 
 
Spaces home  下一个村庄ProfileFriendsBlogMore Tools Explore the Spaces community

下一个村庄

岁月逝,忽若飞
July 12

RDBMS && Delta

Confluence具备保留Wiki页面历史信息的功能
但在实现上,后台数据库里存储的是每个版本的硬拷贝
(列定义:CLOB(2147483647) NOT LOGGED COMPACT)
而不是像版本控制工具那样仅存储差异信息
<Beautiful Code>有一章介绍了SubversionDelta Editor
Subversion可以使用Berkeley DB作为存储系统
如果Delta Editor接口也可以用在关系型数据库就好了

June 30

CICS Task-Private Pool

C语言本身没有自动垃圾收集机制,这让C程序员在使用堆内存时不得不小心翼翼,时刻担心因内存泄露造成灭顶之灾。但CICS环境提供了一些善巧方便,让C程序员也可以像JAVA程序员那样随意使用堆内存。这是一种叫做'CICS Task-Private Pool'的内存池机制,当启动一个任务时AS会自动分配一整块内存,当任务结束时AS自动回收。这样不仅可以避免调用malloc陷入trap的开销,更可以告别内存泄露的问题,下面是包装成C函数的代码:

void * xmalloc (size_t size ){
   void * mem ;
   int r ;
   if(dfheiptr == NULL)EXEC CICS ADDRESS EIB(dfheiptr);
   EXEC CICS GETMAIN SET(mem) FLENGTH(size) RESP(r);
   return r == DFHRESP(NORMAL) ? mem : NULL ;
}

void * xcalloc (size_t size ){
   void * mem ;
   int r ;
   if(dfheiptr == NULL)EXEC CICS ADDRESS EIB(dfheiptr);
   EXEC CICS GETMAIN SET(mem) FLENGTH(size) INITIMG(0) RESP(r);
   return r == DFHRESP(NORMAL) ? mem : NULL ;
}

void xfree(char * mem){
   EXEC CICS FREEMAIN DATA(mem);
}

在此基础上,我们可以构建更高级的通用数据结构。如动态数组,Hash表等。
Apache的APR库有这些数据结构的实现,而且这个库同样使用内存池机制,
我们只需要将代码中的APR订制内存池换成CICS私有内存池即可。例如将

apr_hash_t * ht = apr_palloc(pool, sizeof(apr_hash_t));

替换成

apr_hash_t * ht = xmalloc(sizeof(apr_hash_t));

下面的代码展示了如何使用Hash数据结构实现O/R映射:

trace_t * get_trace(hash_t * ht , char * id ){
   trace_t * ptrace = NULL ;
   if(( ptrace = hash_get( ht , id , HASH_KEY_STRING) ) == NULL){
      //从CICS Task-Private Pool中分配内存,以备存储数据
      ptrace = xmalloc(sizeof(ptrace_t));
      if(ptrace == NULL)return NULL ;
      //从数据库加载数据
      int r = trace_init(ptrace , id );
      if(r)return NULL ;
      //将数据存入Hash中
      hash_set(ht, ptrace->id , HASH_KEY_STRING , ptrace);
   }
   return ptrace ;
}

May 19

Testing CICS Program with RSpec and ActiveRecord

项目使用三层架构。中间层是嵌入C开发的CICS程序,前台使用PowerBuilder做展示。因为中间层的存在,使得数据驱动的验收测试成为可能。即一个中间层应用程序既被PB调用,也被测试脚本调用。由ActiveRecord负责与数据库的交互.RSpec作为测试框架。测试三步曲对应如下:

  • Pre-conditions: 向数据库中插入测试需要的数据
  • Event: 调用CICS服务(通过'win32ole'连接EasyCics)
  • Post-conditions: 验证数据

在使用过程中也碰到一些问题,撮要如下:

  1. 数据库驱动ibm_db中将smallint一律视为boolean型,如果你的数据库确实将smallint作为小整数使用,需要在ibm_db_adapter.rb中simplified_type函数修改类型映射,将boolean改为integer.
  2. ActiveRecord默认不支持复合主键,需要使用第三方的composite_primary_keys.注意使用复合主键查询时参数应使用数组,如:@slab = Slab.find([ID_SLAB , 1])
    而不是官方网页上写的@slab = Slab.find(ID_SLAB , 1)
    BTW,使用复合主键时,调用ActiveRecord::reload方法会有异常
  3. 上回提到的时间戳问题
  4. 实践中经常需要判断数据库中的一条记录是否被调用的CICS服务修改过。(普通情况下所有的修改都通过 ActiveRecord,不会有第三方存在)。可以添加一个方法:

    class ActiveRecord::Base
      def untouched?
        newvalue = self.class.find(self.id)
        self.class.columns.map do |col|
        case col.type
          when :string
            return false unless self.send(col.name).strip == newvalue.send(col.name).strip
          when :timestamp
            return false unless self.send(col.name).to_s == newvalue.send(col.name).to_s
          else
            return false unless self.send(col.name) == newvalue.send(col.name)
          end
        end
        true
      end
    end

    在RSpec中就可以这样写:

    @slab.should be_untouched

    至少是形似英语了

  5. 测试后需要销毁初始插入的数据,以使测试过程可以重复。这一步可以利用Ruby强大的反射机制:

    after :each do
       instance_variables.each do |var|
          if instance_eval(var).class.superclass == ActiveRecord::Base
             instance_eval(var).destroy
          end
       end
    end

April 23

Timestamps Problem while Integrating ActiveRecord with Legacy Database

对我们的数据库使用ActiveRecord做映射
在插入数据时报时间格式错误
查看column信息,发现timestamp类型的列@default值为nil
我们数据库里的时间戳默认值设定为'1900-01-01-00.00.00'
估计是因为该时间在Epoch('1970-01-01-00.00.00')之前,Ruby的Time类无法处理
换成最近的时间如'2000-01-01-00.00.00',果然一切OK

因为修改数据库代价较大,而又不希望写程序时对所有时间戳格式的字段手动赋值一遍
只好修改ActiveRecord,在timestamp.rb的create_with_timestamps方法下添加:

t0 = Time.at(0).utc
self.class.columns.map do |col|
   write_attribute(col.name , t0) if col.type == :timestamp and self.send(col.name).nil?
end

另外,ActiveRecord在创建和保存记录时自动更新名为created_at,updated_at的时间字段
如果系统里用的不是这两个名字,也可以通过修改timestamp.rb来实现。

tmstps = ['tmstp_crea' , 'tmstp_chg']
self.class.columns.map do |column|
   if column.type == :timestamp and self.send(column.name).nil?
      write_attribute(column.name , tmstps.include?(column.name) ? t : t0)
   end
end

March 27

菩萨菩提

自觉,觉人
自渡,渡人
自利,利他
--顾随

March 16

easycics编译优化

一. 使用共享库

如果使用静态链接,每个服务的实现中都包含一份easycics的实现.显然是对存储资源的浪费;且一旦easycics库修改,
需要付出较大的代价重新编译部署,使用共享库则可以避免这些问题.下面是将easycics编译为共享库的makefile:

#Platform - AIX 5.3 ; XL C 9
easycics.so : easycics.o
   xlc -o $@ -bI:/usr/lpp/cics/lib/cicsprC.exp -bE:easycics.exp -bM:SRE -bnoentry easycics.o
easycics.o : easycics.c
   xlc -O2 -qarch=auto -c -I/usr/lpp/cics/include easycics.c
easycics.c : easycics.ccs
   cicstran -lC easycics.ccs

其中easycics.exp是导出符号列表,可以通过下面的Perl脚本解析easycics.h生成

open (HEADER, 'easycics.h' ) or die "$!";
open (EXPFILE, '>easycics.exp' ) or die "$!";
for (<HEADER>) {
    print EXPFILE "$1\n" if (/_stdcall\s+(\w+)/ ) ;
}

下面是对测试程序分别用两种方式编译,产生的文件大小对比(size -f):

静态链接 32870(.text) + 41850(.data) + 2780(.bss) + 1792(.loader) = 79292
动态链接 1473(.text) + 263(.data) + 0(.bss) + 860(.loader) = 2596

可以看到,两者大小有30倍的差距!!

TXSeries每个AS只用一个线程运行客户程序,其他线程用于侦听事件,与RM建立XA等系统任务。easycics并非线程安全,但TXSeries对客户来说实际相当于单线程,故可以使用。

二. 去除cicstran

一般对使用嵌入SQL的CICS服务的编译过程如下:
  1. 将XXXX.sqc经DB2预编译器翻译为XXXX.c
  2. 将XXXX.c重命名为XXXX.ccs
    接着调用cicstcl集成编译工具,实际上分为两步:
  3. 调用cicstran转换工具将XXXX.ccs变为XXXX.c
  4. 调用C编译器完成最后的编译链接
其中cicstran工具用于转换EXEC CICS语句,而easycics库实际上屏蔽了应用程序对EXEC CICS的直接调用.经过对照,cicstran对于使用easycics库的程序,仅仅是添加了两个头文件(<cics_api.h>以及<cics_eib.h>),并在main函数下添加了一个函数调用:

int cics_api_temp_var = cics_api_edf_init_c_extended(0, &CicsArgs);

该函数是用来设置CicsArgs,决定是否启动CICS的EDF(Execution Diagnostic Facility)。因为CicsArgs是静态变量,easycics库中有单独的一份实例,此处调用没有实际效果,可以忽略. 所以,cicstran转换步骤对于没有EXEC CICS调用的程序是多余的. 编译过程可以忽略2,3两步。这样就减少了cicstcl的进程调用开销以及cicstran的文本转换过程,编译速度有很大的提高。此外,cicstcl所依赖的两个环境变量CCFLAGS和USERLIB也不再需要。makefile可以精简成下面的形式:

include ${MAKERULES}
serv := XXXX
$(serv): $(serv).c
$(serv).c : $(serv).sqc

March 06

Quote

"Education is the ability to listen to almost anything without losing
your temper or your self-confidence." --Robert Frost
February 25

Play Shell Game with ClearCase

将目录下所有签出文件取消签出 clt lsco -me -s | xargs -tI {} cleartool unco -rm {}
将目录下所有签出文件签入 clt lsco -s | xargs -tI {} cleartool ci -nc {}
将目录下所有私有文件纳入版本控制 clt ls | grep -v @@ | xargs -tI {} cleartool mkelem -nc -ci {}
February 22

箴言

Ask yourself questions like:

  • "How can I make sure this problem goes away forever? "
  • "How can I produce fewer bugs?"
  • "How can I make it easier to fix the bugs I have?"
  • "How can I make it easier to respond to change quickly?"
  • "How can I make it easier to make my software fast enough?"
February 18

Colbertism

The art of taxtation consists in so plucking the goose as to obtain the largest amount of feathers with the least possible amount of hissing .      --- Jean-Baptiste Colbert
February 11

Port

项目使用的的中间件及数据库平台全面升级
需要在新系统上重新构建和部署
迁移过程暴露了我们在SCM上的不成熟
例如,跳过集成流,将在开发流上编译出来的东西直接部署
造成无法找到和运行环境直接对应的版本(源码等于或新于运行版本)
相当麻烦

一个意外收获是改变了对Perl的观感
迁移过程中经常遇到文本替换,统计分析之类的任务
用Perl来做这类Quick And Dirty的事情非常顺手
例如统计共享库的调用,将dump -H的结果导出到变量中
再用RE解析此变量,最后将结果存入Hash结构
这几个步骤都有内建的机制支持,手挥目送一气呵成
印证了Larry Wall书中的比喻:Perl就像骆驼,并不养眼,但很实用

January 30

Quote

我们有选择不同牌子的电冰箱、洗衣机的自由。   —— 哈维尔概括1970年代的捷克社会

January 21

SOA?啊呸!

翻完《程序员》杂志SOA专辑上那帮'架构宇航员'的大作,倒是想起鲁迅的一篇文章:

他在药方上所开的却不是药名,而是“好药料”三个大字,以及一些唠唠叨叨的名医架子的“主张”。不错,谁也不能说医病应该用坏药料,但这张药方,是不必医生才配摇头。 《"好政府主义"》
View more entries