/// <summary>
        /// Conditionally update the row for this entry, but only if the eTag matches with the current record in data store
        /// </summary>
        /// <param name="siloEntry">Silo Entry to be written</param>
        /// <param name="entryEtag">ETag value for the entry being updated</param>
        /// <param name="tableVersionEntry">Version row to update</param>
        /// <param name="versionEtag">ETag value for the version row</param>
        /// <returns></returns>
        internal async Task <bool> UpdateSiloEntryConditionally(SiloInstanceTableEntry siloEntry, string entryEtag, SiloInstanceTableEntry tableVersionEntry, string versionEtag)
        {
            try
            {
                await storage.UpdateTwoTableEntriesConditionallyAsync(siloEntry, entryEtag, tableVersionEntry, versionEtag);

                return(true);
            }
            catch (Exception exc)
            {
                HttpStatusCode httpStatusCode;
                string         restStatus;
                if (!AzureTableUtils.EvaluateException(exc, out httpStatusCode, out restStatus))
                {
                    throw;
                }

                if (logger.IsEnabled(LogLevel.Trace))
                {
                    logger.Trace("UpdateSiloEntryConditionally failed with httpStatusCode={0}, restStatus={1}", httpStatusCode, restStatus);
                }
                if (AzureTableUtils.IsContentionError(httpStatusCode))
                {
                    return(false);
                }

                throw;
            }
        }
Exemplo n.º 2
0
        public async Task AzureTableDataManager_UpdateTableEntryAsync()
        {
            var data = GenerateNewData();

            try
            {
                await manager.UpdateTableEntryAsync(data, AzureTableUtils.ANY_ETAG);

                Assert.True(false, "Should have thrown RequestFailedException.");
            }
            catch (RequestFailedException exc)
            {
                Assert.Equal((int)HttpStatusCode.NotFound, exc.Status);  // "Update before insert."
                HttpStatusCode httpStatusCode;
                string         restStatus;
                AzureTableUtils.EvaluateException(exc, out httpStatusCode, out restStatus, true);
                Assert.Equal(HttpStatusCode.NotFound, httpStatusCode);
                Assert.Equal(TableErrorCode.ResourceNotFound.ToString(), restStatus);
            }

            await manager.UpsertTableEntryAsync(data);

            var tuple = await manager.ReadSingleTableEntryAsync(data.PartitionKey, data.RowKey);

            Assert.Equal(data.StringData, tuple.Entity.StringData);

            var data2 = data.Clone();

            data2.StringData = "NewData";
            string eTag1 = await manager.UpdateTableEntryAsync(data2, AzureTableUtils.ANY_ETAG);

            tuple = await manager.ReadSingleTableEntryAsync(data2.PartitionKey, data2.RowKey);

            Assert.Equal(data2.StringData, tuple.Entity.StringData);

            var data3 = data.Clone();

            data3.StringData = "EvenNewerData";
            _ = await manager.UpdateTableEntryAsync(data3, eTag1);

            tuple = await manager.ReadSingleTableEntryAsync(data3.PartitionKey, data3.RowKey);

            Assert.Equal(data3.StringData, tuple.Entity.StringData);

            try
            {
                string eTag3 = await manager.UpdateTableEntryAsync(data3.Clone(), eTag1);

                Assert.True(false, "Should have thrown RequestFailedException.");
            }
            catch (RequestFailedException exc)
            {
                Assert.Equal((int)HttpStatusCode.PreconditionFailed, exc.Status);  // "Wrong eTag"
                HttpStatusCode httpStatusCode;
                string         restStatus;
                AzureTableUtils.EvaluateException(exc, out httpStatusCode, out restStatus, true);
                Assert.Equal(HttpStatusCode.PreconditionFailed, httpStatusCode);
                Assert.True(restStatus == TableErrorCode.UpdateConditionNotSatisfied.ToString());
            }
        }
Exemplo n.º 3
0
        internal async Task <bool> DeleteReminderEntryConditionally(ReminderTableEntry reminderEntry, string eTag)
        {
            try
            {
                await DeleteTableEntryAsync(reminderEntry, eTag);

                return(true);
            }catch (Exception exc)
            {
                HttpStatusCode httpStatusCode;
                string         restStatus;
                if (AzureTableUtils.EvaluateException(exc, out httpStatusCode, out restStatus))
                {
                    if (Logger.IsEnabled(LogLevel.Trace))
                    {
                        Logger.Trace("DeleteReminderEntryConditionally failed with httpStatusCode={0}, restStatus={1}", httpStatusCode, restStatus);
                    }
                    if (AzureTableUtils.IsContentionError(httpStatusCode))
                    {
                        return(false);
                    }
                }
                throw;
            }
        }
