星期二, 12月 05, 2006

HyperEstraier 與 qdbm 的一些雜記

的使用了 的 Database 的部份以外,還使用了自己寫的輪子,cabin(3)。

這套輪子功能相當多,提供了許多 Data Structure Function 與 Algorithm 使用,不過如果真的要用的話,我也許會選擇其他 的 library (),像是 libisc (從 裡抽出來的)。

這次遇到 看起來有 memory-leak 的問題是 cabin(3) 的 cbmapout() 產生的。cbmap* 是處理 Hash 的 Data Structure Function,cbmapout() 會將元素從 Hash 中移出,不過我測試的結果發現移出後並不會釋放記憶體,於是就會造成 memory-leak 的「假象」,不過實際上這些記憶體會重複被使用,並沒有 memory-leak 的情況發生。這可能是因為 resize 的 overhead 考量而故意設計的。

所以塞資料進 要注意在塞一定的數量後對每個 node 下一次 sync 指令,強迫將快取的內容寫回硬碟後清掉,另外一個方法是把上一篇對 estmaster.c 的 patch 拿掉,這樣理論上在固定一段時間沒有動作後就會寫回去。(不過就不能一次大量寫進去,快取的大小會超過 process size...)

星期日, 12月 03, 2006

HyperEstraier

Open Source 的 Fulltext Search Engine 其實還蠻多套的,不過對於 UTF-8 環境來說,Fulltext Search 真正的問題在於非拉丁語系的切詞方式,而非底層的技術。

拉丁語系的切詞只要對標點符號及空白的地方切開,但非拉丁語系的語言 (像是 CJK) 並沒有辦法這樣做,解決的方法有幾種:最簡單的就是直接去找各國語言的詞庫 (以及頻率表),然後切詞,但這個方法對於新產生的詞沒有辦法處理,而且對於我們,不知道要如何取得非中文的詞庫。另外一種方法是完全透過 Algorithm 處理切詞,這樣我們就不用想辦法取得其他語言的詞庫,也不用管新的名詞出現。

我最近幫的忙是一個中文站台要對文章做全文搜尋 (UTF-8 環境,所以還是要考慮有少量的外國語言),目前站上的數量大約有 1 million 的文章要處理,文章數量會不斷成長。

當時在找的時候找到幾套軟體,最後因為切詞問題決定使用 ,一方面是作者相當活躍 (與 QDBM 同一個作者),另外一方面作者是日本人,我們認為日文與中文跑出來的效果應該不會差太多... (純粹是希望 :p)

FreeBSD 上安裝 沒什麼問題,直接到 裡安裝就可以了,不過我們測試的結果發現有些地方需要改掉,以免影響 performance 太多。

我把 patch 檔放成 FreeBSD ports patch 的格式,所以只要把這兩個檔案放到 /usr/ports/textprocs/hyperestraier/files/ 裡,再透過 ports 安裝就可以了。第一個檔案是 patch-estmaster.c
--- estmaster.c.orig    Sat Dec  2 19:42:59 2006
+++ estmaster.c Sat Dec 2 19:44:45 2006
@@ -1258,6 +1258,7 @@
}
est_usleep(1000 * 100);
}
+#if 0
if(isec >= g_idleflush * (1.0 - g_cacheratio) &&
(g_cacheratio > 0.0 || isec % (g_idleflush / 2 + 1) == 0)){
if(g_stmode){
@@ -1301,6 +1302,7 @@
}
est_usleep(1000 * 100);
}
+#endif
}
free(stfile);
log_print(LL_INFO, "shutting down");

第二個檔案是 patch-estraier.c
--- estraier.c.orig     Sat Nov 11 16:26:03 2006
+++ estraier.c Thu Nov 30 22:53:10 2006
@@ -2310,7 +2310,9 @@
}
}
db->dnum++;
+#if 0
if(est_db_used_cache_size(db) > db->icmax && !est_db_flush(db, INT_MAX)) err = TRUE;
+#endif
return err ? FALSE : TRUE;
}

