最近在研究Deduplication(重複資料刪除)儲存技術,實現一個dedup原型系統,結果在Coding中遇到了一個莫名其妙的問題。簡略代碼如下:
#include "dedup.h"<br />#ifndef BLOCK_LEN<br />#define BLOCK_LEN 32 * 1024 /* 32K Bytes */<br />#endif<br />#define BACKET_SIZE 10240<br />...<br /> int fd_src, fd_dest;<br /> char buf[BLOCK_LEN] = {0};<br /> unsigned int rwsize, pos, block_id;<br /> unsigned char md5_checksum[16] = {0};<br /> unsigned int *metadata = NULL;<br /> unsigned int block_num = 0;<br /> struct stat stat_buf;<br /> hashtable *htable = NULL;<br /> dedup_file_header dedup_hdr;<br />...<br /> if (-1 == (fd_src = open(argv[1], O_RDONLY)))<br /> {<br /> perror("open source file");<br /> return errno;<br /> }<br />...<br /> htable = create_hashtable(BACKET_SIZE);<br /> if (NULL == htable)<br /> {<br /> perror("create_hashtable");<br /> return errno;<br /> }<br /> pos = 0;<br /> block_id = 0;<br /> if (-1 == fstat(fd_src, &stat_buf))<br /> {<br /> perror("fstat source file");<br /> goto _EXIT;<br /> }<br /> block_num = stat_buf.st_size / BLOCK_LEN;<br /> metadata = (unsigned int *)malloc(sizeof(unsigned int) * block_num);<br /> if (metadata == NULL)<br /> {<br /> perror("malloc metadata");<br /> goto _EXIT;<br /> }<br />
我用大小為1.9MB的檔案作為源檔案,結果 block_num 居然為 61881344,真是出乎想像。塊大小BLOCK_LEN = 32KB,所以block_num應該為59才對。問題出在哪了呢?這段代碼非常簡單了,沒有什麼複雜的邏輯,我反覆review了幾次也沒有發現問題。於是,在家裡轉了兩圈,然後無意中注意到了BLOCK_LEN的宏定義。define總是容易犯些低級的錯誤,難道我也犯了最低級的錯誤不成?
#define BLOCK_LEN 32 * 1024 /* 32K Bytes */
看到這行,我當時就傻了,自己還真犯了最低級、最原始的錯誤。
block_num = stat_buf.st_size / BLOCK_LEN;
上面這行宏替換後就成了:
block_num = stat_buf.st_size / 32 * 1024;
終於明白問題出在何處了,給宏加上(),即#define BLOCK_LEN (32 * 1024) ,一切OK了!
這次經驗教訓深刻,估計我以後很少會再犯類似錯誤了,另外也小有收穫和樂趣 ^-^。
最後提醒一下:宏使用很方便,但要謹慎使用,尤其需要注意書寫格式,盡量多用括弧避免歧義。細節是魔鬼!