Exemplo n.º 4
0
        public async Task AzureTableDataManager_CreateTableEntryAsync()
        {
            var data = GenerateNewData();
            await manager.CreateTableEntryAsync(data);

            try
            {
                var data2 = data.Clone();
                data2.StringData = "NewData";
                await manager.CreateTableEntryAsync(data2);

                Assert.True(false, "Should have thrown RequestFailedException.");
            }
            catch (RequestFailedException exc)
            {
                Assert.Equal((int)HttpStatusCode.Conflict, exc.Status);  // "Creating an already existing entry."
                HttpStatusCode httpStatusCode;
                string         restStatus;
                AzureTableUtils.EvaluateException(exc, out httpStatusCode, out restStatus, true);
                Assert.Equal(HttpStatusCode.Conflict, httpStatusCode);
                Assert.Equal("EntityAlreadyExists", restStatus);
            }
            var tuple = await manager.ReadSingleTableEntryAsync(data.PartitionKey, data.RowKey);

            Assert.Equal(data.StringData, tuple.Entity.StringData);
        }
Exemplo n.º 5
0
        private async Task <bool> TryOperation(Func <Task> func, string operation = null)
        {
            try
            {
                await func().ConfigureAwait(false);

                return(true);
            }
            catch (Exception exc)
            {
                HttpStatusCode httpStatusCode;
                string         restStatus;
                if (!AzureTableUtils.EvaluateException(exc, out httpStatusCode, out restStatus))
                {
                    throw;
                }

                if (logger.IsEnabled(LogLevel.Trace))
                {
                    logger.Trace("{0} failed with httpStatusCode={1}, restStatus={2}", operation, httpStatusCode, restStatus);
                }
                if (AzureTableUtils.IsContentionError(httpStatusCode))
                {
                    return(false);
                }

                throw;
            }
        }
Exemplo n.º 6
0
        public async Task AzureTableDataManager_InsertTwoTableEntriesConditionallyAsync()
        {
            StorageEmulatorUtilities.EnsureEmulatorIsNotUsed();

            var data1 = GenerateNewData();
            var data2 = GenerateNewData();

            try
            {
                await manager.InsertTwoTableEntriesConditionallyAsync(data1, data2, AzureTableUtils.ANY_ETAG);
            }
            catch (RequestFailedException exc)
            {
                Assert.Equal((int)HttpStatusCode.NotFound, exc.Status);  // "Upadte item 2 before created it."
                HttpStatusCode httpStatusCode;
                string         restStatus;
                AzureTableUtils.EvaluateException(exc, out httpStatusCode, out restStatus, true);
                Assert.Equal(HttpStatusCode.NotFound, httpStatusCode);
                Assert.Equal(TableErrorCode.ResourceNotFound.ToString(), restStatus);
            }

            string etag = await manager.CreateTableEntryAsync(data2.Clone());

            var tuple = await manager.InsertTwoTableEntriesConditionallyAsync(data1, data2, etag);

            try
            {
                await manager.InsertTwoTableEntriesConditionallyAsync(data1.Clone(), data2.Clone(), tuple.Item2);

                Assert.True(false, "Should have thrown RequestFailedException.");
            }
            catch (RequestFailedException exc)
            {
                Assert.Equal((int)HttpStatusCode.Conflict, exc.Status);  // "Inserting an already existing item 1."
                HttpStatusCode httpStatusCode;
                string         restStatus;
                AzureTableUtils.EvaluateException(exc, out httpStatusCode, out restStatus, true);
                Assert.Equal(HttpStatusCode.Conflict, httpStatusCode);
                Assert.Equal("EntityAlreadyExists", restStatus);
            }

            try
            {
                await manager.InsertTwoTableEntriesConditionallyAsync(data1.Clone(), data2.Clone(), AzureTableUtils.ANY_ETAG);

                Assert.True(false, "Should have thrown RequestFailedException.");
            }
            catch (RequestFailedException exc)
            {
                Assert.Equal((int)HttpStatusCode.Conflict, exc.Status);  // "Inserting an already existing item 1 AND wring eTag"
                HttpStatusCode httpStatusCode;
                string         restStatus;
                AzureTableUtils.EvaluateException(exc, out httpStatusCode, out restStatus, true);
                Assert.Equal(HttpStatusCode.Conflict, httpStatusCode);
                Assert.Equal("EntityAlreadyExists", restStatus);
            };
        }
