/// <summary> Write state data function for this storage provider.</summary>
        /// <see cref="IStorageProvider.WriteStateAsync"/>
        public async Task WriteStateAsync(string grainType, GrainReference grainReference, IGrainState grainState)
        {
            //It assumed these parameters are always valid. If not, an exception will be thrown, even if not as clear
            //as with explicitly checked parameters.
            var data          = grainState.State;
            var grainId       = GrainIdAndExtensionAsString(grainReference);
            var baseGrainType = ExtractBaseClass(grainType);

            if (Log.IsVerbose3)
            {
                Log.Verbose3((int)RelationalStorageProviderCodes.RelationalProviderWriting, LogString("Writing grain state", ServiceId, Name, grainState.ETag, baseGrainType, grainId.ToString()));
            }

            string storageVersion = null;

            try
            {
                var writeRecord = await Storage.ReadAsync(CurrentOperationalQueries.WriteToStorage, command =>
                {
                    command.AddParameter("GrainIdHash", HashPicker.PickHasher(ServiceId, Name, baseGrainType, grainReference, grainState).Hash(grainId.GetHashBytes()));
                    command.AddParameter("GrainIdN0", grainId.N0Key);
                    command.AddParameter("GrainIdN1", grainId.N1Key);
                    command.AddParameter("GrainTypeHash", HashPicker.PickHasher(ServiceId, Name, baseGrainType, grainReference, grainState).Hash(Encoding.UTF8.GetBytes(baseGrainType)));
                    command.AddParameter("GrainTypeString", (string)baseGrainType);
                    command.AddParameter("GrainIdExtensionString", grainId.StringKey);
                    command.AddParameter("ServiceId", ServiceId);
                    command.AddParameter("GrainStateVersion", !string.IsNullOrWhiteSpace(grainState.ETag) ? int.Parse(grainState.ETag, CultureInfo.InvariantCulture) : default(int?));

                    SerializationChoice serializer = StorageSerializationPicker.PickSerializer(ServiceId, Name, (string)baseGrainType, grainReference, grainState);
                    command.AddParameter("PayloadBinary", (byte[])(serializer.Serializer.Tag == UseBinaryFormatPropertyName ? serializer.Serializer.Serialize(data) : null));
                    command.AddParameter("PayloadJson", (string)(serializer.Serializer.Tag == UseJsonFormatPropertyName ? serializer.Serializer.Serialize(data) : null));
                    command.AddParameter("PayloadXml", (string)(serializer.Serializer.Tag == UseXmlFormatPropertyName ? serializer.Serializer.Serialize(data) : null));
                }, (selector, resultSetCount, token) =>
                                                          { return(Task.FromResult(selector.GetValueOrDefault <int?>("NewGrainStateVersion").ToString())); }, CancellationToken.None).ConfigureAwait(false);

                storageVersion = writeRecord.SingleOrDefault();
            }
            catch (Exception ex)
            {
                Log.Error((int)RelationalStorageProviderCodes.RelationalProviderWriteError, LogString("Error writing grain state", ServiceId, Name, grainState.ETag, baseGrainType, grainId.ToString(), ex.Message), ex);
                throw;
            }

            const string OperationString            = "WriteState";
            var          inconsistentStateException = CheckVersionInconsistency(OperationString, ServiceId, Name, storageVersion, grainState.ETag, baseGrainType, grainId.ToString());

            if (inconsistentStateException != null)
            {
                throw inconsistentStateException;
            }

            //No errors found, the version of the state held by the grain can be updated.
            grainState.ETag = storageVersion;

            if (Log.IsVerbose3)
            {
                Log.Verbose3((int)RelationalStorageProviderCodes.RelationalProviderWrote, LogString("Wrote grain state", ServiceId, Name, grainState.ETag, baseGrainType, grainId.ToString()));
            }
        }
