The Rock

a geek's secret garden

AIX对共享内存的写保护不可靠

在公司系统开发中的某模块需在已开辟的共享内存的一个专属段内进行读写。当共享内存为3G时,模块工作正常。而将内存缩小到1G时,在写内存时出CORE。COREDUMP地点为memcpy库函数或者赋值(=)语句。经过排查发现问题在于共享内存的链接方式——shmat时使用了只读选项。在大内存情况下的顺利运行掩盖了问题本质,为排查增加了困难。那么为何在本该报错的情况下却运行良好?
在Single Unix Specification中对shmat的定义如下:
void *shmat(int shmid, const void *shmaddr, int shmflg);
如果(shmflg&SHM_RDONLY)为非0,调用进程拥有读权限
如果等于0,调用进程拥有读写权限
按规范字面意思理解,以SHM_RDONLY方式链接应仅有读权限,没有写权限。但经过测试发现未必如此。
程序A:
key_t shmkey = 66666;
size_t shmsize = 100000000;
int shmid = shmget(shmkey, shmsize, 0660 | IPC_CREAT);
void *addr = shmat(shmid, 0, 0));
memset(addr, '7', shmsize);
shmdt(addr);
程序B:
key_t shmkey = 66666;
size_t shmsize = 100000000;
int shmid = shmget(shmkey, shmsize, 0660);
void *addr = shmat(shmid, 0, SHM_RDONLY));
char *p = (char *)addr + shmsize - 1;
*p = 'y';
shmdt(addr);
程序A创建共享内存,程序B修改最后一个字符。反复更改shmsize测试发现如下规律:
1、当申请小于256M内存时,程序B写SHM时coredump。
2、当申请大于256M内存时,256M以内不可写,以后可写。也就是说,一块共享内存两种读写权限,写保护只对一段内存起作用。
该现象不会对开发造成影响,编码时明确根据读写用途指定连接共享内存的链接方式则可以避免此类问题。
21 六月 2011 at 18:58 - Comments

DB2数据库中NULL与空字符串的区别

对于DB2的字符型字段,NULL与空串(即’\0′)的概念不同,在开发中要区分对待。
1、在建表时,如果不附加任何约束,那么CHAR型字段可以存储任何合法字符及NULL。
插入x’00′:        可以
插入NULL:   可以
INSERT默认值: NULL
2、NOT NULL约束
插入x’00′:         可以
插入NULL:   失败
INSERT默认值: INSERT失败
3、NOT NULL WITH DEFAULT约束
插入x’00′:         可以
插入NULL:   失败
INSERT默认值: 默认为空格,可指定其他字符,甚至是x’00′
例如 NOT NULL WITH DEFAULT ’4′
NOT NULL WITH DEFAULT x’00′
以SQC方式查询一个值为NULL的字符型字段,可能会引发-305错误。日常应用中习惯以NOT NULL WITH DEFAULT约束建表,该约束只保证字段值非NULL,但可能是任何其他值,包括’\0′。
命令行不容易区分空格、空串、NULL以及’-',可以使用ASCII()或HEX()内建函数来区分:
空串   正常显示:   hex():00
空格   正常显示:   hex():20
NULL   正常显示:-     hex():-
‘-’            正常显示:-     hex(): 2D
21 六月 2011 at 18:34 - Comments

数据库表命名规范

