예제 #1
0
        /// <summary>
        /// Get object caching operation
        /// </summary>
        /// <param name="table">Store table</param>
        /// <param name="partitionKey">Partition key</param>
        /// <param name="key">Key for object or feed</param>
        /// <param name="cacheEntity">Cache entity</param>
        /// <param name="persistentEntity">Persistent store entity</param>
        /// <returns>Caching operation</returns>
        private Operation GetObjectCachingOperation(Table table, string partitionKey, string key, Entity cacheEntity, Entity persistentEntity)
        {
            Operation cachingOperation = null;

            if (cacheEntity != null && this.IsCacheEntityExpired(cacheEntity))
            {
                if (persistentEntity != null)
                {
                    if (table is ObjectTable)
                    {
                        cachingOperation                   = Operation.Replace(table as ObjectTable, partitionKey, key, persistentEntity as ObjectEntity);
                        cachingOperation.Entity.ETag       = cacheEntity.ETag;
                        cachingOperation.Entity.CustomETag = persistentEntity.ETag;
                    }
                    else if (table is FixedObjectTable)
                    {
                        cachingOperation                   = Operation.Replace(table as FixedObjectTable, partitionKey, key, persistentEntity as ObjectEntity);
                        cachingOperation.Entity.ETag       = cacheEntity.ETag;
                        cachingOperation.Entity.CustomETag = persistentEntity.ETag;
                    }
                }
                else
                {
                    if (table is ObjectTable)
                    {
                        ObjectEntity deleteEntity = new ObjectEntity();
                        deleteEntity.ETag = cacheEntity.ETag;
                        cachingOperation  = Operation.Delete(table as ObjectTable, partitionKey, key, deleteEntity);
                    }
                    else if (table is FixedObjectTable)
                    {
                        ObjectEntity deleteEntity = new ObjectEntity();
                        deleteEntity.ETag = cacheEntity.ETag;
                        cachingOperation  = Operation.Delete(table as FixedObjectTable, partitionKey, key, deleteEntity);
                    }
                }
            }
            else if (cacheEntity == null)
            {
                if (persistentEntity != null)
                {
                    if (table is ObjectTable)
                    {
                        cachingOperation = Operation.Insert(table as ObjectTable, partitionKey, key, persistentEntity as ObjectEntity);
                        cachingOperation.Entity.CustomETag = persistentEntity.ETag;
                    }
                    else if (table is FixedObjectTable)
                    {
                        cachingOperation = Operation.Insert(table as FixedObjectTable, partitionKey, key, persistentEntity as ObjectEntity);
                        cachingOperation.Entity.CustomETag = persistentEntity.ETag;
                    }
                }
            }

            return(cachingOperation);
        }
        /// <summary>
        /// Get rollback operation for store operation.
        /// The rollback operation typically deletes the invalid cache entity
        /// </summary>
        /// <param name="preOperation">Pre operation</param>
        /// <param name="preResult">Result of pre operation</param>
        /// <returns>Rollback operation</returns>
        private Operation GetRollbackOperation(Operation preOperation, Result preResult)
        {
            Table     table             = preOperation.Table;
            Operation rollbackOperation = null;

            if (table is ObjectTable)
            {
                ObjectEntity deleteEntity = new ObjectEntity();
                deleteEntity.ETag = preResult.ETag;
                rollbackOperation = Operation.Delete(preOperation.Table as ObjectTable, preOperation.PartitionKey, preOperation.Key, deleteEntity);
            }
            else if (table is FixedObjectTable)
            {
                ObjectEntity deleteEntity = new ObjectEntity();
                deleteEntity.ETag = preResult.ETag;
                rollbackOperation = Operation.Delete(preOperation.Table as FixedObjectTable, preOperation.PartitionKey, preOperation.Key, deleteEntity);
            }
            else if (table is FeedTable)
            {
                if (preResult.EntitiesAffected == 0)
                {
                    return(null);
                }

                // To rollback, we cannot delete the invalidated item in a feed.
                // This will violate the cache feed invariant.
                // The best we can do is to expire the item right away so that the next read can correct the cache.
                // Not the negative sign in the parameter.
                FeedEntity invalidEntity = this.GenerateInvalidCacheEntity <FeedEntity>(-this.config.CacheExpiryInSeconds);
                invalidEntity.ETag = preResult.ETag;
                rollbackOperation  = Operation.Replace(preOperation.Table as FeedTable, preOperation.PartitionKey, preOperation.Key, preOperation.ItemKey, invalidEntity);
            }
            else if (table is CountTable)
            {
                CountEntity deleteEntity = new CountEntity();
                deleteEntity.ETag = preResult.ETag;
                rollbackOperation = Operation.Delete(preOperation.Table as CountTable, preOperation.PartitionKey, preOperation.Key, deleteEntity);
            }

            if (rollbackOperation != null)
            {
                this.SetupCacheEntityETag(rollbackOperation);
            }

            return(rollbackOperation);
        }
        /// <summary>
        /// Get pre operation for a store operation in default mode.
        /// The pre operation is typically a cache invalidation operation.
        /// </summary>
        /// <param name="operation">Store operation</param>
        /// <returns>Pre operation for default mode</returns>
        private Operation GetPreOperation(Operation operation)
        {
            Table         table         = operation.Table;
            OperationType operationType = operation.OperationType;
            Operation     preOperation  = null;

            if (table is ObjectTable)
            {
                if (operationType != OperationType.Insert)
                {
                    ObjectEntity entity = this.GenerateInvalidCacheEntity <ObjectEntity>(this.config.CacheExpiryInSeconds);
                    preOperation = Operation.InsertOrReplace(table as ObjectTable, operation.PartitionKey, operation.Key, entity);
                }
            }
            else if (table is FixedObjectTable)
            {
                if (operationType != OperationType.Insert)
                {
                    ObjectEntity entity = this.GenerateInvalidCacheEntity <ObjectEntity>(this.config.CacheExpiryInSeconds);
                    preOperation = Operation.InsertOrReplace(table as FixedObjectTable, operation.PartitionKey, operation.Key, entity);
                }
            }
            else if (table is FeedTable)
            {
                FeedEntity entity = this.GenerateInvalidCacheEntity <FeedEntity>(this.config.CacheExpiryInSeconds);
                preOperation = Operation.InsertOrReplaceIfNotLast(table as FeedTable, operation.PartitionKey, operation.Key, operation.ItemKey, entity);
            }
            else if (table is CountTable)
            {
                if (operationType != OperationType.Insert)
                {
                    preOperation        = Operation.InsertOrReplace(table as CountTable, operation.PartitionKey, operation.Key, 0);
                    preOperation.Entity = this.GenerateInvalidCacheEntity <CountEntity>(this.config.CacheExpiryInSeconds);
                }
            }

            if (preOperation != null)
            {
                this.SetupCacheEntityETag(preOperation);
            }

            return(preOperation);
        }
        /// <summary>
        /// Get post operation for a store operation in default mode.
        /// The post operation typically makes the cache consistent with the store.
        /// There are exceptions: For merge operations, we simple delete the cache entry
        /// A read operation on the whole item should bring it back to the cache.
        /// </summary>
        /// <param name="operation">Store operation</param>
        /// <param name="preResult">Result of pre operation</param>
        /// <param name="result">Result of operations</param>
        /// <returns>Post operation</returns>
        private Operation GetPostOperation(Operation operation, Result preResult, Result result)
        {
            Table         table         = operation.Table;
            OperationType operationType = operation.OperationType;
            Entity        entity        = operation.Entity;
            Operation     postOperation = null;

            if (table is ObjectTable)
            {
                switch (operationType)
                {
                case OperationType.Insert:
                    postOperation = Operation.Insert(table as ObjectTable, operation.PartitionKey, operation.Key, entity as ObjectEntity);
                    postOperation.Entity.CustomETag = result.ETag;
                    return(postOperation);

                case OperationType.Replace:
                case OperationType.InsertOrReplace:
                    postOperation                   = Operation.Replace(table as ObjectTable, operation.PartitionKey, operation.Key, entity as ObjectEntity);
                    postOperation.Entity.ETag       = preResult.ETag;
                    postOperation.Entity.CustomETag = result.ETag;
                    return(postOperation);

                case OperationType.Delete:
                case OperationType.DeleteIfExists:
                case OperationType.Merge:
                case OperationType.InsertOrMerge:
                    ObjectEntity deleteEntity = new ObjectEntity();
                    deleteEntity.ETag = preResult.ETag;
                    return(Operation.Delete(table as ObjectTable, operation.PartitionKey, operation.Key, deleteEntity));
                }
            }
            else if (table is FixedObjectTable)
            {
                switch (operationType)
                {
                case OperationType.Insert:
                    postOperation = Operation.Insert(table as FixedObjectTable, operation.PartitionKey, operation.Key, entity as ObjectEntity);
                    postOperation.Entity.CustomETag = result.ETag;
                    return(postOperation);

                case OperationType.Replace:
                case OperationType.InsertOrReplace:
                    postOperation                   = Operation.Replace(table as FixedObjectTable, operation.PartitionKey, operation.Key, entity as ObjectEntity);
                    postOperation.Entity.ETag       = preResult.ETag;
                    postOperation.Entity.CustomETag = result.ETag;
                    return(postOperation);

                case OperationType.Delete:
                case OperationType.DeleteIfExists:
                    ObjectEntity deleteEntity = new ObjectEntity();
                    deleteEntity.ETag = preResult.ETag;
                    return(Operation.Delete(table as FixedObjectTable, operation.PartitionKey, operation.Key, deleteEntity));
                }
            }
            else if (table is FeedTable)
            {
                if (preResult.EntitiesAffected == 0)
                {
                    return(null);
                }

                switch (operationType)
                {
                case OperationType.Insert:
                case OperationType.Replace:
                case OperationType.InsertOrReplace:
                    postOperation                   = Operation.Replace(table as FeedTable, operation.PartitionKey, operation.Key, operation.ItemKey, entity as FeedEntity);
                    postOperation.Entity.ETag       = preResult.ETag;
                    postOperation.Entity.CustomETag = result.ETag;
                    return(postOperation);

                case OperationType.Delete:
                case OperationType.DeleteIfExists:
                    FeedEntity deleteEntity = new FeedEntity();
                    deleteEntity.ETag = preResult.ETag;
                    return(Operation.Delete(table as FeedTable, operation.PartitionKey, operation.Key, operation.ItemKey, deleteEntity));
                }
            }
            else if (table is CountTable)
            {
                switch (operationType)
                {
                case OperationType.Insert:
                    postOperation = Operation.Insert(table as CountTable, operation.PartitionKey, operation.Key, (entity as CountEntity).Count);
                    postOperation.Entity.CustomETag = result.ETag;
                    return(postOperation);

                case OperationType.Replace:
                case OperationType.InsertOrReplace:
                    postOperation                   = Operation.Replace(table as CountTable, operation.PartitionKey, operation.Key, entity as CountEntity);
                    postOperation.Entity.ETag       = preResult.ETag;
                    postOperation.Entity.CustomETag = result.ETag;
                    return(postOperation);

                case OperationType.Increment:
                case OperationType.InsertOrIncrement:
                    postOperation = Operation.Replace(table as CountTable, operation.PartitionKey, operation.Key, new CountEntity()
                    {
                        Count = (double)result.Value
                    });
                    postOperation.Entity.ETag       = preResult.ETag;
                    postOperation.Entity.CustomETag = result.ETag;
                    break;

                case OperationType.Delete:
                case OperationType.DeleteIfExists:
                    CountEntity deleteEntity = new CountEntity();
                    deleteEntity.ETag = preResult.ETag;
                    return(Operation.Delete(table as CountTable, operation.PartitionKey, operation.Key, deleteEntity));
                }
            }

            return(postOperation);
        }
