其實想用 TxF (Transactional NTFS, 交易式的 NTFS) 已經很久了,不過老是被一些雜事卡著,到過年期間才有空好好研究一下。這篇主要是介紹而已,就不講太多 Code, 先以瞭解 TxF 是什麼,及如何善用它等等方面為主。詳細的用法,就等後面幾篇吧!
Transactional NTFS, 中文是 “交易式NTFS”,或是常見到的縮寫 “TxF”,早期的相關文章也有人寫 “TxFS”。這是在 Windows Vista / 2008 推出時,首次正式提供的功能。雖然它叫作 Transactional NTFS, 實際上它並不是一個新的檔案系統,而是一組新的 API (跟原有的檔案處理 API 幾乎是一對一的對應), 支援你用交易的方式操作檔案。一起推出的還有 Transactional Registry (TxR),一樣是有對應的 windows API,只不過它處理的對像是 windows registry,不是檔案…。
用這種方式處理檔案的讀寫動作,有種很神奇的感覺,過去都只在資料庫裡有機會這樣用,現在檔案的處理也可以了。配合像是 DTC 這類交易協調器的支援,甚至可以把檔案的處理及資料庫的處理,通通都包裝成一個交易來進行,一但任何一個環節失敗,都可以回復到最初的狀態,感覺好像是在用 DB,而不是寫檔案… 目前官方並沒有推出 managed code 的含式庫,現在要用只有幾種選擇:
這些用起來都有點不踏實,畢竟用 P/Invoke 不是長久之計,總覺的遲早會被替換掉。不過即使如此,這項還是掩蓋不了這技術的價值。我貼一段自己寫的 sample code,讓還沒用過的人體會一下,寫檔案還支援交易處理的 “爽度” …
// 建立 KTM transaction object
IntPtr transaction = CreateTransaction(
IntPtr.Zero,
IntPtr.Zero,
0, 0, 0, 0,
null);
string[] files = new string[] {
@"c:\file1.txt",
@"c:\file2.txt",
@"c:\file3.txt"};
try
{
foreach (string file in files)
{
// 使用支援交易的 delete file API
if (DeleteFileTransactedW(file, transaction) == false)
{
// 刪除失敗
throw new InvalidOperationException();
}
}
// 認可交易
CommitTransaction(transaction);
}
catch (Exception ex)
{
// 還原交易
RollbackTransaction(transaction);
}
CloseHandle(transaction);
範例裡用到的幾個 method, 像是 CreateTransaction()
, DeleteFileTransactedW()
, CommitTransaction()
, RollbackTransaction()
… 等等,都是透過 P/Invoke 的方式呼叫的 win32 api… 除了用的型別不如 pure .net class library 般直覺之外,這樣的 code 也已經很簡單了,短短卅行就可以搞定…
雖然這樣的 code 實在不大合我胃口,但是它畢竟是個堪用的方案… 對於 code 有潔癖的,可以考慮其它的用法。前面是最基本的 API call,如果你不滿意,MS自家的技術 DTC (Distributed Transaction Coordinator) 當然也支援 TxF。DTC 可以提供額外的好處,就是允許你做分散式的交易管理。意思是你配合 DTC,就可以把 Local File I/O 跟 database access 整合在同一個交易範圍內。
這邊的 sample code 我就不貼了,在 managed code 裡去呼叫到 COM 的那堆介面 (啥 QueryInterface
的) 實在跟 .NET programming 的 style 有點格格不入… 在 C# 的世界裡,應該用 TransactionScope
才對。在 MS 的世界裡,TxF + TxR + DB 都可以是 TransactionScope
內的一部份。這部份的 Sample Code 我一樣先不貼了,不然貼一堆 code 又沒篇幅說明,感覺很混…
其實,MS 該做的都做了,唯一缺的就是它竟然沒正式的併入 .NET Framework 內的一員… 如果 TxF 真的是你想用的東西,倒是有個 OpenSource Project 可以考慮一下: AlphaFS, 它的目標是能替換掉 namespace System.IO.*, 所以很多你常用的 class library, 它都有對等一樣用法的版本,當然它提供了更多的功能及改善… 其中 TxF 的支援就在內,你想用 TxF 來開發軟體的話,這是個不錯的選擇…
總之,這篇只是個開始,目的是想先 “預覽” 一下 TxF 的能耐,及未來它配 DTC / TransactionScope
後,能怎麼應用它的方式,還有其它可用的相關資源。接下來我會陸續整理一些相關的研究心得.. (別太期待,大概一兩週生一篇就很偷笑了 XD),下回見 !
參考資訊:
繼上一篇,介紹了如何用windows server内建的磁碟鏡像 (Mirror) 更換硬碟後,這次剛好有windows 2003,就拿來試了一下...
廢話就不多說了,先來看一下 2003 的步驟,再來看看跟 2008 / 2008R2 差在那裡:
整個步驟跟前一篇都差不多,主要都是靠鏡像(MIRROR)搬完資料後,再把新硬碟多的可用空間併進來。唯一的差別就在這裡: 2003 的 "延伸磁區" (英文: extend volume) 是可以把兩個硬碟,或是兩個分割區併在一起使用。在磁碟管理員還是看的到這些分割區的存在。這就有點像 JBOD (Just a Bunch Of Disks) 的模式。
不過在 2008 之後 (其實 vista 也是),這個功能就改了。原本的名字 extend volumn 現在改成直接擴大原分割區,把原分割區後面可用的空間都納進來,就像你砍掉再重建一個大的分割區一樣,只是資料會留著不會掉。當然有 extend 也有相對的 shrink volume, 這功能會把分割區縮小,騰出空間來讓你多切一個分割區...。而原本 JBOD 模式的功能,則改為 span disk, 用起來效果就如上圖一樣,當然你願意的話,也可以把多顆硬碟 (可以不同容量) 通通併成一個來使用,最多可以併到 32 顆硬碟...。
沒經過這次更換硬碟,還真沒發現 2008 / vista 總算內建這組 extend / shrink volume 的功能進來。雖然很陽春,不過已經很實用了,在過去這種動作是得搬出像 partition magic 這類軟體才能做的到,而這種東西每次用起來心裡都會毛毛的,深怕一不小心就把資料都給毀了...。
這篇小品文章就記到這裡,希望有幫到需要的人 :D
老是寫一堆像外星文,沒人看的懂的 multi-threading 文章,偶爾也來換換口味吧。前陣子把 SERVER 的兩顆 750GB HDD (RAID1) 升級了一下,升級成兩顆 1.5TB HDD (RAID1)。更換硬碟是小事,不過這個硬碟上有些服務,如網站,資料庫,還有一些重要資料,跟分享資料夾,想一想要更換也是挺囉唆的...。
想了幾個辦法,不過都不符合我既懶又挑毛病的個性... 原本考慮的更換方式有:
想來想去,我用的是 windows server, 有內建的 Mirror set, 就拿來用一用好了。我真正作的是把 mirror set 的兩顆都升級,不過為了簡化說明,我底下的例子就只以替換一般的硬碟就好,反正道理是一樣的。
說穿了不值錢,就是用 mirror 的磁碟複製特性,加上 extend volume 的功能,我除了需要關機裝上新硬碟之外,其它包含資料複製的所有時間,原服務都不用中斷 (當然速度會慢一點),所有服務的設定也都不用修改,算是既無腦又防呆的完美方案... 只要簡單的按幾下滑鼠就可以達成我的目標。
直接來看看怎麼作的吧! 很簡單,先利用 mirror 把資料轉移到新硬碟... 然後中斷 mirror, 再用 extend volume 把磁區大小調大就可以收工了。來看分解步驟:
之後就大功告成了。這方法不但簡單,而且整個過程中,全程 D:\ 都可以正常的使用。除了 (1) --> (2) 需要關機裝硬碟之外, (2) ~ (5) 全程,放在 D:\ 的 SQL DB,IIS 網站,還有 pagefile 通通都正常運作中。有了 windows server 的磁碟陣列還真是好用啊 :D
不過,事情也是有黑暗面的... 這個方法是有幾個小缺點啦...
偶爾換個口味,貼些小品文章,這邊我也不是很專業,有啥更好的作法也歡迎留 comment 啊 :D
1.6.0.0 出來一陣子了,不過到過年才有空升級... 主要的原因只有一個,就是最近 spam comments 實在太多了 =_=,新版對於這類問題的處理比較像樣一點..
其它改進還有 nested comments 跟其它一堆改進,就不一一列出來了,有興趣的人可到官方網站去看看。
試了一下,升級後沒啥大問題,除了 CSS 有點走樣之外... 如果各位有發現什麼地方漏掉了,請再通知我 :D
祝大家新年快樂 :D
上一篇廢話了這麼多,其實重點只有一個,我這次打算利用 CacheDependency 的機制,只要一聲令下,我想移除的 cache item 就會因為 CacheDependency 的關係自動失效,而不用很辛苦的拿著 cache key 一個一個移除。 我的想法是用 tags 的概念,建立起一套靠某個 tag 就能對應到一組 cache item,然後將它移除。開始之前先來想像一下 code 寫好長什麼樣子:
static void Main(string[] args) { string[] urls = new string[] { "http://columns.chicken-house.net/", // 共 50 組網址... 略 }; foreach (string url in urls) { DownloadData(new Uri(url)); } Console.ReadLine(); TaggingCacheDependency.DependencyDispose("funp.com"); Console.ReadLine(); } private static void Info(string key, object value, CacheItemRemovedReason reason) { Console.WriteLine("Remove: {0}", key); } private static byte[] DownloadData(Uri sourceURL) { byte[] buffer = (byte[])HttpRuntime.Cache[sourceURL.ToString()]; if (buffer == null) { // 直接到指定網址下載。略... buffer = null; HttpRuntime.Cache.Add( sourceURL.ToString(), buffer, new TaggingCacheDependency(sourceURL.Host, sourceURL.Scheme), Cache.NoAbsoluteExpiration, TimeSpan.FromSeconds(600), CacheItemPriority.NotRemovable, Info); } return buffer; } }
public class TaggingCacheDependency : CacheDependency { private static Dictionary<string, List<TaggingCacheDependency>> _lists = new Dictionary<string, List<TaggingCacheDependency>>(); public TaggingCacheDependency(params string[] tags) { foreach (string tag in tags) { if (_lists.ContainsKey(tag) == false) { _lists.Add(tag, new List<TaggingCacheDependency>()); } _lists[tag].Add(this); } this.SetUtcLastModified(DateTime.MinValue); this.FinishInit(); } public static void DependencyDispose(string tag) { if (_lists.ContainsKey(tag) == true) { foreach (TaggingCacheDependency tcd in _lists[tag]) { tcd.NotifyDependencyChanged(null, EventArgs.Empty); } _lists[tag].Clear(); _lists.Remove(tag); } } }
HttpRuntime.Cache.Add( sourceURL.ToString(), buffer, new TaggingCacheDependency(sourceURL.Host, sourceURL.Scheme), Cache.NoAbsoluteExpiration, TimeSpan.FromSeconds(600), CacheItemPriority.NotRemovable, Info);
TaggingCacheDependency.DependencyDispose("funp.com");