Exemplo n.º 7
0
        public async Task AzureTableDataManager_MergeTableAsync()
        {
            StorageEmulatorUtilities.EnsureEmulatorIsNotUsed();
            var data = GenerateNewData();

            try
            {
                await manager.MergeTableEntryAsync(data, AzureTableUtils.ANY_ETAG);

                Assert.True(false, "Should have thrown RequestFailedException.");
            }
            catch (RequestFailedException exc)
            {
                Assert.Equal((int)HttpStatusCode.NotFound, exc.Status);  // "Merge before create."
                HttpStatusCode httpStatusCode;
                string         restStatus;
                AzureTableUtils.EvaluateException(exc, out httpStatusCode, out restStatus, true);
                Assert.Equal(HttpStatusCode.NotFound, httpStatusCode);
                Assert.Equal(TableErrorCode.ResourceNotFound.ToString(), restStatus);
            }

            string eTag1 = await manager.UpsertTableEntryAsync(data);

            var data2 = data.Clone();

            data2.StringData = "NewData";
            await manager.MergeTableEntryAsync(data2, eTag1);

            try
            {
                await manager.MergeTableEntryAsync(data, eTag1);

                Assert.True(false, "Should have thrown RequestFailedException.");
            }
            catch (RequestFailedException exc)
            {
                Assert.Equal((int)HttpStatusCode.PreconditionFailed, exc.Status);  // "Wrong eTag."
                HttpStatusCode httpStatusCode;
                string         restStatus;
                AzureTableUtils.EvaluateException(exc, out httpStatusCode, out restStatus, true);
                Assert.Equal(HttpStatusCode.PreconditionFailed, httpStatusCode);
                Assert.True(restStatus == TableErrorCode.UpdateConditionNotSatisfied.ToString());
            }

            var tuple = await manager.ReadSingleTableEntryAsync(data.PartitionKey, data.RowKey);

            Assert.Equal("NewData", tuple.Entity.StringData);
        }
Exemplo n.º 8
0
        /// <summary>
        /// Inspect an exception returned from Azure storage libraries to check whether it means that attempt was made to read some data that does not exist in storage table.
        /// </summary>
        /// <param name="exc">Exception that was returned by Azure storage library operation</param>
        /// <returns><c>True</c> if this exception means the data being read was not present in Azure table storage</returns>
        public static bool TableStorageDataNotFound(Exception exc)
        {
            HttpStatusCode httpStatusCode;
            string         restStatus;

            if (AzureTableUtils.EvaluateException(exc, out httpStatusCode, out restStatus, true))
            {
                if (AzureTableUtils.IsNotFoundError(httpStatusCode)
                    /* New table: Azure table schema not yet initialized, so need to do first create */)
                {
                    return(true);
                }
                return(StorageErrorCodeStrings.ResourceNotFound.Equals(restStatus));
            }
            return(false);
        }
Exemplo n.º 9
0
        public async Task AzureTableDataManager_UpdateTwoTableEntriesConditionallyAsync()
        {
            StorageEmulatorUtilities.EnsureEmulatorIsNotUsed();

            var data1 = GenerateNewData();
            var data2 = GenerateNewData();

            try
            {
                await manager.UpdateTwoTableEntriesConditionallyAsync(data1, AzureTableUtils.ANY_ETAG, data2, AzureTableUtils.ANY_ETAG);

                Assert.True(false, "Update should have failed since the data has not been created yet");
            }
            catch (RequestFailedException exc)
            {
                Assert.Equal((int)HttpStatusCode.NotFound, exc.Status);  // "Update before insert."
                HttpStatusCode httpStatusCode;
                string         restStatus;
                AzureTableUtils.EvaluateException(exc, out httpStatusCode, out restStatus, true);
                Assert.Equal(HttpStatusCode.NotFound, httpStatusCode);
                Assert.Equal(TableErrorCode.ResourceNotFound.ToString(), restStatus);
            }

            string etag = await manager.CreateTableEntryAsync(data2.Clone());

            var tuple1 = await manager.InsertTwoTableEntriesConditionallyAsync(data1, data2, etag);

            _ = await manager.UpdateTwoTableEntriesConditionallyAsync(data1, tuple1.Item1, data2, tuple1.Item2);

            try
            {
                await manager.UpdateTwoTableEntriesConditionallyAsync(data1, tuple1.Item1, data2, tuple1.Item2);

                Assert.True(false, "Should have thrown RequestFailedException.");
            }
            catch (RequestFailedException exc)
            {
                Assert.Equal((int)HttpStatusCode.PreconditionFailed, exc.Status);  // "Wrong eTag"
                HttpStatusCode httpStatusCode;
                string         restStatus;
                AzureTableUtils.EvaluateException(exc, out httpStatusCode, out restStatus, true);
                Assert.Equal(HttpStatusCode.PreconditionFailed, httpStatusCode);
                Assert.True(restStatus == TableErrorCode.UpdateConditionNotSatisfied.ToString());
            }
        }
