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); }
/// <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); }
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); }
/// <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); }
/// <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); }