2011年9月30日 星期五

用 Chrome console 從鎖右鍵的網站中取得文字

遇到鎖右鍵的網站時, 複製文字變得有點麻煩, 要檢視原始碼再去掉 tag。剛從 Shakalaca 那看到《Become a Javascript Console Power-User》, 學到不錯的方式, 比較省事地取出文字:

  1. 按 F12 開 Chrome console
  2. 點 Elements 選放大鏡
  3. 選取要的段落 (html node)
  4. 在 console 裡打 copy($0.innerText)

這樣就複製好了, 只剩貼到文字編輯器裡去掉不要的部份即可。

2011年9月28日 星期三

C 的型別宣告

直到看了 Dan Saks 的 const T vs T const, 才(比較)明白 C 的型別宣告, 知道 int const *a 和 int * const a 的差別。原本雖然知道 int (*f[10])(int )、int (*f)(int) 和 int *f(int) 的差別, 但沒有很清楚細部原因, 看了這篇後才懂得更徹底。

C 的宣告分幾個部份, 以 static unsigned long int *x[N] 來說, *x[N] 是 declarator, 剩下的是 declaration specifier。declarator 的部份用運算子優先順序來解讀, 語意清楚許多。即 () 最優先, 其次為 [], 再來為 *。所以:

  • int (*f)(float) 表示 f 是函式指標, 指向一個函式其傳回值為 int, 參數為 float
  • int *f(float) 表示 f 是函式, 傳回 int*, 參數為 float
  • int (*f[10])(float) 表示 f 是一個陣列, 每個元素是一函式指標

令人混淆的部份在於, declaration specifier 的順序其實沒有影響。所以, static unsigned int n 和 int unsigned static n 是一樣的。再加上 const 和 volatile 不同於其它 declaration specifier, 它們可以同時寫在 declarator, 於是產生不易理解的結果。

我還在參透 volatile 的效果, 這裡先以 const 為例:

  • int const n 和 const int n 都表示 n 是指向唯讀的 int
  • int const *n 表示 n 是指標, 指標指向的型別為唯讀的 int
  • int * const n 表示 n 是唯讀的指標, 指向 int
  • int const * const n 表示 n 是唯讀的指標, 且 n 指向唯讀的 int

簡單的判別方式是以 * 為分界點, 由右往左看, 包含 * 的右邊是 declarator, 表示 declarator 的型別, 所以這裡有 const 表示是唯讀的指標; * 的左邊是 declaration specifier, 這裡有 const 表示指到的型別為唯讀。附帶一提, 用英文來解讀的話似乎比較清楚, 不知是自己受程式語言的影響, 還是英文天性比較有邏輯一點, 總覺得用英文思考比較有利於理解數學、程式之類的事。

比方說:

  • int *p: p is a pointer to a int
  • int *p[N]: p is an array of pointer to int (用用運算子的優先順序看)

善用 const 產生 immutable 的效果可以減少 bug、易於維護, 學好這些觀念滿實用的。作者建議將 * 貼近 declarator 並且將 const 寫在最右側, 避免誤會。 * 貼近 declarator 是因為 compiler 本來就是這麼解讀的, 將 * 放在 int 旁會不易分辨 declaration specifier 和 declarator。而將 const 寫在最右側則可避免誤會, 像文中的例子:

typedef void *VP;
const VP vectorTable[]

原以為表示 vectorTable 的內容都為 const, 但 compiler 會解讀成

VP const vectorTable[];
// 等同於
void * const vectorTable[];

變成 vectorTable 是一個陣列, 每一個元素是唯讀的指標, 指標指向的型別為 void (即沒指定特定型別)。若希望宣告 vectorTable 的指標不為唯讀, 是指到的型別唯讀, 有兩種作法:

// 1.
void const * vectorTable[];
// 2.
typedef void const *VCP;
VCP vectorTable[];

寫完這篇後讓我想到 int **p 的情況, * 和 * 之間可以插三個 const, 這才體會到作者強調的觀念:

Although C and C++ read mostly from top-to-bottom and left-to-right, pointer declarations read, in a sense, backward.