其他的就照官方網站上所說的用法就可以了。另外一個很重要的資源是 存取 HyperEstraier 的方式,我自己是透過 處理,測試起來沒什麼問題... :p

星期三, 11月 01, 2006

一些 C Macro 的技巧 (Part III:將傳入的參數名稱變化)

假設你想要把傳入參數名稱再變化,用 ## 穿插其中:
#define print_three_var(var)
do {
print_var(var);
print_var(var##2);
print_var(var##3);
} while (0)

因為你不能用 var2 來表示 var + "2",所以你必須用 ##。當你傳入 print_three_var(telephone) 時,他會展開成:
print_var(telephone);
print_var(telephone2);
print_var(telephone3);

補充一下:這邊的 print_var() 是 Part II 裡的 print_var()

一些 C Macro 的技巧 (Part II:將傳入的參數變成字串)

另外一個技巧是將傳入的參數變成字串:
#define print_var(var)     do {         printf("%s: %s\n", #var, var);     } while (0)

關鍵字是 #var。當輸入 print_var(argv[0]); 時就會把以上的 Macro 展開為 printf("%s: %s\n", "argv[0]", argv[0]);

一些 C Macro 的技巧 (Part I:不定變數)

幾個學校課程不太會講到的技巧,第一個是不定變數的使用:
#ifdef DEBUG
#define debug_printf(str, ...) do { printf(str, __VA_ARGS__); } while (0)
#else
#define debug_printf(str, ...)
#endif

關鍵是 __VA_ARGS__,這樣可以很愉快的使用 debug_printf()

星期一, 10月 30, 2006

Perl 的 reference

perlref(5) 是蠻重要的文件,講到 reference 要怎麼用:
$scalarref = \$foo;
$arrayref = \@ARGV;
$hashref = \%ENV;
$coderef = \&handler;
$globref = \*foo;

看起來不難,不過下面馬上就提到陷阱,這兩個其實是一樣的:
@list = (\$a, \@b, \%c);
@list = \($a, @b, %c);

解法是用 [] 做。

星期一, 10月 23, 2006

Math::Polynomial::Solve 的用法

Perl 上有很多東西都有人做過了,所以能儘量去 CPAN 上找就去找,可以省下很多功夫... (自己寫一個還得測試有沒有問題)

Math::Polynomial::Solve 正是其中的一個例子,我們知道五次以上的方程式沒有公式解,但可以用其他的方法找,於是就有人寫了出來,舉例來說,我要找 x^5 + 2 = 0,那麼我的參數就是 (1, 0, 0, 0, 0, 2),丟進去以後他就會給你解:
use Math::Complex;
use Math::Polynomial::Solve qw/poly_roots/;
my @x = poly_roots(1, 0, 0, 0, 0, 2);
foreach (@x) { print $_, "\n"; }

結果應該是:
0.929316490603147-0.675187952399881i
0.929316490603147+0.675187952399881i
-0.35496731310463-1.09247705577745i
-0.35496731310463+1.09247705577745i
-1.14869835499703

星期六, 10月 21, 2006

Curve Fitting on Perl

CPAN 上的 Algorithm-CurveFit 很好玩 :p

先給定一堆 (x, y) 後,再給定已知的方程式 (可以是非線性的) 與要尋找的參數,然後他就可以幫你算 Least Squares Fitting... (不知道這是什麼的,可以參考 MathWorld 上的 Least Squares Fitting 這篇,這是一種統計方法,可以找最相似的原始參數)

不過非線性方程式的速度有點慢,五萬筆資料計算二次的 Fitting 在 Dual Pentium III 1.266Ghz (Tualation) 上跑了 16xx 秒 CPU time,果然是純用 Perl 硬幹出來的東西... (沒有用到 xs 寫 C 加速)

不過還是蠻好用的,所以我就包一包弄進 FreeBSD ports,等這陣子 ports unfrozen 過後就會進去了:ports/104620: [NEW PORT] math/p5-Algorithm-CurveFit: Nonlinear Least Squares Fitting

星期一, 5月 29, 2006

FreeBSD 上 rpc.lockd 的問題

FreeBSD 上 rpc.lockd 常常會自己掛掉。如果是 clients 的 rpc.lockd 掛掉,會使得 flock() over NFS 掛掉,而如果是 servers 的 rpc.lockd 掛掉,會使得所有 clients 的 flock() over NFS 掛掉 =_=

這個問題自從我們將某幾台 ccbsd*.csie clients 換成 FreeBSD 6.0-RELEASE 後就發現這幾台一直有問題,後來決定將 cchome.csie 與 mailgate.csie 也一起升級到 FreeBSD 6.0-RELEASE,看看能不能解決這個問題。結果反而變成大家都有問題... -_- 而且 ccsun*.csie 只要一開機,所有的 clients 就會炸掉,但這些 ccsun*.csie 裡面,如果只開 ccserv.csie 也不會有事情...。

這個問題當時猜測是 FreeBSD 4.x 與 6.x 的 clients 混在一起跑造成的,於是狠下心來將 ccbsd*.csie 全部升級到 FreeBSD 6.0-RELEASE (另外一個原因是 FreeBSD 4.x 已經不繼續維護了),結果升級上去發現問題還是沒變好,只好試著惡搞所有能惡搞的功能 (像是 mount_nfs 裡的 -L local lock),發現還是沒有用。

前幾天想到 ktrace 可以看 system call 的情況,拿出來追,發現 uid=daemon 的 rpc.lockd 最後居然是死在 SIGPIPE,將這個 bug 用 send-pr 送出去幹剿後,rpc.lockd 的 maintainer 丟出一個神秘的 patch:把 SIGPIPE 用 signal(SIGPIPE, SIG_IGN) 堵掉,#bsdchat 上面看到這個 patch 把他叫做「掩耳盜鈴」,當作沒聽到,幹就對了 XD:Problem Report bin/97768 : NFS rpc.lockd will die automatically

雖然這個方法看起來很鳥,但我還是決定把這個 patch 弄進所有 ccbsd*.csie 上跑,然後開 ktrace 盯著看還會有什麼死法。跑了快一天,發現 ccbsd*.csie 跑起來好像不錯,寫了封信跟 maintainer 講... 沒多久就看到 cvs commit 記錄:cvs commit: src/usr.sbin/rpc.lockd kern.c,結果才剛 commit 完沒多久就發現 uid=root rpc.lockd 死掉 XD

看了一下 uid=root rpc.lockd 死掉時 ktrace 的紀錄,發現也是 SIGPIPE 的問題,正覺得奇怪,明明 mask 掉了,怎麼還會死在 SIGPIPE... 回頭看 patch 發現是因為 signal()fork() 後才做,所以 uid=root 那隻沒有處理 SIGPIPE,只好再跟 maintainer 講,問看看能不能把 signal() 放到 fork() 前。(主要是他對 rpc.lockd 比較熟,可能會比較清楚各類後遺症 XD)

結果 maintainer 就叫我去測測,沒問題就照我說的 patch 進 -current XD 我就跑去跟 chwong 要了 cchome.csie 與 mailgate.csie 的 root,要跑 ktrace 盯著看。

測了一天看起來沒問題:rpc.lockd 沒死,mutt 看信也都很正常,看起來 locking 功能運作得很好,就回封信跟 maintainer 講這個情況,過不久就看到他把 signal() 搬到 fork() 前的 cvs commit 紀錄:cvs commit: src/usr.sbin/rpc.lockd kern.c,這個 patch 的 rpc.lockd 到現在都還活得很好,看起來在 6/1 那天就會進 RELENG_6 了 :)

然後在 #bsdchat 上看到 rafan 把這個 patch 也丟進 csie.ntu 的機器上跑,發現對於 NFSv2 的 Sun 也正常多了 (打開 debug mode 還是會看到一堆 error msg,不過至少會動...),於是我剛剛就很高興的跑去學校把 ccsun*.csie 通通開起來測,目前看起來也都沒問題...

折騰了兩個月,NFS 的 rpc.lockd 這件事情看起來暫時穩定多了,希望有長輩把 rpc.lockd 修一修,尤其是 recovery 的部分,如果寫完的話才能隨意關機開機 XD

星期六, 3月 18, 2006

lighttpd + WordPress 2.0 對於 Permlink 的處理

lighttpd + WordPress 2.0 使用 Permlink 的設定,重點在於 lighttpd.conf 裡的 mod_rewrite:
url.rewrite = ( "^/(archives|categories|comments|feed)/" => "/index.php" )

WordPress 裡 Permlink 則是設成:
/archives/%year%/%monthnum%/%day%/%post_id%/

Category 的部份則是:
/categories

星期三, 3月 01, 2006

FreeBSD NFS locking 問題

我們一直以為是 4.x 與 5.x/6.x 之間的問題,結果剛剛 ericlin 丟了一個這幾天的討論串過來,大光頭 Kris 還提供了一個 patch,是 lock_proc.c 這個檔案從 1.17 到 1.18 的 patch (6.0-RELEASE 是 1.18):NFS locking question

這個 patch 看起來是 transmit_result()transmit4_result() 的修正,不知道 4.x 有沒有 svc_getcaller(),如果有的話可以試著 patch 看看...

星期四, 2月 16, 2006

Slave News 與 Archive

由於硬碟故障,今天重新安裝 netnews4.csie.nctu.edu.tw...

Slave News 以前玩過 (上次是五年前剛接 netnews.nctu.edu.tw 的時候,當時要把 News 從現在 Group.NCTU.edu.tw 在用的機器換到現在在用的 1U server 上,為了降低搬移時對 BBS 以及 User 的衝擊,特地用 Slave 的架構同步兩邊的文章),沒想到在這麼多年後又有機會玩到了。

現在的 netnews4.csie (slave) 是跟 netnews.csie (master) 接,設定 xrefslave 以及 nnrpdposthost 後,把 active 與 newsgroups 複製到 netnews4 上,然後就開始跑... 看起來頗不賴 :p

另外這台 server 要當作資工的 archive server。舊的 archive 是學長直接改 INN 的 patch (我也不知道是誰改的),全文搜尋的部份 (很重要的功能) 其實不太好做。我今天跟 ericlin 討論了一下用 SQLite 的想法,他聽了一些以後覺得好像還蠻不錯的,於是我就開始規劃 Table 長什麼樣子,然後寫 SQLite 版本的 archive 了,已經寫完了,剩下還沒 debug 而已,另外就要寫 Web Interface...

剛好昨天看到 Yahoo! 釋出神祕 Library,一起來玩看看 :)

