Skip Navigation Links



Translate this page now :



»Programação
»Programação.NET
»Banco de Dados
»Webdesign
»Office
» Certificações Microsoft 4
»Treinamentos4
»Programação 4
»Webdesign«
»Office & User Tips«
»Grupos de UsuĆ”rios
»CĆ©lulas AcadĆŖmicas«
intcontpiada : 118
O melhor teclado da microsoft
Você já está cadastrado e participa do grupo de usuários de sua cidade ? Se não, comente o porque.
 
 
FaƧa um pequeno teste com 10 questƵes de VB
.:.
Teste seus conhecimentos em Visual Basic, SQL Server e ASP 3.0 com nossas provas on-line
.:.
Aprimore seus conhecimentos em programaĆ§Ć£o com nosso treinamento on-line de lĆ³gica de programaĆ§Ć£o
.:.
Veja nosso calendƔrio de treinamentos
Gostou da PƔgina?
Então

para um amigo!

Pesquisa personalizada
Pesquisar Dicas:

 






Manipulação de Disco Transacional com o Windows Vista

Introdução

Ainda não temos o WinFS, mas o Windows Vista nos trouxe recursos para fazermos a manipulação de disco de forma transacional.

Isso é um grande avanço, podermos envolver a manipulação de arquivos dentro de nossas transações de negócio.

O responsável por permitir isso no Windows Vista é o KTM - Kernel Transaction Manager. Ao contrário do que o nome diz, o KTM não roda apenas em Kernel Mode, este é apenas o nome das APIs para realizarem esta tarefa.

Ao invés de permitir que as APIs tradicionais de manipulação de arquivos atuem de forma transacional, o que foi feito no KTM foi duplicar as APIs. Ou seja : Tinhamos uma createFile agora temos também uma createFileTransacted e assim por diante.

Isso a principio faz com que as classes gerenciadas tradicionais para manipulação de arquivos não consigam aproveitar o recurso da manipulação de arquivos de forma transacional. Mas apenas a principio. Ocorre que um dos overloads da classe fileStream permite que já seja recebido o handle de um arquivo. Isso nos permite integrar o trabalho do KTM facilmente com as aplicações .NET, utilizando classes gerenciadas para a manipulação de arquivos.

 

Objetivo

Demonstrar que podemos utilizar facilmente as transações de disco no ambiente gerenciado fazendo uso de uma classe auxiliar para gerenciar tais transações, o que nos permite inclusive manter nossas aplicações compatíveis com outras versões do Windows, como o XP.

O KTM e as Transações

Existem 2 formas de lidarmos com as transações do KTM : Podemos abrir e fechar as transações diretamente com as API's do KTM ou podemos utilizar transações gerenciadas e incluir as manipulações do KTM dentro das transações gerenciadas.

1) KTM diretamente : É mais leve, porém mais complexo de ser utilizado e envolve código não habitual aos desenvolvedores.

Neste caso através das APIs temos a abertura de transação e o explicito controle do Commit e Rollback das transações, bem como somos os responsáveis por controlar o handle da transação.

2) Transações gerenciadas : Faz uso do System.Transactions, portanto é muito mais familiar aos desenvolvedores, que teoricamente tiveram tempo de se adaptar ao System.Transactions e ao pattern Using, porém é mais pesada pois como é característico do System.Transactions, faz uso do DTC e consequentemente comunicação inter-processos.

Neste caso a transação é criada pelo objeto TransactionScope. Nosso código precisa identificar o código da transação no DTC e fazer com que as operações do KTM participem da transação do DTC, sendo o TransactionScope o responsável pelo commit ou rollback da transação.

Neste artigo pretendo demonstrar que através do uso de uma classe auxiliar, podemos tornar o uso do KTM tão simples quanto o System.Transactions e com síntaxe semelhante, com a vantagem de ser mais leve. Mas não se antecipe, aguarde a conclusão final.

A classe auxiliar

A classe auxiliar, que chamei de DiscoTransacional, possui os seguintes tipos de elementos :

Elementos de instância : Para o uso do KTM, a classe precisa manter o handle da transação e controlar o commit ou rollback, inclusive dispensando o handle da transação após sua finalização, o que nos leva a implementar a interface IDisposable.

Elementos Shared : Para o uso de transações com o DTC, a classe apenas executa sua tarefa dentro de uma transação existente do DTC, não precisando manter informação a esse respeito, commit e rollback são controlados fora da classe

DLLImports e definições de tipos : Poderiam ficar até mesmo como privados, mas no exemplo foram mantidos públicos caso alguém aventure-se a utilizar as APIs diretamente.

Eventos : Os eventos podem ser utilizados para interceptar o commit ou rollback ou outros acontecimentos na classe DiscoTransacional

Utilizando uma transação do KTM

