用Wicd替换Ubuntu 11.10 Network Manager

Ubuntu 11.10的Network Manager不是很稳定,经常断线,特别是网络状态不是很好的时候(根据自己经验总结出来,而且断了就很难连上),dmesg显示超时。实在忍不住了在网上搜搜,别人说可以用Wicd替换掉Network Manager。
动手开始

sudo apt-get install wicd
sudo aptitude remove network-manager

其实如果你比较谨慎,不想立即删除Network Manager的话,你可以先停止服务,然后再禁止掉它。

sudo /etc/init.d/network-manager stop
sudo update-rc.d network-manager disable

然后再重启wicd

sudo /etc/init.d/wicd restart

或者重启系统。

注意了,我一般是通过WPA2来加密无线连接的(也就是路由器开了这个),我们连接Access Point的时候也应当选择这个,通常我们都会输入对应的明文密码,比如SSID为”TA’S WIFI”,PASSWORD为”cheatbot”,我们直接选择对应的SSID并且输入这个明文密码就好了。

但是Wicd这里不一样的,它需要你输入一个Passphrase,也就是Use Encryption下的WPA 1/2 (Passphrase),这个不是直接的明文密码,如果你输入直接的明文密码,连接的时候就会出现密码错误,Bad Password也就是这么出来的,那么这个值从哪里来?

man wpa_passphrase
WPA_PASSPHRASE(8)                                            WPA_PASSPHRASE(8)

NAME
       wpa_passphrase - Generate a WPA PSK from an ASCII passphrase for a SSID

SYNOPSIS
       wpa_passphrase [ ssid ] [ passphrase ]

OVERVIEW
       wpa_passphrase  pre-computes  PSK  entries  for  network  configuration
       blocks of a wpa_supplicant.conf file. An ASCII passphrase and SSID  are
       used to generate a 256-bit PSK.

OPTIONS
       ssid   The SSID whose passphrase should be derived.

       passphrase
              The  passphrase  to  use.  If  not included on the command line,
              passphrase will be read from standard input.

SEE ALSO
       wpa_supplicant.conf(5) wpa_supplicant(8)

LEGAL
       wpa_supplicant is copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>  and
       contributors.  All Rights Reserved.

       This  program  is  dual-licensed  under  both the GPL version 2 and BSD
       license. Either license may be used at your option.

                               07 September 2010             WPA_PASSPHRASE(8)

这里就可以看到实际是执行如下命令

guohai@KNIGHT:~$ wpa_passphrase "TA'S WIFI" "cheatbot"
network={
	ssid="TA'S WIFI"
	#psk="cheatbot"
	psk=f122b3c5a2c1b50064805d44fa8b23802dadfdfa6e2dbb73bdf3d2ee702a4146
}

这里长长的psk就是需要我们填到Properties的Key里面去的,填好这些之后,试着连连看(如果连不上,就重启下系统,我是这样的,然后我还勾选了前面的Automatically connect to this network),然后它就能成功连接上了。

当然稳定性还有待观测,不过到现在还没有出现过之前断开的情况,虽然Wicd没有默认的Network Manager直观,好看,但是只要它稳定好用,我也就满意了。

Lesson Learn之文件被mv给覆盖

昨天晚上发生了一件悲剧的事情,写了一下午的代码在mv过程当中被删除了。事情经过是这样子的,创建好Git仓库之后,准备把代码文件mv进对应的文件夹,原本目录的样子

$ tree
.
|-- a
|-- a.c

就这两个简单的文件,所以我直接用

$ mv a*

大家可以看到这个命令没有敲完,因为后面还缺destination directory,然后我就切换到那个目录看了一眼路径,回来的时候鬼使神差的没有把路径敲上去就让这个命令执行了,然后惨剧就发生了,这个命令没有出错,我有种预感出事情了,但是这个时候心理还是期望a.c把a给覆盖了,但是ls看了下文件大小就觉得完了,源文件被覆盖了,因为mv没有撤回的命令,所以知道麻烦来了,网络上有人说这个时候可以umount被删文件所在的分区,然后用root用户对该分区进行grep,当然关键字就是被删文件当中有的关键字,越特殊越好,我有试过这方法,但是运气没那么好,只搜出来那个文件的名字,没有内容。想想算了,自己再重写一遍吧,源文件生成的可执行程序还在,里面还有些打印的文本信息,根据这些文本信息来重新写也还行,然后花了2个多小时,到凌晨2点,终于算写完了,功能也和侥幸留下的那个可执行文件一样。于是就睡觉了。

但是我在想mv是如何解析”a*”这个字串,然后把文件覆盖掉的呢?
早上起来看了下mv程序的代码

n_files = argc - optind; // optind是排除前面program name和options之后的参数索引,
						 // 也就是被操作的文件或者文件夹
file = argv + optind;

我们都知道argv[0]是program name,所以”a*”这种情况optind就为1,于是

$ mv a*

就被解释成了

$ mv a a.c

所以当然a.c就被a给覆盖了

那为什么mv在覆盖的时候没有给予提示,因为在Linux/Unix的世界里面,它默认你应该知道你在执行什么操作。比如这个命令,移动A文件到B文件,这是再正常正确不过的一种操作,它就是认为你是要用A把B给覆盖的。

当然”a*”变成a和a.c这纯粹是一种巧合,因为一旦你要操作的文件(夹)数目大于2,它就会去检测最后一个是否是文件夹,如果是的,就把前面的文件(夹)移动到最后一个文件夹里面,如果不是,就告诉你输入错了。

if (target_directory_operand (file[n_files - 1]))
	target_directory = file[--n_files];
else if (2 < n_files)
	error (EXIT_FAILURE, 0, _("target %s is not a directory"),
			quote (file[n_files - 1]));

if (target_directory)
{
	int i;

	ok = true;
	for (i = 0; i < n_files; ++i)
		ok &= movefile (file[i], target_directory, true, &x);
}
else
	ok = movefile (file[0], file[1], false, &x);

