-
Notifications
You must be signed in to change notification settings - Fork 6
BRH zh_tw
BRH 看板閱讀紀錄系統是 MapleBBS 3 所使用的看板閱讀紀錄系統,而 BRH
是此系統所使用的資料結構。
在 BBS
使用者目錄下的 .BRH
檔是匯集了此使用者閱讀的所有看板的 BRH
的輸出。
為表示區別,本文將一個看板對應之閱讀紀錄稱為「BRH」,將匯集了多篇看板的閱讀紀錄稱為「BRHs」,而將在使用者目錄下的閱讀紀錄檔案稱為「.BRH
檔」。
- 工作區:目前所閱讀的看板的 BRH 的記憶體存放位置 (
brh_tail
–brh_tail + BRH_WINDOW
)- 本文的術語;「正讀」為 MapleBBS 3 原始碼所使用的對應術語
- 解開:將未解開的 BRH 中的
{final | BRH_SIGN}
解開為{final, final}
- 壓縮:「解開」的逆操作
- Zap:在看板列表中預設不列出某看板;此看板內的文章閱讀紀錄不被記錄
- 本文將 zapped 看板在
.BRH
檔中所對應的 BRH 稱為「zapped BRH」,而連續的多個 zapped BRH 組成的檔案區段稱為「zapped BRHs 區」
- 本文將 zapped 看板在
-
brh_alloc
: 分配空間給新 BRH,會依狀況重新配置記憶體空間 -
brh_put
: 將工作區的 BRH 壓縮並放至非工作區的結尾 -
brh_get
: 從非工作區的 BRHs 找出看板所對應的 BRH,將之放至工作區並解開;未找到時則建立新的 BRH- 會先執行
brh_put
- 會先執行
-
brh_unread
: 判斷指定時間的文章是否為未讀 -
brh_visit
: 已讀或未讀看板所有文章 -
brh_add
: 將指定時間的文章標記為已讀 -
brh_load
: 從使用者的.BRH
檔載入 BRHs 至工作區以及載入 zapped 看板列表;無則建立新的 BRHs -
brh_save
: 儲存非工作區的 BRHs 以及 zapped 看板列表至.BRH
檔,- 會先執行
brh_put
- 在 DreamBBS v2.0 後還會解除相關記憶體的配置
- 會先執行
MapleBBS 3 並未直接在程式碼中使用資料結構操作 BRH,不過仍然定義了可做實作參考的資料結構 struct BoardReadingHistory
/struct BRH
。
注意本文的 time_t
為 32 bits 整數,同 int
。
欄位 | 型別 | 說明 |
---|---|---|
bstamp |
time_t |
看板建立時間 - Zapped BRH 僅有此欄位 |
bvisit (非工作區) bhno (工作區) |
time_t |
- 上次進入看板的時間 (非工作區) - 看板的 HDR 的編號 (工作區) |
bcount |
int |
組成已讀時間區間的 time_t 數量 |
tags |
time_t[] (大小不定) |
已讀時間區間 - 原無正式命名,本文稱之為 tags
|
一個已讀時間區間的可能格式:
-
{final, begin}
:代表[begin, final]
的閉區間。- 若文章時間
t
在任一區間符合begin
≤t
≤final
,則為已讀
- 若文章時間
-
{final | BRH_SIGN}
;僅出現在未解開的 BRH 中;解開後變為{final, final}
變數 | 型別 | 說明 |
---|---|---|
brh_base |
int * |
- 指向用以存放 BRHs 的動態配置記憶體的開頭 - 非工作區 BRHs 的開頭 |
brh_tail |
int * |
- 非工作區 BRHs 的結尾 - 指向工作區 BRH 的 bstamp
|
brh_size |
int |
用以存放 BRHs 的動態配置記憶體的 byte 大小 |
brh_expire |
time_t |
讓此前的閱讀紀錄被忽略 - 載入 .BRH 檔時才設定 |
Macro | 值 | 說明 |
---|---|---|
BRH_EXPIRE |
180 |
讓舊過此天數的文章被視為已讀 |
BRH_MAX |
200 |
tags 所含的最大 time_t 數量 |
BRH_PAGE |
2048 |
原作為動態配置的 BRHs 空間每次重新配置所增加的 byte 大小,但未使用 |
BRH_MASK |
0x7fffffff |
bstamp 與 tags 的實際時間的 mask |
BRH_SIGN |
0x80000000 |
- 表示 zapped 看板 (bstamp ) - 表示頭尾時間相同的已讀時間區間 ( tags 中) |
BRH_WINDOW |
- (sizeof(BRH) + sizeof(time_t) * BRH_MAX * 2) - (sizeof(BRH) + sizeof(time_t) * BRH_MAX) (DreamBBS v3.0) |
BRH 的最大 byte 大小 |
為便於說明,本段定義以下的常數與變數:
-
BBS_BIRTH_TIME
為 BBS 系統誕生的時間,設為 1978 年 2 月 16 日 UTC-0600 (0x0F493860
) -
list
為具有型別int *
的指標,指向 BRHs 中的未知位置
- 時間 tag 一定由大排到小 (
(tags[k] & BRH_MASK) > (tags[k+1] & BRH_MASK)
) - 不會有相同的 tag
bstamp <= bvisit
-
bstamp
和bvisit
都大於BBS_BIRTH_TIME
開頭與結尾判斷:
- BRH 的開頭:
list
符合list[0] >= BBS_BIRTH_TIME && list[0] <= list[1] && list[2] < BBS_BIRTH_TIME
- 與工作區的未解開 BRH 基本相同
-
.BRH
檔中的 BRHs 的結尾可能尚有 zapped BRHs 區 (只有bstamp
);已載入記憶體的 BRHs 則沒有 zapped BRHs 區 - Zapped BRH 的
(bstamp & BRH_SIGN) != 0
且(bstamp & BRH_MASK) >= BBS_BIRTH_TIME
開頭與結尾判斷:
- 未 zapped BRH 的開頭:
list
符合「工作區的未解開 BRH」的 BRH 開頭 - Zapped BRHs 區的開頭:
list
是符合不在其它 BRH 中,或是在最後一個 BRH 的範圍中但list[0] >= list[-1]
中的第一個指標 - Zapped BRH:
(*list & BRH_MASK) >= BBS_BIRTH_TIME && (*list & BRH_SIGN) != 0
,而且list
是 zapped BRHs 區的開頭,或是list[-1]
是一個 zapped BRH
- 開頭為
brh_tail
- 時間 tag 一定由大排到小 (
tags[k] >= tags[k+1]
) - 相同 tag 必在同一區間
- 沒有
bvisit
,只有bhno
- 除了
{1, 1}
,{mode, 0}
,{time(), 0}
三種特殊區間外,tags[k] >= bstamp
-
{1, 1}
,{mode, 0}
,{time(), 0}
三種特殊區間出現時,必是最後一個區間
開頭與結尾判斷:
-
tags
的結尾(可能是tags
已解開但仍有bvisit
的 BRH 開頭):list
符合k>0, list == &tag[2*k]
,list[0] >= list[-1] || list[-1] <= 1 || list[-2] < bstamp
,或是k>=0, list == &tag[2*k]
,list[1] > list[0]
MapleBBS 3.00a 時,在 brh_load
, brh_save
, brh_put
等函式誤用了 memcpy
來移動記憶體範圍可能重疊的 BRH 資料,產生 undefined behavior 而未加以修正。
記憶體範圍可能重疊時,應使用 memmove
而不是 memcpy
以避免 undefined behavior。
在較舊的作業系統上,因為 memcpy
沒有特別的最佳化,所以不會出現問題。但是在較新的作業系統上 memcpy
有特別的最佳化,會讓記憶體範圍重疊的資料複製時出現問題。
MapleBBS 3 的各分支,如未加以修正,在較新的作業系統上運作時,會因為 memcpy
最佳化的 undefined behavior 而出現 BRHs 損壞的現象。
- 未讀標記異常:有時進入看板,所看到的未讀標記與先前的並不一致(例如被自動重設)。
-
造成此現象的 BRH 損壞:
- 此看板的 BRH 開頭部份被意外複製,在使用者的 BRHs 中重複出現。
- 某看板的 BRH 的
bcount
損壞,造成 BRHs 中偶然出現可被解讀為此看板的 BRH 開頭的資料。
-
引發此現象的程式動作:
- 某次嘗試載入此看板的 BRH 時,載入到的是同一看板的不同的 BRH。
-
造成此現象的 BRH 損壞:
- 在進行以下操作時,系統回應時間過久,甚至斷線(伺服器端提供此連線服務的程式崩潰)。
- 登入
- 登出
- 進入看板列表/看板分類列表/我的最愛列表
- 進入某看板
-
造成此現象的 BRH 損壞:
- 此看板的 BRH 的
bcount
被其它資料覆寫,變得過大。 - 某看板的 BRH 的
bcount
損壞,造成 BRHs 中偶然出現可被解讀為此看板的 BRH 開頭的資料,其中的bcount
原為時間值而過大。
- 此看板的 BRH 的
-
引發此現象的程式動作:
- 程式根據損壞的
bcount
嘗試將過大的 BRH 資料載入記憶體,造成執行速度緩慢,甚至造成記憶體空間不足而使程式崩潰。 - 程式根據損壞的
bcount
嘗試存取非法記憶體位址,引發記憶體區段錯誤而強制中止程式的執行。
- 程式根據損壞的
- 刪除
.BRH
檔以重置閱讀紀錄
DreamBBS v2.1 時已完全修正會引起 BRHs 損壞的問題。
修正內容請見:
-
bc67fbb220 「maple/board.c:
brh_get()
: Fix usingmemcpy()
to move data between overlapped ranges.」 -
2f64941529 「maple/board.c:
brh_load()
&brh_save()
: Fix usingmemcpy()
to move data between possibly overlapping ranges; should have usedmemmove()
. [ref: bc67fbb]」
尚未完全解決已存在的 BRHs 損壞所引發的問題。
有關修正損壞的 BRHs 所引發的問題的嘗試,請見:
-
82747bf62f 「maple/board.c:
brh_load()
: Fix and work around the BRH file loading errors caused by invalidbcount
fields of BRH entries.」
- Home
- Install — 安裝說明
- Version
- Project Documentations — 專案說明文件
- Coding Style & Conventions — 程式碼撰寫風格與慣例
- Indentation
- Xover List System — Xover 列表系統
- Menu Systems — 選單系統
- Screen Coordinate System — 畫面座標系統
- BoardReadingHistory — BRH 看板閱讀紀錄系統
- Visio I/O Library — Visio 輸出入函式庫
- Permission System — 權限系統
- TANet BBS Family Genealogy Chart — TANet BBS 家族譜系圖
- 與 MapleBBS 3 的按鍵差異
- [WIP] 與 MapleBBS 3 的差異
- References — 參考資料
- Changelog & TODO
- Issue & TODO list — 問題與代辦事項清單
- MapleBBS-itoc Porting Project — MapleBBS-itoc 移植計畫
- BBS-Lua Changelog
- BBS-Ruby Changelog (external link — 外部鏈結)
- 新式密碼加密 (DLBBS v2.0+)
- [WIP] DreamBBS v3 發佈說明 Release Note
- Release Notes of Version 2.0.0 Artoria
- Version 2.0.0 Artoria 發行說明
- Release Notes of Version 1.0.0 Rimuru
- Version 1.0.0 Rimuru 發行說明
- NoCeM-innbbsd 原始說明文件
- WindTop 3.02 原始說明文件