数据库表命名规范
此规范包括表名命名规范,索引命名规范,外键命名规范和字段名命名规范。
表名命名规则
数据库表的命名以是名词的复数形式且都为小写,如cities, categories, friends等等
如果表名由几个单词组成,则单词间用下划线(“_”)分割,如subscribed_pois,poi_categories等
表名尽量用全名
表名限制在30个字符内。当表的全名超过30字符时,可用缩写来减少表名的长度,如description –> desc;information –> info;address –> addr等
表字段名命名规则
字段名为小写
字段名为有意义的单词,或单词的缩写
如果字段由几个单词组成,则单词间用下划线(“_”)分割,如client_id,post_code等
字段名限制在30个字符内。当字段名超过30字符时,可用缩写来减少字段名的长度,如description –> desc;information –> info;address –> addr等
索引命名规则
索引须按照IDX_table_<column>_<column>,其中<table>是建立索引的表名,<column>是建立索引的字段名
索引名限制在30个字符内。当索引名超过30字符时,可用缩写来减少索引名的长度,如description –> desc;information –> info;address –> addr等
主键、外键命名规则
主键按照PK_<table>的规则命名,其中<table>为数据库表名
唯一键按照UK_<table>_<column>的规则命名,其中<table>为数据块表名,<column>为字段名
外键按照FK_<pppp>_<cccc>_<nn>的规则命名,其中<pppp>为父表名,<cccc>为子表名,<nn>为序列号

数据库规范化设计的一些基本要求:
一、表中应该避免可为空的列。
虽然表中允许空列,但是,空字段是一种比较特殊的数据类型。数据库在处理的时候,需要进行特殊的处理。如此的话,就会增加数据库处理记录的复杂性。当表中有比较多的空字段时,在同等条件下,数据库处理的性能会降低许多。
解决方法:一是通过设置默认值的形式,来避免空字段的产生。二是若一张表中,允许为空的列比较多,接近表全部列数的三分之一。而且,这些列在大部分情况下,都是可有可无的。若数据库管理员遇到这种情况,建议另外建立一张副表,以保存这些列。
二、表不应该有重复的值或者列。
三、表中记录应该有一个唯一的标识符。
四、数据库对象要有统一的前缀名。
五、尽量只存储单一实体类型的数据。
六、尽量符合数据库的几个范式。

设计规范
所有字段在设计时,除以下数据类型timestamp、image、datetime、smalldatetime、uniqueidentifier、binary、sql_variant、binary 、varbinary外,必须有默认值。字符型的默认值为一个空字符值串’’;数值型的默认值为数值0;逻辑型的默认值为数值0;
其中:系统中所有逻辑型中数值0表示为“假”;数值1表示为“真”。
datetime、smalldatetime类型的字段没有默认值,必须为NULL。
当字段定义为字符串形时建议使用varchar而不用nvarchar。
字段的描述
数据库中每个字段的描述(Description)如下:
表内的每一个值只能被表达一次
表内的每一行都应当被唯一的标示
表内不应该存储依赖于其他键的非键信息
如果字段事实上是与其它表的关键字相关联而未设计为外键引用,需建索引。
如果字段与其它表的字段相关联,需建索引。

SQL 开发代码规范
我们规定sql语句编码的时候程序员需要遵循以下规范:
a 所有的关键字的所有字母必须大写。如果一个常量由几个词组成,我们规定两个词之间使用下划线(_)来划分。表名、列名、视图名或它们的别名必须和它们的定义保持一致。
b 注释必须要规范。

其他设计技巧
1)避免使用触发器
触发器的功能通常可以用其他方式实现。在调试程序时触发器可能成为干扰。假如你确实需要采用触发器,你最好集中对它文档化。
2)使用常用英语(或者其他任何语言)而不要使用编码在创建下拉菜单、列表、报表时最好按照英语名排序。假如需要编码,可以在编码旁附上用户知道的英语。
3)保存常用信息。让一个表专门存放一般数据库信息非常有用。在这个表里存放数据库当前版本、最近检查/修复、关联设计文档的名称、客户等信息。这样可以实现一种简单机制跟踪数据库,当客户抱怨他们的数据库没有达到希望的要求而与你联系时,这样做对非客户机/服务器环境特别有用。
4)包含版本机制。在数据库中引入版本控制机制来确定使用中的数据库的版本。时间一长,用户的需求总是会改变的。最终可能会要求修改数据库结构。把版本信息直接存放到数据库中更为方便。
5)编制文档。对所有的快捷方式、命名规范、限制和函数都要编制文档。采用给表、列、触发器等加注释的数据库工具。对开发、支持和跟踪修改非常有用。对数据库文档化,或者在数据库自身的内部或者单独建立文档。这样,当过了一年多时间后再回过头来做第2 个版本,犯错的机会将大大减少。
6)测试、测试、反复测试。建立或者修订数据库之后,必须用用户新输入的数据测试数据字段。最重要的是,让用户进行测试并且同用户一道保证选择的数据类型满足商业要求。测试需要在把新数据库投入实际服务之前完成。
7)检查设计。在开发期间检查数据库设计的常用技术是通过其所支持的应用程序原型检查数据库。换句话说,针对每一种最终表达数据的原型应用,保证你检查了数据模型并且查看如何取出数据。