用這種方式解讀 int const * const * const p 的確比較直覺, p is a read-only pointer to a read-only pointer to a read-only int。

ps. const-correctness 提到更完整的 const 語意, 包含函式的部份。

2011年9月27日 星期二

用 LD_PRELOAD 替換動態連結的函式庫

換掉動態連結的函式庫有不少用途, 比方說像 Scott 提的「用來驗證是否執行到特定函式」, 或如 jserv 提的「在沒有原始碼的情況下修補執行檔的行為」。最近又看到這個東西, 記一下筆記以免忘了。

來看程式碼和執行效果。

mylib.c

#include <stddef.h>
#include <stdio.h>

int putchar(int c) {
    printf("call putchar()\n");
    return c;
}

void *memset(void *s, int c, size_t n) {
    printf("call memset()\n");
    return s;
}

main.c

#include <string.h>
#include <stdio.h>

int main(void) {
    char s[10];
    memset(s, 0, 0);
    putchar('X');
    putchar('\n');
    return 0;
}

執行結果

$ gcc -Wall -fpic -shared -o libmylib.so mylib.c
$ gcc -o main main.c
# 沒用 LD_PRELOAD 的結果
$ ./main
X
# 用 LD_PRELOAD 後的結果, 記得加 "./", 不然會找不到 libmylib.so
$ LD_PRELOAD=./libmylib.so ./main
call putchar()
call putchar()
$ strings main | grep memset

可以看出 putchar 有被換成自己編的版本, 但 memset 沒有。用 strings 查看 binary 檔 main 會發覺並沒有呼叫 memset 的跡象。猜測是 compiler 發覺 memset 實際上沒任何作用, 所以沒呼叫。

修改 main.c, 將 memset(s, 0, 0) 換成 memset(s, 0, 1) 再來看看:

$ gcc -o main main.c
$ strings main | grep memset
memset
$ LD_PRELOAD=./libmylib.so ./main
call memset()
call putchar()
call putchar()

結果顯示有換到 memset, 表示之前是完全沒呼叫 memset, 才會以為沒換到。printf 也是如此, 只輸出字串時, 不會呼叫 printf, 而是用 puts。

參考資料: 《Modifying a Dynamic Library Without Changing the Source Code | Linux Journal》

2011年9月26日 星期一

安裝 PythonWebkit

偶然看到 PythonWebkit 這個專案, 作者花了兩週左右的時間寫好 WebKit 的 python 介面, 於是操作 DOM 不再是 javascript 的專利, 透過 PythonWebkit 就能用 python 操作 DOM。作者自稱除一些小功能外, 這個專案已到可用的階段:

The current status is that the SVG 2D Canvas element is not available, and CSS Styles have to be modified through the style.setProperty function (rather than being accessible as python properties). Other than these gotchas, the Python Webkit bindings are in a useable state, providing full W3C compliant access to the full set of DOM functionality (except SVG Canvas) as provided by Webkit, and ordinarily only accessible via javascript.

不過相關文件超少, 花了些時間才裝成功, 也增加了一些編原始碼的功力。

背景介紹

WebKit歷史很有意思, 有興趣的人自行參照連結。在 Linux 上目前有兩種 port, 一個是用 GTK+ 實作的WebKitGTK+, 另一個是 QT 的實作版本。

PyWebKitGtk 是另外一個基於 WebKitGTK+ 的專案, 透過 WebKit 提供的 gobject binding 提供 python 介面, 但沒有提供直接操作 DOM 的功能。雖然有些補救方案, PythonWebkit 的作者覺得直接改出 python 介面比較省事, 效率也較好, 該頁有寫詳細的設計考量。所以, PythonWebkit 是以 WebKitGTK+ 為底, 修改部份內容直接提供 python 的 DOM API。

剛開始作者用 PyWebKitGtk 的 python module "webkit", 藉此省掉寫 python module 的步驟, 然後加上 patch 讓 webkit (python module) 能取出 DOM。也就是說, PythonWebkit 依賴 PyWebKitGtk; PyWebKitGtk 依賴 WebKitGTK+; WebKitGTK+WebKit 在 Linux 下的實作版本之一。

