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