Esempio n. 1
0
        public async Task WriteWithETagViolation()
        {
            GrainState <EntityWithIntegerKeyWithEtag> grainState =
                Internal.Utils.CreateAndStoreGrainState <EntityWithIntegerKeyWithEtag>(_serviceProvider);

            TestGrainReference grainRef
                = TestGrainReference.Create(grainState.State);

            // update the database
            EntityWithIntegerKeyWithEtag clone = grainState.State.Clone();

            clone.Title = "Updated";
            using (var context = _serviceProvider.GetRequiredService <TestDbContext>())
            {
                context.Entry(clone).State = EntityState.Modified;

                context.SaveChanges();
            }

            // This should fail
            grainState.State.Title = "Failing Update";
            await Assert.ThrowsAsync <InconsistentStateException>(() =>
                                                                  _storage.WriteStateAsync(typeof(GrainWithIntegerKeyWithEtag).FullName,
                                                                                           grainRef,
                                                                                           grainState));
        }
        public async Task UpdateCustomGetterGrainState()
        {
            var entity = new EntityWithGuidKey();

            Internal.Utils.StoreGrainState(_serviceProvider, entity);
            entity.Title += "UPDATED";
            var state = new GrainStateWrapper <EntityWithGuidKey>()
            {
                Value = entity
            };
            var grainState = new GrainState <GrainStateWrapper <EntityWithGuidKey> >()
            {
                State = state
            };

            TestGrainReference grainRef
                = TestGrainReference.Create(entity);

            await _storage.WriteStateAsync(typeof(GrainWithCustomStateGuidKey).FullName,
                                           grainRef,
                                           grainState
                                           );

            Internal.Utils.AssertEntityEqualityVsDb(
                _serviceProvider, grainState.State?.Value);
        }
        private async Task <GrainState <TestStoreGrainState> > Test_PersistenceProvider_WriteRead(string grainTypeName,
                                                                                                  IGrainStorage store, GrainState <TestStoreGrainState> grainState = null, GrainId grainId = default)
        {
            GrainReference reference = (GrainReference)this.fixture.InternalGrainFactory.GetGrain(grainId.IsDefault ? (GrainId)LegacyGrainId.NewId() : grainId);

            if (grainState == null)
            {
                grainState = TestStoreGrainState.NewRandomState();
            }

            Stopwatch sw = new Stopwatch();

            sw.Start();

            await store.WriteStateAsync(grainTypeName, reference, grainState);

            TimeSpan writeTime = sw.Elapsed;

            sw.Restart();

            var storedGrainState = new GrainState <TestStoreGrainState>
            {
                State = new TestStoreGrainState()
            };
            await store.ReadStateAsync(grainTypeName, reference, storedGrainState);

            TimeSpan readTime = sw.Elapsed;

            this.output.WriteLine("{0} - Write time = {1} Read time = {2}", store.GetType().FullName, writeTime, readTime);
            Assert.Equal(grainState.State.A, storedGrainState.State.A);
            Assert.Equal(grainState.State.B, storedGrainState.State.B);
            Assert.Equal(grainState.State.C, storedGrainState.State.C);

            return(storedGrainState);
        }