所以如果我当前目录有2个以上的a打头的文件,那么我执行”mv a*”,它就会给出提示,或者只是说把文件挪动了一个位置,并不会覆盖。

好了,如果你担心以后在执行cp和mv的时候文件会给覆盖的话,你可以加”-i”参数,这样碰到覆盖的情况它就会征求你的意见,当然我们这么做只是为了避免像如上这个例子的巧合和意外。你始终还是要知道你在执行什么操作。

方便起见,你可以在.bashrc当中添加如下配置就可以。

# some interactive reminders
alias mv='mv -i'
alias cp='cp -i'

为什么rm不加,因为你要知道rm就是要把你的资料弄没的,所以要万分小心!

当然如果你知道你要用VCS来管理你的东西,那么一开始就用吧!

在Linux上开启Core dump来调试

这是一篇原来使用Core dump的记录,整理资料的时候看到的,没有深入的分析,只是用法

基本知识不清楚的话,请在网络上搜寻查阅
http://en.wikipedia.org/wiki/Core_dump
http://en.wikipedia.org/wiki/GNU_Debugger

guohai@KNIGHT:~$ ulimit -c
0
guohai@KNIGHT:~$ ulimit -c unlimited
guohai@KNIGHT:~$ ulimit -c
unlimited
guohai@KNIGHT:~$ ./a.out 
Floating point exception (core dumped)

a.out是需要分析的程序,以上命令就是Linux上使用方法,很简单

更多情况请参考
http://www.cppblog.com/kongque/archive/2011/03/07/141262.aspx

那么在Android上怎么开启呢(首先得有root权限)?

$ adb remount
$ adb shell
root@android:/ # ulimit -c                                                     
unlimited

更改Core dump档案存储的路径(这个存储的路径可以根据需要定制)

root@android:/ # echo "/data/coredump/%p_%e" > /proc/sys/kernel/core_pattern

这样当有native crash存在的时候就会出现对应的Core dump档案了
(有时候执行没有生成Core dump,因为没有/data/coredump文件夹也可能导致无法生成Core dump,大概是没有权限创建)

然后就把档案拷贝到宿主机上,用GDB去载入档案,分析出错的原因

———–EOF———–

Run Dalvik on X86

很早以前就想过自己编译一个X86上的Dalvik出来玩玩,尝试之后没有成功,就放下了,最近几个月来又想起来搞搞,按照/PATH/TO/AOSP/dalvik/docs/hello-world.html来编译dalvikvm,创建dex档案,设置各种环境变量之后,运行出现错误

E/dalvikvm(10105): execv '/home/guohai/dev/src/android/git/aosp/out/target/product/generic_x86/system/bin/dexopt' failed: No such file or directory
W/dalvikvm(10102): DexOpt: --- END 'Foo.jar' --- status=0x0100, process failed
E/dalvikvm(10102): Unable to extract+optimize DEX from 'Foo.jar'
Dalvik VM unable to locate class 'Foo'
W/dalvikvm(10102): threadid=1: thread exiting with uncaught exception (group=0xf5a1d9c8)
java.lang.NoClassDefFoundError: Foo
    at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.ClassNotFoundException: Didn't find class "Foo" on path: DexPathList[[zip file "Foo.jar"],nativeLibraryDirectories=[/home/guohai/dev/src/android/git/aosp/out/target/product/generic_x86/system/lib]]
    at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:53)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:501)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:461)
    ... 1 more

在网络上搜了很久没有出现过这种错误现象的,实在无赖提了个问题
在StackOverflow上,一个星期过去了,还是无人问津

最终请教了一个做Dalvik相关工作的同事,在他的帮助之下解决了问题

原来是我的ANDROID_ROOT写的有问题,可能是我没有理解好/PATH/TO/AOSP/dalvik/docs/hello-world.html的意思,也或者是它的内容比较陈旧。
后来改了就可以正常运行了,我改过的rund请参见https://gist.github.com/guohai/5048153

现在描述下主要过程
1. Download AOSP source code

2. Compile dalvik vm on Ubuntu 11.10 X64

source build/envsetup.sh
lunch 2 # choose full_x86-eng, because we want to run it on X86 directly
make dalvikvm core dexopt ext framework android.policy services

3. Compile Java code and package it to dex.

4. Run & enjoy it.

guohai@KNIGHT:~/dev/src/android/git/aosp$ ./rund -cp Foo.jar Foo
I/dalvikvm( 3473): DexOpt: mismatch dep name: '/home/guohai/dev/src/android/git/aosp/out/target/product/generic_x86/system/framework/core.odex' vs. '/system/framework/core.odex'
E/dalvikvm( 3473): /home/guohai/dev/src/android/git/aosp/out/target/product/generic_x86/system/framework/ext.jar odex has stale dependencies
I/dalvikvm( 3473): Zip is good, but no classes.dex inside, and no valid .odex file in the same directory
I/dalvikvm( 3473): DexOpt: mismatch dep name: '/home/guohai/dev/src/android/git/aosp/out/target/product/generic_x86/system/framework/core.odex' vs. '/system/framework/core.odex'
E/dalvikvm( 3473): /home/guohai/dev/src/android/git/aosp/out/target/product/generic_x86/system/framework/framework.jar odex has stale dependencies
I/dalvikvm( 3473): Zip is good, but no classes.dex inside, and no valid .odex file in the same directory
I/dalvikvm( 3473): DexOpt: mismatch dep name: '/home/guohai/dev/src/android/git/aosp/out/target/product/generic_x86/system/framework/core.odex' vs. '/system/framework/core.odex'
E/dalvikvm( 3473): /home/guohai/dev/src/android/git/aosp/out/target/product/generic_x86/system/framework/android.policy.jar odex has stale dependencies
I/dalvikvm( 3473): Zip is good, but no classes.dex inside, and no valid .odex file in the same directory
I/dalvikvm( 3473): DexOpt: mismatch dep name: '/home/guohai/dev/src/android/git/aosp/out/target/product/generic_x86/system/framework/core.odex' vs. '/system/framework/core.odex'
E/dalvikvm( 3473): /home/guohai/dev/src/android/git/aosp/out/target/product/generic_x86/system/framework/services.jar odex has stale dependencies
I/dalvikvm( 3473): Zip is good, but no classes.dex inside, and no valid .odex file in the same directory
I/dalvikvm( 3473): DexOpt: source file mod time mismatch (4244043d vs 425baf6a)
Hello, Dalvik!