後來作者自己重寫一個 python module "pywebkitgtk", 就不用再裝 PyWebKitGtk 了。網路上找 PythonWebkit 的文件, 有部份會提到 PyWebKitGtk, 但現在已用不到它了。弄清楚這堆名稱差不多的專案, 花了我一些時間 ..., 搞清楚後也滿有成就感的。

上面是簡化的說法, 實際上 PythonWebkit 不是直接依賴 WebKitGTK+, 也可以改用基於 DirectFB 的 PyWebkitDFB。由於這還在實驗階段, 我就沒試了。

安裝方式

主要參考 PythonWebkit 的說明, 另外需要參照 WebKitGTK+ 的安裝說明, 了解它用到的套件。在 Ubuntu 下的安裝步驟如下:

1. 升級到 11.04, 11.04 的 glib 版本才夠新 (>= 2.27.4)

不然會出現

configure: error: You need the GLib dev tools in your path

2. 安裝編譯 WebKitGTK+ 需要的套件

注意: 最後三個指令不能用 aptitude, 只有用 apt-get 才能確保移除後仍保有需要的設定

$ apt-get install python-dev python-ply
$ apt-get build-essential
$ apt-get build-dep libwebkit-1.0-2
$ apt-get install libwebkit-1.0-2
$ apt-get remove libwebkit-1.0-2

在 Ubuntu 下自己編原始碼時, 似乎滿常用這招的, 透過原有的套件管理系統裝好相依的套件、取得需要的 header 等資源, 藉此減少手動操作部份。

3. 取得 PythonWebkit 原始碼, 這步會花很長的時間, 好像會到一小時吧

$ git clone git://git.savannah.gnu.org/pythonwebkit.git

4. 切換到 branch python_codegen

$ git checkout python_codegen

注意: 千萬不要加 "-b", 我不熟 git 參數, 誤加了 -b, 變成開一個新的 local branch 叫 python_codegen, 而不是取出遠端的 branch python_codegen。git 指令請參考《Git 版本控制系統(2) 開 branch 分支和操作遠端 repo.》

有取對 branch 的話, grep 整個目錄應該會找到 pywebkitgtk 相關檔案; 反之則否。pywebkitgtk 是 PythonWebkit 產生的 python module, 作用和 PyWebKitGtk 的 webkit 差不多, 不過多了取得 DOM 的方法 (web view 的 GetDomDocument())。

5. 開始編譯

$ mkdir build
$ cd build
$ ../autogen.sh
$ make

我的電腦是三年前買的, 在 VM 裡用雙 CPU 編的話 (配合 make -j 2), 大概四十多分鐘可編完。

執行 autogen.sh 時, 若發現缺了東西, 可用 aptitude search 加關鍵字, 或 apt-file search xxx.h 查看看放在那個套件, 通常是要裝一些 X-dev 的 package。印象中我好像有少了 pygtk。有問題時, 記得用 dpkg -l 和 WebKitGTK+ 的 Dependencies 對一下, 看有沒有少裝什麼。然後再重跑 autogen.sh。

6. 檢查結果

編好的東西放在 .libs/ 下, 不知是不是某種慣例。上網查 make install 的討論, 似乎沒有明確的方法可以找到會裝那些東西進系統。幸運的話, 可以用 checkinstall 裝成 deb 檔, 就能用 dpkg -L 查裝了什麼, 也能用 dpkg -r 移除。不過我用 checkinstall 的結果, 似乎比直接 make install 多裝了不少東西, 最後直接用 make install。

回到正題, 先切到 .libs 下看編完的東西是否可用。.libs/ 下應該要看到 libwebkit 的 so 檔, 還有 pywebkitgtk.so。接著在 .libs/ 目錄下執行 ipython, 依序打入:

import gtk
import pywebkitgtk
url = "http://www.gnu.org/software/pythonwebkit"
wv = pywebkitgtk.WebView(1024,768, url=url)
doc = wv.GetDomDocument()
ns = doc.getElementsByTagName('h2')
ns.length  # 9
ns.item(0).innerHTML  # 'Why is this important - why is it a "big deal"?'