9 六月 2011 at 16:46 - Comments

Google 发布 CityHash 系列散列算法

Google 发布了 CityHash 系列字符串散列算法。今天发布的有两种算法:CityHash64 与 CityHash128。它们分别根据字串计算 64 和 128 位的散列值。这些算法不适用于加密,但适合用在散列表等处。

Google 一直在根据其数据中心常用的 CPU 对算法进行优化,结果发现对大多数个人计算机与笔记本同样有效益。尤其是在 64 位寄存器、指令集级的并行,以及快速非对其内存存取方面。

该算法的开发受到了前人在散列算法方面的巨大启发,尤其是 Austin Appleby 的 MurmurHash。但 CityHash 的主要优点是大部分步骤包含了至少两步独立的数学运算。现代 CPU 通常能从这种代码获得最佳性能。

但 CityHash 也有其缺点:代码较同类流行算法复杂。Google 希望为速度而不是为了简单而优化,因此没有照顾较短输入的特例。

总体而言,CityHash64 与 CityHash128 是解决经典问题的全新算法。在实际应用中,Google 预计 CityHash64 在速度方面至少能提高 30%,并有望提高多达两倍。此外,这些算法的统计特性也很完备。

9 六月 2011 at 16:27 - Comments

fileno()函数

NAME
fileno – map a stream pointer to a file descriptor
SYNOPSIS
#include <stdio.h>
int fileno(FILE *stream);
DESCRIPTION
The  fileno()  function  shall  return  the  integer  file descriptor associated with the stream pointed to by
stream.
RETURN VALUE
Upon successful completion, fileno() shall return the integer value of the  file  descriptor  associated  with
stream.  Otherwise, the value -1 shall be returned and errno set to indicate the error.
ERRORS
The fileno() function may fail if:
EBADF The stream argument is not a valid stream
EXAMPLES
None.
APPLICATION USAGE
None.
RATIONALE
Without  some  specification of which file descriptors are associated with these streams, it is impossible for
an application to set up the streams for another application it starts with fork() and exec. In particular, it
would  not  be possible to write a portable version of the sh command interpreter (although there may be other
constraints that would prevent that portability).
FUTURE DIRECTIONS
None.

相关函数: open, fopen
表头文件:#include <stdio.h>
定义函数: int fileno(FILE *stream)
函数说明:fileno()用来取得参数stream指定的文件流所使用的文件描述词
返回值   :返回文件描述词
范例:
#include <stdio.h>
main()
{
FILE  *fp;
int  fd;
fp = fopen(“/etc/passwd”, “r”);
fd = fileno(fp);
printf(“fd = %d\n”, fd);
fclose(fp);
}

