//----------------------------------------------------------------------- // // Copyright (c) Microsoft. All rights reserved. // // // Implements class Transaction. // //----------------------------------------------------------------------- namespace Microsoft.CTStore { using System; using System.Collections.Generic; /// /// Transaction class /// public class Transaction { /// /// Container name for the transaction /// private string containerName; /// /// Partition key for transaction /// private string partitionKey; /// /// Transaction operations /// private List operations; /// /// Cache only operations in the transaction /// private List cacheOnlyOperations; /// /// Persistent only operations in the transaction /// private List persistentOnlyOperations; /// /// Default operations in the transaction /// private List defaultOperations; /// /// Indices of default operations in the list of operations /// private List defaultOperationIndices; /// /// Entity keys (container name + table name + partition key + key + [Item key]) for operations in the transaction. /// This hash set is used to check if there is more than one operation with the same entity. /// Only one operation is allowed per entity in a transaction. /// private HashSet entityKeys; /// /// Initializes a new instance of the class /// public Transaction() { this.operations = new List(); this.cacheOnlyOperations = new List(); this.persistentOnlyOperations = new List(); this.defaultOperations = new List(); this.defaultOperationIndices = new List(); this.entityKeys = new HashSet(); } /// /// Initializes a new instance of the class /// /// List of operations public Transaction(List operations) : this() { foreach (Operation operation in operations) { this.Add(operation); } } /// /// Gets transaction operations /// public List Operations { get { return this.operations; } } /// /// Gets cache-only operations in transaction /// public List CacheOnlyOperations { get { return this.cacheOnlyOperations; } } /// /// Gets persistent-only operations in transaction /// public List PersistentOnlyOperations { get { return this.persistentOnlyOperations; } } /// /// Gets default operations in transaction /// public List DefaultOperations { get { return this.defaultOperations; } } /// /// Gets default operation indices in transaction /// public List DefaultOperationIndices { get { return this.defaultOperationIndices; } } /// /// Gets container name for the transaction /// public string ContainerName { get { return this.containerName; } } /// /// Gets partition key for the transaction /// public string PartitionKey { get { return this.partitionKey; } } /// /// Add operation to transaction /// /// Table operation public void Add(Operation operation) { if (this.containerName == null) { this.containerName = operation.Table.ContainerName; this.partitionKey = operation.PartitionKey; } else { if (!this.containerName.Equals(operation.Table.ContainerName)) { throw new ArgumentException("All operations in a transaction should be in the same container."); } if (this.partitionKey != operation.PartitionKey) { throw new ArgumentException("All operations in a transaction should have the same partition key."); } } string entityKey = this.GetEntityKey(operation); if (!this.entityKeys.Contains(entityKey)) { this.entityKeys.Add(entityKey); } else { throw new ArgumentException("An entity can appear only once in the transaction."); } // A transaction can either have all CacheOnly operations or no CacheOnly operation // CacheOnly operation cannot be combined with non-CacheOnly operations if ((operation.Table.StorageMode == StorageMode.CacheOnly && (this.operations.Count - this.cacheOnlyOperations.Count > 0)) || (operation.Table.StorageMode != StorageMode.CacheOnly && this.cacheOnlyOperations.Count > 0)) { throw new ArgumentException("CacheOnly operations cannot be combined with non-CacheOnly operations in a transaction."); } if (operation.Table.StorageMode == StorageMode.CacheOnly) { this.cacheOnlyOperations.Add(operation); } else if (operation.Table.StorageMode == StorageMode.PersistentOnly) { this.persistentOnlyOperations.Add(operation); } else if (operation.Table.StorageMode == StorageMode.Default) { this.defaultOperations.Add(operation); this.defaultOperationIndices.Add(this.operations.Count); } this.operations.Add(operation); } /// /// Get unique key for the entity the operation is operating on /// /// Store operation /// Unique entity key private string GetEntityKey(Operation operation) { return string.Join( ":", operation.Table.ContainerName, operation.Table.TableName, operation.PartitionKey, operation.Key, operation.ItemKey); } } }