Para termos idéia do que estamos falando, veja o código para o uso de uma transação do KTM :

 

        Dim tx As IntPtr = DiscoTransacional.CreateTransaction(IntPtr.Zero, _

                                            IntPtr.Zero, 0, 0, 0, Nothing, Nothing)

 

        If DiscoTransacional.DeleteFileTransacted( _

"E:\Users\Dennes\Documents\Test.txt" _

, tx) Then

 

            If Confirmar() Then

                DiscoTransacional.CommitTransaction(tx)

            Else

                DiscoTransacional.RollbackTransaction(tx)

            End If

        Else

            DiscoTransacional.RollbackTransaction(tx)

        End If

        DiscoTransacional.CloseHandle(tx)

 

Neste exemplo foram utilizados os DLLImports e as definições de tipo da classe DiscoTransacional para demonstrar o que é o uso direto do KTM, acessando suas APIs

Utilizando uma transação simplificada do KTM

Agora, utilizando nossa classe DiscoTransacional, podemos utilizar o pattern using para garantir a finalização da transação.

Observe como o código abaixo fica semelhante a uma transação realizada com o TransactionScope.

 

        Using tr As New libTransacao.DiscoTransacional

            tr.AbrirTransacao()

            tr.DeletarArquivo("E:\Users\Dennes\Documents\Test.txt")

            If Confirmar() Then

                tr.Commit()

            End If

        End Using


Neste exemplo a classe DiscoTransacional encapsula toda a complexidade do KTM

1) Na criação da transação, o handle da transação é mantido dentro da classe

2) Ao executar a operação DeletarArquivo, o handle da transação é utilizado para chamar as APIs do KTM

3) Ao executar o commit, da mesma forma o handle da transação é utilizado para chamar o Commit do KTM

4) O pattern using garante que a instância de DiscoTransacional será destruida (levará dispose) no end using

5) A classe disco transacional implementa a interface Idisposable e, se a transação ainda estiver aberta no momento do dispose, faz Rollback utilizando o handle de transação que a classe ainda possui e, de uma forma ou de outra, fecha o handle da transação

Observe que utilizamos os membros de instância da classe DiscoTransacional

Utilizando uma transação com o DTC

Neste caso utilizamos o próprio TransactionScope para iniciar a transação. Fazemos uso dos métodos shared de nossa classe, DiscoTransacional. Esses métodos vão identificar a transação do DTC e fazer com que a execução da tarefa seja feita dentro da transação do DTC.

 

        Using tr As TransactionScope = New TransactionScope()

            libTransacao.DiscoTransacional.DeletarArquivoDTC _

("E:\Users\Dennes\Documents\Test.txt")

            If Confirmar() Then

                tr.Complete()

            End If

        End Using

Como a classe não precisa manter handle da transação e não é a responsável pelo commit nem rollback, neste exemplo utilizamos os membros shared da classe DiscoTransacional

É interessante observarmos o código de como o método DeletarArquivoDTC consegue fazer sua tarefa dentro da transação do DTC :

 

        If IsNothing(Transaction.Current) Then

            Throw New ApplicationException("Não existe transacao")

        End If

        Dim kt As IKernelTransaction

        Dim handle As IntPtr

        kt = TransactionInterop.GetDtcTransaction(Transaction.Current)

        kt.GetHandle(handle)

        DeleteFileTransacted(NomeArquivo, handle)

 

Compatibilidade com o ambiente do Windows XP

Verificar em qual sistema operacional estamos trabalhando para manter a compatibilidade com o Windows XP é uma necessidade fundamental da classe DiscoTransacional.

Mas a questão é : Que tipo de compatibilidade você deseja ?

Ignorar as operações transacionais

Neste caso simplesmente sinalizamos o fato de que as transações não são suportadas. Ainda assim a classe necessita devolver um handle de arquivo, para manter a compatibilidade com o código fora da classe.

Neste ponto os eventos surgem com seu papel essencial : Uma aplicação pode interceptar os eventos transacionais da classe disco transacional e, vendo que o sistema operacional não dará conta da transação, implementar por si só uma pattern de compensação transacional, ou seja, desfazer a tarefa que foi realizada.

Simular as operações transacionais no Windows XP

Pode-se criar uma herança da classe disco transacional para simular as operações transacionais no Windows XP. Neste caso mesmo as operações com DTC precisarão ser feitas a nível de instância, pois a classe precisará guardar as operações realizadas para uma possível compensação durante o rollback.

A Classe DiscoTransacional

 

