2009年12月15日 | 分类: MySQL

mysql自带的这个玩意挺好使的,可以对慢查询里的sql进行排序、计算等操作。

首先得配置my.cnf:

log_slow_queries = /path/slow.log # 定义log位置,注意要有写入的权限

具体的使法如下:

mysqldumpslow -s c -t 40 /path/slow.log

出来的结果是访问次数最多的40个sql,几个参数大概意思如下:

-t 显示多少条
-s 排序,默认是at。c是次数,t是时间,l是lock时间,r是返回结果。如果是ac,at,al,ar则是倒序
-g 可以用正则匹配部分语句

可以参考mysqldumpslow –help,通过这个工具可以看到哪些锁表,或者其他性能问题,还能看到某些SQL_NO_CACHE提示呢,去想办法优化把!

2009年12月15日 | 分类: MySQL, Perl

发现mysql slave服务器经常因为一些特殊字符或者符号产生的更新语句报错,整个同步也会因此而卡在那,最初的办法只是手动去出错的机器,执行下面三条sql语句,跳过错误即可。

slave stop;
set GLOBAL SQL_SLAVE_SKIP_COUNTER=1;
slave start;

一台slave机器用这样方法还行,多台就麻烦了,就顺手写了个简单的perl脚本,方便统一跳过错误,代码如下:

#!/usr/bin/env perl
use strict;
use warnings;

# get slave status
sub get_status {
    my ($ip, $usr, $pass) = @_;
    my $info = `mysql -u$usr -p$pass -h$ip -e 'show slave status\\G;'`;
    if (($info =~ /Slave_IO_Running: Yes/) && ($info =~ /Slave_SQL_Running: No/)) {
        return 1;
    }
    return 0;
}
# mysql slave skip
sub slaveskip {
    my ($ip, $usr, $pass) = @_;
    print "slave error **\n";
    system("mysql -u$usr -p$pass -h$ip -e 'slave stop;'");
    system("mysql -u$usr -p$pass -h$ip -e 'set GLOBAL SQL_SLAVE_SKIP_COUNTER=1;'");
    system("mysql -u$usr -p$pass -h$ip -e 'slave start;'");
}

my @hosts = qw/
192.168.0.101:root:tt1234
192.168.0.102:root: tt1234
192.168.0.103:root: tt1234
/;
foreach (@hosts) {
    my ($ip, $usr, $pass) = split ':';
    print "// ----- $ip\n";
    my $count = 1;
    while ($count < 100000) {
        my $status = get_status($ip, $usr, $pass);
        print "i: $count status: $status\n";
        last if $status == 0;
        slaveskip($ip, $usr, $pass);
        select(undef, undef, undef, 0.1);
        $count++;
    }
    print "\n";
}

exit;
2009年12月15日 | 分类: Memcached

最近一台服务器放进了移动机房,需要访问原电信机房一台Memcached服务器,Memcached服务是以内网形式启动。

依靠google大神,搜索出解决思路,在本地起一个SSH链接,通过本地一个端口实现对另外机器的映射或者叫做转发。

上周本来已经搞定,本周突发灵异事件,竟然不管了,最后百般尝试,完成结果如下:

移动机器IP:220.xxx.xxx.xxx 电信机器IP:155.xxx.xxx.xxx

在移动机器上执行:

shell > ssh -N -f -L 11211:192.168.0.xxx:11211 [email protected]

11211:192.168.0.xxx:11211,格式为:本地端口:memcache启动的IP:端口
这里没有用RSA认证,就直接输入密码。-N 是不需要shell,-f 是程序后台执行,其他参数参见ssh –help。

shell > ps aux

可以看见进程已经在了,下面开始测试代码。

>>> import memcache
>>> mc = memcache.Client(['127.0.0.1:11211'],debug=True)
>>> print mc.get('name')
2009年12月15日 | 分类: Apache, Perl

功能简述

统计出日志里一个或多个页面总共访问的次数,比如aa.jsp, bb.jsp这样页面分别多少次。

实现简述

Apache单个日志文件800M。

