summaryrefslogblamecommitdiffstats
path: root/docs/brc.txt
blob: 954ea5f2c2981f1887daef5f39d9e6f2285df384 (plain) (tree)
1
2
3
4
 
                                                  
                                                                  
                                                              













                                                                              
                                                                         

                                                                             
                                                                     


                               
                               

                                                   


                                                                                                  

                                                                      
                                                                                                           

                                                                              
                                                                             





                                                                               
                                                                           
                                                                              
                           













                                                                            


                                                                              
 
           


                        



                                                             





                                                                        
                                         

                                    

                                                                              
                                                                        
                                                                             
                                                                            


                    
                                         


                                                                    
                                                      
                                      
  
                     

                               
                        









                                                                              
                                     
                                                                                



                                                   

                                                                   
 
                            
 




                                     
  
 
                             
                                                                           

                          
                                                                                                       
                                                               
                                                                          
                                                  

                                                                                 





                                                                            
 
        BRC (v2) documentation by scw   08/05/2003
                    06/12/2007 revised by kcwu
                    12/02/2007 v3 by piaip
 
源起:
     這篇文章主要是介紹 brc_* 的函式,這組函式是 pttbbs 用來紀錄文章已讀/未讀
 的工具,但因為內部的儲存方式十分 tricky 連帶使的內容相當難懂。為了重現及修正
 其中的一個 bug,筆者有幸弄清了其中運作方式,並為其撰寫說明,希望對管理者有幫
 助。
 
什麼人該看這篇文章?
     1. pttbbs 的系統管理者。如果您要對這部份進行修改或抓蟲,希望這篇文章能對
        您有所助益。
     2. 想要研究這種用極少空間記下極大資訊的方法的人。
 