Esempio n. 4
0
        /// <summary>
        /// Async method to cause write of the current grain state data into backing store.
        /// </summary>
        public async Task WriteStateAsync()
        {
            const string what = "WriteState";

            try
            {
                CheckRuntimeContext();

                Stopwatch sw = Stopwatch.StartNew();
                await store.WriteStateAsync(name, grainRef, grainState);

                sw.Stop();
                StorageStatisticsGroup.OnStorageWrite(name, grainRef, sw.Elapsed);
            }
            catch (Exception exc)
            {
                StorageStatisticsGroup.OnStorageWriteError(name, grainRef);
                string errMsgToLog = MakeErrorMsg(what, exc);
                this.logger.Error((int)ErrorCode.StorageProvider_WriteFailed, errMsgToLog, exc);
                // If error is not specialization of OrleansException, wrap it
                if (!(exc is OrleansException))
                {
                    throw new OrleansException(errMsgToLog, exc);
                }
                throw;
            }
        }
        private async Task PersistState()
        {
            //create a write-request ID, which is used for group commit
            int writeRequestId = ++_writeRequestIdGen;

            //add the write-request ID to the pending write requests
            _pendingWriteRequests.Add(writeRequestId);

            //wait before any previous write is done
            using (await _writeLock.LockAsync())
            {
                // If the write request is not there, it was handled by another worker before we obtained the lock.
                if (_pendingWriteRequests.Contains(writeRequestId))
                {
                    //clear all pending write requests, as this attempt will do them all.
                    _pendingWriteRequests.Clear();

                    //write the state back to the storage unconditionally
                    var saveETag = this.queueState.ETag;
                    try
                    {
                        this.queueState.ETag = StorageProviderUtils.ANY_ETAG;
                        await StorageProvider.WriteStateAsync(_grainTypeName, _lazyParent.Value, this.queueState);
                    }
                    finally
                    {
                        if (this.queueState.ETag == StorageProviderUtils.ANY_ETAG)
                        {
                            this.queueState.ETag = saveETag;
                        }
                    }
                }
            }
        }
        public async Task SinglePropertyWrite()
        {
            GrainState <EntityWithIntegerKey> grainState =
                Internal.Utils.CreateAndStoreGrainState <EntityWithIntegerKey>(_serviceProvider);


            grainState.State.Title  = "Should get updated";
            grainState.State.KeyExt = "Should not get updated";


            TestGrainReference grainRef
                = TestGrainReference.Create(grainState.State);

            GrainStorageContext <EntityWithIntegerKey> .ConfigureEntryState(
                entry => entry
                .Property(e => e.Title)
                .IsModified = true
                );

            await _storage.WriteStateAsync(typeof(GrainWithIntegerKey).FullName,
                                           grainRef,
                                           grainState);


            var stored = (EntityWithIntegerKey)
                         Internal.Utils.FetchEntityFromDb(_serviceProvider, grainState.State);

            Assert.Equal("Should get updated", stored?.Title);
            Assert.NotEqual("Should not get updated", stored?.KeyExt);


            GrainStorageContext <EntityWithIntegerKey> .Clear();

            // Future updates should update the whole object if not configured
            await _storage.WriteStateAsync(typeof(GrainWithIntegerKey).FullName,
                                           grainRef,
                                           grainState);

            stored = (EntityWithIntegerKey)
                     Internal.Utils.FetchEntityFromDb(_serviceProvider, grainState.State);

            Assert.Equal(stored, grainState.State);
        }
Esempio n. 7
0
        private async Task TestWriteAsync <TGrain, TState, TKey>()
            where TState : Entity <TKey>, new()
            where TGrain : Grain <TState>
        {
            GrainState <TState> grainState = CreateGrainState <TState>();

            TestGrainReference grainRef
                = TestGrainReference.Create(grainState.State);

            await _storage.WriteStateAsync(typeof(TGrain).FullName,
                                           grainRef,
                                           grainState
                                           );

            Internal.Utils.AssertEntityEqualityVsDb(_serviceProvider, grainState.State);
        }