Exemplo n.º 10
0
        public async Task AzureTableDataManager_DeleteTableAsync()
        {
            var data = GenerateNewData();

            try
            {
                await manager.DeleteTableEntryAsync(data, AzureTableUtils.ANY_ETAG);

                Assert.True(false, "Should have thrown StorageException.");
            }
            catch (StorageException exc)
            {
                Assert.Equal((int)HttpStatusCode.NotFound, exc.RequestInformation.HttpStatusCode);  // "Delete before create."
                HttpStatusCode httpStatusCode;
                string         restStatus;
                AzureTableUtils.EvaluateException(exc, out httpStatusCode, out restStatus, true);
                Assert.Equal(HttpStatusCode.NotFound, httpStatusCode);
                Assert.Equal(StorageErrorCodeStrings.ResourceNotFound, restStatus);
            }

            string eTag1 = await manager.UpsertTableEntryAsync(data);

            await manager.DeleteTableEntryAsync(data, eTag1);

            try
            {
                await manager.DeleteTableEntryAsync(data, eTag1);

                Assert.True(false, "Should have thrown StorageException.");
            }
            catch (StorageException exc)
            {
                Assert.Equal((int)HttpStatusCode.NotFound, exc.RequestInformation.HttpStatusCode);  // "Deleting an already deleted item."
                HttpStatusCode httpStatusCode;
                string         restStatus;
                AzureTableUtils.EvaluateException(exc, out httpStatusCode, out restStatus, true);
                Assert.Equal(HttpStatusCode.NotFound, httpStatusCode);
                Assert.Equal(StorageErrorCodeStrings.ResourceNotFound, restStatus);
            }

            var tuple = await manager.ReadSingleTableEntryAsync(data.PartitionKey, data.RowKey);

            Assert.Null(tuple);
        }
Exemplo n.º 11
0
        private void CheckAlertWriteError(string operation, object data1, string data2, Exception exc)
        {
            HttpStatusCode httpStatusCode;

            if (AzureTableUtils.EvaluateException(exc, out httpStatusCode, out _) && AzureTableUtils.IsContentionError(httpStatusCode))
            {
                // log at Verbose, since failure on conditional is not not an error. Will analyze and warn later, if required.
                if (Logger.IsEnabled(LogLevel.Debug))
                {
                    Logger.Debug((int)Utilities.ErrorCode.AzureTable_13,
                                 $"Intermediate Azure table write error {operation} to table {TableName} data1 {(data1 ?? "null")} data2 {(data2 ?? "null")}", exc);
                }
            }
            else
            {
                Logger.Error((int)Utilities.ErrorCode.AzureTable_14,
                             $"Azure table access write error {operation} to table {TableName} entry {data1}", exc);
            }
        }
Exemplo n.º 12
0
        /// <summary>
        /// Insert (create new) row entry
        /// </summary>
        internal async Task <bool> TryCreateTableVersionEntryAsync()
        {
            try
            {
                var versionRow = await storage.ReadSingleTableEntryAsync(DeploymentId, SiloInstanceTableEntry.TABLE_VERSION_ROW);

                if (versionRow != null && versionRow.Item1 != null)
                {
                    return(false);
                }
                SiloInstanceTableEntry entry = CreateTableVersionEntry(0);
                await storage.CreateTableEntryAsync(entry);

                return(true);
            }
            catch (Exception exc)
            {
                HttpStatusCode httpStatusCode;
                string         restStatus;
                if (!AzureTableUtils.EvaluateException(exc, out httpStatusCode, out restStatus))
                {
                    throw;
                }

                if (logger.IsEnabled(LogLevel.Trace))
                {
                    logger.Trace("InsertSiloEntryConditionally failed with httpStatusCode={0}, restStatus={1}", httpStatusCode, restStatus);
                }
                if (AzureTableUtils.IsContentionError(httpStatusCode))
                {
                    return(false);
                }

                throw;
            }
        }
Exemplo n.º 13
0
 internal async Task <string> UpsertRow(ReminderTableEntry reminderEntry)
 {
     try
     {
         return(await UpsertTableEntryAsync(reminderEntry));
     }
     catch (Exception exc)
     {
         HttpStatusCode httpStatusCode;
         string         restStatus;
         if (AzureTableUtils.EvaluateException(exc, out httpStatusCode, out restStatus))
         {
             if (Logger.IsEnabled(LogLevel.Trace))
             {
                 Logger.Trace("UpsertRow failed with httpStatusCode={0}, restStatus={1}", httpStatusCode, restStatus);
             }
             if (AzureTableUtils.IsContentionError(httpStatusCode))
             {
                 return(null);                                                   // false;
             }
         }
         throw;
     }
 }
 /// <summary> Decodes Storage exceptions.</summary>
 public bool DecodeException(Exception e, out HttpStatusCode httpStatusCode, out string restStatus, bool getRESTErrors = false)
 {
     return(AzureTableUtils.EvaluateException(e, out httpStatusCode, out restStatus, getRESTErrors));
 }