1.内核(kernel)利用文件描述符(file descriptor)来访问文件。文件描述符是非负整数。打开现存文件或新建文件时,内核会返回一个文件描述符。读写文件也需要使用文件描述符来指定待读写的文件。
习惯上,标准输入(standard input)的文件描述符是 0,标准输出(standard output)是 1,标准错误(standard error)是 2。尽管这种习惯并非 Unix 内核的特性,但是因为一些 shell 和很多应用程序都使用这种习惯,因此,如果内核不遵循这种习惯的话,很多应用程序将不能使用。
POSIX 定义了 STDIN_FILENO、STDOUT_FILENO 和 STDERR_FILENO 来代替 0、1、2。这三个符号常量的定义位于头文件 unistd.h。
文件描述符的有效范围是 0 到 OPEN_MAX。一般来说,每个进程最多可以打开 64 个文件(0 — 63)。对于 FreeBSD 5.2.1、Mac OS X 10.3 和 Solaris 9 来说,每个进程最多可以打开文件的多少取决于系统内存的大小,int 的大小,以及系统管理员设定的限制。Linux 2.4.22 强制规定最多不能超过 1,048,576 。
文件描述符是由无符号整数表示的句柄,进程使用它来标识打开的文件。文件描述符与包括相关信息(如文件的打开模式、文件的位置类型、文件的初始类型等)的文件对象相关联,这些信息被称作文件的上下文。
2. 指向那个文件的指针,指的是你打开的那个文件的指针,也可以说是句柄。
3.当打开或创建一个文件的时候,内核向进程返回一个文件描述符..比如用open函数..creat函数等等.
它并非是定义的.
但是对于标准输入,输出,和错误.其分别用0,1,2标识,同时它们又有相应的常量STDIN_FILENO,STDOUT_FILENO,STDERR_FILENO
4.不唯一.
比如有两个进程.一个读,一个写的.它们打开同一文件,那么对于这个文件来说就有两个文件描述符.
但文件并不知道自己的文件描述符,因为文件描述符是进程所拥有的.
5.struct stat描述了文件的属性..诸如是什么类型的文件,为谁所有,属于哪个组,何时被修改过等等
9 六月 2011 at 11:31 - Comments

DB2数据库的隔离级解读与试验

基本信息

摘要:在DB2中,共有四种隔离级:RS,RR,CS,UR.以下对四种隔离级进行一些描述,同时附上个人做试验的结果。隔离级是影响加锁策略的重要环节,它直接影响加锁的范围及锁的持续时间。两个应用程序即使执行的相同的操作,也可能由于选择的隔离级的不同而造成加锁的结果不同。

隔离级解读和试验

隔离级是影响加锁策略的重要环节,它直接影响加锁的范围及锁的持续时间。两个应用程序即使执行的相同的操作,也可能由于选择的隔离级的不同而造成加锁的结果不同。在DB2中,共有四种隔离级:RS,RR,CS,UR.以下对四种隔离级进行一些描述,同时附上个人做试验的结果。

  • 读可靠性(RS-Read Stability)

如果使用这种隔离级,在一个事务中所有被读取过的行上都会被加上NS锁,直到该事务被提交或回滚,行上的锁才会被释放。这样可以保证在一个事务中即使多次读取同一行,得到的值不会改变。

但是,如果使用这种隔离级,在一个事务中,如果使用同样的搜索标准重新打开已被处理过的游标,则结果集可能改变。(可能会增加某些行,这些行被称为幻影行(Phantom))。这是因为RS隔离级不能阻止通过插入或更新操作在结果集中加入新行。

个人笔记:

 根据实际测试情况,RS模式下:查询完毕以后,满足条件的结果集中的记录被锁定,不满足条件的不被锁定。

 可以对不满足条件的记录更新,也可以插入新的记录。其他人可以查询满足已经锁定的记录,但不可以更新。

  • 重复读(RR-Repeat Read)

如果使用这种隔离级,在一个事务中所有被读取过的行上都会被加上S锁,直到该事务被提交或回滚,行上的锁才会被释放。这样可以保证在一个事务中即使多次读取同一行,得到的值不会改变。

另外,在同一事务中如果以同样的搜索标准重新打开已被处理过的游标,得到的结果集不会改变。重复读相对于读可靠性而言,加锁的范围更大。

对于读可靠性,应用程序只对符合要求的所有行加锁,而对于重复读,应用程序将对所有被扫描过的行都加锁。例如,如果一个应用程序对一个表中的 10000行数据进行扫描,最终找到了100条符合搜索条件的结果行。如果该应用程序使用的是读可靠性隔离级,应用程序将只对这符合条件的100行加锁;如果该应用程序使用的是重复读隔离级,应用程序将对被扫描过的10000行都加锁。

