On parle Windows, C#, Apple, Android, Js, …

Transactional NTFS (partie 1/2)

Transactional NTFS et DotNet

Microsoft introduit un concept intéressant à partir des versions de Windows Vista et Server 2008.
Cette nouveauté est appelée Transactional NTFS (TxF).
Elle permet aux développeurs d’écrire des fonctions d’Entrée/Sortie garantissant le succès complet ou le rejet complet en cas d’erreur d’un ensemble d’opérations.

Malheureusement il n’existe pas de classe DotNet(au moins jusqu’à la version 3.5 SP1) permettant de manipuler simplement ce type d’opérations.

Pour manipuler ces opérations, nous avons besoin de passer par le P/Invoke pour utiliser ces fonctions :

CreateTransaction, CommitTransaction, RollbackTransaction et DeleteFileTransacted

class Win32Native
{
   [StructLayout(LayoutKind.Sequential)]
   public struct SECURITY_ATTRIBUTES
   {
       int nLength;
       IntPtr lpSecurityDescriptor;
       int bInheritHandle;
   }

   [DllImport("ktmw32.dll", SetLastError = true, CharSet = CharSet.Auto)]
   public static extern SafeFileHandle CreateTransaction
     (SECURITY_ATTRIBUTES securityAttributes
      , IntPtr guid, int options, int isolationLevel, int isolationFlags, 
      int milliSeconds, string description);

   [DllImport("ktmw32.dll", SetLastError = true, CharSet = CharSet.Auto)]
   public static extern bool CommitTransaction(SafeFileHandle transaction);

   [DllImport("ktmw32.dll", SetLastError = true, CharSet = CharSet.Auto)]
   public static extern bool RollbackTransaction(SafeFileHandle transaction);

   [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
   public static extern bool DeleteFileTransacted
     (string filename, SafeFileHandle transaction);
}

Notez que j’utilise SafeFileHandle dans la signature des méthodes à la place de IntPtr pour les ancienne ressources non managées afin de garantir que les éléments seront bien libérés même si l’application doit s’arrêter.

L’étape suivante est la définition d’une classe permettant d’appeler simplement les fonctions déclarées.

 public class FileManager : IDisposable
{
   private bool _commited = false;
   private SafeFileHandle _tx = null;

   public FileManager()
   {
       _tx = Win32Native.CreateTransaction
         (new Win32Native.SECURITY_ATTRIBUTES(), IntPtr.Zero
         , 0, 0, 0, 0, null);
   }

   public bool DeleteFile(string filename)
   {
       return Win32Native.DeleteFileTransacted
         (filename, _tx);
   }

   public void Commit()
   {
       if (Win32Native.CommitTransaction(_tx))
           _commited = true;
   }

   private void Rollback()
   {
       Win32Native.RollbackTransaction(_tx);
   }

   protected virtual void Dispose(bool disposing)
   {
       if (disposing)
       {
           if (!_commited)
           {
               Rollback();
           }
       }
   }

   public void Dispose()
   {
       Dispose(true);
   }
}

Exemple avec la suppression de 2 fichiers

 

Supposons que nous devons supprimer automatiquement 2 fichiers. Les 2 fichiers doivent être supprimés en même temps. Si un des 2 fichiers ne peut pas être supprimé, les 2 fichiers doivent être conservés.

    using (FileManager manager = new FileManager())
    {
        manager.DeleteFile("file1.txt");
        Console.WriteLine("file1.txt is marked for deletion in current transaction. Press Enter...");
        Console.ReadLine();

        //throw new Exception("something very bad happens here");

        manager.DeleteFile("file2.txt");
        Console.WriteLine("file2.txt is marked for deletion in current transaction.");

        manager.Commit();
    }

La méthode DeleteFile marque le fichier pour la suppression dans le transaction courante, mais ne la supprimera uniquement si la méthode Commit est appelée.

Grâce à TFX et les transactions distribuées, les opérations sur les fichiers et les opérations SQL peuvent s’effectuer dans une même opération.

Dans la 2ème partie, nous verrons comment utiliser la fonction CreateFileTransacted pour traiter de façon unique la lecture et l’écriture d’un fichier.

Laissez un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.