public async Task <GrainStateRecord> Read(string partitionKey, string rowKey) { if (logger.IsVerbose3) { logger.Verbose3((int)ProviderErrorCode.AzureTableProvider_Storage_Reading, "Reading: PartitionKey={0} RowKey={1} from Table={2}", partitionKey, rowKey, TableName); } try { Tuple <GrainStateEntity, string> data = await tableManager.ReadSingleTableEntryAsync(partitionKey, rowKey); GrainStateEntity stateEntity = data.Item1; var record = new GrainStateRecord { Entity = stateEntity, ETag = data.Item2 }; if (logger.IsVerbose3) { logger.Verbose3((int)ProviderErrorCode.AzureTableProvider_Storage_DataRead, "Read: PartitionKey={0} RowKey={1} from Table={2} with ETag={3}", stateEntity.PartitionKey, stateEntity.RowKey, TableName, record.ETag); } return(record); } catch (Exception exc) { if (AzureStorageUtils.TableStorageDataNotFound(exc)) { if (logger.IsVerbose2) { logger.Verbose2((int)ProviderErrorCode.AzureTableProvider_DataNotFound, "DataNotFound reading: PartitionKey={0} RowKey={1} from Table={2} Exception={3}", partitionKey, rowKey, TableName, exc); } return(null); // No data } throw; } }
public async Task WriteStateAsync(string grainType, GrainReference grainReference, IGrainState grainState) { string id = GetKeyString(grainReference); try { var entity = new GrainStateEntity { ETag = grainState.ETag, Id = id, GrainType = grainType, State = grainState.State }; var spResponse = await ExecuteWithRetries(() => this._dbClient.ExecuteStoredProcedureAsync <string>( UriFactory.CreateStoredProcedureUri(this._options.DB, this._options.Collection, WRITE_STATE_SPROC), new RequestOptions { PartitionKey = new PartitionKey(grainType) }, entity)).ConfigureAwait(false); grainState.ETag = spResponse.Response; } catch (Exception exc) { this._logger.LogError(exc, $"Failure writing state for Grain Type {grainType} with Id {id}."); throw; } }
public async Task ClearStateAsync(string grainType, GrainReference grainReference, IGrainState grainState) { if (this._cosmos == null) { throw new ArgumentException("GrainState collection not initialized."); } string id = this.GetKeyString(grainReference); string partitionKey = await this.BuildPartitionKey(grainType, grainReference); if (this._logger.IsEnabled(LogLevel.Trace)) { this._logger.Trace( "Clearing: GrainType={0} Key={1} Grainid={2} ETag={3} DeleteStateOnClear={4} from Collection={4} with PartitionKey {5}", grainType, id, grainReference, grainState.ETag, this._options.DeleteStateOnClear, this._options.Collection, partitionKey); } var pk = new PartitionKey(partitionKey); var requestOptions = new ItemRequestOptions { IfMatchEtag = grainState.ETag }; try { if (this._options.DeleteStateOnClear) { if (string.IsNullOrWhiteSpace(grainState.ETag)) { return; //state not written } await ExecuteWithRetries(() => this._container.DeleteItemAsync <GrainStateEntity>( id, pk, requestOptions)); } else { var entity = new GrainStateEntity { ETag = grainState.ETag, Id = id, GrainType = grainType, State = null, PartitionKey = partitionKey }; var response = await ExecuteWithRetries(() => string.IsNullOrWhiteSpace(grainState.ETag)? this._container.CreateItemAsync(entity, pk) : this._container.ReplaceItemAsync(entity, entity.Id, pk, requestOptions)) .ConfigureAwait(false); grainState.ETag = response.Resource.ETag; } } catch (Exception exc) { this._logger.LogError(exc, $"Failure clearing state for Grain Type {grainType} with Id {id}."); throw; } }
public async Task Delete(GrainStateRecord record) { GrainStateEntity entity = record.Entity; if (logger.IsVerbose3) { logger.Verbose3((int)AzureProviderErrorCode.AzureTableProvider_Storage_Writing, "Deleting: PartitionKey={0} RowKey={1} from Table={2} with ETag={3}", entity.PartitionKey, entity.RowKey, TableName, record.ETag); } await tableManager.DeleteTableEntryAsync(entity, record.ETag); record.ETag = null; }
public async Task Write(GrainStateRecord record) { GrainStateEntity entity = record.Entity; if (logger.IsVerbose3) { logger.Verbose3((int)AzureProviderErrorCode.AzureTableProvider_Storage_Writing, "Writing: PartitionKey={0} RowKey={1} to Table={2} with ETag={3}", entity.PartitionKey, entity.RowKey, TableName, record.ETag); } string eTag = String.IsNullOrEmpty(record.ETag) ? await tableManager.CreateTableEntryAsync(record.Entity) : await tableManager.UpdateTableEntryAsync(entity, record.ETag); record.ETag = eTag; }
/// <summary> /// Deserialize from Azure storage format /// </summary> /// <param name="grainState">The grain state data to be deserialized in to</param> /// <param name="entity">The Azure table entity the stored data</param> internal void ConvertFromStorageFormat(GrainState grainState, GrainStateEntity entity) { Dictionary <string, object> dataValues = null; try { if (entity.Data != null) { // Rehydrate dataValues = SerializationManager.DeserializeFromByteArray <Dictionary <string, object> >(entity.Data); } else if (entity.StringData != null) { dataValues = Newtonsoft.Json.JsonConvert.DeserializeObject <Dictionary <string, object> >(entity.StringData, jsonSettings); } if (dataValues != null) { grainState.SetAll(dataValues); } // Else, no data found } catch (Exception exc) { var sb = new StringBuilder(); if (entity.Data != null) { sb.AppendFormat("Unable to convert from storage format GrainStateEntity.Data={0}", entity.Data); } else if (entity.StringData != null) { sb.AppendFormat("Unable to convert from storage format GrainStateEntity.StringData={0}", entity.StringData); } if (dataValues != null) { int i = 1; foreach (var dvKey in dataValues.Keys) { object dvValue = dataValues[dvKey]; sb.AppendLine(); sb.AppendFormat("Data #{0} Key={1} Value={2} Type={3}", i, dvKey, dvValue, dvValue.GetType()); i++; } } Log.Error(0, sb.ToString(), exc); throw new AggregateException(sb.ToString(), exc); } }
public async Task WriteStateAsync(string grainType, GrainReference grainReference, IGrainState grainState) { if (this._dbClient == null) { throw new ArgumentException("GrainState collection not initialized."); } string id = GetKeyString(grainReference); string partitionKey = await BuildPartitionKey(grainType, grainReference); if (this._logger.IsEnabled(LogLevel.Trace)) { this._logger.Trace( "Writing: GrainType={0} Key={1} Grainid={2} ETag={3} from Collection={4} with PartitionKey={5}", grainType, id, grainReference, grainState.ETag, this._options.Collection, partitionKey); } try { var entity = new GrainStateEntity { ETag = grainState.ETag, Id = id, GrainType = grainType, State = grainState.State, PartitionKey = partitionKey }; var entityString = JsonConvert.SerializeObject(entity, this._options.JsonSerializerSettings); var spResponse = await ExecuteWithRetries(() => this._dbClient.ExecuteStoredProcedureAsync <string>( UriFactory.CreateStoredProcedureUri(this._options.DB, this._options.Collection, WRITE_STATE_SPROC), new RequestOptions { PartitionKey = new PartitionKey(partitionKey) }, entityString)).ConfigureAwait(false); grainState.ETag = spResponse.Response; } catch (Exception exc) { this._logger.LogError(exc, $"Failure writing state for Grain Type {grainType} with Id {id}."); throw; } }
/// <summary> /// Serialize to Azure storage format in either binary or JSON format. /// </summary> /// <param name="grainState">The grain state data to be serialized</param> /// <param name="entity">The Azure table entity the data should be stored in</param> /// <remarks> /// See: /// http://msdn.microsoft.com/en-us/library/system.web.script.serialization.javascriptserializer.aspx /// for more on the JSON serializer. /// </remarks> internal void ConvertToStorageFormat(GrainState grainState, GrainStateEntity entity) { // Dehydrate var dataValues = grainState.AsDictionary(); int dataSize; if (useJsonFormat) { // http://james.newtonking.com/json/help/index.html?topic=html/T_Newtonsoft_Json_JsonConvert.htm string data = Newtonsoft.Json.JsonConvert.SerializeObject(dataValues, jsonSettings); if (Log.IsVerbose3) { Log.Verbose3("Writing JSON data size = {0} for grain id = Partition={1} / Row={2}", data.Length, entity.PartitionKey, entity.RowKey); } dataSize = data.Length; entity.StringData = data; } else { // Convert to binary format byte[] data = SerializationManager.SerializeToByteArray(dataValues); if (Log.IsVerbose3) { Log.Verbose3("Writing binary data size = {0} for grain id = Partition={1} / Row={2}", data.Length, entity.PartitionKey, entity.RowKey); } dataSize = data.Length; entity.Data = data; } if (dataSize > MAX_DATA_SIZE) { var msg = string.Format("Data too large to write to Azure table. Size={0} MaxSize={1}", dataSize, MAX_DATA_SIZE); Log.Error(0, msg); throw new ArgumentOutOfRangeException("GrainState.Size", msg); } }
/// <summary> Clear / Delete state data function for this storage provider. </summary> /// <remarks> /// If the <c>DeleteStateOnClear</c> is set to <c>true</c> then the table row /// for this grain will be deleted / removed, otherwise the table row will be /// cleared by overwriting with default / null values. /// </remarks> /// <see cref="IStorageProvider.ClearStateAsync"/> public async Task ClearStateAsync(string grainType, GrainReference grainReference, IGrainState grainState) { if (tableDataManager == null) { throw new ArgumentException("GrainState-Table property not initialized"); } string pk = GetKeyString(grainReference); if (Log.IsVerbose3) { Log.Verbose3((int)AzureProviderErrorCode.AzureTableProvider_WritingData, "Clearing: GrainType={0} Pk={1} Grainid={2} ETag={3} DeleteStateOnClear={4} from Table={5}", grainType, pk, grainReference, grainState.ETag, isDeleteStateOnClear, tableName); } var entity = new GrainStateEntity { PartitionKey = pk, RowKey = grainType }; var record = new GrainStateRecord { Entity = entity, ETag = grainState.ETag }; string operation = "Clearing"; try { if (isDeleteStateOnClear) { operation = "Deleting"; await tableDataManager.Delete(record).ConfigureAwait(false); } else { await tableDataManager.Write(record).ConfigureAwait(false); } grainState.ETag = record.ETag; // Update in-memory data to the new ETag } catch (Exception exc) { Log.Error((int)AzureProviderErrorCode.AzureTableProvider_DeleteError, string.Format("Error {0}: GrainType={1} Grainid={2} ETag={3} from Table={4} Exception={5}", operation, grainType, grainReference, grainState.ETag, tableName, exc.Message), exc); throw; } }
/// <summary> /// Deserialize from Azure storage format /// </summary> /// <param name="entity">The Azure table entity the stored data</param> internal object ConvertFromStorageFormat(GrainStateEntity entity) { object dataValue = null; try { if (entity.Data != null) { // Rehydrate dataValue = SerializationManager.DeserializeFromByteArray <object>(entity.Data); } else if (entity.StringData != null) { dataValue = Newtonsoft.Json.JsonConvert.DeserializeObject <object>(entity.StringData, jsonSettings); } // Else, no data found } catch (Exception exc) { var sb = new StringBuilder(); if (entity.Data != null) { sb.AppendFormat("Unable to convert from storage format GrainStateEntity.Data={0}", entity.Data); } else if (entity.StringData != null) { sb.AppendFormat("Unable to convert from storage format GrainStateEntity.StringData={0}", entity.StringData); } if (dataValue != null) { sb.AppendFormat("Data Value={0} Type={1}", dataValue, dataValue.GetType()); } Log.Error(0, sb.ToString(), exc); throw new AggregateException(sb.ToString(), exc); } return(dataValue); }
/// <summary> Write state data function for this storage provider. </summary> /// <see cref="IStorageProvider.WriteStateAsync"/> public async Task WriteStateAsync(string grainType, GrainReference grainReference, GrainState grainState) { if (tableDataManager == null) { throw new ArgumentException("GrainState-Table property not initialized"); } string pk = GetKeyString(grainReference); if (Log.IsVerbose3) { Log.Verbose3((int)AzureProviderErrorCode.AzureTableProvider_WritingData, "Writing: GrainType={0} Pk={1} Grainid={2} ETag={3} to Table={4}", grainType, pk, grainReference, grainState.Etag, tableName); } var entity = new GrainStateEntity { PartitionKey = pk, RowKey = grainType }; ConvertToStorageFormat(grainState, entity); var record = new GrainStateRecord { Entity = entity, ETag = grainState.Etag }; try { await tableDataManager.Write(record); grainState.Etag = record.ETag; } catch (Exception exc) { Log.Error((int)AzureProviderErrorCode.AzureTableProvider_WriteError, string.Format("Error Writing: GrainType={0} Grainid={1} ETag={2} to Table={3} Exception={4}", grainType, grainReference, grainState.Etag, tableName, exc.Message), exc); throw; } }
/// <summary> /// Deserialize from Azure storage format /// </summary> /// <param name="grainState">The grain state data to be deserialized in to</param> /// <param name="entity">The Azure table entity the stored data</param> internal void ConvertFromStorageFormat(IGrainState grainState, GrainStateEntity entity) { Dictionary<string, object> dataValues = null; try { if (entity.Data != null) { // Rehydrate dataValues = SerializationManager.DeserializeFromByteArray<Dictionary<string, object>>(entity.Data); } else if (entity.StringData != null) { dataValues = Newtonsoft.Json.JsonConvert.DeserializeObject<Dictionary<string, object>>(entity.StringData, jsonSettings); } if (dataValues != null) { grainState.SetAll(dataValues); } // Else, no data found } catch (Exception exc) { var sb = new StringBuilder(); if (entity.Data != null) { sb.AppendFormat("Unable to convert from storage format GrainStateEntity.Data={0}", entity.Data); } else if (entity.StringData != null) { sb.AppendFormat("Unable to convert from storage format GrainStateEntity.StringData={0}", entity.StringData); } if (dataValues != null) { int i = 1; foreach (var dvKey in dataValues.Keys) { object dvValue = dataValues[dvKey]; sb.AppendLine(); sb.AppendFormat("Data #{0} Key={1} Value={2} Type={3}", i, dvKey, dvValue, dvValue.GetType()); i++; } } Log.Error(0, sb.ToString(), exc); throw new AggregateException(sb.ToString(), exc); } }
/// <summary> /// Serialize to Azure storage format in either binary or JSON format. /// </summary> /// <param name="grainState">The grain state data to be serialized</param> /// <param name="entity">The Azure table entity the data should be stored in</param> /// <remarks> /// See: /// http://msdn.microsoft.com/en-us/library/system.web.script.serialization.javascriptserializer.aspx /// for more on the JSON serializer. /// </remarks> internal void ConvertToStorageFormat(IGrainState grainState, GrainStateEntity entity) { // Dehydrate var dataValues = grainState.AsDictionary(); int dataSize; if (useJsonFormat) { // http://james.newtonking.com/json/help/index.html?topic=html/T_Newtonsoft_Json_JsonConvert.htm string data = Newtonsoft.Json.JsonConvert.SerializeObject(dataValues, jsonSettings); if (Log.IsVerbose3) Log.Verbose3("Writing JSON data size = {0} for grain id = Partition={1} / Row={2}", data.Length, entity.PartitionKey, entity.RowKey); dataSize = data.Length; entity.StringData = data; } else { // Convert to binary format byte[] data = SerializationManager.SerializeToByteArray(dataValues); if (Log.IsVerbose3) Log.Verbose3("Writing binary data size = {0} for grain id = Partition={1} / Row={2}", data.Length, entity.PartitionKey, entity.RowKey); dataSize = data.Length; entity.Data = data; } if (dataSize > MAX_DATA_SIZE) { var msg = string.Format("Data too large to write to Azure table. Size={0} MaxSize={1}", dataSize, MAX_DATA_SIZE); Log.Error(0, msg); throw new ArgumentOutOfRangeException("GrainState.Size", msg); } }
/// <summary> Write state data function for this storage provider. </summary> /// <see cref="IStorageProvider.WriteStateAsync"/> public async Task WriteStateAsync(string grainType, GrainReference grainReference, IGrainState grainState) { if (tableDataManager == null) throw new ArgumentException("GrainState-Table property not initialized"); string pk = GetKeyString(grainReference); if (Log.IsVerbose3) Log.Verbose3((int)AzureProviderErrorCode.AzureTableProvider_WritingData, "Writing: GrainType={0} Pk={1} Grainid={2} ETag={3} to Table={4}", grainType, pk, grainReference, grainState.Etag, tableName); var entity = new GrainStateEntity { PartitionKey = pk, RowKey = grainType }; ConvertToStorageFormat(grainState, entity); var record = new GrainStateRecord { Entity = entity, ETag = grainState.Etag }; try { await tableDataManager.Write(record); grainState.Etag = record.ETag; } catch (Exception exc) { Log.Error((int)AzureProviderErrorCode.AzureTableProvider_WriteError, string.Format("Error Writing: GrainType={0} Grainid={1} ETag={2} to Table={3} Exception={4}", grainType, grainReference, grainState.Etag, tableName, exc.Message), exc); throw; } }
/// <summary> Clear / Delete state data function for this storage provider. </summary> /// <remarks> /// If the <c>DeleteStateOnClear</c> is set to <c>true</c> then the table row /// for this grain will be deleted / removed, otherwise the table row will be /// cleared by overwriting with default / null values. /// </remarks> /// <see cref="IStorageProvider.ClearStateAsync"/> public async Task ClearStateAsync(string grainType, GrainReference grainReference, IGrainState grainState) { if (tableDataManager == null) throw new ArgumentException("GrainState-Table property not initialized"); string pk = GetKeyString(grainReference); if (Log.IsVerbose3) Log.Verbose3((int)AzureProviderErrorCode.AzureTableProvider_WritingData, "Clearing: GrainType={0} Pk={1} Grainid={2} ETag={3} DeleteStateOnClear={4} from Table={5}", grainType, pk, grainReference, grainState.Etag, isDeleteStateOnClear, tableName); var entity = new GrainStateEntity { PartitionKey = pk, RowKey = grainType }; var record = new GrainStateRecord { Entity = entity, ETag = grainState.Etag }; string operation = "Clearing"; try { if (isDeleteStateOnClear) { operation = "Deleting"; await tableDataManager.Delete(record); } else { await tableDataManager.Write(record); } grainState.Etag = record.ETag; // Update in-memory data to the new ETag } catch (Exception exc) { Log.Error((int)AzureProviderErrorCode.AzureTableProvider_DeleteError, string.Format("Error {0}: GrainType={1} Grainid={2} ETag={3} from Table={4} Exception={5}", operation, grainType, grainReference, grainState.Etag, tableName, exc.Message), exc); throw; } }
public async Task WriteStateAsync(string grainType, GrainReference grainReference, IGrainState grainState) { if (this._cosmos == null) { throw new ArgumentException("GrainState collection not initialized."); } string id = this.GetKeyString(grainReference); string partitionKey = await this.BuildPartitionKey(grainType, grainReference); if (this._logger.IsEnabled(LogLevel.Trace)) { this._logger.Trace( "Writing: GrainType={0} Key={1} Grainid={2} ETag={3} from Collection={4} with PartitionKey={5}", grainType, id, grainReference, grainState.ETag, this._options.Collection, partitionKey); } ItemResponse <GrainStateEntity> response = null; try { var entity = new GrainStateEntity { ETag = grainState.ETag, Id = id, GrainType = grainType, State = grainState.State, PartitionKey = partitionKey }; if (string.IsNullOrWhiteSpace(grainState.ETag)) { response = await ExecuteWithRetries(() => this._container.CreateItemAsync( entity, new PartitionKey(partitionKey))).ConfigureAwait(false); grainState.ETag = response.Resource.ETag; } else { response = await ExecuteWithRetries(() => this._container.ReplaceItemAsync( entity, entity.Id, new PartitionKey(partitionKey), new ItemRequestOptions { IfMatchEtag = grainState.ETag })) .ConfigureAwait(false); grainState.ETag = response.Resource.ETag; } } catch (CosmosException dce) when(dce.StatusCode == HttpStatusCode.PreconditionFailed) { throw new CosmosConditionNotSatisfiedException(grainType, grainReference, this._options.Collection, "Unknown", grainState.ETag, dce); } catch (Exception exc) { this._logger.LogError(exc, $"Failure writing state for Grain Type {grainType} with Id {id}."); throw; } }
/// <summary> /// Deserialize from Azure storage format /// </summary> /// <param name="entity">The Azure table entity the stored data</param> internal object ConvertFromStorageFormat(GrainStateEntity entity) { object dataValue = null; try { if (entity.Data != null) { // Rehydrate dataValue = SerializationManager.DeserializeFromByteArray<object>(entity.Data); } else if (entity.StringData != null) { dataValue = Newtonsoft.Json.JsonConvert.DeserializeObject<object>(entity.StringData, jsonSettings); } // Else, no data found } catch (Exception exc) { var sb = new StringBuilder(); if (entity.Data != null) { sb.AppendFormat("Unable to convert from storage format GrainStateEntity.Data={0}", entity.Data); } else if (entity.StringData != null) { sb.AppendFormat("Unable to convert from storage format GrainStateEntity.StringData={0}", entity.StringData); } if (dataValue != null) { sb.AppendFormat("Data Value={0} Type={1}", dataValue, dataValue.GetType()); } Log.Error(0, sb.ToString(), exc); throw new AggregateException(sb.ToString(), exc); } return dataValue; }