个人笔记

 根据实际测试情况,RR模式下:查询完毕以后,不可以对不满足条件的进行更新,也不可以插入新记录。可能原因是:如果允许别人更新记录或者插入新记录的话,则可能造成原来结果集的破坏,重新读的时候和以前不同。

 select for update with rr/rs 是可以用来实现记录锁。是一种特殊情况。即便是RR,仍然可以对其他记录操作。

  • 游标可靠性(CS-Cursor Stability)

如果使用这种隔离级,在一个事务中,结果集中只有正在被读取的那一行(游标指向的行)将被加上NS锁,其他未被处理的行上不被加锁。这种隔离级只能保证正在被处理的行的值不会被其他并发的程序所改变。该隔离级是DB2缺省的隔离级。

个人笔记

仅仅在游标在该行的时候锁定,这是一种非常弱的隔离状态。

  • 未提交读(UR-Uncommitted Read)

如果使用这种隔离级,对于只读操作,不加行锁。典型的只读操作包括:

 SELECT语句的结果集只读(比如语句中包括ORDER BY子句);

定义游标是指明起为FOR FETCH ONLY。

该隔离级可以改善应用程序的性能,同时可以最大程度的允许并发。但是,应用程序的数据完整性将受到威胁。如果需要读取未提交的数据,该隔离级是唯一选择。

个人笔记

读的时候完全不受限制,对于同一行记录的完整性也无法保证。

总结

以上我们所提的隔离级的加锁范围和持续时间都是针对于读操作而言的。

对于更改操作,被修改的行上会被加上X锁,不论使用何种隔离级,X锁直到提交或回滚之后才会被释放。

20 五月 2011 at 19:31 - Comments

shell脚本:一次读取文件的一行,并输出

写法一:
#!/bin/bash
while read  line
do
    echo $line     #这里可根据实际用途变化
    echo $line   > >   /path/write_file.txt
done <  urfile

写法二:

#!/bin/bash

cat urfile | while read line
do
echo $line
done

注意:以上代码中urfile 为被读取的文件

20 五月 2011 at 17:09 - Comments

简单Shell快捷键

工作以来都在接触Linux和Unix系统,所以对这两类系统用的多,也比较熟悉。渐渐的,Shell中的快捷键也运用自如,一次朋友看到我快捷的操作shell命令,很好奇的建议,什么时候教教他这些快捷方式。特撰写此文,来提高大家的工作效率和保护你们的键盘。

下述所有命令在Linux/unix的shell下有效,这里以bash为主。如有出入,以你自己的操作系统为准。

开始描述之前,先问几个常见的问题。

例如你在终端中输入了下面的这个find命令:

  • 是不是遇到过需要将光标移动到最前面?
  • 是不是遇到过移到最前面后,又要移动到最后面(例如添加 | xargs rm -f )?
  • 是不是遇到过删除一部分命令,例如删除searchme?
  • 是不是在输出太多时,想清屏幕?
  • 是不是想找到昨天输入的一条很长的命令?

如果你遇到过其中的一条或者两条问题,那么请往下看吧。你绝对没有浪费你的5分钟,来读下面的解释。

Ctrl + a 可以快速切换到命令行开始处
Ctrl + e 切换到命令行末尾
Ctrl + r 在历史命令中查找
Ctrl + u 删除光标所在位置之前的所有字符
Ctrl + k 删除光标所在位置之后的所有字符

Ctrl + c 终止命令(懂的人都知道,其实是发送SIGINT)信号到进程
Ctrl + d 结束当前输入、退出shell
Ctrl + z 转入后台运行

少见的技巧:

!! 执行上一条执行过的命令

!$ 显示系统最近的一条命令的参数

