標籤:

OS X 上的文件版本恢復功能的實現原理是什麼?

如「文本編輯」,「預覽」等應用都具備文件版本恢復的功能,當你修改了一個文本或圖像之後,你都可以通過瀏覽版本庫恢復過去的版本。那麼這個功能是怎麼實現的?如果是在系統里存一份原始文件的副本,記錄每次修改信息的話,這個存儲位置又是在哪裡?

相關鏈接:OS X Lion:關於自動保存和版本


OS X 高手進階裡面有一章節專門說這個問題,,,我吃晚飯回來整理下格式貼過來吧。

------------------------------------------------------------------------------------------------

文檔版本是在 OS X 10.7 Lion 開始加入到系統中的特性。它與 Auto Save (自動保存) 技術相輔相成,為用戶帶來文檔版本控制的基礎功能。首先通過一個簡單的例子來了解文檔版本。使用系統默認的 文本編輯 應用程序,創建一個名為 Revision.rtf 的文檔,輸入 "文檔版本1" 後保存到桌面

。然後再次打開此文檔,替換內容為 "文檔版本2"。此時,點擊 文本編輯 文件菜單,在 復原到 菜單下,選擇瀏覽所有版本,你就會看到類似 Time Machine 的界面

。此時,你可以通過點擊屏幕最右側的時間線來選擇文檔的歷史版本進行瀏覽。如果你想要將當前文檔恢復為一個歷史版本,找到對應的版本後按下 恢復 按鈕即可。這樣以來,你的當前版本就被放置到歷史版本中,而你剛剛選擇的歷史版本則變為文檔的當前版本。這對於用戶來說,是一個非常方便的功能,並且,你可以在歷史版本中直接拷貝需要的內容而無需整個恢復文檔。

文檔版本功能的存在對於傳統的文檔操作方式,只有一處稍稍不同。在使用以往的,基於文檔的應用程序操作文檔時,按下按下鍵盤 ?S 即會保存文檔。而在支持 文檔版本 技術的應用程序里,?S 則是保存文檔的一個版本。但是,很多用戶還是保留著操作文檔時隨機按下保存鍵保存當前文檔內容的習慣,那麼,這時會不會使得文檔版本功能變為磁碟空間的"殺手"呢?

這還是要從文檔版本的實現說起。首先在終端執行

sudo su -

在輸入管理員密碼後,終端即顯示如下 (img)

。這就說明目前我們在終端中已經進入了超級用戶 root 的狀態。由於 root 有著最高的許可權,所以此時執行任何操作要非常小心。這裡這是為各位講解文檔版本的實現,在一般情況下,不要隨意使用 root 方式。執行此命令

cd /

進入磁碟根目錄,然後執行

ls -al

你會看在輸出中看到一個名為 .DocumentRevisions-V100 的文件夾

。這就是文檔版本功能用於保存文檔歷史版本的地方。使用命令

cd /.DocumentRevisions-V100

進入到此文件夾中,然後還是使用 ls -al 命令查看文件夾的全部內容

。這裡我們要關心的是兩個文件夾。PerUID 和 db-V1。其中 db-V1 用於存儲 sqlite 資料庫文件。資料庫則用於紀錄各個版本的文件信息,包括文件名、版本(此處稱為 Generation) 等,同時也紀錄了每一個文件各個版本存儲路徑。而這個存儲路徑,則時指向 PerUID 下的某個文件夾中的某個文件。PerUID 文件夾下存在按照用戶ID (UID) 為文件名的文件夾,用於存儲不同用戶的文檔歷史版本。在終端執行

id

即可獲得當前用戶的 UID 。由於當前我們是 root 的身份,所以,要獲得自己用戶的 UID,則需要執行(你需要將命令中的 buick 替換為你自己的真實用戶名)

id ibuick

以獲得用戶 ID (如果系統中只有你一個管理員用戶,通常為 501)。

首先我們來觀察資料庫的組成,這裡含有三個重要的表,分別為 files,storage 和 generation 。首先在 files 資料庫中,我們可以找到有關 Revision.rtf 的信息

。這裡包含了文件名,路徑,inode等信息。不過,我們更為關心的是 file_storage_id,使用這個 id 可以找到存儲於 generations 表中的有關 Revision.rtf 文件的歷史版本信息。根據這個 id (2667),在 Gernaration 表中,可以找到三個此文檔的歷史版本記錄 (img)。這也可以通過前文介紹的 瀏覽所有版本 功能進行驗證。根據 generation_path 中指定的路徑,我們可以回到 PerUID 文件夾下找到 Revision.rtf 文檔的歷史版本

