/// <summary> /// Returns the orphaned transaction <see cref="Guid" />s discovered after /// <see cref="Open" /> returns <see cref="LogStatus.Recover" />. /// </summary> /// <returns>The list of transaction <see cref="Guid" />s.</returns> /// <exception cref="TransactionException">Thrown if the log is not open.</exception> /// <remarks> /// This method returns only the IDs for valid, non-corrupted transaction /// operation logs. It will delete any corrupted logs it finds. /// </remarks> public List <Guid> GetOrphanTransactions() { var orphans = new List <Guid>(); Guid id; using (TimedLock.Lock(syncLock)) { if (!isOpen) { throw new TransactionException(NotOpenMsg); } foreach (string file in Helper.GetFilesByPattern(folder + Helper.PathSepString + "*.log", SearchOption.AllDirectories)) { if (FileOperationLog.Validate(file, out id)) { orphans.Add(id); } else { try { File.Delete(file); } catch { // Ignore errors } } } return(orphans); } }
/// <summary> /// Opens the transaction log, returning a <see cref="LogStatus" /> /// value indicating the state of the transaction log. /// </summary> /// <param name="manager">The <see cref="TransactionManager" />.</param> /// <returns>The log's <see cref="LogStatus" /> code.</returns> /// <remarks> /// <para> /// This method will return <see cref="LogStatus.Ready" /> if the log is ready to /// begin handling transactions. /// </para> /// <para> /// <see cref="LogStatus.Recover" /> will be returned if the log was not /// closed properly (probably due to a system or application failure) and /// there are transactions that need to be recovered. The <see cref="TransactionManager" /> /// will call <see cref="GetOrphanTransactions" /> to get the <see cref="Guid" />s of /// the orphaned transactions and will then call <see cref="OpenOperationLog" /> /// to open each transaction operation log and then undo or redo the transaction /// operations depending on the state of the operation log. /// </para> /// <para> /// The method returns <see cref="LogStatus.Corrupt" /> if the transaction /// log is corrupt and that there's the potential for the resource to /// be in an inconsistent state after recovering the remaining transactions. /// </para> /// </remarks> /// <exception cref="TransactionException">Thrown if the log is already open.</exception> public LogStatus Open(TransactionManager manager) { bool orphans; Guid id; try { if (isOpen) { throw new TransactionException("Transaction log is already open."); } Helper.CreateFolderTree(folder); lockFile = new FileStream(folder + Helper.PathSepString + "transactions.lock", FileMode.Create, FileAccess.ReadWrite); orphans = false; foreach (var file in Helper.GetFilesByPattern(folder + Helper.PathSepString + "*.log", SearchOption.AllDirectories)) { orphans = true; if (!FileOperationLog.Validate(file, out id)) { return(LogStatus.Corrupt); } } isOpen = true; syncLock = manager.SyncRoot; return(orphans ? LogStatus.Recover : LogStatus.Ready); } catch { if (lockFile != null) { lockFile.Close(); lockFile = null; } throw; } }