Patrick He on August 14th, 2010

Android 2.2 出世已经不短时间,不过担心 Hero 这种已经 out of date 的机型硬件规格不支持,以及非官方 ROM 的稳定性问题,一直没有刷新升级。最近看到有爱玩 Android 的同事刷了 VillainROM 1.1.9 版,速度甚至比基于 Android 2.1 的 BeHero+ 1.2 还快,也很稳定,可以实用,于是忍不住也想升级一把。

以前已经刷新过好几次 ROM,都很顺利。于是直接下载最新出炉的 VillainROM 1.2.1 版,按照老经验,将文件更名为 update.zip 放到 /sdcard 下,重启手机进入 recovery mode,清除数据后开始升级,不料进行到一半,提示 “Can’t find update script”,升级过程中止。Google 一下,说是因为 recovery 工具版本太低所致,于是开始下载 1.6.2 版本的 recovery 工具(这里下载),将之也拷贝到 /sdcard 下,在 gnome-terminal 中执行
./adb shell
# flash_image recovery /sdcard/recovery.img

很快得到反馈:
flash_image not found
执行
# ls -l /system/bin/flash_image
发现原来之前刷的 BeHero+ 1.2 ROM 中没有包含 flash_image 程序。前置条件还是未满足,再次 Google 寻找 flash_image这里下载),下载后解压文件,执行
./adb push ~/tmp/flash_image /system/bin/
讲下载到的 flash_image 拷贝到手机上。然后升级 recovery 工具,用新版 recovery 工具刷 VillainROM,一切顺利。

升级到 VillainROM 1.2.1 后,发现速度确实不错,基本稳定,不过使用过程中出现过一次浏览器崩溃的情况。这个 ROM 把 HTC Sense 给去掉了,因此喜欢 HTC Sense 的用家需要考虑是否刷这个 ROM。

Tags: , , ,

Patrick He on July 10th, 2010
  • 互联网产品大多属于短平快的软件系统:业务逻辑简单,开发周期短,改进快速。
  • 在开发新产品的初期,应该重点关注业务,其次是架构,再次是开发框架。
    待产品推广开来,用户基数快速增长,这个阶段中改善软件系统的架构变得非常重要,需要在用户飞速增长的同时提供良好的基本用户体验。架构需要保证高性能以提供较低的响应时间,并且降低单位用户的成本;具有良好的伸展性,便于通过简单的扩展便能线性地提高系统的吞吐量;系统要具备可监控性,在出现故障时能第一时间告警,最好能够具有一定的自我修复功能。
    到了产品的成熟期之后,用户增长速度将会变得较为平缓,原有的产品可能会朝平台方向发展,需要通过扩展众多的附加应用来延长产品的生命力。在这个阶段,提高开发效率的问题会变得重要起来,因此需要改善系统开发框架,使后续开发变得更为快速、容易。
  • 避免复杂的开发框架,复杂的框架往往会给系统引入高复杂性,容易降低系统的健壮性和可维护性。
  • 用语言本身所擅长的机制解决问题,避免用框架来解决语言本身的局限。
  • 远离复杂的元框架!
Patrick He on July 10th, 2010

最近将 Eclipse 从 3.5 升级到 3.6,发现之前自己设置的 SVN 快捷键失效,比如说 svn commit 设置成了 ctrl+alt+n, c 的组合快捷键,在按下 ctrl+alt+n 的时候,Eclipse 右下角会弹出 tip 窗口提示下一步,再按 c 并无反应。经过摸索发现,原来是 perspective 中没有关联到 svn 的 command group。如果遇到类似问题,可以在工具条空白处右击,弹出右键菜单,选择 Customize Perspective,切换到 Command Group Availability,选择左侧 Available command groups 中的 SVN 即可。

Tags: ,

Patrick He on March 26th, 2010

今天在计划备份数据时想到,硬盘寿命对备份计划的影响。之前 Ubuntu 存在一个 bug,导致磁头较频繁地降落在停止区(本意是节能),在支持 S.M.A.R.T. 技术的硬盘中可以查询到 Load cycle count 这个参数,即该操作的次数。但是这个操作对硬盘寿命是有影响的,现代的硬盘,可以执行数十万次这样的操作,根据网络上的说法,可以执行至少30万次,多的可以到60万次。

