Exemplo n.º 1
0
        /// <summary>
        /// Read data entries and their corresponding eTags from the Azure table.
        /// </summary>
        /// <param name="filter">Filter string to use for querying the table and filtering the results.</param>
        /// <returns>Enumeration of entries in the table which match the query condition.</returns>
        public async Task <IEnumerable <Tuple <T, string> > > ReadTableEntriesAndEtagsAsync(string filter)
        {
            const string operation = "ReadTableEntriesAndEtags";
            var          startTime = DateTime.UtcNow;

            try
            {
                TableQuery <T> cloudTableQuery = filter == null
                    ? new TableQuery <T>()
                    : new TableQuery <T>().Where(filter);

                try
                {
                    Func <Task <List <T> > > executeQueryHandleContinuations = async() =>
                    {
                        TableQuerySegment <T> querySegment = null;
                        var list = new List <T>();
                        //ExecuteSegmentedAsync not supported in "WindowsAzure.Storage": "7.2.1" yet
                        while (querySegment == null || querySegment.ContinuationToken != null)
                        {
                            querySegment = await tableReference.ExecuteQuerySegmentedAsync(cloudTableQuery, querySegment?.ContinuationToken);

                            list.AddRange(querySegment);
                        }

                        return(list);
                    };

                    IBackoffProvider backoff = new FixedBackoff(AzureTableDefaultPolicies.PauseBetweenTableOperationRetries);

                    List <T> results = await AsyncExecutorWithRetries.ExecuteWithRetries(
                        counter => executeQueryHandleContinuations(),
                        AzureTableDefaultPolicies.MaxTableOperationRetries,
                        (exc, counter) => AzureStorageUtils.AnalyzeReadException(exc.GetBaseException(), counter, TableName, Logger),
                        AzureTableDefaultPolicies.TableOperationTimeout,
                        backoff);

                    // Data was read successfully if we got to here
                    return(results.Select(i => Tuple.Create(i, i.ETag)).ToList());
                }
                catch (Exception exc)
                {
                    // Out of retries...
                    var errorMsg = $"Failed to read Azure storage table {TableName}: {exc.Message}";
                    if (!AzureStorageUtils.TableStorageDataNotFound(exc))
                    {
                        Logger.Warn(ErrorCode.AzureTable_09, errorMsg, exc);
                    }
                    throw new OrleansException(errorMsg, exc);
                }
            }
            finally
            {
                CheckAlertSlowAccess(startTime, operation);
            }
        }
Exemplo n.º 2
0
        /// <summary>
        /// Read data entries and their corresponding eTags from the Azure table.
        /// </summary>
        /// <param name="predicate">Predicate function to use for querying the table and filtering the results.</param>
        /// <returns>Enumeration of entries in the table which match the query condition.</returns>
        internal async Task <IEnumerable <Tuple <T, string> > > ReadTableEntriesAndEtagsAsync(Expression <Func <T, bool> > predicate)
        {
            const string operation = "ReadTableEntriesAndEtags";
            var          startTime = DateTime.UtcNow;

            try
            {
                CloudTable     tableReference  = tableOperationsClient.GetTableReference(TableName);
                TableQuery <T> cloudTableQuery = tableReference.CreateQuery <T>().Where(predicate).AsTableQuery();
                try
                {
                    Func <Task <List <T> > > executeQueryHandleContinuations = async() =>
                    {
                        TableQuerySegment <T> querySegment = null;
                        var list = new List <T>();
                        while (querySegment == null || querySegment.ContinuationToken != null)
                        {
                            querySegment = await cloudTableQuery.ExecuteSegmentedAsync(querySegment != null?querySegment.ContinuationToken : null);

                            list.AddRange(querySegment);
                        }

                        return(list);
                    };

                    IBackoffProvider backoff = new FixedBackoff(AzureTableDefaultPolicies.PauseBetweenTableOperationRetries);

                    List <T> results = await AsyncExecutorWithRetries.ExecuteWithRetries(
                        counter => executeQueryHandleContinuations(),
                        AzureTableDefaultPolicies.MaxTableOperationRetries,
                        (exc, counter) => AzureStorageUtils.AnalyzeReadException(exc.GetBaseException(), counter, TableName, Logger),
                        AzureTableDefaultPolicies.TableOperationTimeout,
                        backoff);

                    // Data was read successfully if we got to here
                    return(results.Select((T i) => Tuple.Create(i, i.ETag)).ToList());
                }
                catch (Exception exc)
                {
                    // Out of retries...
                    var errorMsg = string.Format("Failed to read Azure storage table {0}: {1}", TableName, exc.Message);
                    if (!AzureStorageUtils.TableStorageDataNotFound(exc))
                    {
                        Logger.Warn(ErrorCode.AzureTable_09, errorMsg, exc);
                    }
                    throw new OrleansException(errorMsg, exc);
                }
            }
            finally
            {
                CheckAlertSlowAccess(startTime, operation);
            }
        }