Esempio n. 8
0
        /// <summary>Faults if exception is provided, otherwise calls through to  decorated storage provider.</summary>
        /// <param name="grainType">Type of this grain [fully qualified class name]</param>
        /// <param name="grainReference">Grain reference object for this grain.</param>
        /// <param name="grainState">State data object to be written for this grain.</param>
        /// <returns>Completion promise for the Write operation on the specified grain.</returns>
        public async Task WriteStateAsync(string grainType, GrainReference grainReference, IGrainState grainState)
        {
            IStorageFaultGrain faultGrain = grainFactory.GetGrain <IStorageFaultGrain>(grainType);

            try
            {
                await InsertDelay();

                await faultGrain.OnWrite(grainReference);
            }
            catch (Exception)
            {
                logger.Info($"Fault injected for WriteState for grain {grainReference} of type {grainType}");
                throw;
            }
            logger.Info($"WriteState for grain {grainReference} of type {grainType}");
            await realStorageProvider.WriteStateAsync(grainType, grainReference, grainState);
        }
        protected override async Task <int> WriteAsync()
        {
            enter_operation("WriteAsync");

            var  updates = GetCurrentBatchOfUpdates();
            bool batchSuccessfullyWritten = false;
            bool logsSuccessfullySaved    = false;

            var writebit = _snapshotState.StateAndMetaData.FlipBit(Services.MyClusterId);

            if (!_useIndependentEventStorage)
            {
                foreach (var x in updates)
                {
                    _snapshotState.StateAndMetaData.Log.Add(x.Entry);
                }

                _snapshotState.StateAndMetaData.GlobalVersion += updates.Length;
                logsSuccessfullySaved = true;
            }
            else
            {
                try
                {
                    int expectedVersion = _snapshotState.StateAndMetaData.GlobalVersion + updates.Length;

                    await _eventStorage.SaveEvents(
                        _grainTypeName,
                        Services.GrainReference,
                        updates.Select(x => x.Entry),
                        expectedVersion - _snapshotState.StateAndMetaData.Log.Count);

                    _snapshotState.StateAndMetaData.GlobalVersion = expectedVersion;
                    logsSuccessfullySaved = true;
                }
                catch (Exception e)
                {
                    LastPrimaryIssue.Record(new UpdateEventStorageFailed()
                    {
                        Exception = e
                    }, Host, Services);
                }
            }

            if (logsSuccessfullySaved)
            {
                try
                {
                    if (_snapshotStrategy(GetSnapshotStrategyInfo()))
                    {
                        _snapshotState.StateAndMetaData.SnapshotVersion     = _confirmedVersionInternal;
                        _snapshotState.StateAndMetaData.SnapshotUpdatedTime = DateTime.Now;
                        _snapshotState.StateAndMetaData.Snapshot            = _confirmedViewInternal.DeepClone();
                    }

                    await _grainStorage.WriteStateAsync(_grainTypeName, Services.GrainReference, _snapshotState);

                    batchSuccessfullyWritten = true;

                    Services.Log(LogLevel.Debug, "write ({0} updates) success {1}", updates.Length, _snapshotState);

                    UpdateConfirmedView(updates.Select(u => u.Entry));

                    LastPrimaryIssue.Resolve(Host, Services);
                }
                catch (Exception e)
                {
                    LastPrimaryIssue.Record(new UpdateSnapshotStorageFailed()
                    {
                        Exception = e
                    }, Host, Services);
                }
            }

            if (!batchSuccessfullyWritten)
            {
                Services.Log(LogLevel.Debug, "write apparently failed {0}", LastPrimaryIssue);

                while (true)
                {
                    await LastPrimaryIssue.DelayBeforeRetry();

                    try
                    {
                        await _grainStorage.ReadStateAsync(_grainTypeName, Services.GrainReference, _snapshotState);

                        Services.Log(LogLevel.Debug, "read success {0}", _snapshotState);

                        if (_confirmedVersionInternal < _snapshotState.StateAndMetaData.SnapshotVersion)
                        {
                            _confirmedVersionInternal = _snapshotState.StateAndMetaData.SnapshotVersion;
                            _confirmedViewInternal    = _snapshotState.StateAndMetaData.Snapshot;
                        }

                        var logs = await RetrieveLogSegment(
                            _confirmedVersionInternal,
                            _snapshotState.StateAndMetaData.GlobalVersion);

                        Services.Log(LogLevel.Debug, "read success {0}", logs);

                        UpdateConfirmedView(logs);

                        LastPrimaryIssue.Resolve(Host, Services);

                        break;
                    }
                    catch (Exception e)
                    {
                        LastPrimaryIssue.Record(new ReadFromSnapshotStorageFailed()
                        {
                            Exception = e
                        }, Host, Services);
                    }

                    Services.Log(LogLevel.Debug, "read failed {0}", LastPrimaryIssue);
                }

                if (writebit == _snapshotState.StateAndMetaData.GetBit(Services.MyClusterId))
                {
                    Services.Log(LogLevel.Debug, "last write ({0} updates) was actually a success {1}", updates.Length, _snapshotState);

                    batchSuccessfullyWritten = true;
                }
            }

            exit_operation("WriteAsync");

            if (!batchSuccessfullyWritten)
            {
                return(0);
            }

            return(updates.Length);
        }