在 Linux 系统中,可以通过执行

$ sudo smartctl --all /dev/sda | grep 'Load_Cycle_Count'
193 Load_Cycle_Count 0x0032 098 098 000 Old_age Always - 51433

最后一个数字就是 load cycle count 的值,可以看到我笔记本的硬盘在两年多的时间中已经执行了51433次此类操作,因此可以推断该硬盘磁头的寿命还很长。

Tags:

Patrick He on March 17th, 2010

一般情况下我们都会在安装 Linux 的时候,将 Grub 引导记录安装在 MBR 上。这样在重新安装 Windows 之后,MBR 被覆盖,也就不能用 Grub 进行引导了。网上有很多资料介绍如何能够重新加载 Linux,比如使用 grub4dos、利用 Windows OS Loader。个人感觉最简便的方法是使用 Linux Live CD 重新安装 Grub,下面以 Ubuntu Live CD 为例简要说明一下重新安装 Grub 的步骤。

使用 ubuntu-desktop-cd 启动,进入 live 模式。开启一个 terminal,输入

ubuntu@ubuntu:~$ sudo su
root@ubuntu:~$ grub
grub> root (hd0, 1)
grub> setup (hd0)
grub> quit

对于 Grub 而言,所有接口的硬盘都是被识别为 hd 的,无论用户的硬盘使用的是 IDE 还是 SATA 接口。和 Linux 对 dev 的标识不同,Grub 的计数是从0开始的。因而 hd0 表示第一块硬盘,而 (hd0, 1) 即表示第一块硬盘的第二个分区(也就是说在 fdisk 看来,应该是标识为 sda2 的)。root 命令后面需要指定的是用户 Linux 的 /boot 所在的分区,如果没有为 /boot 单独分区,那么也就是指定 / 所在的分区。setup 命令需要指定 grub 安装在哪一块硬盘上。重启之后即可。

PS. 几个月内可能需要安装 Windows 系统,Windows 安装后会覆盖系统原先的 MBR,导致引导多系统的 Grub 不能工作,于是找出这篇写于2006年末的文章,以备使用。原文发表于 CSDN Blog。

Tags: , ,

Patrick He on January 9th, 2010

升级到 Ubuntu 9.10 后,在显示方面发生了好几次问题,之前解决了无法进入 XWindow 环境的问题。在更新过一次驱动程序后又遭遇到窗口丢失标题栏的问题。具体表现是窗口标题栏、边框都消失,也不相应 alt+f4、alt+tab 之类的视窗环境快捷键。开始时没有找到根本原因,只发现在 System->Preferences->Appearances 中 Visual Effects 变为 None,需要选择 Norma 或者 Extra 来激活 compiz 才能将恢复正常。每次启动 XWindow 之后都要如此操作,不但麻烦,而且还要重新选择 compiz 中自己需要的 plugin。

在网上搜索发现这个问题很早就出现,ubuntuforums.org 上有大把2007年的帖子在讨论这个问题。但是找到的各种方法都没有能够将我的系统恢复正常。不过这些方法应该也是一些必需的步骤。

最基础的是要安装驱动程序,我的笔记本是 nVidia 的显示卡,因此需要安装 nvidia-glx 相应的驱动程序。Ubuntu repository 中最新的驱动程序是 nvidia-glx-185,如果需要更新的驱动程序,可以添加相应的 apt repository:

sudo add-apt-repository ppa:nvidia-vdpau/ppa && sudo apt-get update

更新 apt 之后可以安装 nvidia-glx-190/195 版本的驱动程序。当然驱动程序不是版本越高越好,稳定性是首要考虑的因素,可以按照自己电脑的实际情况选择相应的版本。

安装驱动程序之后,还可能需要修改 /etc/X11/xorg.conf 文件,找到 Device section,例如:

Section "Device"
Identifier "nVidia Corporation NVIDIA Default Card"
VendorName "NVIDIA Corporation"
BoardName "Quadro NVS 140M"
Option "RenderAccel" "true"
Option "AddARGBGLXVisuals" "True"
Driver "nvidia"
Option "NoLogo" "True"
EndSection

重点是标红的那行 Option。在网上还看到有方法这样添加:

sudo nvidia-xconfig --add-argb-glx-visuals -d 24

nvidia-xconfig 会把 option 添加到 Screen section,这种做法并不是很提倡,option 应该和相关的设备尽量放在一起比较好。

到以上步骤都是网上比较常见的解决方案,但是我经过以上的设置还是没有恢复出标题栏来。后来在 System->Preferences->Startup Applications 发现有一项 Compiz Tray Icon 启动名为 compiz-tray-icon 的程序,在 terminal 中尝试手动执行这条命领,发现系统中不存在 compiz-tray-icon!然后在进入 XWindow 后标题栏消失的情况下执行

pgrep -fl compiz

发现系统中根本不存在包含 compiz 名字的进程,因此确定是 compiz 未能正常启动。而 Startup Applications 中的 Compiz Tray Icon 可能是以前版本遗留下来的配置,在 9.10 中 compiz-tray-icon 却消失了。再调查一番,发现有一个替代的程序,叫做 fusion-icon,执行

apt-cache show fusion-icon

得到的软件描述是:

Description: tray icon to launch and manage Compiz Fusion
The OpenCompositing Project brings 3D desktop visual effects that
improve the usability and eye candy of the X Window System and provide
increased productivity.
.
This package contains a tray icon that allows you to easily enable, disable and
restart Compiz, and change the currently used window manager and/or window
decorator.

于是安装这个软件包

sudo apt-get install fusion-icon

并且在 Startup Applications 删除无效的 Compiz Tray Icon,添加新的一项 Fusion Icon

Add Fusion Icon into Startup Applications

另为了使用 Emerald,在 CompizConfig Setting Manager 中启用 Windows Decoration,将 General->Command 设置为

emerald --replace

重新启动 XWindow,大功告成。

Tags: , , , ,

十月底 Ubuntu 9.10 正式发布,用 Alternative CD 从 9.04 升级,一切顺利。但是重启后,发现 Grub 中最新的 2.6.31 版本内核无法启动,系统在启动后进入命令行模式,屏幕不停闪烁,而且键盘输入也呈现问题,完全无法输入密码登录系统。幸好还保留了一个老版本的内核 2.6.28 可以正常启动,但是在安装了 nvidia-glx-185 显卡驱动之后,连 2.6.28 也无法启动了,故障的状况和 2.6.31 类似。上网搜索了一下,在云风的 blog 上看到他也遇到过类似的问题,但是我在查看 /etc/X11/xconf 文件之后,并没有发现分辨率的设置有异。不过因此得到了提示,手动执行 startx,控制台上输出报错信息显示因为某些出现 error 导致 nvidia 驱动无法正常加载,只是报错信息比较含糊,没有办法定位问题之所在,而模糊的信息,也无法提供良好的搜索关键字。

在浪费了若干时间之后,想到可以在 Ubuntu Forum 上或许可以寻找到一些有用的信息。果然,在 Installation & Upgrades 版块就有一篇 stick 在顶部的 thread《ATI & Nvidia: no X, just blinking on 2.6.31 (Karmic 9.10) 》,文中的问题描述和我遇到的情况别无二致。该 thread 中提供了好几种解决方案,我采用的方法(by Sunflower1970)是

  1. 备份并修改 X 的配置文件:
    sudo cp /etc/X11/xconf /etc/X11/xconf.bak && sudo vi /etc/X11/xconf
  2. 找到类似显示设备配置的段落,类似:
    Section "Device"
    Identifier "Default Device"
    Driver "the driver here"
    Option "NoLogo" "True"
    EndSection
  3. Driver 一项修改成为 vesa,之后保存配置文件,重启系统即可。