Declarações públicas e DLLImports

   10     Public Const FILE_ATTRIBUTE_NORMAL = &H80
   11     Public Const GENERIC_READ = &H80000000
   12     Public Const GENERIC_WRITE = &H40000000
   13     Public Const CREATE_ALWAYS = 2
   14 
   15 #Region "Declarações shared"
   16 
   17 #Region "Transacao"
   18     'APIs para o controle transacional
   19 
   20     <DllImport("Kernel32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
   21         Public Shared Function CloseHandle(ByVal handle As IntPtr) As Boolean
   22     End Function
   23 
   24 
   25     <DllImport("Ktmw32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
   26     Public Shared Function CommitTransaction(ByVal transaction As IntPtr) _ 
                   As Boolean
   27     End Function
   28 
   29     <DllImport("Ktmw32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
   30     Public Shared Function RollbackTransaction(ByVal transaction As IntPtr) _ 
                     As Boolean
   31     End Function
   32 
   33     <DllImport("Ktmw32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
   34     Public Shared Function CreateTransaction( _
   35     ByVal securityAttributes As IntPtr, _
   36     ByVal guid As IntPtr, ByVal options As Int32, _ 
                  ByVal isolationLevel As Int32, _
                  ByVal isolationFlags As Int32, _
                  ByVal milliSeconds As Int32, ByVal description As String) _ 
                      As IntPtr
   37 
   38     End Function
   39 #End Region
   40 
   41 #Region "Declaracoes de APIs para arquivos"
   42     <DllImport("Kernel32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
   43 Public Shared Function DeleteFileTransacted(<MarshalAs(UnmanagedType.LPWStr)> _
          ByVal file As String, _
   44     ByVal transaction As IntPtr) As Boolean
   45     End Function
   46 
   47     <DllImport("Kernel32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
   48     Public Shared Function CreateFileTransacted( _
   49         <MarshalAs(UnmanagedType.LPWStr)> ByVal fileName As String, _
   50     ByVal fileAccess As Integer, _
   51     ByVal fileShare As Integer, _
   52     ByVal securityAttributes As IntPtr, _
   53     ByVal creationDisposition As Integer, _
   54     ByVal flags As Integer, _
   55     ByVal Template As IntPtr, _
   56     ByVal transaction As IntPtr, _
   57     ByVal miniVersion As IntPtr, _
   58     ByVal extendedOpenInformation As IntPtr) As _ 
             Microsoft.Win32.SafeHandles.SafeFileHandle
   59 
   60     End Function
   61 #End Region

 

Observem a declaração das APIs para abertura e fechamento da transação e para a manipulação de arquivos, sendo que para a manipulação de arquivos existem inúmeras outras API's, esta classe está apenas fazendo um exemplo com a CreateFileTransacted e DeleteFileTransacted.

 

Elementos de Instância

 

    7     Dim vIsTransacao As Boolean
    8     Dim tx As IntPtr

 

   99 #Region "Elementos de instância"
  100 
  101 #Region "Controle transacional na classe"
  102     Public Property IsTransacao() As Boolean
  103         Get
  104             Return vIsTransacao
  105         End Get
  106         Private Set(ByVal value As Boolean)
  107             vIsTransacao = value
  108         End Set
  109     End Property
  110 
  111     Public Sub AbrirTransacao()
  112         tx = CreateTransaction(IntPtr.Zero, IntPtr.Zero, _ 
                     0, 0, 0, Nothing, Nothing)
  113         IsTransacao = True
  114     End Sub
  115 
  116     Public Sub Commit()
  117         If IsTransacao Then
  118             CommitTransaction(tx)
  119         Else
  120             Throw New ApplicationException("Não existe transacao")
  121         End If
  122         CloseHandle(tx)
  123         IsTransacao = False
  124     End Sub
  125 
  126     Public Sub Rollback()
  127         If IsTransacao Then
  128             RollbackTransaction(tx)
  129         Else
  130             Throw New ApplicationException("Não existe transacao")
  131         End If
  132         CloseHandle(tx)
  133         IsTransacao = False
  134     End Sub
  135 
  136 #End Region
  137 
  138 
  139 #Region "Controle de arquivos na classe"
  140     Public Sub DeletarArquivo(ByVal NomeArquivo As String)
  141         DeleteFileTransacted(NomeArquivo, tx)
  142     End Sub
  143 
  144     Public Function CriarArquivo(ByVal nomearquivo As String) _
                   As Microsoft.Win32.SafeHandles.SafeFileHandle

  145         If Not IsTransacao Then
  146             Throw New _
                     ApplicationException( _ 
                     "Este método foi criado para ser usado em uma transacao")
  147         End If
  148         Dim fh As Microsoft.Win32.SafeHandles.SafeFileHandle = _
  149                CreateFileTransacted(nomearquivo, _
  150                GENERIC_READ Or GENERIC_WRITE, _
  151                0, _
  152                IntPtr.Zero, _
  153                CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, _
  154                IntPtr.Zero, tx, IntPtr.Zero, IntPtr.Zero)
  155 
  156         Return (fh)
  157     End Function
  158 #End Region
  159 #End Region

 

Os elementos de instância permitem o uso do KTM diretamente, planejados para serem utilizados junto com a clausula using, conforme exemplo anterior. Observe como o handle da transação é mantido como um atributo da instância, exigindo então a implementação do Dispose e padrão de finalização, que você vê a seguir :

 

  162 #Region "Suporte de finalização"
  163     Private disposedValue As Boolean = False   ' To detect redundant calls
  164 
  165     ' IDisposable
  166     Protected Overridable Sub Dispose(ByVal disposing As Boolean)
  167         If Not Me.disposedValue Then            
  168             If disposing Then
  169                 If IsTransacao Then
  170                     Rollback()
  171                 End If
  172             End If
  173         End If
  174         Me.disposedValue = True
  175     End Sub
  176 
  177 #Region " IDisposable Support "
  178     ' This code added by Visual Basic to correctly implement
          ' the disposable pattern.
  179     Public Sub Dispose() Implements IDisposable.Dispose
  180         ' Do not change this code.  Put cleanup code in 
              'Dispose(ByVal disposing As Boolean) above.
  181         Dispose(True)
  182         GC.SuppressFinalize(Me)
  183     End Sub
  184 #End Region
  185 
  186     Protected Overrides Sub finalize()
  187         If IsTransacao Then
  188             Rollback()
  189         End If
  190     End Sub
  191 #End Region

 

Elementos Shared

 

   63 #Region "Manipulacao com DTC"
   64     Public Shared Sub DeletarArquivoDTC(ByVal NomeArquivo As String)
   65         If IsNothing(Transaction.Current) Then
   66             Throw New ApplicationException("Não existe transacao")
   67         End If
   68         Dim kt As IKernelTransaction
   69         Dim handle As IntPtr
   70         kt = TransactionInterop.GetDtcTransaction(Transaction.Current)
   71         kt.GetHandle(handle)
   72         DeleteFileTransacted(NomeArquivo, handle)
   73     End Sub
   74 
   75     Public Shared Function CriarArquivoDTC(ByVal NomeArquivo As String) _
                         As Microsoft.Win32.SafeHandles.SafeFileHandle

   76         If IsNothing(Transaction.Current) Then
   77             Throw New ApplicationException("Não existe transacao")
   78         End If
   79         Dim kt As IKernelTransaction
   80         Dim handle As IntPtr
   81         kt = TransactionInterop.GetDtcTransaction(Transaction.Current)
   82         kt.GetHandle(handle)
   83 
   84         Dim fh As Microsoft.Win32.SafeHandles.SafeFileHandle = _
   85        CreateFileTransacted(NomeArquivo, _
   86        GENERIC_READ Or GENERIC_WRITE, _
   87        0, _
   88        IntPtr.Zero, _
   89        CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, _
   90        IntPtr.Zero, handle, IntPtr.Zero, IntPtr.Zero)
   91 
   92         Return (fh)
   93     End Function

 

Os elementos shared transferem a responsabilidade do controle transacional para o DTC, neste caso fazendo uso do System.Transactions confrome exemplo anterior. Observe como ambas as funções verificam a existência de uma transação atual e a utilizam para realizar a operação transacional. Para isso é utilizada uma interface chamada IKernelTransaction, que você vê a seguir :

 

  196 <ComImport(), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), _
  197 Guid("79427A2B-F895-40e0-BE79-B57DC82ED231")> _
  198 Friend Interface IKernelTransaction
  199     Sub GetHandle(ByRef handle As IntPtr)

 

 

Conclusão

Através do encapsulamento proporcionado pela orientação a objetos utilizar o KTM pode ficar tão simples quanto utilizar as transações do DTC. Isso nos incentiva a um maior uso do KTM, por ser mais leve que o DTC. O DTC por sua vez pode ser relegado a papeis mais importantes, quando, por exemplo, houverem recursos de banco e disco envolvidos em um mesmo processo transacional.

O encapsulamento, da mesma forma, pode garantir a compatibilidade da aplicação entre o Windows XP e o Windows Vista sem que isso tenha um grande impacto na equipe e no processo de desenvolvimento.

 

 





Envie seus comentįrios sobre este artigo

Nome :

E-mail :

Comentários :


Avise-me quando houverem novos comentįrios nesta pįgina

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
Conheça mais sobre o nosso site :

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::



Quer saber mais?
Faça um curso na Búfalo Informática, Treinamento e Consultoria e
Prepare-se para o Mercado!
Veja o que a Búfalo tem para você.

ļæ½ BĆŗfalo InformĆ”tica, Treinamento e Consultoria - Rua Ɓlvaro Alvim, 37 Sala 920 - CinelĆ¢ndia - Rio de Janeiro / RJ
Tel.: (21)2262-1368 (21) 9240-5134 (21) 9240-7281 e-Mail:
contato@bufaloinfo.com.br