public async Task <bool> UpdateRow(MembershipEntry entry, string etag, TableVersion tableVersion) { try { if (logger.IsEnabled(LogLevel.Debug)) { logger.Debug("UpdateRow entry = {0}, etag = {1}", entry.ToFullString(), etag); } var siloEntry = Convert(entry); int currentEtag = 0; if (!int.TryParse(etag, out currentEtag)) { logger.Warn(ErrorCode.MembershipBase, $"Update failed. Invalid ETag value. Will retry. Entry {entry.ToFullString()}, eTag {etag}"); return(false); } siloEntry.ETag = currentEtag + 1; bool result; try { var conditionalValues = new Dictionary <string, AttributeValue> { { CURRENT_ETAG_ALIAS, new AttributeValue { N = etag } } }; var etagConditionalExpression = $"{SiloInstanceRecord.ETAG_PROPERTY_NAME} = {CURRENT_ETAG_ALIAS}"; await storage.UpsertEntryAsync(TABLE_NAME_DEFAULT_VALUE, siloEntry.GetKeys(), siloEntry.GetFields(), etagConditionalExpression, conditionalValues); result = true; } catch (ConditionalCheckFailedException) { result = false; logger.Warn(ErrorCode.MembershipBase, $"Update failed due to contention on the table. Will retry. Entry {entry.ToFullString()}, eTag {etag}"); } return(result); } catch (Exception exc) { logger.Warn(ErrorCode.MembershipBase, $"Intermediate error updating entry {entry.ToFullString()} to the table {TABLE_NAME_DEFAULT_VALUE}.", exc); throw; } }
private async Task WriteStateInternal(IGrainState grainState, GrainStateRecord record, bool clear = false) { var fields = new Dictionary <string, AttributeValue>(); if (record.BinaryState != null && record.BinaryState.Length > 0) { fields.Add(BINARY_STATE_PROPERTY_NAME, new AttributeValue { B = new MemoryStream(record.BinaryState) }); } else if (!string.IsNullOrWhiteSpace(record.StringState)) { fields.Add(STRING_STATE_PROPERTY_NAME, new AttributeValue(record.StringState)); } int newEtag = 0; if (clear) { fields.Add(GRAIN_REFERENCE_PROPERTY_NAME, new AttributeValue(record.GrainReference)); fields.Add(GRAIN_TYPE_PROPERTY_NAME, new AttributeValue(record.GrainType)); int currentEtag = 0; int.TryParse(grainState.ETag, out currentEtag); newEtag = currentEtag; fields.Add(ETAG_PROPERTY_NAME, new AttributeValue { N = newEtag++.ToString() }); await storage.PutEntryAsync(tableName, fields).ConfigureAwait(false); } else if (string.IsNullOrWhiteSpace(grainState.ETag)) { fields.Add(GRAIN_REFERENCE_PROPERTY_NAME, new AttributeValue(record.GrainReference)); fields.Add(GRAIN_TYPE_PROPERTY_NAME, new AttributeValue(record.GrainType)); fields.Add(ETAG_PROPERTY_NAME, new AttributeValue { N = "0" }); var expression = $"attribute_not_exists({GRAIN_REFERENCE_PROPERTY_NAME}) AND attribute_not_exists({GRAIN_TYPE_PROPERTY_NAME})"; await storage.PutEntryAsync(tableName, fields, expression).ConfigureAwait(false); } else { var keys = new Dictionary <string, AttributeValue>(); keys.Add(GRAIN_REFERENCE_PROPERTY_NAME, new AttributeValue(record.GrainReference)); keys.Add(GRAIN_TYPE_PROPERTY_NAME, new AttributeValue(record.GrainType)); int currentEtag = 0; int.TryParse(grainState.ETag, out currentEtag); newEtag = currentEtag; newEtag++; fields.Add(ETAG_PROPERTY_NAME, new AttributeValue { N = newEtag.ToString() }); var conditionalValues = new Dictionary <string, AttributeValue> { { CURRENT_ETAG_ALIAS, new AttributeValue { N = currentEtag.ToString() } } }; var expression = $"{ETAG_PROPERTY_NAME} = {CURRENT_ETAG_ALIAS}"; await storage.UpsertEntryAsync(tableName, keys, fields, expression, conditionalValues).ConfigureAwait(false); } grainState.ETag = newEtag.ToString(); }