public async Task<bool> InsertRow(MembershipEntry entry, TableVersion tableVersion)
        {
            try
            {
                if (logger.IsEnabled(LogLevel.Debug)) logger.Debug("InsertRow entry = {0}", entry.ToFullString());
                var tableEntry = Convert(entry);

                bool result;

                try
                {
                    var expression = $"attribute_not_exists({SiloInstanceRecord.DEPLOYMENT_ID_PROPERTY_NAME}) AND attribute_not_exists({SiloInstanceRecord.SILO_IDENTITY_PROPERTY_NAME})";

                    await storage.PutEntryAsync(TABLE_NAME_DEFAULT_VALUE, tableEntry.GetFields(true), expression);
                    result = true;
                }
                catch (ConditionalCheckFailedException)
                {
                    result = false;
                    logger.Warn(ErrorCode.MembershipBase,
                        $"Insert failed due to contention on the table. Will retry. Entry {entry.ToFullString()}");
                }
                    
                return result;
            }
            catch (Exception exc)
            {
                logger.Warn(ErrorCode.MembershipBase,
                    $"Intermediate error inserting entry {entry.ToFullString()} to the table {TABLE_NAME_DEFAULT_VALUE}.", exc);
                throw;
            }
        }
        private async Task <bool> TryCreateTableVersionEntryAsync()
        {
            var keys = new Dictionary <string, AttributeValue>
            {
                { $"{SiloInstanceRecord.DEPLOYMENT_ID_PROPERTY_NAME}", new AttributeValue(this.clusterId) },
                { $"{SiloInstanceRecord.SILO_IDENTITY_PROPERTY_NAME}", new AttributeValue(SiloInstanceRecord.TABLE_VERSION_ROW) }
            };

            var versionRow = await storage.ReadSingleEntryAsync(this.options.TableName, keys, fields => new SiloInstanceRecord(fields));

            if (versionRow != null)
            {
                return(false);
            }

            if (!TryCreateTableVersionRecord(0, null, out var entry))
            {
                return(false);
            }

            var notExistConditionExpression =
                $"attribute_not_exists({SiloInstanceRecord.DEPLOYMENT_ID_PROPERTY_NAME}) AND attribute_not_exists({SiloInstanceRecord.SILO_IDENTITY_PROPERTY_NAME})";

            try
            {
                await storage.PutEntryAsync(this.options.TableName, entry.GetFields(true), notExistConditionExpression);
            }
            catch (ConditionalCheckFailedException)
            {
                return(false);
            }

            return(true);
        }
        /// <summary>
        /// Async method to put an entry into the remider table
        /// </summary>
        /// <param name="entry"> The entry to put </param>
        /// <returns> Return the entry ETag if entry was upsert successfully </returns>
        public async Task <string> UpsertRow(ReminderEntry entry)
        {
            var reminderId = ConstructReminderId(serviceId, entry.GrainRef, entry.ReminderName);

            var fields = new Dictionary <string, AttributeValue>
            {
                { REMINDER_ID_PROPERTY_NAME, new AttributeValue(reminderId) },
                { GRAIN_HASH_PROPERTY_NAME, new AttributeValue {
                      N = entry.GrainRef.GetUniformHashCode().ToString()
                  } },
                { SERVICE_ID_PROPERTY_NAME, new AttributeValue(serviceId.ToString()) },
                { GRAIN_REFERENCE_PROPERTY_NAME, new AttributeValue(entry.GrainRef.ToKeyString()) },
                { PERIOD_PROPERTY_NAME, new AttributeValue(entry.Period.ToString()) },
                { START_TIME_PROPERTY_NAME, new AttributeValue(entry.StartAt.ToString()) },
                { REMINDER_NAME_PROPERTY_NAME, new AttributeValue(entry.ReminderName) },
                { ETAG_PROPERTY_NAME, new AttributeValue {
                      N = random.Next(int.MaxValue).ToString()
                  } }
            };

            try
            {
                if (logger.IsEnabled(LogLevel.Debug))
                {
                    logger.Debug("UpsertRow entry = {0}, etag = {1}", entry.ToString(), entry.ETag);
                }

                await storage.PutEntryAsync(TABLE_NAME_DEFAULT_VALUE, fields);

                entry.ETag = fields[ETAG_PROPERTY_NAME].N;
                return(entry.ETag);
            }
            catch (Exception exc)
            {
                logger.Warn(ErrorCode.ReminderServiceBase,
                            $"Intermediate error updating entry {entry.ToString()} to the table {TABLE_NAME_DEFAULT_VALUE}.", exc);
                throw;
            }
        }
Exemple #4
0
        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();
        }