//-----------------------------------------------------------------------
//
// 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);
}
}
}