void ITransactionNotification.TransactionCompleted(IFileSystemTransaction transaction, bool committed) { _log.Debug("LongSlaveTransactionManager notified"); Check.Require(_pendingTransaction != null); //do not want to dispose when notified by the transaction because it already knows it itself ScrapPendingTransaction(false);; }
/// <summary> /// Create transaction scope wrapping existing storage transaction. /// </summary> /// <param name="transactionToUse"> /// Transaction to wrap; may be null. /// </param> /// <param name="dispose"> /// Dispose underlying storage transaction at the end of the scope. /// </param> /// <returns> /// New scope. /// </returns> public IStorageTransactionScope CreateTransactionScope(IFileSystemTransaction transactionToUse, bool dispose) { CheckTransactionsSupported(); Check.DoAssertLambda(transactionToUse == null || transactionToUse is KtmTransaction, () => new ArgumentException("Unknown transaction type")); Check.DoAssertLambda(transactionToUse == null || transactionToUse.IsActive, () => new ArgumentException("The transaction is not active")); _log.Debug("Creating storage transaction scope from provided transaction"); return(KtmTransactionScope.Create((KtmTransaction)transactionToUse, dispose)); }
public TransactedFileSystemPath(IFileSystemTransaction transaction , IFileSystemTransactionLog transactionLog , IFileSystemPath path ) : base(path.FullPath) { this.transaction = transaction; this.transactionLog = transactionLog; }
/// <summary> /// Detach the underlying transaction from the context. This will ensure that the transaction will not be disposed /// but context handling will not change. /// </summary> /// <returns> /// <see cref="UnderlyingTransaction"/> /// </returns> /// <remarks> /// After detaching <see cref="UnderlyingTransaction"/> will return <see langword="null"/>. /// </remarks> /// <exception cref="InvalidOperationException"> /// <see cref="UnderlyingTransaction"/> is <see langword="null"/> /// </exception> public IFileSystemTransaction DetachTransaction() { Check.DoCheckOperationValid(_current != null, "No transaction to detach"); ToBeDisposed = false; IFileSystemTransaction retval = _current; _current = null; return(retval); }
/// <summary> /// Must not throw exceptions /// </summary> /// <param name="committed"> /// Whether transaction was committed successfully. /// </param> /// <remarks> /// Note that this method may be executed in a concurrent worker thread. /// </remarks> void ITransactionNotification.TransactionCompleted(IFileSystemTransaction transaction, bool committed) { if (committed) { DropUnsavedItems(); } if (_clearDirtyFlagWhenTransactionCompletes) { _dirty = false; } }
/// <summary> /// Default factory method /// </summary> /// <param name="repository"> /// The repository manager. /// </param> /// <param name="pendingTransaction"> /// Pending transaction to reuse if not <see langword="null"/>. /// </param> /// <returns> /// </returns> /// <remarks> /// The most common factory method creates scope catering for the current environment. If pending transaction is provided /// the method acts like <see cref="CreateWrapPending(IRepositoryManager, IFileSystemTransaction)"/>. Otherwise it will act /// as <see cref="StorageTransactionScope(IRepositoryManager, bool)"/>, using repository settings /// (<see cref="repository.Settings.StorageTransactionSettings"/>) to decide if and what kind of transaction to create. /// When wrapping existing pending transaction or when creating slave transaction the scope will be configured not to dispose /// transaction at the end of the scope. /// </remarks> public static StorageTransactionScope Create(IRepository repository, IFileSystemTransaction pendingTransaction) { if (pendingTransaction == null) { // see remarks return(new StorageTransactionScope(repository, false)); } else { return(CreateWrapPending(repository, pendingTransaction)); } }
/// <summary> /// Scrap pending transaction /// </summary> /// <param name="dispose"> /// Dispose it before throwing away /// </param> public void ScrapPendingTransaction(bool dispose) { IFileSystemTransaction pendingTransaction = _pendingTransaction; if (pendingTransaction != null) { if (dispose) { pendingTransaction.Dispose(); } _pendingTransaction = null; } }
/// <summary> /// Create scope which will not create its own transaction, but would only pick up existing ambient transaction. /// </summary> /// <param name="repository"> /// Repository /// </param> /// <param name="pendingTransaction"> /// Pending transaction to reuse if not <see langword="null"/>. /// </param> /// <returns> /// New transaction scope not owning a transaction. /// </returns> /// <remarks> /// /// </remarks> /// <exception cref="InvalidOperationException"> /// Current transactional context is inconsistent with the <paramref name="pendingTransaction"/>. /// </exception> /// <remarks> /// When <paramref name="pendingTransaction"/> is not null the ambient transaction must be: /// - null /// - equal to <paramref name="pendingTransaction"/> /// - belong to the same master transaction /// Otherwise the "always start new transaction" option must be ON (<see cref="IRepositoryManager.Settings.StorageTransactionSettings"/>). /// If top level scope is created lazy and it is not NULL scope then there is external transaction being used in repository. /// </remarks> public static StorageTransactionScope CreateLazy(IRepository repository, IFileSystemTransaction pendingTransaction) { StorageTransactionScope retval; if (pendingTransaction == null) { retval = new StorageTransactionScope(repository: repository, disposeIfSlave: false, okToStartOwnTransaction: false); // proxy may have to be a new transaction instance, but slave of an existing managed transaction Check.Ensure(!retval.IsTransactionOwner, "Lazy scope must not create and own a transaction, it can only be a proxy to an existing transaction."); } else { CheckContextForPendingTransaction(repository: repository, pendingTransaction: pendingTransaction); retval = Create(repository, pendingTransaction); Check.Ensure(pendingTransaction == retval.UnderlyingTransaction); } Check.Ensure(!retval.ToBeDisposed, "Lazy scope must not own or dispose underlying transaction"); return(retval); }
private static void CheckContextForPendingTransaction(IRepository repository, IFileSystemTransaction pendingTransaction) { Check.DoCheckOperationValid( GetAmbientTransaction(repository) == null || GetAmbientTransaction(repository) == pendingTransaction || IsAlwaysNewTransactionOptionOn(repository) || ( pendingTransaction.MasterTransaction != null && GetAmbientTransaction(repository).MasterTransaction == pendingTransaction.MasterTransaction ) , StorageResources.ContextInconsistentWithPendingTransaction); }
/// <summary> /// Factory method for scenario when you already have active transaction which you want to reuse and transaction to live outside /// the code block marked by the scope. /// </summary> /// <param name="repository"> /// The repository. /// </param> /// <param name="pendingTransaction"> /// Transaction to [re]use or null. /// </param> /// <returns> /// <see cref="StorageTransactionScope"/> /// </returns> /// <remarks> /// This is a factory method wrapping long living transaction. At the end of the scope transaction will not be /// committed or rolled back or disposed. The context will be changed only if the <paramref name="pendingTransaction"/> /// is not already ambient. At the end of the scope the context will be restored if it had been changed at the start. /// </remarks> public static StorageTransactionScope CreateWrapPending(IRepository repository, IFileSystemTransaction pendingTransaction) { CheckContextForPendingTransaction(repository: repository, pendingTransaction: pendingTransaction); return(new StorageTransactionScope(repository, pendingTransaction, false)); }
/// <summary> /// Create new instance wrapping the specified transaction instance. /// </summary> /// <param name="transactionToUse"> /// Transaction to wrap in the scope. If null, the scope will clear transaction context. /// </param> /// <param name="dispose"> /// Whether to dispose the <paramref name="transactionToUse"/> when the scope is disposed. /// </param> protected StorageTransactionScope(IRepository repository, IFileSystemTransaction transactionToUse, bool dispose) { Initialize( repository.ObjectFactory.FileSystemProvider.CreateTransactionScope(transactionToUse, dispose) , repository); }
public void TransactionCompleted(IFileSystemTransaction transaction, bool committed) { Console.WriteLine("TransactionSubscriber notified"); Interlocked.Increment(ref _timesNotified); _committed = committed; }
/// <summary> /// This method should cover all functionality of Txfs. /// </summary> /// <param name="tx"></param> private void Scenario(IFileSystemTransaction tx) { // Equality Assert.AreEqual(this.path.Child("testing.txt"), this.path.Child("testing.txt")); Assert.AreNotEqual(this.path.Child("testing.txt"), null); Assert.AreNotEqual(this.path.Child("testing.txt"), 425); Assert.AreEqual(this.path.FullPath.GetHashCode(), this.path.GetHashCode()); // Create directory. tx.Transact(this.path).CreateDirectory(); Assert.IsTrue(this.path.IsDirectory()); Assert.IsTrue(Directory.Exists(this.path.FullPath)); // Create sub-directory with non-existent parent. var nonExistentNestedSubDirectoryPath = this.path.Child("First").Child("Second"); tx.Transact(nonExistentNestedSubDirectoryPath).CreateDirectory(); Assert.IsTrue(nonExistentNestedSubDirectoryPath.IsDirectory()); Assert.IsTrue(Directory.Exists(nonExistentNestedSubDirectoryPath.FullPath)); // Write JSON file. var jsonFilePath = this.path.Child("Test.json"); tx.Transact(jsonFilePath).WriteJsonFile(new { Hello = "World" }); Assert.IsTrue(jsonFilePath.IsFile()); Assert.IsTrue(File.Exists(jsonFilePath.FullPath)); Assert.AreEqual("{\"Hello\":\"World\"}", jsonFilePath.ReadAllText()); tx.Transact(jsonFilePath).WriteJsonFile(42); Assert.AreEqual(42, jsonFilePath.ReadJsonFile <int>()); // Delete sub-directory. tx.Transact(nonExistentNestedSubDirectoryPath).DeleteDirectory(); Assert.IsFalse(nonExistentNestedSubDirectoryPath.IsDirectory()); Assert.IsFalse(Directory.Exists(nonExistentNestedSubDirectoryPath.FullPath)); Assert.IsTrue(nonExistentNestedSubDirectoryPath.Parent().IsDirectory()); Assert.IsTrue(Directory.Exists(nonExistentNestedSubDirectoryPath.Parent().FullPath)); // Flag file as created. File.WriteAllText(jsonFilePath.FullPath, "Hello world!"); tx.Transact(jsonFilePath).FlagFileCreated(); // Create directory from ZIP file. var zipFilePath = "testing.zip".AsFileSystemPath(); var testingPath = this.path.Child("testing"); tx.Transact(testingPath).CreateDirectoryFromZipFile(zipFilePath); Assert.IsTrue(testingPath.IsDirectory()); Assert.IsTrue(Directory.Exists(testingPath.FullPath)); Assert.AreEqual("Hello World", testingPath.Child("testing.txt").ReadAllText()); var files = testingPath.GetFiles(); Assert.AreEqual(1, files.Length); Assert.AreEqual("testing.txt", files[0].GetFileName()); Assert.AreEqual("testing", files[0].GetFileNameWithoutExtension()); Assert.AreEqual(".txt", files[0].GetExtension()); // Delete file. tx.Transact(jsonFilePath).DeleteFile(); Assert.IsFalse(jsonFilePath.IsFile()); Assert.IsFalse(File.Exists(jsonFilePath.FullPath)); // Attempt to read non-existent file. var exceptions = 0; try { jsonFilePath.ReadAllText(); } catch (FileNotFoundException) { exceptions++; } Assert.AreEqual(1, exceptions); // Get files from non-existent directory. try { nonExistentNestedSubDirectoryPath.GetFiles(); } catch (DirectoryNotFoundException) { exceptions++; } Assert.AreEqual(2, exceptions); }