最后这个比较有用,比如我先用cat /etc/mysql/my.cnf,然后我想用vi编辑。一般的做法是先用↑ 显示最后一条命令,然后用Ctrl + a 移动到命令最前,删除cat,然后再输入vi命令。

利用了上面的命令后,可以用vi !$来代替。

20 五月 2011 at 17:01 - Comments

[系统管理] tail 命令详解

功能:显示指定文件的后若干行。
语法:tail [+ / - num ] [参数] 文件
tail命令中各个选项的含义为:
+num 从第num行以后开始显示。
- num 从距文件尾num行处开始显示。如果省略num参数,系统默认值为10。
l 以文本行为num的计数单位。与参数选项+num或- num选项同时使用时,num表示要显示的文本行行数。
c 以字节为num的计数单位。与参数选项+num或- num选项同时使用时,num表示要显示的字符数。
(l、c选项可以省略,系统默认值为l,即按行计数)。
使用tail命令的-f选项可以方便的查阅正在改变的日志文件,tail -f filename会把filename里最尾部的内容显示在屏幕上,并且不但刷新,使你看到最新的文件内容。

查看文件内容的特殊方法
相信最基本的cat和less,more你已经很熟悉了,如果有特殊的要求呢:
1. 如果你只想看文件的前5行,可以使用head命令,如:
head -5 /etc/passwd
2. 如果你想查看文件的后10行,可以使用tail命令,如:
tail -20 /etc/passwd
tail -f /var/log/messages
参数-f使tail不停地去读最新的内容,这样有实时监视的效果
tail -f /var/log/messages

20 五月 2011 at 16:48 - Comments

FTP教学

先进入命令提示字符状态( DOS Model 下)

C:\>

C:\>ftp www.fcic.org.tw 联机 FTP Server

输入使用者名称  例如: jack
输入密码为          例如: ******

ftp> ls                     观看远程目前所在目录档案列表

ftp> bin                  以 2 进制方式传档

ftp> hash                每2048 bytes 以一个 # 代替

ftp> get  test.txt     下传 test.txt档案

ftp> mget *.*         下传远程目录之所有档案

ftp> prompt            关闭询问讯息

ftp> mput *.*         上传本机目前所在目录之所有档案

ftp> cd                   目录名称 切换远程目录

ftp> lcd                  切换本机目录

ftp> delete test.txt 删除 test.txt档案

ftp> ?                     查询可以使用之命令为何

ftp> bye                 结束 FTP联机

ftp> user                重新一次登入使用者名称


所有命令详述如下

指令名称 指令及语法功能说明
ascii 以ASCII方式传送文件
bell 每完成一次文件?送传送,提示警告音响
binary 设定以二进制方式传送文件
bye 终止主机FTP传输过程,并退出FTP管理方式
case 当值为ON时,用MGET命令拷贝的文件名到本地机器中,全部全部转换为小写字母
cd 同UNIX的CD命令 (切换远程目录)
cdup 返回上一层目录
chmod 改变远程主机的文件权限
close 终止远程的FTP过程,返回到FTP命令状态
delete 删除远程主机中的档案文件
dir 列出目前远程主机目录中的文件.如果有本地文件,就将结果写至本地文件
get 将远程主机中档案传送至本地主机中
help [command] 输出命令的解释
lcd 改变目前本地主机的工作目录
ls 同DIR
macdef 定义命令
mdelete 删除一批档案文件
mget 从远程主机接收一批档案文件至本地主机
mkdir 在远程主机中建立目录
mput 将本地主机中一批档案文件传送至远程主机
open 重新建立一个新的连接
prompt 交互提示模式
put 将本地单一档案文件传送至远程主机中
pwd 列出目前远程主机目录
quit 同BYE(离开此系统)
recv 同GET
rename 改变远程主机中的档案文件名称
rmdir 删除远程主机中的目录
send 同PUT
status 显示目前FTP的状态
system 显示远程主机系统类型
user 重新以别的用户名称登入远程主机
20 五月 2011 at 16:46 - Comments