2009年12月28日星期一

Python study

python解释器启动:
python
退出 : Ctrl + d 或 exit() (2.5.2)
查看版本 : python -V

help() 进入帮助模式:
输入modules, keywords, topic可以查看
要看全的python帮助,要设置环境变量 PYTHONDOCS 如
$env PYTHONDOCS=/usr/share/doc/python

python程序的编写
文件头
#!/usr/bin/python

注释 : 用#

数据类型:
整型,长整型,浮点数,复数(-5+4j)
布尔型:True, False;注意大小写
字符串
  • 用'或", '与"是相同的,其中可以用转义字符\,如\' \n, 行末的\表示下行继续,而不是开始新行
  • 自然字串,表示不用转义,在字串前加r或R,如 r'Hello world \n',对于正则表达式,应采用自然字串.
  • Unicode字串,加前缀u或U.
  • 用'''或"""三引号可以表示多行字串,在三引号中可以自由使用'或", 也可以用转义,也可加前缀u,r, u必须在r前面
  • 字串不可变
  • 字串会自动级连 如 : 'hello' " world"会变成'hello world'
None表示没有值
没有char数据类型

变量名:第一个字符必须是字母表字母,大小写都可,或_,其它部分可以再加上数字,大小敏感,不能有空格, 对变量不需要声明数据类型
del a #删除变量a

对象 : 程序中的任何东西都是对象,包括数,字串,函数.
;可以用以分隔逻辑行,建议用一个物理行只含有一个逻辑行.

缩进是重要的,用来决定语句的分组,

特别的运算符:
x**y 返回x的y次幂
// 取整除
% 取模
<< 左移, >> 右移一比特
& 按位与
| 按位或
^ 按位异或
~按位取反
not 非
and 与
or 或

优先级:
lambda; or;and;not x;in, not in;is, is not; <, <=, >,>=,!=,==;|;^;&;<<,>>;+,-;*,/,%;+x,-x(正负号);
~x;**;x.attribute;x[index];x[index:index](寻址段);f(arguments ...);(experession,...);[express,...](列表显示);{key:datum, ...}(字典显示);'expression,...'

控制流
if的语法
if guess==number:
print 'Congratualtions'
elif guess < number:
print 'No, it is a little highter than that'
else:
print 'No, it is a little lower than that'

print 'Done'

使用while语句:

running = True;
while <条件>
[else:
]
注意while可以带else从句

for循环:
for i in range(1,5)
print i
else:
print "The for loop is over"
else部分是可选的,总是在for结束时执行一次,除非遇到break

break用于终止循环,这使得for,while的else块不执行
continue 用于跳过循环块中剩余的语句

函数:
def sayHello():
print 'Hello world'

sayHello() #调用

可以使用参数如
def printMax(a,b)
if a>b:
print a, 'is maximum'
else:
print b, 'is maximum'

对数值或数值型变量采用值传递.

在函数中可以定义局部量也可以定义全局量,这样可以为函数外的变量赋值

def func():
global x

print 'x is', x
x = 2
print 'change local x to ', x

x = 50
func()
print 'value of is', x

同C++一样,形参表末尾的参数,可以有默认参数

键参数,如
def func(a, b=5, c=10):
print 'a is',a,'and b is',b,'and c is',c

func(3,7)
func(25,c=24)
func(c=50,a=100) #指定键参数a, c

return用来返回,也可以返回一个值

pass表示一个空的语句块

DocStrings
来自函数的第一个逻辑行的字串. help 也只是取到了函数的__doc__属性
如:
print int.__doc__
print 'hello'.__doc__

模块:
使用sys模块 :
import sys

sys.argv字串列表,指的是命令行参数列表
sys.argv[0]指是程序(python文件)名,1以后是参数

如果使用from sys import argv 可以每次用argv时避免打sys. 也可以
from sys import *
from mymodule import sayhi, version #import 了两个成员

模块的__name__
如:
#!/usr/bin/python
# Filename: using_name.py

if __name__ == '__main__': #表示python程序被单独运行
print 'This program is being run by itself'
else: #表示被调用
print 'I am being imported from another module'

用dir来查看模块属性
import sys
dir(sys)

dir() # 得到当前模块的属性

列表 list, 是一个类,
['apple','orange','banana']
可以改变,增删,排序,从0开始索引

元组 tuple
不可改变值,如同字串
('apple','orange','banana')

list和tuple都可以嵌套,且不会改变身分

使用tuple输出

age = 22
name = 'Swaroop'

print '%s is %d year old' %(name,age)
print 'name is %s'%name #只有一个参数时name

字典dict
d={key1:value1, key2=value2}
key是无顺序的
d[key1]来索引

索引 : 用[]
slice :
d[1:3]从第一个元素一直取到第三个,实际是返回第1,2个,
d[1:-1]从第一个直到倒数第一个,不包括倒数第一个
d[2:] 从第2个到结尾
d[:]全部

对象赋值是引用
shoplist = ['apple', 'mango', 'carrot', 'banana']
mylist = shoplist #mylist 是shoplist的一个引用.

复制:
mylist = shoplist[:] #生成shoplist的一个复制

字符串的方法:
name = 'Swaroop'
if name.startwith('Swa') : #startwith 返回布尔值
print 'Yes, the string start with "Swa"'

if 'a' in name : # in 某个子串是否存在
print 'Yes, it contains the string "a"'

if name.find('war') != -1 : # 查看某子串的位置, -1表示没有
print 'Yes, it contains the string "war"'

delimiter = '_*_'
mylist = [ 'Brazil', 'Russia', 'India', 'China' ]
print delimiter.join(mylist) #用分隔符将字串list连接起来

''.join(alist) #直接连接list或tuple,没有分隔符

定义类:
class Person :
'''Represents an person'''
population = 0 #相当于静态量
def __init__(self, name): #定义初始化函数,注意必须有self
self.name = name #相当于普通成员变量
population += 1

def sayHi(self) :
print 'Hello, my name is', self.name
def __del__ (self): #相当于析构函数
population -= 1
p = Person('Hzt')
p.sayHi()

继承
class SchoolMember:
'''Represents any scool member. '''
def __init__(self, name, age):
self.name = name
self.age = age
...
def tell(self) :
...

class Teacher(SchoolMember) :
'''Represents a teacher'''
def __init__(self, name, age,salary):
SchoolMember.__init__(self, name, age)
self.salary = salary
...

def tell(self):
...

class Student(SchoolMember):
'''Represents a student'''
def __init__(self, name, age, marks):
SchoolMember.__init__(self,name,age)
self.marks = marks
...

def tell(self):
...


有关print的一些技巧:
print line, #输出一行内容并避免自动的换行符
print #输出一个换行符

储存与读取(序列化及反序列化)
#!/usr/bin/python

import cPickle as p # cPickle速度更快; 用import ... as 可以使用更短的模块名
#import pickle as p

shoplist = 'shoplist.data'

shoplist = [ 'apple', 'mango', 'carrot' ]
f = file(shoplistfile, 'w') #创建一个可写入的文件
p.dump(shoplist, f) #用pickle写入一个对象

del shoplist #删除shoplist对象

f = file(shoplistfile)
storedlist = p.load(f) #读出这个list对象
print storedlist

错误和异常:
try: #开始捕捉错误
s = raw_input('Enter something -->')
except EOFError: #如果错误是EOFError
print '\nWhy did you do an EOF on me?'
sys.exit()
except: #其它的错误
print '\nSome error/Exception occurred.'

print 'Done'

还可以加上else块,如果没有异常, else从句会执行

如何引发异常
class ShortInputException(Exception):
'''A user-defined exception class.'''
def __init__(self, length, atleast):
Exception.__init__(self)
self.length = length
self.atleast = atleast

try: #开始捕捉错误
s = raw_input('Enter something -->')
if len(s) <3:
raise ShortInputException(len(s), 3)#抛出异常

except EOFError: #如果错误是EOFError
print '\nWhy did you do an EOF on me?'
except ShortInputException, x: #如果错误是ShortInputException, 用x来引用
print 'ShortInputException: The input was of length %d, \
was expecting at %d' % (x.length, x.atleast)
else: #else从句
print 'No exception was raised'

以下的块不能与try ... except合用,只能嵌套使用
try:
...
finally:
...

特殊方法:
__init__(self, ...) #初始化方法
__del__(self) #析构方法
__str__(self) #使用print语句或对对象调用str()时
__lt__(self,other) #当使用小于(<)时,对+, >都有特殊方法
__getitem__(self, key) #使用x[key]索引时调用
__len__(self) #对序列对象使用内建的len()函数时调用

在函数中接收元组或字典,用*或**前缀如
def powersum(power, *args)
total = 0
for i in args:
total += pow(i,power)
return total

如果使用**作前缀,所有多余的函数参数会被认为是一个字典的键/值对.

exec 'print "Hello world"' #执行一个python语句

eval('2*3') #计算一个字串中有效Python表达式.







2009年12月27日星期日

Ganglia 3.1.2 源码

gmond :

主要有4个文件:
cmdline.h
cmdline.c
ganglia.h
gmetric.c

main :
  1. Parse 命令行到全局量args_info,类型是结构体 struct gengetopt_args_info(cmdline.h)
  2. 创建全局量global_context,类型是struct Ganglia_pool*. 实际类型是apr_pool_t*(apache的内存池). struct Ganglia_pool根本未定义.
  3. 通过分析配置文件,创建全局量gmond_config,类型是struct Ganglia_gmond_config* (未定义类型),实际类型是cfg_t(confuse.h, 是一个section,section可以嵌套,还包含一个选项(字符,数据,布尔,其它的section)的列表.
  4. 创建全局量send_channels (UDP发送通道),类型是struct Ganglia_udp_send_channels*,实际是apr_array_header_t*.这个send_channels的数组对应到每一个配置文件中的udp_send_channel.
  5. 创建全局量gmetric,仅分配空间, 类型struct Ganglia_metric* , struct Ganglia_metric中有Ganglia_pool,struct Ganglia_metadata_message* 和char* 的value及void* 的extra. Ganglia_metadata_message表明了一个metric的类型,名称,计量单位,slope(斜率),tmax(在两个gmetric call之间最大秒数,默认60)和dmax(这个gmetric最大生命周期,默认0)
  6. 然后判断一下命令行参数是否有spoof及heartbeat如果都有,设置gmetric为heartbeat;否则设置metric的各项参数(name,value,type,unit, slope, tmax, dmax)
  7. 如果有spoof或heartbeat,将它们加入metric的extra子域中(apr_table_t)
  8. 然后将metric通过send_channels发送出去( Ganglia_metric_send() 来自libgmond.c),先发 metadata,再发value
  9. 清理

2009年12月16日星期三

Ganglia & Nagios



ganglia.info


术语:
XDR : eXternal Data Representation.外部数据表示法.独立于机器架构,在异种机器间传送数据.XDR定义了如下数据类型: boolean, char(8bits),int(32bits),hyper(64bits),float,double,quadruple,enumeration, structure,string,fixed length array, variable length array, union, opaque data, optional data(类似C指针,但还有一个"存在与否"的标记), 参考RFC 1014, RFC 1832, RFC 4506

分成如下模块:

监控:
gmond : ganglia monitoring daemon, 是一个轻量的服务.在每台你希望监控的机器上安装.采用简单的监听/发布协议,通过XDR收集监控状态并 通过TCP上的XML来共享这些信息.gmond是可移植的,收集几十种系统数据,如CPU,内存,磁盘,网络,进程数据.

gmetad : ganglia meta daemon,一个服务从其它的gmetad和gmond来源存贮它们的状态到磁盘中多个索引过的round-robin数据库.gmetad提供了简单的查询机制来收集特定的一组机器的信息.gmetad支持层次化的委托方式来建立可管理的监控域.

gmetric : ganglia metric tool是一人命令行工具,你可以用来加入定制的检测值到ganglia的主机.可以用来伪造gmond信息,使它看起来象一个不同的主机.

gstat : ganglia stat tool是一个命令行工具来直接查询gmond的检测值

web : ganglia web frontend 图形化的web介面展现保存在gmetad上的检测数据,用PHP写的.

执行:
Ganglia 执行环境:
GEXEC是一个可扩展的集群远程执行工具.提供了快速,RSA鉴权的并行的分布工作.提供了透明的标准输入输出,出错和信号.提供了本地环境的复制.能够健壮的扩展到系统到几千个节点
可以利用authd (from RocketCalc)来获得更好的性能和易维护性.

还有embedded metrics, 用这个可以发送gmetric兼容的数据包,支持了多种语言,如C++, python, perl...



Hadoop有集成的钩子在ganglia上
http://wiki.apache.org/hadoop/GangliaMetrics
可以在Hadoop配置文件中配置,向指定的ganglia服务器发送数据.这个实现些已经在Hadoop的代码中(hadoop-core)了.实现是直接用UDP发数据包到ganglia服务器,还是比较简单的.

jmxetric
集成JMX,将MBean属性报告到Ganglia.
http://code.google.com/p/jmxetric


Nagios主要功能:
  • 监控网络服务(SMTP,POP3,HTTP,NNTP,PING...)
  • 监控主机资源(CPU,磁盘使用...)
  • 简单插件设计可以让用户容易开发他们的服务检查
  • 并行的服务检查
  • 可以定义网络主机层次结构,可以检测和区分下线的主机和不可达的主机
  • 在服务或主机发生问题和解决时,通过email,呼机,或用户定义的方法来发送通知
  • 自动log文件轮替
  • 支持实现冗余监控主机
  • 可选的Web接口.
查看ganglia的内容,可以telnet到主机(gmond)的tcp端口(默认8649)来读取


Nagios相对功能比较完整:
开源source forge
有通知功能
多用户,多角色的dashboard和控制接口
超过200社区提供了插件, 如下两大类
  • 输入源
  • 通知机制
扩展到监控超过100000节点
支持ganglia作为输入源

集成nagios时,注意将节点的cfg文件(在/usr/local/nagios/etc/及子目录中)中,定义host 名字的时候与ganglia汇报的相一致

define host {
use desktop-server
host_name NJ-ZHENTAOHUANG.WORKGROUP
address NJ-ZHENTAOHUANG.WORKGROUP
}

从ganglia中TCP端口中读到的是:
NAME="NJ-HZT-VM2.WORKGROUP" IP="10.64.38.211" REPORTED="1262598648" TN="9" TMAX="20" DMAX="0" LOCATION="n ...





2009年12月1日星期二

MySQL插件式存储引擎



插件式存储引擎本身是数据库服务器的组件,负责对执行真正的数据IO操作,也使得并强制一定的功能集为特定的应用服务.

插入引擎的方法:
mysql> INSTALL PLUGIN ha_example SONAME 'ha_example.so';
拔出引擎的方法:
mysql> UNINSTALL PLUGIN ha_example;


在存储引擎中一些支持底层结构的组件的是什么?一些关键功能如下:
并发 : 锁粒度的要求.以及多版本并发控制和快照读的功能
事务支持: 遵从ACID原则
引用完整性:使服务器强制关系型数据库通过DDL定义的外键保证引用完整
物理存贮:存贮数据到磁盘
索引支持:不同的应用场景总是从不同的索引策略中受益,每个存贮引擎总有它自己的索引方式,虽然一些如B树索引总是对所有引擎通用的.
内存缓冲:采用内存缓冲能取得更好的响应时间
性能辅助:包括多IO的线程来并行操作.线程并发,数据库检查点,大批量插入处理
其它目标的特性:如地理空间操作,安全限制等等

源码:
自定义存贮引擎要实现handler接口,这个是在sql/handler.h.可以参考的例子在storage/下
可参考的实现如 : csv (272k), MyISAM (1.5M), Innobase(5.5M)(InnoDB), Innodb_plugin(6.7M)

handler类主要提供了创建,删除表,写,更新,删除行,索引,更新,Scan,锁的虚函数.子类重载它来实现一个数据存贮引擎.