BRC 是什麼?如何運作?
     brc_* 是定義在 pttbbs/mbbsd/board.c 中的一組函式,負責紀錄文章已讀/未讀,
 它的特點是用的空間極少。可以在 24k 以內的空間記下一個人在全站的文章已讀/
 未讀。當然,這樣的方法不可能真正完美,但是對於使用上已經足夠了。為什麼說是不
 完美呢?這跟紀錄的儲存方式有關。
     紀錄檔在 home/[first charactor of id]/[id]/.brc2。檔案格式如下:
 
 FILE     := RECORDS ;
 RECORDS  := RECORDS RECORD | ;
 RECORD   := BRC_BID BRC_DATA ;
 BRC_DATA := BRC_NUM BRC_LIST ;
 BRC_LIST := NUM NUM ... NUM ;  (共 BRC_NUM 個 NUM)
 BRC_BID 是 board bid, sizeof(brcbid_t)=2 bytes.
 BRC_NUM    是對這個板的儲存量,sizeof(brcnbrd_t)=2 bytes 以 binary 方式儲存,其值 <= MAX_NUM (80)
 BRC_LIST   是對這個板的紀錄,剛好有 BRC_NUM 個 sizeof(time4_t)=4 bytes integers。
 另外在 24576 bytes (#define BRC_MAXSIZE 24576) 之外的資料不會被用到。
 
     在下面會看到,BRC_BID 跟 BRC_NUM 跟 BRC_LIST 都會放在相應的變數中, brc_currbid & brc_num & brc_list 。
     判定一個檔案是否已經讀過的方法是在 brc_list 中搜尋檔案建立的時間,也就是
 檔名 M.xxxxxxxxxx.A.yyy 中 xxxxxxxxx 的那個數字。如果這個數字有在 brc_list 中
 出現就是已讀,要不如果 brc_list 中所有的數字都比這個檔案的建立時間大(也就是
 這個檔案的建立時間在所有 brc_list 中的時間點之前)也是已讀,最後為了節省空間
 還有一個判定(其實這個判定是第一個做的),如果檔案建立時間在 login 時間的一年
 之前,一律是已讀。
     這樣可以看出為什麼這個方法不是真正完美但是已經足夠。不完美的原因有三個:
 首先, brc_num <= 80 也就是 brc_list 最多存八十個數,這表示除了很久以前的文章
 外,只會有八十篇是已讀的。第二就是所有一年前的文章都會被判為已讀。最後,如果一
 個人看的板太多,讓 .brc2 大小超過 BRC_MAXSIZE 有些板的紀錄就會不見( 24576
 bytes 最少可以存 73 個板的資料,這還是用全部板 brc_num 都是 80 計算的)。但這
 三個小缺點影響應該不大吧?

v3 說明

     Dec 2007 開始 ptt brc 引入 v3 格式,與前板不相容。所謂的 v3 是由於 BBS
 「推文」系統被濫用而產生的需求。推文的形式是在原文後附加新的一行文,但舊
 BRC 系統無法分辨此類更動;若想讓人分辨是否有新推文各家作法不一,常見的是比
 照 edit_post 把檔案改名。這種方式除了效率不彰外,還有並非每個人都想看新推文
 的問題。
     考量許久後,從 BRC 下手還是正解。 在每個 BRC 記錄上多新增一個 modified
 time 即可。 此方法可同時適用於分離檔案與原文附加的推文系統。代價是 BRC 大小
 加倍成長,不過這似乎不是什麼大問題。
     由於 v2 v3 實際差異並不大,這裡的說明保留以 v2 為主。 麻煩自己查 svn
 就知道 v3 改了哪邊了。

 - ptt2 更換 brc V3 前夕, MAX_BOARD 到達上限 (42000),討論後決定順便把 brc V3
 設計成 brcbid_t = int32。

 
BRC v2 實作
 
 interface: (in proto.h)
 
  int brc_initialize();
  void brc_finalize();

  int brc_unread(int bid, char *fname, int bnum, int *blist);
      判斷一篇文章是否已讀。
      傳入值:文章檔名 (fname) 以及 brc_num (bnum) 和 brc_list (blist)。
      傳回值:如果由 bnum 和 blist 判斷本篇文章未讀傳回 1。
              否則傳回 0。
      額外效果:無。
  
  int brc_initial_board(char *boardname);
      初始化在一個板的已讀未讀狀態。
      傳入值:要初始化的板名。
      傳回值:若找到之前的紀錄傳回新的 brc_num,否則傳回 0。
      額外效果:如果傳入的看板就是目前看板會直接傳回 brc_num, 不做別的事。否則
      本函式會先將目前的 brc data 寫回 brc_buf 中,更改 currboard ,取得
      currbid 和 currbrdattr 後再讀取並更新 brc_num 及 brc_list。如果在使用者
      的 brc_buf 中沒有關於這個板的紀錄,會設定 brc_num = 1,brc_list[0] = 1
      並傳回 0。
  
  void brc_update();
      將目前的 brc data 寫入 brc_buf 中。
      額外效果:如果 brc data 未被更改或使用者權限不足則不會有動作。
  
  void brc_addlist(char *fname);
      將文章標示為已讀。使用前需先 brc_initial_board()
      傳入值:要標示為已讀的文章檔名。
  
 constant definition:
  
  #define BRC_MAXSIZE     24576
      .brc2 的有效大小。
  
  #define BRC_MAXNUM      80
      brc_num 的最大值。
  
 private variables: (in board.c)
  
  static time_t brc_expire_time;
      brc_list 中值的下限,時間在此之前的一律當作已讀。會在 init_brdbuf 中被設
      定為 login_start_time - 365 * 86400。
  
  static char   brc_buf[BRC_MAXSIZE];
      呼叫 read_brc_buf 後 .brc2 的前 BRC_MAXSIZE bytes 會被置入這個 buffer 中。

  static int    brc_size;
      呼叫 read_brc_buf 後 brc_buf 中的有效字元數。

  static int    brc_changed = 0;
      從上次讀取 .brc2 到當時為止,brc_num 與 brc_list 是否改變過。

  static int    brc_currbid;

  static int    brc_num;
      brc_list 中的有效數字個數。

  static int    brc_list[BRC_MAXNUM];
      已讀文章的存檔時間。
  

  static void read_brc_buf();
      從 .brc2 中讀取最多 BRC_MAXSIZE bytes 並存入 brc_buf 中,將存入的字元
      數存在 brc_size 中。

  static char * brc_putrecord(char *ptr, char *endp, brcbid_t bid, brcnbrd_t num, const time4_t *list);
      與 brc_getrecord() 的作用正好相反,將資料寫入 puffer 中。
      傳入值:ptr 指向要寫入的 buffer,bid, num, list 分別是要寫入的資料。
      傳回值:指向寫入的 record 下一個字元的指標。
      額外效果:若資料是合法的 (num > 0 && list[0] > brc_expire_time) 且空間足夠,
      資料會被寫入 ptr, endp 之間。

  static int brc_unread_time(time_t ftime, int bnum, int *blist);
      跟 brc_unread() 類似,只是傳入的是檔案建立的時間。
      傳入值:文章的建立時間 (ftime) 及 brc_num (bnum) 和 brc_list (blist)。
      傳回值:如果由 bnum 和 blist 判斷本篇文章未讀傳回 1。
              否則傳回 0。