一些对我有些帮助的资料
http://stackoverflow.com/questions/6146983/helloworld-cannot-run-under-dalvikvm
http://stackoverflow.com/questions/11773506/how-to-launch-jar-with-exec-app-process-on-android-ics
http://blog.csdn.net/johnnynuaa/article/details/6543425

附上自己无法运行的启动脚本

#!/bin/sh

# base directory, at top of source tree; replace with absolute path
base=`pwd`

# configure root dir of interesting stuff
root=$base/out/target/product/generic_x86/system
export ANDROID_ROOT=$root #为什么这里不能指到target的路径?

export LD_LIBRARY_PATH=$root/lib:$LD_LIBRARY_PATH

# configure bootclasspath
bootpath=$root/framework
export BOOTCLASSPATH=$bootpath/core.jar:$bootpath/ext.jar:$bootpath/framework.jar:$bootpath/android.policy.jar:$bootpath/services.jar

# this is where we create the dalvik-cache directory; make sure it exists
export ANDROID_DATA=/tmp/dalvik_$USER
mkdir -p $ANDROID_DATA/dalvik-cache

exec $base/out/host/linux-x86/bin/dalvikvm -Xdexopt:none $@

在Ubuntu 11.10 X64上编译Android源码

初次在Ubuntu 11.10 X64上编译ICS的源码,可能会遇到一些编译错误,不过解决方法也不是很难。
首先要清楚Android官方是支持在这个系统上编译Android的源码的,所以只要设置正确都是能编译成功的。
具体的参考此处http://source.android.com/source/initializing.html

有个依赖包lib32readline5-dev已经被废弃了,但是可以用lib32readline-gplv2-dev替代。
如果缺少什么依赖包的话一般安装一下就可以了,大多都是比较简单的

因为历史原因有些代码只能用老版本的gcc(g++)编译,而11.10上默认的版本又是比较新的4.6,所以我们需要安装老版本的gcc(g++)

sudo apt-get install gcc-4.4
sudo apt-get install g++-4.4

网络上有些资料写的是可以通过update-alternatives来管理不同版本的gcc(g++),通过设置4.4版本为默认值,来达到默认启用4.4来编译。
也有通过手动修改符号链接指向gcc(g++)来启用4.4的。

实际上我们在这里不需要这么麻烦,只要机器上有4.4的编译器,并且在PATH目录中
只需要简单的指定make的参数就可以使用指定版本的编译器了

$ . build/envsetup.sh
$ lunch full-eng
$ make CC=gcc-4.4 CXX=g++-4.4 -j4

就比http://source.android.com/source/building.html上的编译指令多了两个参数
CC=gcc-4.4 CXX=g++-4.4
是不是很简单?

编译的时候可能会出些错误,比如
g++-4.4: selected multilib ’32’ not installed

sudo apt-get install g++-4.4-multilib

fatal error: GL/glx.h: No such file or directory

sudo apt-get install libgl1-mesa-dev

常见的错误可以参考http://blog.csdn.net/sunboy_2050/article/details/6977386

Tips about Oneiric Ocelot

一直不想升级Maverick Meerkat,因为觉得Unity太不习惯了,因为平时开的东西多,Unity切换太麻烦了。
还是习惯底部的Task Bar,但是最近没有办法,因为驱动问题,Maverick Meerkat支持的不太好,只能升级。

1、Ubuntu 11.10 安装Gnome 3替换Unity
sudo apt-get install gnome-shell
Logout之后在登录界面就可以选择Gnome Classic了

2、Ubuntu 11.10 英文环境 Gnome 3,中文输入法不自动启动
进入language support,keyboard input method system 选择 ibus就OK了

3、顶部快速启动栏无法像以前一样拖动,删除。其实你需要按住Alt key再像原来一样操作就可以了。

4、Ubuntu 11.10 X64 下让浏览器支持Applet
$ cd /usr/lib/mozilla/plugins
$ sudo ln -s $JAVA_HOME/jre/lib/amd64/libnpjp2.so
再去http://java.com/en/download/testjava.jsp测试下看看

5、以前的Sticky Notes没了,现在用Xpad代替,也还不错

6、如果SDHC无法识别,先检查下机器的Removable Media有没有禁止或者过滤掉某些选项
我的电脑Thinkpad T400就是因为禁止掉了而显示不出来,不是网络上有些所说的读卡器驱动问题

7、无法记住荧幕亮度

查看
/sys/class/backlight/$DEVICE_ID/brightness里面的数值

sudo gedit /etc/rc.local

#!/bin/sh -e
#
# rc.local
#
# This script is executed at the end of each multiuser runlevel.
# Make sure that the script will “exit 0” on success or any other
# value on error.
#
# In order to enable or disable this script just change the execution
# bits.
#
# By default this script does nothing.

echo 7 > /sys/class/backlight/acpi_video0/brightness

exit 0

每次启动是设置一个值进去,这就相当于记住了参数

8、StarDict词典拷贝到/usr/share/stardict/dic/识别不出来
检查词典文件是否具有R权限

9、删除ubuntuone-syncdaemon

sudo apt-get purge ubuntuone-client

10、用Wicd替换Ubuntu 11.10 Network Manager
http://guoh.org/lifelog/2013/09/replacing-ubuntu-11-10-network-manager-with-wicd/

MySQL主从复制基本实验