最初程序使用Python编写,按行来统计,分别使用in(最慢)和index方法去查找,然后使用了正则匹配,程序运行时间从最初的1分50多秒优化到1分10秒左右,参考了qyb博客中提到的gc.disable(),有了一定的提升,最终还是需要1分左右。

然后随意用了Perl写了一个,用了最土鳖的<LOG>这样的按行分析,最后正则匹配,然后++,速度竟然在40-50秒之间,惊叹!后来经过shucho指点,在正则部分采用了预编译,效果那是相当惊人!800M文件只用了7秒左右。卧槽!

程序片段

# --------------------------------------------------------------------
use strict;
use Benchmark;

my $LOG_FILE = '/usr/local/apache/logs/access.log';
# 下面qr部分起了关键作用,预编译了表达式
my @EXT_LIST = map {qr/$_/} qw{
aaServlet
bbServlet
};

my $startime = new Benchmark;
my %result;
map {$result{$_} = 0} @EXT_LIST;
open LOG_FILE, $LOG_FILE;
while (<LOG_FILE>){
    foreach my $ext (@EXT_LIST){
        $result{$ext}++ if $_ =~ /$ext/;
    }
}
close LOG_FILE;

while (my ($key, $value) = each(%result)){
    $key =~ s/\(\?-xism:(.*?)\)/$1/g;
    print "$key:\t$value\n";
}

printf "** %s\n\n", timestr(timediff(new Benchmark, $startime));
2009年12月10日 | 分类: Editor

俺最新.emcas配置地址是:http://github.com/smallfish/editor/blob/master/emacs/.emacs

最近手痒,看到不少牛x人物都是用emacs,遂在windows下装一个玩玩。

下载地址:http://ftp.gnu.org/pub/gnu/emacs/windows/emacs-23.1-bin-i386.zip

解压到:D:\emacs-23.1

可以看到bin、etc、lisp等目录。主要运行都在bin目录。

runemacs.exe   这个就是运行文件拉,可以发送到桌面快捷方式。

可以运行一下addpm.exe这个,其作用就是把emacs加入到开始程序菜单里。

试着运行一下runemacs.exe,可以发现默认光标的位置,那是一个入门教程喔,还是中文的耶~

建议都看下这个入门的教程,常用的快捷键都有说明。

接下来加点常用的功能把,比如显示行号,goto line的功能。(俺也只配置了这个两项)

配置文件主要是_emacs或者.emacs,win下建议_emacs,点号开头的文件需要到cmd下才行。

_emacs文件放到哪儿呢?俺是直接修改了win注册表选项。

选项是:HKEY_CURRENT_USER\Software\GNU\Emacs,注意GNU\Emacs是需要新建的。接下来在Emacs里新建一个HOME项,值是你的emacs路径,比如我的:D:\emacs-23.1\bin。

然后需要做的就是把_emacs文件在这个bin目录下。

经过几经周折,显示行号和goto功能的配置如下:

(global-linum-mode 1)
(global-set-key [(meta g)] 'goto-line)

第一行是显示行号

第二行是设置meta+g转到goto功能,meta在windows下可以用alt来操作。

其他功能以后在后续补上,快捷键挺多,用了一会手指发酸。C-x 数字(1 2 3)挺好,可以开多窗口浏览了。

2009年12月8日 | 分类: Python

git-tree

简介

git是由Linus Torvalds编写的一个开放源码的版本控制系统. 它的主要目标是高度分散, 效率超过其他竞争对手.

我就是使用git维护本网站. 我知道git不应该这样的粗重任务的使用, 即每一个开发者维护一份代码拷贝, 但是它工作的很好, 所有我使用它.

本文的目的就是说明如何在家里或者笔记本里维护一个本地拷贝, 然后让这些修改提交到互联网主机上. 下面就是介绍如何设置.

安装

# Gentoo
emerge git
# Debian/Ubuntu
apt-get install git-core
# RedHat/Fedora
yum install git

初始化

你会进入你的服务器的目录和初始化git仓库.

# 进入你的web目录
cd /$wherever/html/
# 初始化仓库
git init
# 添加所有内容
git add .
# 提交 -m备注
git commit -a -m "The Initial Import."

然后返回你的html父目录, 克隆新的git-ized web目录.

# 返回你的html目录
cd ..
# 克隆你的web目录到 html.git
git clone --bare html html.git

现在你已经初始化好了仓库, 并将整个目录(递归)到该库中, 并进行了初次提交, 为web目录建立了一个git克隆. 这个git目录(html.git)是整个过程的关键.

获取一份开发环境的拷贝

1. 转到你的开发系统
2. 安装git
3. 从你的开发目录运行下面命令

git clone ssh://yoursite.com/path/to/html.git

现在已经获得一个完整的网站服务器版本的本地拷贝.

使你的web目录克隆Git目录

记住, 你的html.git是这里的关键, 而不是现有的html目录, 所以你要切换出来, 备份目录, 然后:

# 备份html目录, 然后克隆html.git
mv html html.backup; git clone html.git

这在当前目录获取一份html.git的拷贝, 当然名字还是html. 这就是为什么备份旧的html目录.

自动推送修改

把你的html.git目录添加到post-update钩子中

cd ../htdocs
env -i git pull

修改钩子程序为可执行

chmod +x post-update

在你的开发环境的变动

现在编辑的网站, 打开一个新的TextMate项目(你使用TextMate对吗?), 并拖动到html克隆目录. 整个结构都准备好了.

1. 通常的变动
2. 保存更改
3. 运行下面的程序, 例如(QuickSearchBox, TextMate等)

# This is for an OS X box
cd /Users/daniel/Development/html/
git commit -a -m "Another update."
git push

这基本上是更新到git仓库最重要的两个命令: commit(注意:你的标记(如果想回滚的话))和push(推送到服务器).

[根据你的操作系统和git安装, 你可能需要chmod +x 钩子程序, 然后再继续]

现在你只需要激活post-update 钩子程序, 将会自动的获取web目录.

如果你在服务器端的操作基本也是相同的git commit和git push, 然后你的开发环境下git pull同步备份就可以了. 当然你还可以使用脚本, 如果你需要的话.

原文参见: http://danielmiessler.com/blog/using-git-to-maintain-your-website

2009年12月1日 | 分类: Python

tornado.database模块简单包装了下对MySQL的操作,短小精悍。

无奈源码中无连接池功能,遂加上了一段DBUtils模块功能。

主要修改了reconnect()方法,大致在database.py第86行左右。(tornado 0.2 win版)

原代码如下:

    def reconnect(self):
        """Closes the existing database connection and re-opens it."""
        self.close()
        self._db = MySQLdb.connect(**self._db_args)
        self._db.autocommit(True)

修改后:

    def reconnect(self):
        """Closes the existing database connection and re-opens it."""
        self.close()
        try:
            from DBUtils import PooledDB
            pool_con = PooledDB.PooledDB(creator=MySQLdb, **self._db_args)
            self._db = pool_con.connection()
        except:
            self._db = MySQLdb.connect(**self._db_args)
            self._db.autocommit(True)

至于安装DBUtils模块可以去http://pypi.python.org/pypi/DBUtils/下载,也可以简单的用easy_install:

easy_install -U DBUtils

PooledDB有这么几个参数:

* creator
    可以生成 DB-API 2 连接的任何函数或 DB-API 2 兼容的数据库连接模块。
* mincached
    启动时开启的空连接数量(缺省值 0 意味着开始时不创建连接)
* maxcached
    连接池使用的最多连接数量(缺省值 0 代表不限制连接池大小)
* maxshared
    最大允许的共享连接数量(缺省值 0 代表所有连接都是专用的)
* maxconnections
    最大允许连接数量(缺省值 0 代表不限制)
* blocking
    设置在达到最大数量时的行为(缺省值 0 或 False)
* maxusage
    单个连接的最大允许复用次数(缺省值 0 或 False 代表不限制的复用)
* setsession:
    一个可选的SQL命令列表用于准备每个会话,如 ["set datestyle to german", ...]

creator 函数或可以生成连接的函数可以接受这里传入的其他参数,例如主机名、数据库、用户名、密码等。你还可以选择传入creator函数的其他参数,允许失败重连和负载均衡。

具体可以参照下:http://www.webwareforpython.org/DBUtils/Docs/UsersGuide.zh.html

2009年11月20日 | 分类: Python

这是一篇关于pysvn模块的指南.

完整和详细的API请参考 pysvn Programmer’s Reference.

pysvn是操作Subversion版本控制的Python接口模块. 这个API接口可以管理一个工作副本, 查询档案库, 和同步两个.

该API不能创建新的仓库; 只能作用在现有仓库上. 如果你需要创建一个仓库, 请使用Subversion的svnadmin命令.

使用这个API, 你可以check out一份工作拷贝, 添加, 编辑, 和删除工作文件, 和check in, 比较, 或者放弃更改. 仓库属性, 如关键字扩展, 行字符结束, 或者忽略的列表也可以检查和控制.

Subversion 模型

Subversion是一个更新-编辑-提交的模型. 首先在本地建立一个工作副本. 在工作副本上进行修改, 最后提交到中央仓库 (可以是本地或者远程).

这个模型允许多人偶尔会同时修改同一个文件. 大多情况下. Subversion不会干预合并这些不同修改, 如果一个提交失败, 用户或者应用则要重新检查和修改然后再次提交.

常见任务

本节给出一些使用pysvn接口的常用例子. 业务可以会递归的处理目录. 添加参数recurse=False以防止这种行为; 例如, 你可以需要添加内容没有增加一个目录.

check out一份工作副本

import pysvn
client = pysvn.Client()
#check out the current version of the pysvn project
client.checkout('http://localhost/example/trunk',
    './examples/pysvn')
#check out revision 11 of the pysvn project
client.checkout('http://localhost/example/trunk',
   './examples/pysvn-11',
   revision=pysvn.Revision(pysvn.opt_revision_kind.number, 11))

这是一个建立example测试项目的例子,目录是examples/pysvn. 这个项目是用在剩下的例子.

添加一个文件或者目录到仓库

import pysvn
# write a file foo.txt
f = file('./examples/pysvn/foo.txt', 'w')
f.write('Sample versioned file via pithon\n')
f.close()
client = pysvn.Client()
#schedule the addition;
#  the working copy will now track the file as a scheduled change
client.add('./examples/pysvn/foo.txt')
#committing the change actually adds the file to the repository
client.checkin(['./examples/pysvn/foo.txt'], 'Adding a sample file')

这个例子是在工作副本中创建了’foo.txt’文件, 然后添加到仓库. 请注意Client.import_()命令会同时增加和提交. 大多数应用, 会在许多修改后再提交.

更新工作副本

import pysvn
client = pysvn.Client()
client.update('./examples/pysvn')

从仓库中更新其他用户修改并保存到本地副本. 大多数应用应该经常这样做以防止冲突.

提交更新到仓库

import pysvn
# edit the file foo.txt
f = open('./examples/pysvn/foo.txt', 'w')
f.write('Sample versioned file via python\n')
f.close()
# checkin the change with a log message
client = pysvn.Client()
client.checkin(['./examples/pysvn'], 'Corrected spelling of python in foo.txt')

提交到Subversion是原子的. 要么所有修改都成功提交, 要么提交失败. 大部分应用会提交工作副本所有修改, 如本例所示, 或者通过个别文件或者目录, 但必须是同一单位.

放弃工作副本修改

import pysvn
# edit the file foo.txt
f = file('./examples/pysvn/foo.txt', 'w')
f.write('This change will never be seen\n')
f.close()
#discard the edits
client = pysvn.Client()
client.revert('./examples/pysvn/foo.txt')

这丢弃在工作拷贝和恢复的文件或目录的任何未提交的未经编辑的状态变化.

正在计划增加或移除留无版本或恢复到工作拷贝.

重命名或者移动文件

import pysvn
client = pysvn.Client()
#rename the file client side
client.move('./examples/pysvn/foo.txt', './examples/pysvn/foo2.txt')
#checkin the change removes the file from the repository
client.checkin(['./examples/pysvn/foo.txt', './examples/pysvn/foo2.txt'], 'Foo has become Foo2')

移动或重命名文件删除旧路径或名称的文件, 并增加了在新的位置, 同时保留以前的版本有关的信息.

在这个例子里, 我们通过文件名Client.checkin()传递父目录也将是有效的.

转移和合并可以在服务器端单步完成; 可以参见仓库任务的那节例子.

从仓库中删除文件或目录

import pysvn
client = pysvn.Client()
#schedule the removal;
#  the file will be removed from the working copy
client.remove('./examples/pysvn/foo2.txt')
#committing the change removes the file from the repository
client.checkin(['./examples/pysvn/foo2.txt'], 'Removing sample file')

有些人把删除的文件, 或是用完全清除存储库目录. 该文件仍然存在于以前的版本, 可以通过检查或以其他方式进行审查以前修订的内容检索.

确定等待变动

import pysvn
client = pysvn.Client()
changes = client.status('./examples/pysvn')
print 'files to be added:'
print [f.path for f in changes if f.text_status == pysvn.wc_status_kind.added]
print 'files to be removed:'
print [f.path for f in changes if f.text_status == pysvn.wc_status_kind.deleted]
print 'files that have changed:'
print [f.path for f in changes if f.text_status == pysvn.wc_status_kind.modified]
print 'files with merge conflicts:'
print [f.path for f in changes if f.text_status == pysvn.wc_status_kind.conflicted]
print 'unversioned files:'
print [f.path for f in changes if f.text_status == pysvn.wc_status_kind.unversioned]

生成差异或补丁

import pysvn
client = pysvn.Client()
diff_text = client.diff('./tmp-file-prefix-', '.')

获取仓库URL

import pysvn
client = pysvn.Client()
entry = client.info('.')
print 'Url:',entry.url

仓库任务

本节说明任务的例子, 操纵或检查仓库.虽然共同任务, 通过本地工作副本时间的变化, 这些任务直接影响到库
获取仓库目录的清单

import pysvn
client = pysvn.Client()
entry_list = client.ls('.')

从仓库获取文件内容

import pysvn
client = pysvn.Client()
file_content = client.cat('file.txt')

创建一个标记或分支

import pysvn
client = pysvn.Client()
log_message = "reason for change"
def get_log_message():
    return True, log_message
client.callback_get_log_message = get_log_message
client.copy('http://svnrepo.com/svn/trunk', 'http://svnrepo.com/svn/tag/%s' % tag_name )

从仓库中转移或者重命名

import pysvn
client = pysvn.Client()
client.move( 'file_old.txt', 'file_new.txt' )

锁定文件

import pysvn
client = pysvn.Client()
client.lock( 'file.txt', 'reason for locking' )

锁定文件并锁定其他用户或者工作副本

import pysvn
client = pysvn.Client()
client.lock( 'file.txt', 'reason for locking', force=True )

解锁

import pysvn
client = pysvn.Client()
client.unlock( 'file.txt' )

解锁文件并锁定其他用户或工作副本

import pysvn
client = pysvn.Client()
client.unlock( 'file.txt', force=True )

测试锁定文件

Method 1:

all_entries = self.client.info2( path, recurse=False )
for path, info in all_entries:
    if info['lock']:
        if info['lock']['token'] != '':
            print '%s is locked' % path
        print info['lock']['comment']

Method 2:

all_status = self.client.status( path, recurse=False, update=True )
for status in all_status:
    if status.entry is not None:
        if status.entry.lock_token is not None:
            print '%s is locked' % status.path
2009年11月19日 | 分类: Python

Cython代码跟Python不一样,必须要编译。

编译经过两个阶段:

* Cython编译.pyx文件为.c文件

* C编译器会把.c文件编译成.so文件(Windows上是.pyd)

以下会分节介绍几种方式来建立你的扩展模块。

注意: -a 选项,如果使用该选项将会为.c文件生成一份很漂亮的HTML文件,双击高亮的章节部分会展开代码,这对理解,优化和调试模块将会非常有帮助。

命令行

从命令行执行Cython编译器,输入选项和.pyx文件列表。

$ cython -a yourmod.pyx

会生成一个yourmod.c文件(指定-a选项会生成一个HTML文件)

编译.c文件取决于你的操作系统,请参考下如何在你的系统写Python扩展模块文档。

下面是一个Linux系统的例子:

$ gcc -shared -pthread -fPIC -fwrapv -O2 -Wall -fno-strict-aliasing \
 -I/usr/include/python2.5 -o yourmod.so yourmod.c

gcc需要提供包含的文件和扩展库的链接。

在目录里会生成yourmod.so文件。

现在只需要导入你的yourmod模块就可以了。

Distutils

确保你的系统已经安装好Distutils。

下面假设需要编译的文件叫hello.pyx。

建立一个setup.py的脚本:

from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext

ext_modules = [Extension("hello", ["hello.pyx"])]

setup(
    name = ’Hello world app’,
    cmdclass = {’build_ext’: build_ext},
    ext_modules = ext_modules
)

在命令行执行:python setup.py build_ext –inplace

现在可以在shell或者脚本里正常导入使用了。

Pyximport

在纯Python代码里调用Cython代码:

>>> import pyximport; pyximport.install()
>>> import helloworld
Hello World

这仅仅是简单调用Cython,不需要C库也不需要构建脚本。

当然也可以实验性的在Python调用。允许在Python模块中运行Cython代码在任何一个.pyx和.py模块。这包
括标准库和包。如果Cython编译失败的话,pyximport会返回到加载失败的模块处。

.py安装是这样:

>>> pyximport.install(pyimport = True)

原文:http://docs.cython.org/src/reference/compilation.html

2009年11月17日 | 分类: Python

在偶的ubuntu里编写pyrex程序编译成so还是挺爽的,用 timeit.Timer 测试性能提升不少,今天在windows也尝试了一番。

需要的工具有:
- Pyrex http://www.cosc.canterbury.ac.nz/greg.ewing/python/Pyrex/
- Dev C++ http://www.bloodshed.net/devcpp.html

Pyrex 可以通过easy_install Pyrex来安装。
Dev C++ 安装完在系统环境变量Path里加上Dev C++安装目录/bin 目录。

测试扩展代码:

# file: foo.pyx
""" simple pyrex module """
cdef class Foo:
    """ foo doc ... """
    cdef char *name
    def __init__(self, name):
        self.name = name
    def __repr__(self):
        return "foo names: %s" % (self.name)

# file: setup.py
from distutils.core import setup
from distutils.extension import Extension
from Pyrex.Distutils import build_ext

setup(
    name='foo', ext_modules=[Extension("foo", ["foo.pyx"])],
    cmdclass={'build_ext':build_ext}
)

写好两个文件后,进入命令提示符:

C:\>python setup.py build_ext --inplace -c mingw32
running build_ext
pyrexc foo.pyx --> foo.c
building 'foo' extension
creating build
creating build\temp.win32-2.5
creating build\temp.win32-2.5\Release
C:\Program Files\DEV-CPP\Bin\gcc.exe -mno-cygwin -mdll -O -Wall -ID:\Python25\include -ID:\Python25\PC -c foo.c -o build\temp.win32-2.5\Release\foo.o writing build\temp.win32-2.5\Release\foo.def C:\Program Files\DEV-CPP\Bin\dllwrap.exe -mno-cygwin -mdll -static --entry _DllMain@12 --output-lib build\temp.win32-2.5\Release\libfoo.a --def build\temp.win32-2.5\Release\foo.def -s build\temp.win32-2.5\Release\foo.o -LD:\Python25\libs -L D:\Python25\PCBuild -lpython25 -lmsvcr71 -o foo.pyd

编译完毕,可以看到当前目录下多了:build目录、foo.c、foo.pyd。foo.pyd 即是编译好的二进制扩展。

C:\>python
ActivePython 2.5.0.0 (ActiveState Software Inc.) based on
Python 2.5 (r25:51908, Mar 9 2007, 17:40:28) [MSC v.1310 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import foo
<module 'foo' from 'foo.pyd'>
>>> foo.Foo("smallfish")
foo names: smallfish