星期三, 2月 01, 2006

Firewall

剛剛在把 Firewall Spec 上的東西寫成 SQLite3 的 table。

邊看邊碎碎念:我當初怎麼會自己寫這些 Spec 啊,這些 Spec 要寫超多 code 的 XD

Anyway,只要 table 寫出來,其他刻 code 就很快了。第一版先用 Perl 寫,然後再開始改寫成其他語言... (應該不會發生第一個版本寫完就沒機會用其他語言寫的情況吧?@_@)

星期一, 1月 30, 2006

炸了整排的機器

過個年,整排機器炸掉:
  • csie.NCTU.edu.tw 的三台 NIS server 炸了兩台,mailgate 也炸掉 (於是 /var/mail 就沒掛上來),鑰匙管理系統因為是使用某台 NIS 上的 MySQL server,所以也上不去,於是不知道有誰有鑰匙,最後在 IRC 上問到在 lwhsu 那邊...
  • Deer.twbbs.org 也炸了,晚點回新竹看一看...
希望這樣就好...

星期日, 1月 29, 2006

OpenLDAP

OpenLDAP 官方網站的 A Quick-Start Guide 寫得很簡單,不過實際上到了 ldapadd 的地方就不會動了,會有錯誤訊息:
testbase [/home/staff/gslin/work] -gslin- ldapadd -x -D 'cn=Manager,dc=testbase,dc=gslin,dc=org' -W -f test.ldif
Enter LDAP Password:
adding new entry "dc=testbase,dc=gslin,dc=org"
ldap_add: Naming violation (64)
additional info: value of naming attribute 'dc' is not present in entry

