public void BinaryData_Rollback() { string text = "Lorem ipsum..."; File file = new File(this.TestRoot); var bin = new BinaryData(); bin.FileName = "1.txt"; bin.SetStream(Tools.GetStreamFromString(text)); file.Binary = bin; file.Save(); int id = file.Id; file = Node.Load <File>(id); TransactionScope.Begin(); try { // Save binary file.Binary = null; file.Save(); } finally { // Rollback TransactionScope.Rollback(); } file = Node.Load <File>(id); Assert.IsNotNull(file.Binary, "#1"); Assert.IsTrue(file.Binary.Size > 0, "#2"); Assert.IsTrue(Tools.GetStreamString(file.Binary.GetStream()) == text, "#3"); }
/// <summary> /// Marks orphaned file records (the ones that do not have a referencing binary record anymore) as Deleted. /// </summary> public void CleanupFilesSetDeleteFlag() { var isLocalTransaction = false; if (!TransactionScope.IsActive) { TransactionScope.Begin(); isLocalTransaction = true; } try { using (var proc = new SqlProcedure { CommandText = CleanupFileSetIsdeletedScript, CommandType = CommandType.Text }) { proc.CommandType = CommandType.Text; proc.ExecuteNonQuery(); } if (isLocalTransaction && TransactionScope.IsActive) { TransactionScope.Commit(); } } catch (Exception ex) { if (isLocalTransaction && TransactionScope.IsActive) { TransactionScope.Rollback(); } throw new DataException("Error during setting deleted flag on files.", ex); } }
private static void RegisterSchema(SchemaEditor origSchema, SchemaEditor newSchema, SchemaWriter schemaWriter) { using (var op = SnTrace.Database.StartOperation("Write storage schema modifications.")) { // Ensure transaction encapsulation bool isLocalTransaction = !TransactionScope.IsActive; if (isLocalTransaction) { TransactionScope.Begin(); } try { List <PropertySet> modifiedPropertySets = new List <PropertySet>(); schemaWriter.Open(); WriteSchemaModifications(origSchema, newSchema, schemaWriter, modifiedPropertySets); foreach (PropertySet modifiedPropertySet in modifiedPropertySets) { NodeTypeDependency.FireChanged(modifiedPropertySet.Id); } schemaWriter.Close(); if (isLocalTransaction) { TransactionScope.Commit(); } ActiveSchema.Reset(); op.Successful = true; } catch (Exception ex) { SnLog.WriteException(ex, null, EventId.RepositoryRuntime); throw new SchemaEditorCommandException("Error during schema registration.", ex); } finally { IDisposable unmanagedWriter = schemaWriter as IDisposable; if (unmanagedWriter != null) { unmanagedWriter.Dispose(); } try { if (isLocalTransaction && TransactionScope.IsActive) { TransactionScope.Rollback(); } } catch (Exception ex2) { // This catch block will handle any errors that may have occurred // on the server that would cause the rollback to fail, such as // a closed connection (MSDN). const string msg = "Error during schema transaction rollback."; SnLog.WriteException(ex2, msg, EventId.RepositoryRuntime); throw new SchemaEditorCommandException(msg, ex2); } } } }
public void TransactionScope_IsActive() { Test(() => { TransactionScope.Begin(); Assert.AreEqual(true, TransactionScope.IsActive); TransactionScope.Rollback(); }); }
public void TransactionScope_IsolationLevel_ValueTest1() { Test(() => { TransactionScope.Begin(IsolationLevel.Serializable); Assert.AreEqual(IsolationLevel.Serializable, TransactionScope.IsolationLevel); TransactionScope.Rollback(); }); }
public void TransactionScope_IsolationLevel() { Test(() => { TransactionScope.Begin(); Assert.AreEqual(IsolationLevel.ReadCommitted, TransactionScope.IsolationLevel); TransactionScope.Rollback(); }); }
/// <summary> /// Finalizes a chunked save operation. /// </summary> /// <param name="versionId">Content version id.</param> /// <param name="propertyTypeId">Binary property type id.</param> /// <param name="fileId">File identifier.</param> /// <param name="fullSize">Full size (stream length) of the binary value.</param> /// <param name="source">Binary data containing metadata (e.g. content type).</param> public void CommitChunk(int versionId, int propertyTypeId, int fileId, long fullSize, BinaryDataValue source = null) { // start a new transaction here if needed var isLocalTransaction = !TransactionScope.IsActive; if (isLocalTransaction) { TransactionScope.Begin(); } try { // commit the process: set the final full size and checksum using (var cmd = new SqlProcedure { CommandText = CommitChunkScript, CommandType = CommandType.Text }) { cmd.Parameters.Add("@FileId", SqlDbType.Int).Value = fileId; cmd.Parameters.Add("@VersionId", SqlDbType.Int).Value = versionId; cmd.Parameters.Add("@PropertyTypeId", SqlDbType.Int).Value = propertyTypeId; cmd.Parameters.Add("@Size", SqlDbType.BigInt).Value = fullSize; cmd.Parameters.Add("@Checksum", SqlDbType.VarChar, 200).Value = DBNull.Value; cmd.Parameters.Add("@ContentType", SqlDbType.NVarChar, 50).Value = source != null ? source.ContentType : string.Empty; cmd.Parameters.Add("@FileNameWithoutExtension", SqlDbType.NVarChar, 450).Value = source != null ? source.FileName.FileNameWithoutExtension == null ? DBNull.Value : (object)source.FileName.FileNameWithoutExtension : DBNull.Value; cmd.Parameters.Add("@Extension", SqlDbType.NVarChar, 50).Value = source != null?ValidateExtension(source.FileName.Extension) : string.Empty; cmd.ExecuteNonQuery(); } } catch (Exception ex) { // rollback the transaction if it was opened locally if (isLocalTransaction && TransactionScope.IsActive) { TransactionScope.Rollback(); } throw new DataException("Error during committing binary chunk to file stream.", ex); } finally { // commit the transaction if it was opened locally if (isLocalTransaction && TransactionScope.IsActive) { TransactionScope.Commit(); } } }
public void TransactionScope_Begin_AlreadyActive() { try { TransactionScope.Begin(); TransactionScope.Begin(); } finally { TransactionScope.Rollback(); } }
/// <summary> /// Creates a new SnTransaction object and starts a db transaction if the /// TransactionScope is not yet active. Call this in a 'using' statement. /// </summary> /// <param name="isolationLevel">Transaction isolation level.</param> /// <param name="timeout">Timeout for the transaction.</param> /// <returns>A disposable SnTransaction object.</returns> public static SnTransaction Begin(IsolationLevel?isolationLevel = null, TimeSpan?timeout = null) { var tran = new SnTransaction { _isLocalTransaction = !TransactionScope.IsActive }; if (tran._isLocalTransaction) { TransactionScope.Begin( isolationLevel ?? IsolationLevel.ReadCommitted, timeout ?? TimeSpan.FromSeconds(Configuration.Data.TransactionTimeout)); } return(tran); }
public void TransactionScope_Commit_UseCase1() { string name = "CommitTest-" + Guid.NewGuid().ToString(); AddPathToDelete("/Root/" + name); TransactionScope.Begin(); var folder = new Folder(Repository.Root); folder.Name = name; folder.Save(); TransactionScope.Commit(); folder = (Folder)Node.LoadNode(folder.Id); Assert.IsNotNull(folder); Assert.AreEqual(name, folder.Name); }
public void TransactionScope_Commit_UseCase1() { Test(() => { var name = "CommitTest-1"; TransactionScope.Begin(); var folder = new Folder(Repository.Root); folder.Name = name; folder.Save(); TransactionScope.Commit(); folder = (Folder)Node.LoadNode(folder.Id); Assert.IsNotNull(folder); Assert.AreEqual(name, folder.Name); }); }
private void ExecuteScripts(List <StringBuilder> scripts) { using (var traceOperation = Logger.TraceOperation("Execute storage schema scripts.")) { // Ensure transaction encapsulation bool isLocalTransaction = !TransactionScope.IsActive; if (isLocalTransaction) { TransactionScope.Begin(); } try { if (_slotsToReset.Count > 0) { StringBuilder sb = new StringBuilder(); scripts.Insert(0, sb); WriteSlotsToResetScripts(sb, _slotsToReset); } foreach (StringBuilder script in scripts) { using (var proc = new SqlProcedure { CommandText = script.ToString(), CommandType = CommandType.Text }) { proc.ExecuteNonQuery(); } } if (isLocalTransaction) { TransactionScope.Commit(); } traceOperation.IsSuccessful = true; } finally { if (isLocalTransaction && TransactionScope.IsActive) { TransactionScope.Rollback(); } } } }
private static void RegisterSchema(SchemaEditor origSchema, SchemaEditor newSchema, SchemaWriter schemaWriter) { using (var traceOperation = Logger.TraceOperation("Write storage schema modifications.")) { // Ensure transaction encapsulation bool isLocalTransaction = !TransactionScope.IsActive; if (isLocalTransaction) { TransactionScope.Begin(); } try { List <PropertySet> modifiedPropertySets = new List <PropertySet>(); schemaWriter.Open(); WriteSchemaModifications(origSchema, newSchema, schemaWriter, modifiedPropertySets); foreach (PropertySet modifiedPropertySet in modifiedPropertySets) { NodeTypeDependency.FireChanged(modifiedPropertySet.Id); } schemaWriter.Close(); if (isLocalTransaction) { TransactionScope.Commit(); } ActiveSchema.Reset(); traceOperation.IsSuccessful = true; } finally { IDisposable unmanagedWriter = schemaWriter as IDisposable; if (unmanagedWriter != null) { unmanagedWriter.Dispose(); } if (isLocalTransaction && TransactionScope.IsActive) { TransactionScope.Rollback(); } } } }
//[TestMethod] public void TransactionScope_Rollback_UseCase1() { Test(() => { var name = "RollbackTest-1"; var folder = new Folder(Repository.Root); folder.Name = name; TransactionScope.Begin(); folder.Save(); int id = folder.Id; Assert.AreNotEqual(0, id); TransactionScope.Rollback(); Assert.AreEqual(0, folder.Id, "Node.Id must be set back to 0 after a rollback event."); folder = (Folder)Node.LoadNode(id); Assert.IsNull(folder); }); }
//[TestMethod()] public void TransactionScope_Rollback_UseCase1() { string name = "RollbackTest-" + Guid.NewGuid().ToString(); AddPathToDelete("/Root/" + name); var folder = new Folder(Repository.Root); folder.Name = name; TransactionScope.Begin(); folder.Save(); int id = folder.Id; Assert.AreNotEqual(0, id); TransactionScope.Rollback(); Assert.AreEqual(0, folder.Id, "Node.Id must be set back to 0 after a rollback event."); folder = (Folder)Node.LoadNode(id); Assert.IsNull(folder); }
public override int Read(byte[] buffer, int offset, int count) { if (buffer == null) { throw new ArgumentNullException(nameof(buffer)); } if (offset + count > buffer.Length) { throw new ArgumentException("Offset + count must not be greater than the buffer length."); } if (offset < 0) { throw new ArgumentOutOfRangeException(nameof(offset), "The offset must be greater than zero."); } if (count < 0) { throw new ArgumentOutOfRangeException(nameof(count), "The count must be greater than zero."); } // Calculate the maximum count of the bytes that can be read. // Return immediately if nothing to read. var maximumReadableByteCount = Length - Position; if (maximumReadableByteCount < 1) { return(0); } var isLocalTransaction = false; var realCount = (int)Math.Min(count, maximumReadableByteCount); if (CanInnerBufferHandleReadRequest(realCount)) { Array.Copy(_innerBuffer, Position - _innerBufferFirstPostion, buffer, offset, realCount); } else { if (!TransactionScope.IsActive) { // make sure we do not use an obsolete value FileStreamData = null; // Start a new transaction here to serve the needs of the SqlFileStream type. TransactionScope.Begin(); isLocalTransaction = true; } try { // Load transaction data for SqlFilestream. If this is not a local transaction, // than we will be able to use this data in the future if the client calls // the Read method multiple times and will not have to execute SQL queries // every time. var ctx = BlobStorageBase.GetBlobStorageContext(this.FileId); if (ctx != null) { if (ctx.Provider == BlobStorageBase.BuiltInProvider) { FileStreamData = ((SqlClient.BuiltinBlobProviderData)ctx.BlobProviderData).FileStreamData; } } if (FileStreamData == null) { throw new InvalidOperationException("Transaction data and file path could not be retrieved for SqlFilestream"); } using (var fs = new SqlFileStream(FileStreamData.Path, FileStreamData.TransactionContext, FileAccess.Read, FileOptions.SequentialScan, 0)) { fs.Seek(Position, SeekOrigin.Begin); _innerBuffer = null; var bytesRead = 0; var bytesStoredInInnerBuffer = 0; while (bytesRead < realCount) { var bytesToReadInThisIteration = (int)Math.Min(this.Length - Position - bytesRead, BlobStorage.BinaryChunkSize); var bytesToStoreInThisIteration = Math.Min(bytesToReadInThisIteration, realCount - bytesRead); var tempBuffer = new byte[bytesToReadInThisIteration]; // copy the bytes from the file stream to the temp buffer // (it is possible that we loaded a lot more bytes than the client requested) fs.Read(tempBuffer, 0, bytesToReadInThisIteration); // first iteration: create inner buffer for caching a part of the stream in memory if (_innerBuffer == null) { _innerBuffer = new byte[GetInnerBufferSize(realCount)]; _innerBufferFirstPostion = Position; } // store a fragment of the data in the inner buffer if possible if (bytesStoredInInnerBuffer < _innerBuffer.Length) { var bytesToStoreInInnerBuffer = Math.Min(bytesToReadInThisIteration, _innerBuffer.Length - bytesStoredInInnerBuffer); Array.Copy(tempBuffer, 0, _innerBuffer, bytesStoredInInnerBuffer, bytesToStoreInInnerBuffer); bytesStoredInInnerBuffer += bytesToStoreInInnerBuffer; } // copy the chunk from the temp buffer to the buffer of the caller Array.Copy(tempBuffer, 0, buffer, bytesRead, bytesToStoreInThisIteration); bytesRead += bytesToReadInThisIteration; } } } catch { // ReSharper disable once InvertIf if (isLocalTransaction && TransactionScope.IsActive) { TransactionScope.Rollback(); // cleanup isLocalTransaction = false; FileStreamData = null; } throw; } finally { if (isLocalTransaction && TransactionScope.IsActive) { TransactionScope.Commit(); // Set filestream data to null as this was a local transaction and we cannot use it anymore FileStreamData = null; } } } Position += realCount; return(realCount); }
/// <summary> /// Starts a chunked save operation on an existing content. It does not write any binary data /// to the storage, it only makes prerequisite operations - e.g. allocates a new slot in the storage. /// </summary> /// <param name="blobProvider">Blob storage provider.</param> /// <param name="versionId">Content version id.</param> /// <param name="propertyTypeId">Binary property type id.</param> /// <param name="fullSize">Full size (stream length) of the binary value.</param> /// <returns>A token containing all the information (db record ids) that identify a single entry in the blob storage.</returns> public string StartChunk(IBlobProvider blobProvider, int versionId, int propertyTypeId, long fullSize) { var isLocalTransaction = !TransactionScope.IsActive; if (isLocalTransaction) { TransactionScope.Begin(); } var ctx = new BlobStorageContext(blobProvider) { VersionId = versionId, PropertyTypeId = propertyTypeId, FileId = 0, Length = fullSize }; string blobProviderName = null; string blobProviderData = null; if (blobProvider != BlobStorageBase.BuiltInProvider) { blobProvider.Allocate(ctx); blobProviderName = blobProvider.GetType().FullName; blobProviderData = BlobStorageContext.SerializeBlobProviderData(ctx.BlobProviderData); } try { using (var cmd = new SqlProcedure { CommandText = InsertStagingBinaryScript, CommandType = CommandType.Text }) { cmd.Parameters.Add("@VersionId", SqlDbType.Int).Value = versionId; cmd.Parameters.Add("@PropertyTypeId", SqlDbType.Int).Value = propertyTypeId; cmd.Parameters.Add("@Size", SqlDbType.BigInt).Value = fullSize; cmd.Parameters.Add("@BlobProvider", SqlDbType.NVarChar, 450).Value = blobProviderName != null ? (object)blobProviderName : DBNull.Value; cmd.Parameters.Add("@BlobProviderData", SqlDbType.NVarChar, int.MaxValue).Value = blobProviderData != null ? (object)blobProviderData : DBNull.Value; int binaryPropertyId; int fileId; using (var reader = cmd.ExecuteReader()) { if (reader.Read()) { binaryPropertyId = reader.GetSafeInt32(0); fileId = reader.GetSafeInt32(1); } else { throw new DataException("File row could not be inserted."); } } ctx.FileId = fileId; return(new ChunkToken { VersionId = versionId, PropertyTypeId = propertyTypeId, BinaryPropertyId = binaryPropertyId, FileId = fileId }.GetToken()); } } catch (Exception ex) { if (isLocalTransaction && TransactionScope.IsActive) { TransactionScope.Rollback(); } throw new DataException("Error during saving binary chunk to SQL Server.", ex); } finally { if (isLocalTransaction && TransactionScope.IsActive) { TransactionScope.Commit(); } } }