导致该问题的原因是系统自动安装 nvidia 显卡驱动失败,但是依旧修改了 /etc/X11/xconf 的配置,于是 X 在启动时根据配置去加载没有安装成功的驱动程序,导致出现故障。可以在成功启动系统之后,再尝试自行安装专用的显卡驱动程序。我是按照 chessmani 提供的方法利用 envyng 来安装 nvidia 显卡驱动的。步骤如下:

  1. 增加 PPA 并且更新 apt 源:
    sudo add-apt-repository ppa:nvidia-vdpau/ppa && sudo apt-get update
  2. 安装 envyng:
    sudo apt-get install envyng-core
  3. 安装 nvidia-190-modaliases 以便 envyng-core 检测到需要安装的驱动:
    sudo apt-get install nvidia-190-modaliases
  4. 执行 envyng 开始安装驱动。注意首先卸载旧版本的驱动。
    sudo envyng -t
    按照出现的提示操作即可。

Tags: ,

Patrick He on October 11th, 2009

在编程中,有些操作可能在执行过程中失败,比如说连接某个远程服务的过程中出现超时,而我们不希望因为一次偶然的超时导致整个操作流程被废弃;或者在访问缓存时发现数据不存在于缓存中,因此触发异步过程去数据库中获取数据放入缓存,并且期望在短时间内远程访问数据库的操作能够完成以便能够及时地拿到数据返回给客户端。在条件允许的情况下,我们可以对失败的操作重新尝试一次或着若干次。

我们可以将实现重试操作的代码嵌入到相关的类中,但是更好的方法是应用 Command pattern 将重试的职责分离出来,成为可以复用代码。

最简单的方法,是使用 Callable 接口表示需要重试的操作。编写一个 RetryService 的服务类用于调用相应的 Callable 对象。

public class RetryService {

	private final ExecutorService executorService;

	private RetryService(ExecutorService executorService) {
		this.executorService = executorService;
	}

	/**
	 * Factory method
	 *
	 * @param executorService
	 * @return
	 */
	public static RetryService createRetryService(
			ExecutorService executorService) {
		return new RetryService(executorService);
	}

	/**
	 * 执行可能需要重试的方法,最多若干次,如果执行成功立即返回,否则将重试指定的次数。
	 *
	 * @param task
	 *            operation to retry
	 * @param maxRetryCount
	 *            the maximum number of times this task will be executed
	 * @throws ExecutionException
	 *             if the computation threw an exception
	 * @throws InterruptedException
	 *             if the current thread was interrupted while waiting
	 * @throws TimeoutException
	 *             if the wait timed out
	 * @throws NullPointerException
	 *             if task is null
	 */
	public <T> T submit(Callable<T> task, int maxRetryCount, long timeout,
			TimeUnit unit) throws InterruptedException, ExecutionException,
			TimeoutException {
		if (task == null) {
			throw new NullPointerException();
		}

		for (int i = 0; i < maxRetryCount; i++) {
			Future<T> future = executorService.submit(task);
			try {
				return future.get(timeout, unit);
			} catch (TimeoutException e) {
				if (i <= maxRetryCount - 1) {
					throw new TimeoutException(e.getMessage());
				} else {
					continue;
				}
			}
		}
		// failed to get result
		return null;
	}

}

Tags: ,

Patrick He on October 8th, 2009

最近有朋友问如何在文件中选择不包含诸如1900、1901、……1999字符串的行,目标文件中所有数据都是由数字字符组成。
如果使用 grep 这样的工具,只用写很一个非常简单的正则表达式就能解决问题:

grep -v '19\d\d' target_file

grep 的 -v 选项表示选择 target_file 中不匹配目标正则表达式的行。
对于诸如 Java 或者 Ruby 这样的程序设计语言,则没有提供类似的参数。我们需要直接使用正则表达式来匹配不包含以上字符串的行。解决这个问题的正则表达式如下:

^((?!19\d\d)\d)+$

其中 (?!19\d\d) 的作用是,一旦正则表达式引擎发现行内包含有符合 19\d\d 模式的数据,即判断该行不匹配此模式;如果一直没有发现符合 19\d\d 模式的数据,而且所有数据都是数字字符,则该行数据匹配此模式。这样就能选取到目标文件中所有不包含以上字符串的行。