其他的說明文件也都是照這份延伸出去的,所以就卡住了... 我超討厭這種情況 -_-

這代表又要用 Google 找半天了...

Update:我用 my-domain.com 的例子就成功了,至少知道問題在哪裡了 o_O

星期一, 1月 09, 2006

管理一堆 FreeBSD 的方法

以前在計中弄二三十台 FreeBSD 的時候就是用 screen + portupgrade 一次把幾十台機器升級,升級完整個重開機就好了,不用管什麼東西升級完要重跑。安裝新軟體如果需要指定 WITH_BLAH=yes 或是其他的東西,記得到每台上面的 /usr/local/etc/pkgtools.conf 改一下。(以前的 ports 還沒有 OPTIONS 這個功能)

這個模式在我一個人管的時候很好,但是當要傳承的時候就糟糕了:要瞭解這種方法的人大概都需要玩過一陣子 FreeBSD,知道只靠系統基本的套件管理是不夠的,才會有感覺。D2 上面是到了 ronnywang 才接下去。現在在交大資工當系計中助教也遇到同樣的問題。

一種想法是利用 package 更新 (這個在將 ccbsd*.csie.nctu.edu.tw 重灌成 FreeBSD 6 已經實行一段時間了),但目前最大的問題在於使用 package 會:
  • 無法善用每台機器的 CPUTYPE。
  • 某些 ports 無法產生 package,像是 screen (技術問題)、jdk (授權問題)。