Esempio n. 10
0
        /// <inheritdoc/>
        protected override async Task <int> WriteAsync()
        {
            enter_operation("WriteAsync");

            var  updates = GetCurrentBatchOfUpdates();
            bool batchsuccessfullywritten = false;

            var writebit = GlobalLog.StateAndMetaData.FlipBit(Services.MyClusterId);

            foreach (var x in updates)
            {
                GlobalLog.StateAndMetaData.Log.Add(x.Entry);
            }

            try
            {
                // for manual testing
                //await Task.Delay(5000);

                await globalGrainStorage.WriteStateAsync(grainTypeName, Services.GrainReference, GlobalLog);

                batchsuccessfullywritten = true;

                Services.Log(LogLevel.Debug, "write ({0} updates) success {1}", updates.Length, GlobalLog);

                UpdateConfirmedView();

                LastPrimaryIssue.Resolve(Host, Services);
            }
            catch (Exception e)
            {
                LastPrimaryIssue.Record(new UpdateLogStorageFailed()
                {
                    Exception = e
                }, Host, Services);
            }

            if (!batchsuccessfullywritten)
            {
                Services.Log(LogLevel.Debug, "write apparently failed {0}", LastPrimaryIssue);

                while (true) // be stubborn until we can read what is there
                {
                    await LastPrimaryIssue.DelayBeforeRetry();

                    try
                    {
                        await globalGrainStorage.ReadStateAsync(grainTypeName, Services.GrainReference, GlobalLog);

                        Services.Log(LogLevel.Debug, "read success {0}", GlobalLog);

                        UpdateConfirmedView();

                        LastPrimaryIssue.Resolve(Host, Services);

                        break;
                    }
                    catch (Exception e)
                    {
                        LastPrimaryIssue.Record(new ReadFromLogStorageFailed()
                        {
                            Exception = e
                        }, Host, Services);
                    }

                    Services.Log(LogLevel.Debug, "read failed {0}", LastPrimaryIssue);
                }

                // check if last apparently failed write was in fact successful

                if (writebit == GlobalLog.StateAndMetaData.GetBit(Services.MyClusterId))
                {
                    Services.Log(LogLevel.Debug, "last write ({0} updates) was actually a success {1}", updates.Length, GlobalLog);

                    batchsuccessfullywritten = true;
                }
            }

            exit_operation("WriteAsync");

            if (!batchsuccessfullywritten)
            {
                return(0);
            }

            return(updates.Length);
        }
        /// <inheritdoc/>
        protected override async Task <int> WriteAsync()
        {
            enter_operation("WriteAsync");

            var  state   = CopyTentativeState();
            var  updates = GetCurrentBatchOfUpdates();
            bool batchsuccessfullywritten = false;

            var nextglobalstate = new GrainStateWithMetaDataAndETag <TLogView>(state);

            nextglobalstate.StateAndMetaData.WriteVector   = GlobalStateCache.StateAndMetaData.WriteVector;
            nextglobalstate.StateAndMetaData.GlobalVersion = GlobalStateCache.StateAndMetaData.GlobalVersion + updates.Length;
            nextglobalstate.ETag = GlobalStateCache.ETag;

            var writebit = nextglobalstate.StateAndMetaData.FlipBit(Services.MyClusterId);

            try
            {
                // for manual testing
                //await Task.Delay(5000);

                await globalGrainStorage.WriteStateAsync(grainTypeName, Services.GrainReference, nextglobalstate);

                batchsuccessfullywritten = true;

                GlobalStateCache = nextglobalstate;

                Services.Log(LogLevel.Debug, "write ({0} updates) success {1}", updates.Length, GlobalStateCache);

                LastPrimaryIssue.Resolve(Host, Services);
            }
            catch (Exception e)
            {
                LastPrimaryIssue.Record(new UpdateStateStorageFailed()
                {
                    Exception = e
                }, Host, Services);
            }

            if (!batchsuccessfullywritten)
            {
                Services.Log(LogLevel.Debug, "write apparently failed {0} {1}", nextglobalstate, LastPrimaryIssue);

                while (true) // be stubborn until we can read what is there
                {
                    await LastPrimaryIssue.DelayBeforeRetry();

                    try
                    {
                        await globalGrainStorage.ReadStateAsync(grainTypeName, Services.GrainReference, GlobalStateCache);

                        Services.Log(LogLevel.Debug, "read success {0}", GlobalStateCache);

                        LastPrimaryIssue.Resolve(Host, Services);

                        break;
                    }
                    catch (Exception e)
                    {
                        LastPrimaryIssue.Record(new ReadFromStateStorageFailed()
                        {
                            Exception = e
                        }, Host, Services);
                    }

                    Services.Log(LogLevel.Debug, "read failed {0}", LastPrimaryIssue);
                }

                // check if last apparently failed write was in fact successful

                if (writebit == GlobalStateCache.StateAndMetaData.GetBit(Services.MyClusterId))
                {
                    GlobalStateCache = nextglobalstate;

                    Services.Log(LogLevel.Debug, "last write ({0} updates) was actually a success {1}", updates.Length, GlobalStateCache);

                    batchsuccessfullywritten = true;
                }
            }

            exit_operation("WriteAsync");

            if (!batchsuccessfullywritten)
            {
                return(0);
            }

            return(updates.Length);
        }