Ejemplo n.º 2
0
        /// <summary>Clear state data function for this storage provider.</summary>
        /// <see cref="IStorageProvider.ClearStateAsync(string, GrainReference, IGrainState)"/>.
        public async Task ClearStateAsync(string grainType, GrainReference grainReference, IGrainState grainState)
        {
            //It assumed these parameters are always valid. If not, an exception will be thrown,
            //even if not as clear as when using explicitly checked parameters.
            var grainId       = GrainIdAndExtensionAsString(grainReference);
            var baseGrainType = ExtractBaseClass(grainType);

            if (Log.IsVerbose3)
            {
                Log.Verbose3((int)RelationalStorageProviderCodes.RelationalProviderClearing, LogString("Clearing grain state", ServiceId, Name, grainState.ETag, baseGrainType, grainId.ToString()));
            }

            string storageVersion = null;

            try
            {
                var grainIdHash   = HashPicker.PickHasher(ServiceId, Name, baseGrainType, grainReference, grainState).Hash(grainId.GetHashBytes());
                var grainTypeHash = HashPicker.PickHasher(ServiceId, Name, baseGrainType, grainReference, grainState).Hash(Encoding.UTF8.GetBytes(baseGrainType));
                var clearRecord   = (await Storage.ReadAsync(CurrentOperationalQueries.ClearState, command =>
                {
                    command.AddParameter("GrainIdHash", grainIdHash);
                    command.AddParameter("GrainIdN0", grainId.N0Key);
                    command.AddParameter("GrainIdN1", grainId.N1Key);
                    command.AddParameter("GrainTypeHash", grainTypeHash);
                    command.AddParameter("GrainTypeString", baseGrainType);
                    command.AddParameter("GrainIdExtensionString", grainId.StringKey);
                    command.AddParameter("ServiceId", ServiceId);
                    command.AddParameter("GrainStateVersion", !string.IsNullOrWhiteSpace(grainState.ETag) ? int.Parse(grainState.ETag, CultureInfo.InvariantCulture) : default(int?));
                }, (selector, resultSetCount, token) => { return(Task.FromResult(selector.GetValue(0).ToString())); }, CancellationToken.None).ConfigureAwait(false));
                storageVersion = clearRecord.SingleOrDefault();
            }
            catch (Exception ex)
            {
                Log.Error((int)RelationalStorageProviderCodes.RelationalProviderDeleteError, LogString("Error clearing grain state", ServiceId, Name, grainState.ETag, baseGrainType, grainId.ToString(), ex.Message), ex);
                throw;
            }

            const string OperationString            = "ClearState";
            var          inconsistentStateException = CheckVersionInconsistency(OperationString, ServiceId, Name, storageVersion, grainState.ETag, baseGrainType, grainId.ToString());

            if (inconsistentStateException != null)
            {
                throw inconsistentStateException;
            }

            //No errors found, the version of the state held by the grain can be updated and also the state.
            grainState.ETag = storageVersion;
            if (Log.IsVerbose3)
            {
                Log.Verbose3((int)RelationalStorageProviderCodes.RelationalProviderCleared, LogString("Cleared grain state", ServiceId, Name, grainState.ETag, baseGrainType, grainId.ToString()));
            }
        }
