1. 資料庫文件被其他線程覆蓋或刪除在文件描述符關掉以後,繼續使用這個文件描述符訪問打開文件,獲取文件描述符fd(其實是一個整形)關閉文件打開sqlite文件,獲取文件描述符(碰巧也是)fd另一個線程繼續使用fd,寫文件sqlite文件被損壞在事務進行過程中,進行資料庫備份或恢覆在資料庫事務過程中,... ...
1. 資料庫文件被其他線程覆蓋或刪除
- 在文件描述符關掉以後,繼續使用這個文件描述符訪問
- 打開文件,獲取文件描述符fd(其實是一個整形)
- 關閉文件
- 打開sqlite文件,獲取文件描述符(碰巧也是)fd
- 另一個線程繼續使用fd,寫文件
- sqlite文件被損壞
- 在事務進行過程中,進行資料庫備份或恢復
在資料庫事務過程中,資料庫文件既包括老的內容,也包括新的內容。如果此時拷貝這個文件,資料庫可能會被損壞。 備份資料庫最好使用sqlite的api。 - 刪除日誌文件
日誌文件中包括rollback需要的信息。刪除以後,無法正確回滾,有可能會導致資料庫損壞。
2. 文件鎖相關
sqlite使用文件鎖來在保證多線程訪問。如果文件鎖機制不正常,會導致同時讀寫文件等信息,導致資料庫損壞
- 文件系統沒有正確的實現文件鎖的機制
在網路操作系統中,比較常見 - 不正確使用close()函數
在Unix中,close()函數會解除所有線程的文件鎖。
例如A、B線程打開了資料庫文件,使用sqlite的api。此時,線程C依次調用了open()
,read()
以及close()
。此時,這個文件的所有鎖已經沒了。因此A、B有可能會同時寫數據到文件中。 - 兩個進程使用不同的鎖協議(locking protocols)
預設使用POSIX advisory locking
,可以用sqlite3_open_v2()
函數修改。如果不一致,可能發生同時讀寫,資料庫損壞。 - 在資料庫文件使用時rename或unlink
兩個進程A、B,同時對一個資料庫文件建立資料庫連接。A關閉連接,unlink文件,用同樣的名字創建一個新的資料庫文件,在打開這個資料庫。這樣子A、B兩個進程在使用不同的資料庫,名字卻是一樣的。 然而,日誌文件是根據資料庫名字來區分資料庫文件的。因此這兩個進程的資料庫文件會是同一個。導致資料庫文件損壞。 - 一個文件有多個連接
也就是說一個資料庫文件有多個名字。假如A、B使用不同的名字打開同一個資料庫鏈接,會有兩個日誌文件。 如果線程A crash了,B檢測到需要進行rollback。找不到日誌文件,無法回滾。
3. sync失敗
為了保證資料庫文件的一致性(consistent),會調用fsync()
系統調用,把記憶體中的數據刷到磁碟中。如果這個sync操作失敗,會導致資料庫文件損壞
- sync系統調用和文檔描述不一致
USB快閃記憶體經常這樣子。例如寫大數據時,在函數返回已寫入成功時,USB的指示燈還在亮著。 - 使用PRAGMAs禁用sync
synchronous=OFF
可以提高速度,卻會導致文件不一致。
4. 硬碟、快閃記憶體損壞
5. 記憶體損壞
當野指針、記憶體溢出等原因,可能導致記憶體中的資料庫結構損壞,從而有可能導致資料庫文件損壞。
當進行memory-mapped I/O時,由於記憶體直接映射到磁碟,如果發生數組越界等,記憶體中的數據損壞,磁碟文件也會損壞
6. 其他操作系統問題
- 文件系統崩潰 ##7.sqlite的bug