注意, 上述程式要在 X Window 下執行。import gtk 後, 在產生 WebView 物件時會跳出視窗。若沒有 import gtk 的話, 不會有任何錯誤訊息, 但取得的 doc 裡面卻沒任何東西, ns.length 會是 0。

7. 安裝到系統

$ sudo make install

然後檢查 /usr/local/lib 是否有在 ldconfig 路徑中:

$ grep -R "/usr/local/lib" /etc/ld.so.conf.d/

若沒有的話, 在 /etc/ld.so.conf.d/ 下新增一個檔案:

$ sudo echo "/usr/local/lib" > /etc/ld.so.conf.d/webkit.conf

最後是更新 ldconfig 的 cache:

$ sudo ldconfig

不確定原本 /etc/ld.so.conf.d/ 下就有 /usr/local/lib 的情況是否要執行 ldconfig, 好像要執行才會 ok, 但看文件說, 一般 make install 時應該會自動執行這個動作。

之後就能在任何地方直接 import pywebkitgtk 啦。

用法

附上一個小例子: 取出 TechCrunch 文章有多少人按 Facebook 的 like:

import os

import gtk 
import pywebkitgtk

wv = pywebkitgtk.WebView(10, 10, url='http://techcrunch.com/2011/09/25/clinging-to-friction-some-thoughts-on-facebooks-f8/')
os.sleep(10)  # Wait Facebook plugin to be loaded.
dom = wv.GetDomDocument()
iframes = dom.getElementsByClassName('fb_ltr')
for i in range(iframes.length):
    e = iframes.item(i)
    ns = e.contentDocument.getElementsByClassName('connect_widget_button_count_count')
    if ns.length > 0:
        print ns.item(0).firstChild.nodeValue  # Count of "FB like"

TechCrunch 的推文數大多是用 AJAX 載入到 iframe 裡, 用普通的方法無法抓到內容。上面的作法相當粗糙, 就將就用啦, 這不是本篇的重點。

產生 wv 後會看到 console 出現一堆訊息, 大概是載入頁面後, 以及執行完後續 AJAX 時產生的。之後再來看看這些訊息是否有害。

PythonWebkit 沒有多提相關 API, 因為作者為了方便大家查文件, 讓 PythonWebkit 和原本的 DOM API 100% 相容 (目前只有 CSS 部份有一點不同), 所以, 直接學 DOM 就可以了。配合 ipython 直接操作, 還滿容易試的。

Trouble shooting

1. configure: error: You need the GLib dev tools in your path

參考 這篇, 要用新版 glib, Ubuntu 要到 11.04 才符合。我鐵齒的從 10.04 一路試, 直到 11.04 才真的 ok。不過 libsoup 用 2.24 也 OK, 不需要像 PythonWebkit 說要用最新版才行(2.29.90), 不確定之後會有什麼問題。

2. 編譯時出現 "error: webkitmarshal.h: No such file or directory"

參照這篇, 執行

$ touch ./Source/WebKit/gtk/webkitmarshal.list

然後重跑 make。

3. 無法 import pywebkitgtk / 沒有編出 pywebkitgtk.so

記得在取得 repository 後要先執行 "git checkout pyhton_codegen" 才執行 ../autogen.sh, 千萬不要寫成 "git checkout -b pyhton_codegen"

4. import pywebkitgtk 時說找不到 libwebkitgtk

In [1]: import pywebkitgtk
---------------------------------------------------------------------------
ImportError                               Traceback (most recent call last)
/usr/local/lib/<ipython-input-1-8dab5af5d34b> in <module>()
----> 1 import pywebkitgtk

ImportError: libwebkitgtk-python-1.0.so.0: cannot open shared object file: No such file or directory

先用 ldd 檢查路徑是否確實有問題:

$ ldd /usr/local/lib/python2.7/dist-packages/pywebkitgtk.so | grep libwebkitgtk
	libwebkitgtk-python-1.0.so.0 => not found