最近这一两个月业余时间基本都在看MySQL的书,看明白了一些,又忘了一些,哈哈,总的来说没有什么很大的收获
今天无聊了,弄个Replication(http://dev.mysql.com/doc/refman/5.1/en/replication.html)来玩玩
MySQL的Replication可以用在很多地方,比如平衡负载,备份等等
主要它复制的时候是一个异步的过程(有没有将随机读写变成顺序读写这个值得研究,对于大多数磁盘来说,顺序读写可能更快些),可以从某些程度上来说提高性能,当然生成Binary-log也是有代价的,不过会换来更多的好处(在网络传输影响很小的情况下),比如读写分离将读压力分出去了,比如多机备份

也有很多人写类似的文章和书籍,我也就记录个实践的过程

我这里实践所有的环境都是Linux 2.6.35-28-generic #50-Ubuntu SMP Fri Mar 18 19:00:26 UTC 2011 i686 GNU/Linux,两个数据库,一个5.1.57-log作为Master,一个5.5.8作为Slave,都装在一台机器上,启用不同的配置和端口
目的就想在Master插入一条数据,在Slave也能看到,性能以及安全的配置都没有考虑

看官方配置说明的时候就需要弄清楚哪些是在Master上配的,哪些是在Slave上配的

因为我的Slave是5.5,以前的版本,比如5.1中可用的
master-user = repl
master-password = repl
master-port = 3307
这些配置文件参数在5.5的Slave就不能用了,如果你不小心配置了这些参数,MySQL服务器将无法正常启动
看下MySQL日志你应该会发现类似于这样的提示(unknown variable ‘master-host=‘)
2121 110809 22:53:21 mysqld_safe Starting mysqld daemon with databases from /usr/local/mysql/data
2122 110809 22:53:21 [Note] Plugin ‘FEDERATED’ is disabled.
2123 InnoDB: The InnoDB memory heap is disabled
2124 InnoDB: Mutexes and rw_locks use InnoDB’s own implementation
2125 InnoDB: Compressed tables use zlib 1.2.3
2126 110809 22:53:21 InnoDB: Using Linux native AIO
2127 110809 22:53:21 InnoDB: Initializing buffer pool, size = 128.0M
2128 110809 22:53:21 InnoDB: Completed initialization of buffer pool
2129 110809 22:53:21 InnoDB: highest supported file format is Barracuda.
2130 110809 22:53:21 InnoDB: 1.1.4 started; log sequence number 42505789
2131 110809 22:53:21 [ERROR] /usr/local/mysql/bin/mysqld: unknown variable ‘master-host=127.0.0.1′
2132 110809 22:53:21 [ERROR] Aborting
2133
2134 110809 22:53:21 InnoDB: Starting shutdown…
2135 110809 22:53:22 InnoDB: Shutdown completed; log sequence number 42505789
2136 110809 22:53:22 [Note] /usr/local/mysql/bin/mysqld: Shutdown complete
2137
2138 110809 22:53:22 mysqld_safe mysqld from pid file /usr/local/mysql/data/KNIGHT.pid ended

那么在5.5的Slave中我是先配置了这几个参数
replicate-do-db = replication
replicate-ignore-db = mysql
replicate-ignore-db = information_schema
有意的指定和排除了一些库参与同步
之后启动Slave,然后通过change master to master_host=’127.0.0.1′, master_port=3307, master_user=’repl’, master_password=’repl’, master_log_file=’master-cutoe-binlog.000001′, master_log_pos=600, master_connect_retry=10;
slave start;
来实现Slave的开始复制

Master配置文件主要参数如下:
server-id = 1
log-bin = master-cutoe-binlog
binlog_format = mixed
sync_binlog = 1
innodb_flush_log_at_trx_commit = 2

Slave配置文件主要参数如下:
server-id = 2
replicate-do-db = replication
replicate-ignore-db = mysql
replicate-ignore-db = information_schema

如果配置都对了的话,先起Master,再起Slave
在Master和Slave中创建好需要复制的库和表,比如
create database replication;
create table user(id int primary key auto_increment, name varchar(20), age smallint);
(让复制自动在Slave中创建和Master一样的表在这里我没有尝试,有空可以试试)
还要在Master中创建一个Slave用来访问Master的用户
CREATE USER ‘repl’@’%’ IDENTIFIED BY ‘repl’;
GRANT REPLICATION SLAVE ON *.* TO ‘repl’@’%’; –为什么不能指定该用户只对单独的库具有复制权限,目前不清楚原因
然后在Master中mysql> show master status;
在Slave中通过change master to,slave start开启复制
并mysql> show slave status \G
就应该会看到Slave_IO_State: Waiting for master to send event
这个时候再在Master中执行个Insert语句,如果没有错误的话,应该可以在Slave的相应表中看到刚刚你在Master插入的一样的数据
基本可以通过mysql> show slave status \G查看到复制过程中发生的所有情况,例如错误信息

如果Slave复制失败,你可以根据错误信息进行修正,然后执行
mysql> slave stop;
mysql> slave start;
就可以把原来应该复制过来的数据都复制过来

别忘了一个很简单的命令也是要常用的
mysql> show processlist \G

Good Luck & Good Night…

试玩HandlerSocket for MySQL

有这么一个场景,单台MySQL数据库服务器,最大表约500万记录,常用表100万记录,每行记录的数据量不是很大
查询还算频繁,插入修改删除数据不是那么多,多个应用同时访问这个数据库
有个应用就是查询为主,没有修改,少量的删除
查询SQL语句很简单,根据用户ID查询他下面的记录(某些字段),根据记录ID查询整条记录,两表关联查询100万的关联500万
目前应用的实现也很简单,简陋的数据库连接池,客户端发送SQL语句到SQL服务器
现在也没有遇到很大的问题,没有宕机什么的问题,但就是客户端反映慢,但是看服务器的负载都不是很高

所以老大就说太慢了,需要解决

这个慢是比较显然的啊,每次解析执行SQL语句,网络传输,数据库服务器内存较小,缓存不够

所以当然就想到了在应用层加缓存,但是在几个月之前曾经看到过HandlerSocket的简单介绍,只知道它可以加快查询,没有细看

所以突然觉得目前这个也可以改用HandlerSocket,而且更合适,向老大建议,当然建议都是木有用的,因为我做不鸟主,老大有老大的想法

所以只能自己研究看看这个东西适合不了

于是就开始下载编译安装这个东西了,步骤还算简单

具体安装参见installation.en.txt

我开始想用5.1的源码和5.5的二进制版本混合编译(目前我自己用的5.5的MySQL),天知道能不能成功(最后是不能成功的,我又用5.1的源码重新编译了一个MySQL数据库出来,然后编译HandlerSocket并把它安装到5.1中了,后来看到介绍是源码版本一定要和当前安装的数据库的版本一致,之所以需要源码是因为HandlerSocket插件用到了MySQL源码之中的几个头文件之类的吧,总之不看README是很头疼的。比如有的酒店的电梯是要用房卡刷了电梯之后才能按楼层的,README写的清清楚楚,汗)
我的编译步骤如下
$ ./autogen.sh
$ ./configure –with-mysql-source=/home/guohai/dev/src/database/mysql-5.1.57 –with-mysql-bindir=/home/guohai/dev/a/mysql/mysql-5.1.57-linux2.6-i686/bin –with-mysql-plugindir=/home/guohai/dev/a/mysql/mysql-5.1.57-linux2.6-i686/lib/mysql/plugin

$ make
$ sudo make install

mysql> install plugin handlersocket soname ‘handlersocket.so’;
Query OK, 0 rows affected (0.03 sec)

mysql> show plugins;
+—————+——–+—————-+——————+———+
| Name | Status | Type | Library | License |
+—————+——–+—————-+——————+———+
| binlog | ACTIVE | STORAGE ENGINE | NULL | GPL |
| partition | ACTIVE | STORAGE ENGINE | NULL | GPL |
| CSV | ACTIVE | STORAGE ENGINE | NULL | GPL |
| MEMORY | ACTIVE | STORAGE ENGINE | NULL | GPL |
| InnoDB | ACTIVE | STORAGE ENGINE | NULL | GPL |
| MyISAM | ACTIVE | STORAGE ENGINE | NULL | GPL |
| MRG_MYISAM | ACTIVE | STORAGE ENGINE | NULL | GPL |
| handlersocket | ACTIVE | DAEMON | handlersocket.so | BSD |
+—————+——–+—————-+——————+———+
8 rows in set (0.00 sec)

这样插件就安装好了,接下来就是装个客户端试试看了,用的淘宝的那个

当然还要在my.cnf中增加类似参数
loose_handlersocket_port = 9998
# the port number to bind to (for read requests)
loose_handlersocket_port_wr = 9999
# the port number to bind to (for write requests)
loose_handlersocket_threads = 16
# the number of worker threads (for read requests)
loose_handlersocket_threads_wr = 1
# the number of worker threads (for write requests)
open_files_limit = 65535
# to allow handlersocket accept many concurrent
# connections, make open_files_limit as large as
# possible.

弄hs4j还是报了几个错误,什么open_table,原因是我表名没有写对,巨汗,不过这个提示也够瓜的
估计也是我没有理解这个东西

然后我又报了个错误
Exception in thread “main” com.google.code.hs4j.exception.HandlerSocketException: Connection has been closed
at com.google.code.hs4j.impl.HSClientImpl.awaitResponse(HSClientImpl.java:417)
at com.google.code.hs4j.impl.HSClientImpl.insert0(HSClientImpl.java:325)
at com.google.code.hs4j.impl.HSClientImpl.insert(HSClientImpl.java:309)
at com.google.code.hs4j.example.HS4JExample.main(HS4JExample.java:29)
这个我把keys写少了一个,所以报错了
总之都是我的问题

就这样解决几个问题之后客户端就基本可用了

然后我还试了下Python的客户端,装好Python的插件http://packages.python.org/python-handler-socket/
就可以开始玩了,照着例子也很简单

看了还算多的文章介绍以及issues,这个东西在某些特定的情况下还是可以开始用的吧,以前提的比较多的问题,什么auto_increment之类的也都解决了

觉得最关键的是就是参数怎么配置,才能让这个东西在需要的场景下发挥最大的能力

还得多看看,多试试才有更充分的把握

参考
https://github.com/ahiguti/HandlerSocket-Plugin-for-MySQL
http://yoshinorimatsunobu.blogspot.com/2010/10/using-mysql-as-nosql-story-for.html 你懂的
https://github.com/killme2008/hs4j
http://whitesock.iteye.com/blog/811339
http://rdc.taobao.com/team/jm/archives/545
http://www.cnblogs.com/inrie/archive/2011/01/28/1946572.html 系列文章
http://huoding.com/2011/04/10/62

流水帐总是很简单,再把编译MySQL的主要过程也记在这里吧,凑点字数
我用的是Ubuntu 10.10 X86,以前编译过很多软件开发包,所以如果编译的时候遇到缺什么包装上就行了
下载就不说了,下载都不会的就不要从源码编译了,我用的是mysql-5.1.57.tar.gz
编译参见INSTALL-SOURCE
2.11.2. Installing MySQL from a Standard Source Distribution

$ ./configure –prefix=/home/guohai/dev/a/mysql/mysql-5.1.57-linux2.6-i686 –with-unix-socket-path=/tmp/mysql51.sock –with-tcp-port=3307 –with-named-curses-libs=/lib/libncurses.so.5 –enable-assembler –with-plugins=partition,innobase –with-charset=utf8 –with-collation=utf8_general_ci –with-extra-charsets=big5,ascii,gbk,utf8,latin1 –with-big-tables –without-debug

$ make
$ make install

$ cd /home/guohai/dev/a/mysql/mysql-5.1.57-linux2.6-i686
$ chown -R mysql .
$ chgrp -R mysql .

我以前已经装过MySQL5.5所以这些用户以及组都是有的

guohai@KNIGHT:~/dev/a/mysql/mysql-5.1.57-linux2.6-i686$ sudo cp ‘/home/guohai/dev/src/database/mysql-5.1.57/support-files/my-medium.cnf’ ./my.cnf

$ sudo bin/mysql_install_db –user=mysql –basedir=/home/guohai/dev/a/mysql/mysql-5.1.57-linux2.6-i686 –datadir=/home/guohai/dev/a/mysql/mysql-5.1.57-linux2.6-i686/data

启动数据库
$ sudo bin/mysqld_safe –defaults-file=/home/guohai/dev/a/mysql/mysql-5.1.57-linux2.6-i686/my.cnf –user=mysql &
注意这个参数传递的顺序,我开始一直把–user=mysql放前面,启动的时候报错,MySQL日志记载unknown variable ‘defaults-file’
110601 23:23:28 [ERROR] /home/guohai/dev/a/mysql/mysql-5.1.57-linux2.6-i686/libexec/mysqld: unknown variable ‘defaults-file=/home/guohai/dev/a/mysql/mysql-5.1.57-linux2.6-i686/my.cnf’
110601 23:23:28 [ERROR] Aborting
110601 23:23:28 InnoDB: Starting shutdown…
110601 23:23:33 InnoDB: Shutdown completed; log sequence number 0 44233
110601 23:23:33 [Note] /home/guohai/dev/a/mysql/mysql-5.1.57-linux2.6-i686/libexec/mysqld: Shutdown complete

然后看了mysqld_safe下这个脚本的写法,发现它有对传入的第一个参数判断是否为defaults,于是我就把defaults-file这个参数放到第一位,就正常启动了

一切都好了,然后就是设置了
/home/guohai/dev/a/mysql/mysql-5.1.57-linux2.6-i686$ sudo bin/mysql_secure_installation
一步步来就好了,注意默认my.cnf的位置,我的就放在mysql-5.1.57安装目录下

可能还要修改下MySQL数据文件存放的路径,我最开始编译的时候没有指定,然后它帮我生成的是放在mysql-5.1.57安装目录的一个var目录下面的,而我在my.cnf中指定的是data目录
所以我就修改了一个脚本中的,把var改为data了,具体是哪个脚本忘记了

再重启下,就可以用mysql命令连接上去了,基本正常

MySQL编译简单,关键是编译出自己想要的MySQL,编译出符合自己业务高性能的MySQL就是技术活了,参数很关键
只要参数用的好,没有程序写不鸟;只要工具用的好,没有程序写不鸟;夸张了点

还有刚开始编译出来你可能找不到mysqld这个东西,我反正一开始是没有找到,以为自己编译的出错了,后来才发现在libexec下而不是在bin下面,多用用工具搜索搜索就出来了

另外也可以参见Ubuntu二进制安装MySQL 5.5
地址http://lucane.iteye.com/blog/866355

自己动手编译OpenJDK

无聊的时候决定自己动手编译个JDK,曾经想在X86上编译一个Dalvik出来玩玩,但基于那玩意是高手才玩的起的,所以自己那个想法就不了了知了
看了一圈后发现OpenJDK还是比较容易编译的,所以就来炒份现饭
现代JDK这么容易自己编译还是归功于开源和社区

开场白就说这么多,下面是过程记录
下载源码,解压,阅读README和README-builds.html,然后就可以开工了

我是在Linux 2.6.35-28-generic #50-Ubuntu i686 GNU/Linux上编译的,我编译的是openjdk-7-ea-src-b141-05_may_2011这个版本

主要需要以下条件
Basic Linux Check List
1. Install the Bootstrap JDK, set ALT_BOOTDIR.
2. Optional Import JDK, set ALT_JDK_IMPORT_PATH.(可以不要,如果你是完全编译的话)
3. Install or upgrade the FreeType development package.(这个基本有了)
4. Install Ant 1.7.1 or newer, make sure it is in your PATH.

然后在环境变量下做些设置
ALT_BOOTDIR=$SUN_JDK1.6.0_25_HOME(我是用的SUN的JDK6来作为Bootstrap JDK的)
LANG=C(需要设置成这样,否则编译会报错,Linux一般是zh_CN.utf8改下就可以)
ALT_CUPS_HEADERS_PATH=$CUPS_HOME/include(何为CUPS见此)

另外环境变量中不要出现JAVA_HOME,CLASSPATH,有的话就把它们注释掉

记得使修改过的环境变量生效

然后就cd到$openjdk_src下开始执行make sanity检测
成功的话就执行make all ALLOW_DOWNLOADS=true WARNINGS_ARE_ERRORS=开始较为耗时的编译之旅

这两个参数的意思还是比较明白
ALLOW_DOWNLOADS=true就是编译的时候发现缺少某些预知的源码或依赖时,它会自动去下载,前提是必须联网
WARNINGS_ARE_ERRORS=就是禁止编译器把一些警告当错误,如果不加这个就可能会因为类似于这样的cc1plus: warnings being treated as errors提示而终止编译,这不是我们所希望的

但是不要高兴的太早,多多少少可能会遇到点问题,不过找找Google应该都能解决

下面贴出我在编译的时候遇到的问题
1、
/home/guohai/dev/src/java/openjdk-7-ea-src-b141-05_may_2011/hotspot/src/os/linux/vm/os_linux.cpp
cc1plus: warnings being treated as errors
/home/guohai/dev/src/java/openjdk-7-ea-src-b141-05_may_2011/hotspot/src/os/linux/vm/os_linux.cpp: In static member function ‘static bool os::Linux::hugetlbfs_sanity_check(bool, size_t)’:
/home/guohai/dev/src/java/openjdk-7-ea-src-b141-05_may_2011/hotspot/src/os/linux/vm/os_linux.cpp:2853: error: use of assignment suppression and length modifier together in gnu_scanf format
make[6]: *** [os_linux.o] Error 1
make[6]: Leaving directory `/home/guohai/dev/src/java/openjdk-7-ea-src-b141-05_may_2011/build/linux-i586/hotspot/outputdir/linux_i486_compiler2/product’

WARNINGS_ARE_ERRORS=

2、
../../../src/solaris/native/sun/awt/awt.h:38: fatal error: X11/Intrinsic.h: No such file or directory
compilation terminated.
make[5]: *** [/home/guohai/dev/src/java/openjdk-7-ea-src-b141-05_may_2011/build/linux-i586/tmp/sun/sun.awt/awt/obj/BufImgSurfaceData.o] Error 1
make[5]: *** Waiting for unfinished jobs….
make[5]: Leaving directory `/home/guohai/dev/src/java/openjdk-7-ea-src-b141-05_may_2011/jdk/make/sun/awt’
make[4]: *** [library_parallel_compile] Error 2
make[4]: Leaving directory `/home/guohai/dev/src/java/openjdk-7-ea-src-b141-05_may_2011/jdk/make/sun/awt’
make[3]: *** [all] Error 1
make[3]: Leaving directory `/home/guohai/dev/src/java/openjdk-7-ea-src-b141-05_may_2011/jdk/make/sun’
make[2]: *** [all] Error 1
make[2]: Leaving directory `/home/guohai/dev/src/java/openjdk-7-ea-src-b141-05_may_2011/jdk/make’
make[1]: *** [jdk-build] Error 2
make[1]: Leaving directory `/home/guohai/dev/src/java/openjdk-7-ea-src-b141-05_may_2011′
make: *** [build_product_image] Error 2

sudo apt-get install libxt-dev

3、
../../../src/solaris/native/sun/xawt/XToolkit.c:48: fatal error: X11/extensions/XTest.h: No such file or directory
compilation terminated.
make[5]: *** [/home/guohai/dev/src/java/openjdk-7-ea-src-b141-05_may_2011/build/linux-i586/tmp/sun/sun.awt.X11/xawt/obj/XToolkit.o] Error 1
make[5]: *** Waiting for unfinished jobs….
make[5]: Leaving directory `/home/guohai/dev/src/java/openjdk-7-ea-src-b141-05_may_2011/jdk/make/sun/xawt’
make[4]: *** [library_parallel_compile] Error 2

sudo apt-get install libxtst-dev

从2011-05-12 20:39开始编译,遇到问题,前前后后经历了近一个小时
另外如果编译出错了,并且你解决了错误,貌似你只需要继续执行make all ALLOW_DOWNLOADS=true WARNINGS_ARE_ERRORS=
就可以了,它会接着编译,而不需要从头开始编译
当你看到下面这种提示时
— Build times ———-
Target all_product_build
Start 2011-05-12 21:28:48
End 2011-05-12 21:37:48
00:00:04 corba
00:00:12 hotspot
00:00:03 jaxp
00:00:05 jaxws
00:08:32 jdk
00:00:04 langtools
00:09:00 TOTAL
————————-
应该就可以完工了,cd到$openjdk_src/build/platform/下,看看j2sdk-image和j2re-image中的内容是不是很熟悉?
cd$openjdk_src/build/platform/bin/下执行如下命令就应该可以看到结果,当然版本,硬件架构可能不一样
总之你就自己编译出了一个带自己名字的JDK了

$openjdk_src/build/linux-i586/bin$ ./java -version
openjdk version “1.7.0-internal”
OpenJDK Runtime Environment (build 1.7.0-internal-guohai_2011_05_12_20_39-b00)
OpenJDK Server VM (build 21.0-b11, mixed mode)

$openjdk_src/build/linux-i586/bin$ ./javac -version
javac 1.7.0-internal

有图
compile-my-openjdk

编译成功之后再把那些需要改回来的东西改回来


sudo apt-get install libfreetype6-dev
sudo apt-get install libasound2-dev
sudo apt-get install libcups2-dev

Nginx+FastCGI+MySQL+Linux搭建Trac 0.12.2环境

完整详细的安装方法请参考官网http://trac.edgewall.org/wiki/TracInstall或者INSTALL
本文主要记录我在安装的时候遇到的一些问题和解决办法,有误导的地方欢迎指正

一般都是装数据库,装服务器,装Trac程序

0、安装Python环境,默认都有,只需要检查版本是否符合,安装需要的Python插件

1、安装数据库,我这里用的是MySQLhttp://lucane.iteye.com/blog/866355
Trac是Python写的,访问MySQL用的是MySQL-python
需要配置的就是$MYSQL_PYTHON_HOME/site.cfg/site.cfg
下的mysql_config = $MYSQL_HOME/bin/mysql_config
目前我的这些东西都在一台机器上,如果分布在多台机器上还真不知道怎么装

2、安装Nginx,我这里是编译安装
./configure –prefix=$PATH_TO_INSTALL/nginx
make
make install
可能启动的时候报错,类似于下面这样
[emerg]: bind() to 0.0.0.0:80 failed (13: Permission denied)
这是因为端口号的问题,在Linux中1024下的端口号都需要root用户才能使用
所以普通用户启动程序绑定会报出权限问题,我这里是把Nginx绑定的端口号改为8888

Nginx比较简陋,启动之后关闭一般要通过kill命令杀进程,具体的参考Nginx相关手册
这里列出几个简单的

修改配置文件后检查配置文件语法是否正确
nginx -t -c $NGINX_HOME/conf/nginx.conf
t因该是表示测试的意思,c就是指定所用配置文件的地方,这里可以自由发挥

停止Nginx
kill -quit PID_OF_NGINX

平滑重启Nginx
kill -hup PID_OF_NGINX

启动Nginx就不说了

关键是这个配置文件,这里比较复杂,至少对于新手来说是这样的
我也是参考了http://marshalys.blogspot.com/2009/02/freebsdtrac.html才弄出来的

我先把我的配置文件贴出来,可能有些无用,但是暂时就这样了
nginx.conf

    server {
        listen       8888;
        server_name  localhost;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location / {
            fastcgi_pass 0.0.0.0:8080;

            auth_basic "Trac Realm"; 
            auth_basic_user_file $KEY_PATH/trac.htpasswd;

            fastcgi_param PATH_INFO $fastcgi_script_name;
            fastcgi_param REQUEST_METHOD $request_method;
            fastcgi_param QUERY_STRING $query_string;
            fastcgi_param CONTENT_TYPE $content_type;
            fastcgi_param CONTENT_LENGTH $content_length;
            fastcgi_pass_header Authorization;
            fastcgi_param REMOTE_ADDR           $remote_addr;
            fastcgi_param SERVER_PROTOCOL       $server_protocol;
            fastcgi_param SERVER_PORT           $server_port;
            fastcgi_param SERVER_NAME           $server_name;
            fastcgi_intercept_errors off;

            # for authentication to work
            fastcgi_param AUTH_USER $remote_user;
            fastcgi_param REMOTE_USER $remote_user;
        }

其中
auth_basic “Trac Realm”;
auth_basic_user_file $KEY_PATH/trac.htpasswd;

# for authentication to work
fastcgi_param AUTH_USER $remote_user;
fastcgi_param REMOTE_USER $remote_user;
是Trac授权用的,可以先不用管

当然弄好之后先要测试Nginx能否将Python转发给FastCGI处理,写个简单的测试fcgi.py放到$NGINX_HOME/html/下
其中fcgi.py的内容如下

执行python fcgi.py &
打开浏览器,键入http://localhost:8888/如果能看到Hello World字样就说明OK
当然这些端口号神马的都是根据自己的实际情况

3、安装Trac
你可以把它认为是Python的模块插件
所以安装方式和安普通模块是一样的
我这里编译安装
python setup.py build
sudo python setup.py install

接下来就是创建实例了,参考INSTALL
trac-admin /path/to/projectenv initenv

需要填些数据库连接,实例名字之类的,我这里数据库连接如下
mysql://trac:trac@127.0.0.1:3306/trac
是这种格式
DATABASE_TYPE://USERNAME:PASSWD@HOST:PORT/DATABASE_INSTANCE
在HOST那里你如果填的是localhost就可能会出下面这个错误
OperationalError: (2002, “Can’t connect to local MySQL server through socket ‘/var/run/mysqld/mysqld.sock’ (2)”)
将localhost换成127.0.0.1就不会报错了,原因是它指定的sock和你机器上实际的sock路径不一致,填IP就强制要求通过TCP/IP之类的去连,不用socket

安装完成之后可以用它自带的服务器测试下
执行tracd –port 8000 /path/to/projectenv
打开浏览器,键入http://localhost:8000/如果能看到Trac的东西就说明OK

4、整合,把我们的Trac部署到Nginx上去
很简单,写个trac-standalone-fcgi.py放到$TRAC_HOME/cgi-bin当中,这里的$TRAC_HOME是Trac本身安装的位置,不是trac-admin创建出来的实例(或工程,项目)的位置
简单的说如果你把Trac认为是Python的一个插件,那么这个$TRAC_HOME就是这个插件的位置
trac-standalone-fcgi.py的内容如下

执行python trac-standalone-fcgi.py &
当然你需要把之前打开的一些东西都停止,比如fcgi.py或tracd等
打开浏览器,键入http://localhost:8888/如果能看到Trac的东西就说明OK
注意这些端口号和地址,要理解清楚,弄清楚

5、权限配置
如果第四步成功搞定的话,你就可以浏览些内容了,但不会发现你无法添加内容等等
这里权限用户管理有好多种方法,具体参考官网说明,我这里是把用户信息放在key文件中的,采用basic认证的方式
就是那种user:passwd键值对形式存放的
这样做的话,先要生成这样的配置文件,可以用Apache的htpasswd工具来生成
我这里使用的$TRAC_HOME/contrib/htpasswd.py来生成的
./htpasswd.py -c -b $KEY_PATH/trac.htpasswd admin admin
./htpasswd.py -b $KEY_PATH/trac.htpasswd use1 use2
注意第二个就不用-c参数了,估计这里是第一个已经创建文件了,后面的就是往里面添加内容,所以不需要-c参数
有了这个用户密码文件,还要把它和我们的Nginx关联起来,在$NGINX_HOME/conf/nginx.conf中加这两行
auth_basic “Trac Realm”;
auth_basic_user_file $KEY_PATH/trac.htpasswd;
还需要和我们的实例(或工程,项目)关联起来,一般这里只需要增加个管理员就行了(方便在Web界面中操作),命令如下
trac-admin /path/to/projectenv permission add admin TRAC_ADMIN
你也可以help看下该命令更多的用法,比如
trac-admin /path/to/projectenv permission list

这样你再重启Nginx和trac-standalone-fcgi.py就可以看见需要你输入用户名密码的提示了,这是采用HTTP的认证方式,所以会哐哐的提示你输入用户名密码
你可以安装些插件来完成普通的基于表单的验证方式

不过你密码文件创建完成之后可以通过自带的服务器验证下是否成功
tracd -p 8000 –basic-auth=projectenv,$KEY_PATH/trac.htpasswd,” /path/to/projectenv
它提示你需要输入用户名密码,用管理员登录之后能看见Admin Tab,能创建Ticket就说明OK

我在部署在Nginx上的时候,开始死命的都看不见Admin Tab,不能创建Ticket,后来发现很多人也有类似的问题
后来在$NGINX_HOME/conf/nginx.conf加入了
# for authentication to work
fastcgi_param AUTH_USER $remote_user;
fastcgi_param REMOTE_USER $remote_user;
就OK了

参考http://trac.edgewall.org/wiki/TracFastCgi