예제 #5
0
 /// <summary>
 /// Insert operation on object table
 /// </summary>
 /// <param name="table">Object table</param>
 /// <param name="partitionKey">Partition key for entity</param>
 /// <param name="objectKey">Key for entity</param>
 /// <param name="entity">Object entity</param>
 /// <returns>Table operation</returns>
 public static Operation Insert(ObjectTable table, string partitionKey, string objectKey, ObjectEntity entity)
 {
     ValidateObjectTableParameters(table, partitionKey, objectKey, entity);
     return(new Operation()
     {
         Table = table,
         OperationType = OperationType.Insert,
         PartitionKey = partitionKey,
         Key = objectKey,
         Entity = entity.Clone()
     });
 }
예제 #6
0
 /// <summary>
 /// Validate object table parameters and throw exceptions
 /// </summary>
 /// <param name="table">Object table</param>
 /// <param name="partitionKey">Partition key</param>
 /// <param name="objectKey">Object key</param>
 /// <param name="entity">Object entity</param>
 private static void ValidateObjectTableParameters(Table table, string partitionKey, string objectKey, ObjectEntity entity)
 {
     ValidateObjectTableParameters(table, partitionKey, objectKey);
     if (entity == null)
     {
         throw new ArgumentNullException("Entity cannot be null");
     }
 }
예제 #7
0
 /// <summary>
 /// Delete operation on fixed object table
 /// </summary>
 /// <param name="table">Fixed object table</param>
 /// <param name="partitionKey">Partition key for entity</param>
 /// <param name="objectKey">Key for entity</param>
 /// <param name="entity">Object entity</param>
 /// <returns>Table operation</returns>
 public static Operation Delete(FixedObjectTable table, string partitionKey, string objectKey, ObjectEntity entity = null)
 {
     ValidateObjectTableParameters(table, partitionKey, objectKey);
     return(new Operation()
     {
         Table = table,
         OperationType = OperationType.Delete,
         PartitionKey = partitionKey,
         Key = objectKey,
         Entity = entity != null?entity.Clone() : null
     });
 }