出現 "not found" 表示 pywebkitgtk.so 找不到 libwebkitgtk-python-1.0.so.0。接著檢查 /etc/ld.so.conf.d/* 有沒有含 /usr/local/lib (當然, 要先確定你的 libwebkit-python-1.0.so 有裝到那)

將 /usr/local/lib 加到 ldconfig 的路徑後, 執行 sudo ldconfig

另外看到有人提到在編譯前這麼做:

$ export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig

不過我試了沒成功, 之後有空再來看 pkgconfig 是什麼。

其它參考資料和雜項心得

  • Program Library HOWTO: 動態函式庫的相關知識, 有提到 LD_LIBRARY_PATH 和 LD_DEBUG, 必要時可協助除錯。
  • 作者個人網站, 有他的 e-mail。原本想說再試不出來就寄信問看看。話說找這個也花了點時間, PythonWebkit 整篇都沒提到他是誰啊 ..., 在這封信才看到多一點情報。
  • 有問題時, 可以看看 commit log, 了解主要的修改為何。從這次的經驗, 發覺除系統安裝的知識外, 操作 VCS 的知識和讀 commit (changeset) 的能力也很重要。

HTML DOM 筆記

有了 pythonwebkit 後, 可以用 python 直接存取 DOM。於是得自己學一下 DOM 的操作方式, 不能再依賴 jQuery 啦。

花個半小時邊看邊操作 《HTML DOM Tutorial》, 很快就有個基本概念了。記一下自己不熟的部份:

  • DOM 的 node 類型有: document, element, text, attribute, comment
  • element node 沒有包含文字, 要從它的 text node 拿:
    • document.getElementsByTagName('p')[0].nodeValue # null
    • document.getElementsByTagName('p')[0].firstChild.nodeValue # the expected texts
  • 操作 iframe 的內容
    • 取得 iframe 的 DOM: d = document.getElementsByTagName('iframe')[0].contentDocument
    • 接著就能用一樣的 DOM API 操作 d
    • 我只有在 Chrome 下試, 畢竟 pythonwebkit 的功能應該和 Chrome 差不多才對。要跨瀏覽器操作 DOM 的話, 得多試幾種變數, 取出 iframe 的 DOM

2011年9月23日 星期五

vim 停住一會兒才啟動的解法

有時用 putty 連到 server, 打 vi 後會停一兩秒才進去。有時在 screen 下甚至會停住不動。參考這篇的說法, 用 vi -X 不要連線到 X Server 就 ok 了。

會有這樣的問題, 是因為我用到 gnome 版的 vim (vim.gnome):

$ which vi
/usr/bin/vi
$ ll /usr/bin/vi
lrwxrwxrwx 1 root root 20 2010-05-12 12:17 /usr/bin/vi -> /etc/alternatives/vi*
$ ll /etc/alternatives/vi
lrwxrwxrwx 1 root root 18 2010-08-06 13:58 /etc/alternatives/vi -> /usr/bin/vim.gnome*
$ ll /usr/bin/vim.gnome
-rwxr-xr-x 1 root root 2144568 2009-01-08 11:03 /usr/bin/vim.gnome*

若用 vim.tiny 或 vim.basic, 不加 -X 也不會停一會兒。

相關除錯指令:

  • vi -V 會看到「讀取 viminfo 檔案 "/home/fcamel/.viminfo" 訊息開啟 X Window 失敗」 (Reading viminfo file "/home/fcamel/.viminfo" info oldfilesOpening the X display failed)
  • 在 X Window 下無此問題

安裝完 Ubuntu 後的初步設定

2017-04-04 更新

記一下個人裝 Ubuntu 後, 會做的基本設定。

  1. sudo apt-get install aptitude
  2. sudo aptitude update
  3. sudo aptitude install build-essential apt-file checkinstall manpages-dev htop rsync screen cdargs openssh-server mosh vim git subversion exuberant-ctags cscope python-dev python-setuptools id-utils python-pip
  4. sudo apt-file update
  5. git clone git://github.com/fcamel/configs.git
  6. cd configs && ./install.sh # 裝我個人用的設定檔, 如 vim, bash, screen

若需要裝 java, 另外需做:

  1. sudo aptitude install python-software-properties
  2. sudo add-apt-repository "deb http://archive.canonical.com/ natty partner"
  3. sudo aptitude update
  4. sudo aptitude install sun-java6-jdk

若是用 Parallel 的話,裝完 Parallel 附的 Ubuntu 後要作的事:

  • 修改網路:Actions -> Configure -> Hardware -> Network -> 選 Ethernet,這樣會自己有獨立的 LAN IP
  • 新增硬碟空間:在關閉 OS 的情況下,Actions -> COnfigure -> Hardware -> Hard Disk 1 -> Edit,然後調整大小。作完後重開 VM。再用 gparted 動態調大 partition 大小。需要先刪掉 swap, 再刪 extended partition,才有空間調 root partition。

日後想到什麼再補。

Ubuntu 用 UUID 掛載硬碟的原因

之前看 Ubuntu 的 fstab 改用 UUID 覺得很納悶, 為啥要在 /dev/disk/by-uuid/ 下建 soft link 再指到 /dev/sdXN (X 是 abcd, N 是 1-8), 然後在 fstab 裡用 UUID 而不用 /dev/sdXN。

今天用 VirtualBox 移除硬碟後才發覺它的好處: 加裝或移除硬碟後, 雖然 /dev/sdXN 的 X 會變 (如移掉第二顆硬碟, /dev/sdc3 會變 /dev/sdb3), UUID 卻不會變。所以若 /etc/fstab 用 UUID 來掛載 partition, 可以直接開機, 而省掉進單人模式改 /etc/fstab 的步驟。

2011年9月12日 星期一

tab vs. space

討論 coding style 時, 這個常會戰到爆。記一下在多人一起開發一陣子軟體後的心得。

我後來覺得 space 比較方便, 因為可確保任何地方看到的畫面一致, 且不需另外設定。支援 tab 的人認為只需要一次設定就可以了, 這樣可保留彈性。困難的地方在於有太多地方可能會看到程式碼: IDE、editor、VCS log、issue tracking、e-mail、其它可能的 web-based 工具 (如 code review)。而有些地方無法提供客制化設定 tab 寬度 (如 e-mail)。

以我自己用 Java 來說, 平時可能用 Eclipse, 特定需求時用 vim, 偶而要用 hgtk 看別人的 commit (一些程式碼的 diff), 或用 hg blame 看修改記錄 (輸出到 console 或用 hgtk 看), 偶而寄 code diff 給別人討論。在這些過程中, 會發覺 tab 實在是不太方便。

至於 space 的缺點: 一但定了就很難改, 實務上不是問題, 各個語言都有標準規範 (大概都是四個空白), 照著公定規範做就是了。若不幸地原本已有一大堆其它長度, 讀個一陣也會習慣, 應該會比在不同地方, 縮排亂掉來得好。

MySQL vs. PostgreSQL

去年的隨手心得, 記在這備忘。主要是參考《MySQL vs PostgreSQL - WikiVS》 2010-09 的版本, 後來情況應該也有些變化。另外, 很多東西還是要自己測過才準, 後來和一些很熟 DB 的前輩聊, 發覺實際情況還是和看到的有些出入。需求不同, 又有太多細節可以調整了。

後來覺得選用 MySQL 的好處是:

  • 資源最豐富, 有書有文件, 也有一堆顧問公司 (如 Percona)
  • 有許多大公司實際執行到海量的實例, 不用擔心會流量會卡住 (雖說大部份時候應該要先擔心服務不夠好, 流量太小)
  • 有些 syntax sugar 或特制功能很好用, 像是 insert ... on duplicate update , 或 insert ignore
  • 有趣的是, 該文認為 MySQL 比 PostgreSQL 流行的原因之一, 是因為 PostgreSQL 沒法限制各個 database 的大小, 對於商用服務來說, 這點很重要 (商用服務會在意限制資源、管理權限等, open source 專案先以個人需求為主, 一開始大概都不會重視這些吧)

備忘

fcamel 2010-09-01 19:54:43
MySQL vs. PostgreSQL, 有這種對照文真不錯, 書上有看過的相關觀念可以重新消化一次, 之前沒看過的....在這也有看沒感覺
MySQL vs PostgreSQL - WikiVS
MySQL vs PostgreSQLFrom WikiVS, the open comparison websiteJump to: navigation, search MySQL Postgr
發表回應
1

fcamel 2010-09-01 19:55:43
PostgreSQL 只有一個 engine, 一般來說在大量同時寫入下會比 MySQL 搭各種 engine 快
2

fcamel 2010-09-01 19:56:36
PostgreSQL 比較穩, RDBMS 功能較齊全, 這點在 stackoverflow 上可找出一卡車支持者。也可找出一卡車 MySQL 使用者說他們遇到 DB 炸了多少次
3

fcamel 2010-09-01 19:57:24
MySQL + MyISAM 有無敵快的 count, 因為它沒 MVCC, 可以視情況直接 count index 而不用取 data rows。又因為沒 MVCC, 可以安心地 cache count
4

fcamel 2010-09-01 19:58:58
8.x 的 PostgreSQL 沒有 Insert Ignore / Replace
5

fcamel 2010-09-01 20:00:31
MySQL + MyISAM 在 read-only 或低頻率寫入的情況下是超級快, 因為它沒 constraint, 沒 MVCC。無賴戰法: 我就什麼功能都沒有, 但是只讀不寫的話, 我超快的哦!!
6

fcamel 2010-09-01 20:00:49
剛好我們現在正好只需要這種無賴戰法 XD
7

fcamel 2010-09-01 20:06:12
mysql 內建 replication 機制, 效率比 PostgreSQL 好 (?)
8

fcamel 2010-09-01 20:07:41
Ubuntu 8.04 的 mysql 版本有點舊, 只到 5.0.51a, 之後有幾版大幅提昇速度, 5.1 又有多 sharding 的樣子。
9

fcamel 2010-09-01 20:10:56
PostgrelSQL 有 Bitmap Indexes, 可以合併兩個以上的 indexes, 之後來看看這是啥。一直很好奇怎麼做才能同時用兩個 indexes
10

fcamel 2010-09-01 20:13:45
MySQL 有 covering index, 而 PostgrelSQL 沒有, 令我滿意外的, 原以為 index 那區 MySQL 會兵敗如山倒
11

fcamel 2010-09-01 20:15:14
PostgreSQL 支援 expression indexes, 意思是也可以查 "%keyword%" 嗎? 太神奇了! 之後來查查這是啥
12

fcamel 2010-09-01 20:19:32
這個有意思: "In PostgreSQL there is no built-in mechanism for limiting database size. This is the main reason why the most of the web hosting companies are using MySQL. Also, PostgreSQL doesn't have scheduled procedures. "
13

fcamel 2010-09-01 20:20:32
結果 PostgreSQL 無法流行的主因是沒做這種看似不重要的功能嗎? XD
14

fcamel 2010-09-01 20:23:40
天啊...., 難怪有人提到他比較喜歡 PostgreSQL 的 license, MySQL client library 是 GPL 非 LGPL!! 若沒和 Sun (現在是 Oracle?) 買授權, 就得 open source, 太可怕了...
15

fcamel 2010-09-01 20:30:10
看完兩者的討論後還真想用 PostgreSQL 啊, 考量現況還是繼續用 MySQL 比較務實 Orz
16

fcamel 2010-09-01 20:41:29
stackoverflow 有人提到用 PostgreSQL 加 column 似乎不用鎖住 table, 他們之前用 mysql + replication 的結果, 就不敢加 column, 只好另開 table 用 join 取資料
17

榮尼王 2010-09-01 20:53:54
mysql 加上 master-master 架構的話,alter table 就隨便了啊
18

fcamel 2010-09-01 21:04:56
soga, 還沒看深, 果然各種問題都有一定的配套解法, 謝啦。
 回應

讓 mysql 使用 utf-8 的相關設定

這對於新手來說應該很有幫助吧

在 [mysqld] 下的相關設定:

character-set-server=utf8
collation-server=utf8_general_ci
init-connect='SET NAMES utf8'

MySQL 的設定檔位置不太好找, 細節參考《fcamel 技術隨手記: 更改 mysql conf 的注意事項》

warm up server 的一般作法

一開始用 MySQL 的 MyISAM 時, 發覺有語法可以事先載入整個 index, 就以為大部份 server 應該有提供這功能。不過後來發覺 InnoDB 沒有, 所以要自己下 SELECT 掃一次 table, 讓 MySQL 自動觸發 cache 機制。後來用 Solr, 查了一陣子, 似乎也沒有這種機制。大概設計 server 的人覺得另外設計語法會增加維護成本, 不如讓大家自己查詢全部要用的資料, 讓 server 自己管好 cache 比較實際吧。

mysql flush key cache

MyISAM 的 index 會暫存到 key cache 裡, 若想預先載入整個 table 的 indexes 到 key cache 裡, 可以用 LOAD INDEX INTO CACHE。但若要 flush key cache 的話, 並沒有像 flush query cache 那樣有 RESET QUERY CACHE 的語法。替代作法是, 改變 key cache 的大小或 block size, MySQL 就會重設 key cache。

2011年9月6日 星期二

使用 ReviewBoard API 刪掉多個 request

ReviewBoard 沒有提供批次刪掉的介面, 測試期間產生一堆 request, 懶得用手一個個刪, 想說用 API 來刪。

使用 ReviewBoardweb api, 需要在連線中的 http header 加上 cookie 資訊用作身份認證。用 python 的 httplib2 做這事也不會太麻煩, 不過若能用 command line 解決, 會更簡單一些。後來我用 curl 做這事, 順便熟悉一下它的功能, 常看文件用 curl 示範 API 用法。

參考《Use CURL to Login to Websites with a Script》的教學, 學會 curl 登入網頁的用法。依我的需求消化後的步驟如下:

  1. FireBug 之類的工具找出 login form 需要的欄位。
  2. 連到 web server 產生 coolkie: curl --cookie-jar cjar http://myhost/account/login/
  3. 送出 username/password 登入, 並更新 cookie (存到 cjar 裡): curl --cookie cjar --cookie-jar cjar http://myhost/account/login/ --data 'username=fcamel' --data 'password=xxxx'
  4. 使用 FireBug 觀察 ReviewBoard 刪除 request 時連的網址 (或是看 web api 文件)
  5. 執行指令砍掉編號 1 ~ 10 的 request: for i in {1..10}; do curl --cookie cjar --cookie-jar cjar http://myhost/api/json/reviewrequests/$i/close/discarded/; done

備註: 砍 request 要用 http://myhost/api/json/reviewrequests/$i/delete/, 但要有 admin 權限

在同一個 apache 裡跑兩個 port

使用 apache2 + mod_wsgi 的作法架 ReviewBoard 的話, relative path 有 bug, 無法將 ReviewBoard 架在 http://.../reviews/ 這樣的位置。網路上搜搜看到也有人提到同樣的問題。自己試著硬解了一陣子, 沒有很乾淨又一致正確的結果。後來想說, 乾脆在同一台機器的 apache 裡跑聽兩個 port 好了, 這樣就能在用專屬非 80 的 port 來架 ReviewBoard

查了一下, 架法還滿簡單的: 見 VirtualHost Examples, 另外 CommonMisconfigurations - Httpd Wiki 也滿有幫助的。使用多個 port 時, 記得要加 listen。Ubuntu 的話是加在 /etc/apache2/ports.conf 裡, 它會被 /etc/apache2/apache2.conf include 進去。

在 Fedora 下裝 id-utils

Fedora 似乎因為執行檔撞名,而沒有提供 id-utils 的套件 ,但這是使用 gj 的必要套件,只好自己編。從官網抓好 tarball ,解開來編譯 (./configure && make)就是了。 但編譯後會遇到錯誤: ./stdio.h:10...