Tags:

Patrick He on October 8th, 2009

在 Linux 服务器上,有众多命令行小工具可以用于监控服务器性能和状态。这些工具对于快速判断服务器运行情况,非常有帮助。

  • top
    top 是最常用的命令之一,用来持续显示系统资源的最新使用状况。
    [patrick@ubuntu:~]$ top
    top - 23:39:07 up  5:55,  3 users,  load average: 0.16, 0.22, 0.18
    Tasks: 141 total,   2 running, 138 sleeping,   0 stopped,   1 zombie
    Cpu(s):  3.1%us,  1.1%sy,  0.0%ni, 95.8%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
    Mem:   2041888k total,  1314284k used,   727604k free,    57688k buffers
    Swap:  1951856k total,        0k used,  1951856k free,   728052k cached
    PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
    6043 root      20   0  855m  50m  13m R    3  2.5  12:11.37 Xorg
    2477 root      15  -5     0    0    0 S    1  0.0   0:02.28 scsi_eh_3
    7008 patrick   20   0 15648 4936 3948 S    1  0.2   0:10.46 gnome-screensav

    按 M 将会按照占用内存的大小排列进程,按 P 则会按照 CPU 占用率进行排列。
    VIRT 表示进程使用的内存总大小,包括进程实际使用的内存、映射过的文件、与其它进程共享的内存等。RES 表示实际使用中的内存大小,SHR 表示与其它进程共享的内存大小。
  • uptime
    uptime 最常用的作用是快速查看当时的系统负载情况。
    [patrick@ubuntu:~]$ uptime
    23:48:26 up  6:04,  3 users,  load average: 0.76, 0.38, 0.24

    通常来说,负载值/CPU数目 <= 1 的情况下,表示系统拥有足够的剩余处理能力,当负载值/CPU数目 > 1 的时候,就表示有进程需要等待 CPU 了。
  • vmstat
    vmstat 会提供有关内存、交换分区、进程、IO、CPU 的报告。
    [patrick@ubuntu:~]$ vmstat -S M
    procs -----------memory---------- ---swap-- -----io---- -system-- ----cpu----
    r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa
    0  0      0    697     57    712    0    0    28    17  161  552  8  2 89  1
  • iostat
    iostat 提供有关 CPU 的平均使用情况,以及 IO 信息。
    [patrick@ubuntu:~]$ iostat -x
    Linux 2.6.24-19-generic (ubuntu)     06/28/2008
    avg-cpu:  %user   %nice %system %iowait  %steal   %idle
    8.46    0.01    1.91    1.00    0.00   88.62
    Device:         rrqm/s   wrqm/s     r/s     w/s   rsec/s   wsec/s avgrq-sz avgqu-sz   await  svctm  %util
    sda               0.70     2.88    1.48    1.97    56.64    38.80    27.66     0.07   21.16   3.31   1.14
    sdb               0.09     0.00    0.06    0.00     6.44     0.00   113.77     0.00   17.13   5.41   0.03
  • mpstat
    mpstat 提供全局与单个 CPU 使用情况的统计报告。
    [patrick@ubuntu:~]$ mpstat -P ALL
    Linux 2.6.24-19-generic (ubuntu)     06/28/2008
    11:57:36 PM  CPU   %user   %nice    %sys %iowait    %irq   %soft  %steal   %idle    intr/s
    11:57:36 PM  all    8.48    0.01    1.69    0.99    0.05    0.17    0.00   88.61    183.99
    11:57:36 PM    0    8.63    0.02    1.66    1.08    0.08    0.28    0.00   88.25    152.05
    11:57:36 PM    1    8.33    0.00    1.73    0.90    0.02    0.07    0.00   88.95     31.93
    11:57:36 PM    2    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00      0.00
  • netstat
    netstat 可以用来显示活动的 TCP 连接、计算机侦听的端口、以太网统计信息、IP 路由表、IPv4 统计信息(对于 IP、ICMP、TCP 和 UDP 协议)以及 IPv6 统计信息(对于 IPv6、ICMPv6、通过 IPv6 的 TCP 以及通过 IPv6 的 UDP 协议)。
    [patrick@ubuntu:~]$ netstat -a
    Active Internet connections (servers and established)
    Proto Recv-Q Send-Q Local Address           Foreign Address         State
    tcp        0      0 localhost:mysql         *:*                     LISTEN
    tcp        0      0 localhost:8118          *:*                     LISTEN
    tcp        0      0 localhost:ipp           *:*                     LISTEN
    tcp        0      0 localhost:9050          *:*                     LISTEN
    tcp        0      0 192.168.1.3:59421       by2msg1204111.gate:msnp ESTABLISHED
  • ps
    ps 可以提供一个当前运行的进程的列表。
    [patrick@ubuntu:~]$ ps aux
    USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
    root         1  0.0  0.0   2844  1688 ?        Ss   Jun28   0:01 /sbin/init
    root         2  0.0  0.0      0     0 ?        S<   Jun28   0:00 [kthreadd]
    root         3  0.0  0.0      0     0 ?        S<   Jun28   0:00 [migration/0]
    root         4  0.0  0.0      0     0 ?        S<   Jun28   0:00 [ksoftirqd/0]
    root         5  0.0  0.0      0     0 ?        S<   Jun28   0:00 [watchdog/0]
    root         9  0.0  0.0      0     0 ?        S<   Jun28   0:00 [events/0]
  • pstree
    pstree 会显示出当前运行中的进程之间的树状结构。
    [patrick@ubuntu:~]$ pstree
    init─┬─/usr/bin/revela
    ├─NetworkManager───{NetworkManager}
    ├─NetworkManagerD
    ├─gconfd-2
    ├─gdm───gdm─┬─Xorg
    │           └─x-session-manag─┬─bluetooth-apple
    │                             ├─compiz───compiz.real───compiz-decorato───gtk-window-deco
    │                             ├─gnome-panel
    │                             ├─gnome-settings-─┬─pulseaudio─┬─gconf-helper
    │                             │                 │            └─2*[{pulseaudio}]
    │                             │                 └─{gnome-settings-}
    │                             ├─nautilus───{nautilus}
    │                             ├─nm-applet
    │                             ├─python
    │                             ├─scim
    │                             ├─seahorse-agent
    │                             ├─update-notifier
    │                             └─{x-session-manag}
  • pgrep
    pgrep 会根据提供的正则表达式查找进程。
    [patrick@ubuntu:~]$ pgrep -l 'scim'
    6966 scim
    7006 scim-launcher
    7046 scim-helper-man
    7047 scim-panel-gtk
    7049 scim-launcher
    7213 scim-bridge
  • lsof
    lsof 用于列出进程所打开的文件列表。
    [patrick@ubuntu:~]$ lsof -p 12894
    COMMAND   PID    USER   FD   TYPE     DEVICE     SIZE    NODE NAME
    firefox 12894 patrick  cwd    DIR        8,7     4096 5423105 /home/patrick
    firefox 12894 patrick  rtd    DIR        8,5     4096       2 /
    firefox 12894 patrick  txt    REG        8,5    26924  557548 /usr/lib/firefox-3.0/firefox
    firefox 12894 patrick  mem    REG        8,5    17884  900100 /lib/tls/i686/cmov/libnss_dns-2.7.so
    firefox 12894 patrick  mem    REG        8,5     7552  899934 /lib/libnss_mdns4_minimal.so.2

    因为在 Linux 中,端口也是被视作文件的,所以也可以使用 lsof -i 显示计算机上所有打开的因特网地址。
    [patrick@ubuntu:~]$ lsof -i
    COMMAND   PID    USER   FD   TYPE DEVICE SIZE NODE NAME
    pidgin  11114 patrick   14u  IPv4  58594       UDP 192.168.1.3:54865->reverse.gdsz.cncnet.net:8000
    pidgin  11114 patrick   15u  IPv4  57930       TCP 192.168.1.3:59421->by2msg1204111.phx.gbl:msnp (ESTABLISHED)

Tags: ,