。由於文本文件結構簡單,佔用磁碟空間小,且易於壓縮等特性,所以將整個文檔保存並作為歷史版本並不是很大的問題。但對於一些結構複雜,體積較大,且不容易壓縮的文件(如圖片或其它二進位數據等),每次都保存一個完整的文檔作為歷史版本就不可接受了。對於這種類型的文件,文檔版本還提供了另外一種技術,即對文檔進行分塊存儲。這樣一旦文檔發生改變,則只需記錄改變的部分並創建一個新數據塊保存即可。當用戶瀏覽或恢復時,文檔版本會根據文檔分塊動態合併出各個版本供用戶瀏覽和恢復。整個技術基於一個名為 Rabin Fingerprint 的演算法,有興趣的朋友可以查看其相關的論文。這裡簡單的通過例子描述來為各位介紹一下此演算法。一般的文檔分割,都是基於固定偏移量(offset)進行的。比如一個 10MB 的文件可以被分割位等大小的,每個為1MB 的塊,共10份。如果新版本中對此文檔的更改處於文件末尾,則文檔版本機制可以簡單的創建一個新的末尾分塊即可(此時文檔塊可以是11份)。不幸的情況發生了,用戶又一次打開了文檔,並在文檔頭加入了數據。由於固定偏移量分割方法,則需要對此文檔重新分塊。這種做法對於一個10MB的文件來說可能不是什麼大問題,但是如果此文件為 100MB,500MB,那麼無論是性能還是可用性、穩定性均無法被接受。Rabin Fingerprinting 針對固定偏移量分割法的弊端,提出了按照文檔結構,動態進行分割的演算法。比如一篇文章,含有很多段落,這時使用 Rabin Fingerprinting 則可以簡單的根據段落對文章進行分割,那麼無論改變發生在何處,都不會像固定偏移量那樣導致所有塊重建。當然,文檔版本機制還對常見的文檔格式,如 PNG,JPEG,MOV,MP4 等擁有很好的處理方法,因為這些文檔的結構基本固定。如果這時系統中有一個文檔版本並不「熟悉」的文檔格式,則分塊存儲的效率會下降(最慘烈的情況是變為與固定偏移量相當)。另外,文件的大小也是文檔版本機制是否決定對於文檔進行分塊存儲的考量之一。一般情況下,小於 32KB 的文檔不會進行分塊存儲,而是像前文中介紹的 Revision.rtf 那樣整文件存儲。隨著文件的體積增長,則會酌情進行分塊處理。體積越大的文件,每個數據塊也會相應的變大,從而避免了出現成千上萬個文檔分塊的情況。由於文檔分塊的處理方法並不直觀,所以這裡就不在過多介紹了,在 .DocumentRevisions-V100 文件夾下,有一個名 .cs (Chunk Storage) 的文件夾,裡面就存儲著分塊的文檔數據。

無論是 Auto Save 還是 Document Revision,這些技術的存在給用戶帶來的極大的便利性,也大大提高了應用程序的可靠性,使得用戶丟失數據的幾率降低。但是,這些技術也明顯的對硬體的運算能力和磁碟 I/O 提出了更高的要求,比如大文件的分塊存儲。 另外,這些技術的存在也是 OS X 下磁碟剩餘空間在不停變化的原因之一。最後,文檔版本與 Time Machine 之間也有著非常緊密的聯繫。如果你開啟了 Time Machine,則一些文檔的古老版本會隨著 Time Machine 被從本機硬碟移動到備份存儲當中,從而節省磁碟空間。這也同時解釋了為何當你瀏覽文檔版本,那些存儲在 Time Machine 中的版本也同樣會被載入進來的原因。

------------------------------------------------------------------------------------------------

以上內容直接引用自 OS X 高手進階 Definition #14: Document Revision 文檔版本本作者拒絕任何形式的轉載

------------------------------------------------------------------------------------------------

需要注意的是,

1. 文檔版本並非孤立,需要 Auto Save 的配合。

2. 文檔版本目前對於大文件處理性能較差,比如高手進階的 iBooks Author 工程,會導致嚴重的性能下降。當然,如果文件不大,倒是沒有任何問題。


文本文檔還好,都是k級別的,但對幾兆的照片來說,每次用preview修改照片,ctrl+s一次就會在版本庫里生成一個副本,其實挺浪費磁碟空間的。在當時發行Lion推出這個功能的時候,雖說還沒有帶ssd的rmbp,mbp的機械硬碟也比較富餘,但也存在小容量的mba,對於沒有用time machine來說還真會在不知不覺中多了不少冗餘。個人認為Apple還應該在以後的版本里對此功能做個設置,可以讓用戶自定義最多保存的歷史版本數,為此功能設置個命令行的開關與情理功能。畢竟ssd空間還是太緊張了,經不起這麼複製。目前來講可以到 王飛 提及的那個 DocumentRevision文件夾去清除不需要的歷史版本騰出空間。

---------------------

搬運關閉 Preview(預覽) 的自動保存功能的方法:

defaults write com.apple.Preview ApplePersistence -bool no

同理想關閉文本編輯的自動保存,把Preview換成TextEdit即可


推薦閱讀:

Linux 和 OS X 的具體差異有哪些?
有哪些值得推薦的支持 Touch Bar 的應用?
想用外置硬碟為 iMac(1TB)作 TimeMachine 作網路備份,請教根據我家目前的設備(詳見問題補充),何種方案更佳?
如何在 OS X Yosemite 和 Windows 10 中間做出選擇?
請問怎樣才能充分實現Macbook air的價值,實現效益最大化?

TAG:Mac | macOS |