protected virtual async Task Write(ITurnContext context) { StoreItems changes = new StoreItems(); var state = context.Services.Get <StateT>(this._propertyName); if (state == null) { state = new StateT(); } var key = _keyDelegate(context); changes[key] = state; if (this._settings.LastWriterWins) { foreach (var item in changes) { if (item.Value is IStoreItem valueStoreItem) { valueStoreItem.eTag = "*"; } } } await _storage.Write(changes).ConfigureAwait(false); }
/// <summary> /// Storage extension to Read as strong typed StoreItem objects /// </summary> /// <typeparam name="StoreItemT"></typeparam> /// <param name="storage"></param> /// <param name="keys"></param> /// <returns></returns> public static async Task <StoreItems <StoreItemT> > Read <StoreItemT>(this IStorage storage, params string[] keys) where StoreItemT : class { var storeItems = await storage.Read(keys).ConfigureAwait(false); var newResults = new StoreItems <StoreItemT>(); foreach (var kv in storeItems) { newResults[kv.Key] = kv.Value as StoreItemT; } return(newResults); }
public async Task <StoreItems> Read(string[] keys) { var storeItems = new StoreItems(); foreach (var key in keys) { var item = await ReadIStoreItem(key).ConfigureAwait(false); if (item != null) { storeItems[key] = item; } } return(storeItems); }
public Task <StoreItems> Read(string[] keys) { var storeItems = new StoreItems(); lock (_syncroot) { foreach (var key in keys) { if (_memory.TryGetValue(key, out object value)) { if (value != null) { storeItems[key] = FlexObject.Clone(value); } else { storeItems[key] = null; } } } } return(Task.FromResult(storeItems)); }
public Task Write(StoreItems changes) { lock (_syncroot) { foreach (var change in changes) { object newValue = change.Value; object oldValue = null; if (_memory.TryGetValue(change.Key, out object x)) { oldValue = x; } IStoreItem newStoreItem = newValue as IStoreItem; IStoreItem oldStoreItem = oldValue as IStoreItem; if (oldValue == null || newStoreItem?.eTag == "*" || oldStoreItem?.eTag == newStoreItem?.eTag) { // clone and set etag newValue = FlexObject.Clone(newValue); newStoreItem = newValue as IStoreItem; if (newStoreItem != null) { newStoreItem.eTag = (_eTag++).ToString(); } _memory[change.Key] = newValue; } else { throw new Exception("etag conflict"); } } } return(Task.CompletedTask); }
public DictionaryStorage(StoreItems dictionary = null) { _memory = dictionary ?? new StoreItems(); }
public async Task Write(StoreItems changes) { // Similar to the Read method, the funky threading in here is due to // concurrency and async methods. // // When this method is called, it may happen (in parallel) from any number of // thread. // // If an operation is in progress, the Open will fail with an // IOException. If this happens,the best thing to do is simply wait a moment // and retry. The Retry MUST go through the eTag processing again. // // Alternate approach in here would be to use a SemaphoreSlim and use the async/await // constructs. foreach (var change in changes) { DateTime start = DateTime.UtcNow; while (true) { try { object newValue = change.Value; object oldValue = await this.ReadIStoreItem(change.Key).ConfigureAwait(false); IStoreItem newStoreItem = newValue as IStoreItem; IStoreItem oldStoreItem = oldValue as IStoreItem; if (oldValue == null || newStoreItem?.eTag == "*" || oldStoreItem?.eTag == newStoreItem?.eTag) { string key = SanitizeKey(change.Key); string path = Path.Combine(this.folder, key); var oldTag = newStoreItem?.eTag; if (newStoreItem != null) { newStoreItem.eTag = Guid.NewGuid().ToString("n"); } var json = JsonConvert.SerializeObject(newValue, serializationSettings); if (newStoreItem != null) { newStoreItem.eTag = oldTag; } using (TextWriter file = new StreamWriter(path)) { await file.WriteAsync(json).ConfigureAwait(false); break; } } else { throw new Exception($"etag conflict key={change}"); } } catch (IOException) { if ((DateTime.UtcNow - start).TotalSeconds < 5) { await Task.Delay(0).ConfigureAwait(false); } else { throw; } } } } }