Exemplo n.º 3
0
        /// <summary>
        /// Read a single table entry from the storage table.
        /// </summary>
        /// <param name="partitionKey">The partition key for the entry.</param>
        /// <param name="rowKey">The row key for the entry.</param>
        /// <returns>Value promise for tuple containing the data entry and its corresponding etag.</returns>
        public async Task <Tuple <T, string> > ReadSingleTableEntryAsync(string partitionKey, string rowKey)
        {
            const string operation = "ReadSingleTableEntryAsync";
            var          startTime = DateTime.UtcNow;

            if (Logger.IsVerbose2)
            {
                Logger.Verbose2("{0} table {1} partitionKey {2} rowKey = {3}", operation, TableName, partitionKey, rowKey);
            }
            T retrievedResult = default(T);

            try
            {
                try
                {
                    string queryString = TableQuery.CombineFilters(
                        TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, partitionKey),
                        TableOperators.And,
                        TableQuery.GenerateFilterCondition("RowKey", QueryComparisons.Equal, rowKey));
                    var query = new TableQuery <T>().Where(queryString);
                    TableQuerySegment <T> segment = await Task.Factory
                                                    .FromAsync <TableQuery <T>, TableContinuationToken, TableQuerySegment <T> >(
                        tableReference.BeginExecuteQuerySegmented,
                        tableReference.EndExecuteQuerySegmented <T>, query, null, null);

                    retrievedResult = segment.Results.SingleOrDefault();
                }
                catch (StorageException exception)
                {
                    if (!AzureStorageUtils.TableStorageDataNotFound(exception))
                    {
                        throw;
                    }
                }
                //The ETag of data is needed in further operations.
                if (retrievedResult != null)
                {
                    return(new Tuple <T, string>(retrievedResult, retrievedResult.ETag));
                }
                if (Logger.IsVerbose)
                {
                    Logger.Verbose("Could not find table entry for PartitionKey={0} RowKey={1}", partitionKey, rowKey);
                }
                return(null);  // No data
            }
            finally
            {
                CheckAlertSlowAccess(startTime, operation);
            }
        }
Exemplo n.º 4
0
        /// <summary>
        /// Read a single table entry from the storage table.
        /// </summary>
        /// <param name="partitionKey">The partition key for the entry.</param>
        /// <param name="rowKey">The row key for the entry.</param>
        /// <returns>Value promise for tuple containing the data entry and its corresponding etag.</returns>
        public async Task <Tuple <T, string> > ReadSingleTableEntryAsync(string partitionKey, string rowKey)
        {
            const string operation = "ReadSingleTableEntryAsync";
            var          startTime = DateTime.UtcNow;

            if (Logger.IsVerbose2)
            {
                Logger.Verbose2("{0} table {1} partitionKey {2} rowKey = {3}", operation, TableName, partitionKey, rowKey);
            }
            T retrievedResult = default(T);

            try
            {
                try
                {
                    string queryString            = TableQueryFilterBuilder.MatchPartitionKeyAndRowKeyFilter(partitionKey, rowKey);
                    var    query                  = new TableQuery <T>().Where(queryString);
                    TableQuerySegment <T> segment = await tableReference.ExecuteQuerySegmentedAsync(query, null);

                    retrievedResult = segment.Results.SingleOrDefault();
                }
                catch (StorageException exception)
                {
                    if (!AzureStorageUtils.TableStorageDataNotFound(exception))
                    {
                        throw;
                    }
                }
                //The ETag of data is needed in further operations.
                if (retrievedResult != null)
                {
                    return(new Tuple <T, string>(retrievedResult, retrievedResult.ETag));
                }
                if (Logger.IsVerbose)
                {
                    Logger.Verbose("Could not find table entry for PartitionKey={0} RowKey={1}", partitionKey, rowKey);
                }
                return(null);  // No data
            }
            finally
            {
                CheckAlertSlowAccess(startTime, operation);
            }
        }