另外,有時候會發生套件安裝好,但是無法產生 package 的慘劇。這個方法其實問題還蠻多的。

我昨天又想到了另外一個作法,我不知道可不可行,不過看起來會比原來的方法好,但是重新安裝機器時的速度一定會比 package 的方法慢:
  • 每天在 ccduty 上產生 package list (像是 sysutils/screen 這種字串,一行一個),排序後塞入 svn repository。另外將 /usr/local/etc/pkgtools.conf 也塞進去。
  • 要安裝新機器的時候,先將 /usr/local/etc/pkgtools.conf 抓回來,再用 cat ports-list.txt | xargs portinstall 把軟體安裝進去。
也許 ccbsd8 可以試看看這種方式。

星期二, 1月 03, 2006

The GNU Problem Report Management System

The GNU Problem Report Management System 就是 GNATS,我打算拿這套系統給系上用。

初期 (等下先弄的部分) 可能先做:
  • 將每次開會完所決定的事項到 GNATS 上面指定,下次開會的時候就知道到底做的如何了。
  • 值班系統會負責 submit pr 給每一班的值班助教,請他們檢查一些東西 (第一班與最後一班會多一些東西),如果值班助教有遇到問題,但是自己解決不了的,可以利用 Change Responsible 的功能交棒給下一班,如果自己能解決,只是要比較久的也可以註明上去。(這樣就不會有上一班以為交給下一班,下一班以為上一班自己要解決的事了 o_O)
再來可能會做的:
  • 將鑰匙管理系統移到上面,兩把鑰匙變成兩個狀態永遠是 open 的 pr,鑰匙的移交透過 Change Responsible 的功能實做。如果怕一個 pr 太長,那就每次開會的時候總管檢查過鑰匙後把舊的 pr close 掉,再開一個新的 pr。
  • 訂閱 CERT、{FreeBSD,Linux} Security Advisory,寫一個 Shell Script 接,然後每次收到以後就送 pr 進去,要求每個 TA 檢查系統。
目前大概只想到這樣...