Ejemplo n.º 3
0
        /// <summary> Read state data function for this storage provider.</summary>
        /// <see cref="IStorageProvider.ReadStateAsync(string, GrainReference, IGrainState)"/>.
        public async Task ReadStateAsync(string grainType, GrainReference grainReference, IGrainState grainState)
        {
            //It assumed these parameters are always valid. If not, an exception will be thrown, even if not as clear
            //as with explicitly checked parameters.
            var grainId       = GrainIdAndExtensionAsString(grainReference);
            var baseGrainType = ExtractBaseClass(grainType);

            if (Log.IsVerbose3)
            {
                Log.Verbose3((int)RelationalStorageProviderCodes.RelationalProviderReading, LogString("Reading grain state", ServiceId, Name, grainState.ETag, baseGrainType, grainId.ToString()));
            }

            try
            {
                SerializationChoice choice = StorageSerializationPicker.PickDeserializer(ServiceId, Name, baseGrainType, grainReference, grainState, null);
                if (choice.Deserializer == null)
                {
                    var errorString = LogString("No deserializer found", ServiceId, Name, grainState.ETag, baseGrainType, grainId.ToString());
                    Log.Error((int)RelationalStorageProviderCodes.RelationalProviderNoDeserializer, errorString);
                    throw new InvalidOperationException(errorString);
                }

                var commandBehavior = choice.PreferStreaming ? CommandBehavior.SequentialAccess : CommandBehavior.Default;
                var grainStateType  = grainState.State.GetType();
                var grainIdHash     = HashPicker.PickHasher(ServiceId, Name, baseGrainType, grainReference, grainState).Hash(grainId.GetHashBytes());
                var grainTypeHash   = HashPicker.PickHasher(ServiceId, Name, baseGrainType, grainReference, grainState).Hash(Encoding.UTF8.GetBytes(baseGrainType));
                var readRecords     = (await Storage.ReadAsync(CurrentOperationalQueries.ReadFromStorage, (command =>
                {
                    command.AddParameter("GrainIdHash", grainIdHash);
                    command.AddParameter("GrainIdN0", grainId.N0Key);
                    command.AddParameter("GrainIdN1", grainId.N1Key);
                    command.AddParameter("GrainTypeHash", grainTypeHash);
                    command.AddParameter("GrainTypeString", baseGrainType);
                    command.AddParameter("GrainIdExtensionString", grainId.StringKey);
                    command.AddParameter("ServiceId", ServiceId);
                }), async(selector, resultSetCount, token) =>
                {
                    object storageState = null;
                    int?version;
                    if (choice.PreferStreaming)
                    {
                        //When streaming via ADO.NET, using CommandBehavior.SequentialAccess, the order of
                        //the columns on how they are read needs to be exactly this.
                        const int binaryColumnPositionInSelect = 0;
                        const int xmlColumnPositionInSelect = 1;
                        const int jsonColumnPositionInSelect = 2;
                        var streamSelector = (DbDataReader)selector;
                        if (!(await streamSelector.IsDBNullAsync(binaryColumnPositionInSelect)))
                        {
                            using (var downloadStream = streamSelector.GetStream(binaryColumnPositionInSelect, Storage))
                            {
                                storageState = choice.Deserializer.Deserialize(downloadStream, grainStateType);
                            }
                        }

                        if (!(await streamSelector.IsDBNullAsync(xmlColumnPositionInSelect)))
                        {
                            using (var downloadStream = streamSelector.GetTextReader(xmlColumnPositionInSelect))
                            {
                                storageState = choice.Deserializer.Deserialize(downloadStream, grainStateType);
                            }
                        }

                        if (!(await streamSelector.IsDBNullAsync(jsonColumnPositionInSelect)))
                        {
                            using (var downloadStream = streamSelector.GetTextReader(jsonColumnPositionInSelect))
                            {
                                storageState = choice.Deserializer.Deserialize(downloadStream, grainStateType);
                            }
                        }

                        version = await streamSelector.GetValueAsync <int?>("Version");
                    }
                    else
                    {
                        //All but one of these should be null. All will be read and an appropriate deserializer picked.
                        //NOTE: When streaming will be implemented, it is worthwhile to optimize this so that the defined
                        //serializer will be picked and then streaming tried according to its tag.
                        object payload;
                        payload = selector.GetValueOrDefault <byte[]>("PayloadBinary");
                        if (payload == null)
                        {
                            payload = selector.GetValueOrDefault <string>("PayloadXml");
                        }

                        if (payload == null)
                        {
                            payload = selector.GetValueOrDefault <string>("PayloadJson");
                        }

                        if (payload != null)
                        {
                            storageState = choice.Deserializer.Deserialize(payload, grainStateType);
                        }

                        version = selector.GetValue <int?>("Version");
                    }

                    return(Tuple.Create(storageState, version?.ToString(CultureInfo.InvariantCulture)));
                }, CancellationToken.None, commandBehavior).ConfigureAwait(false)).SingleOrDefault();

                object state = readRecords != null ? readRecords.Item1 : null;
                string etag  = readRecords != null ? readRecords.Item2 : null;
                if (state == null)
                {
                    Log.Info((int)RelationalStorageProviderCodes.RelationalProviderNoStateFound, LogString("Null grain state read (default will be instantiated)", ServiceId, Name, grainState.ETag, baseGrainType, grainId.ToString()));
                    state = Activator.CreateInstance(grainStateType);
                }

                grainState.State = state;
                grainState.ETag  = etag;
                if (Log.IsVerbose3)
                {
                    Log.Verbose3((int)RelationalStorageProviderCodes.RelationalProviderRead, LogString("Read grain state", ServiceId, Name, grainState.ETag, baseGrainType, grainId.ToString()));
                }
            }
            catch (Exception ex)
            {
                Log.Error((int)RelationalStorageProviderCodes.RelationalProviderReadError, LogString("Error reading grain state", ServiceId, Name, grainState.ETag, baseGrainType, grainId.ToString(), ex.Message), ex);
                throw;
            }
        }