Exemplo n.º 5
0
        /// <summary>
        /// Read data entries and their corresponding eTags from the Azure table.
        /// </summary>
        /// <param name="predicate">Predicate function to use for querying the table and filtering the results.</param>
        /// <returns>Enumeration of entries in the table which match the query condition.</returns>
        internal async Task <IEnumerable <Tuple <T, string> > > ReadTableEntriesAndEtagsAsync(Expression <Func <T, bool> > predicate)
        {
            const string operation = "ReadTableEntriesAndEtags";
            var          startTime = DateTime.UtcNow;

            try
            {
                TableServiceContext svc = tableOperationsClient.GetDataServiceContext();
                // Improve performance when table name differs from class name
                // http://www.gtrifonov.com/2011/06/15/improving-performance-for-windows-azure-tables/
                svc.ResolveType = ResolveEntityType;

                //IQueryable<T> query = svc.CreateQuery<T>(TableName).Where(predicate);
                CloudTableQuery <T> cloudTableQuery = svc.CreateQuery <T>(TableName).Where(predicate).AsTableServiceQuery(); // turn IQueryable into CloudTableQuery

                try
                {
                    Func <Task <List <T> > > executeQueryHandleContinuations = async() =>
                    {
                        // Read table with continuation token
                        // http://convective.wordpress.com/2013/11/03/queries-in-the-windows-azure-storage-client-library-v2-1/

                        // 1) First wrong sync way to read:
                        // List<T> queryResults = query.ToList(); // ToList will actually execute the query and add entities to svc. However, this will not handle continuation tokens.
                        // 2) Second correct sync way to read:
                        // http://convective.wordpress.com/2010/02/06/queries-in-azure-tables/
                        // CloudTableQuery.Execute will properly retrieve all the records from a table through the automatic handling of continuation tokens:
                        Task <ResultSegment <T> > firstSegmentPromise = Task <ResultSegment <T> > .Factory.FromAsync(
                            cloudTableQuery.BeginExecuteSegmented,
                            cloudTableQuery.EndExecuteSegmented,
                            null);

                        // 3) Third wrong async way to read:
                        // return firstSegmentPromise;
                        // 4) Forth correct async way to read - handles continuation tokens:

                        var list = new List <T>();

                        Task <ResultSegment <T> > nextSegmentAsync = firstSegmentPromise;
                        while (true)
                        {
                            ResultSegment <T> resultSegment = await nextSegmentAsync;
                            var capture = resultSegment.Results;
                            if (capture != null) // don't call Count or Any or anything else that can potentialy cause multiple evaluations of the IEnumerable
                            {
                                list.AddRange(capture);
                            }

                            if (!resultSegment.HasMoreResults)
                            {
                                // All data was read successfully if we got to here
                                break;
                            }

                            // ask to read the next segment
                            nextSegmentAsync = Task <ResultSegment <T> > .Factory.FromAsync(
                                resultSegment.BeginGetNext,
                                resultSegment.EndGetNext,
                                null);
                        }

                        return(list);
                    };

                    IBackoffProvider backoff = new FixedBackoff(AzureTableDefaultPolicies.PauseBetweenTableOperationRetries);

                    List <T> results = await AsyncExecutorWithRetries.ExecuteWithRetries(
                        counter => executeQueryHandleContinuations(),
                        AzureTableDefaultPolicies.MaxTableOperationRetries,
                        (exc, counter) => AzureStorageUtils.AnalyzeReadException(exc.GetBaseException(), counter, TableName, Logger),
                        AzureTableDefaultPolicies.TableOperationTimeout,
                        backoff);

                    // Data was read successfully if we got to here
                    return(PairEntitiesWithEtags(svc, results));
                }
                catch (Exception exc)
                {
                    // Out of retries...
                    var errorMsg = string.Format("Failed to read Azure storage table {0}: {1}", TableName, exc.Message);
                    if (!AzureStorageUtils.TableStorageDataNotFound(exc))
                    {
                        Logger.Warn(ErrorCode.AzureTable_09, errorMsg, exc);
                    }
                    throw new OrleansException(errorMsg, exc);
                }
            }
            finally
            {
                CheckAlertSlowAccess(startTime, operation);
            }
        }