/// <inheritdoc/> public IDictionary <string, T> All <T>(VersionedDataKind <T> kind) where T : class, IVersionedData { if (_allCache != null) { return(FilterItems <T>(_allCache.Get(kind))); } return(FilterItems <T>(_core.GetAllInternal(kind))); }
/// <summary> /// Unmarshals a feature store item from a JSON string. This is a convenience method for /// feature store implementations, so that they can use the same JSON library that is used /// within the LaunchDarkly SDK rather than importing one themselves. All of the storeable /// classes used by the SDK are guaranteed to support this type of deserialization. /// </summary> /// <typeparam name="T">class of the object that will be returned</typeparam> /// <param name="kind">specifies the type of item being decoded</param> /// <param name="data">the JSON string</param> /// <returns>the unmarshaled item</returns> /// <exception cref="UnmarshalException">if the string format is invalid</exception> public static T UnmarshalJson <T>(VersionedDataKind <T> kind, string data) where T : IVersionedData { try { return(JsonConvert.DeserializeObject <T>(data)); } catch (JsonException e) { throw new UnmarshalException("Unable to unmarshal " + typeof(T).Name, e); } }
/// <inheritdoc/> public void Upsert <T>(VersionedDataKind <T> kind, T item) where T : IVersionedData { Exception failure = null; IVersionedData newState = item; try { newState = _core.UpsertInternal(kind, item); } catch (Exception e) { // Normally, if the underlying store failed to do the update, we do not want to update the cache - // the idea being that it's better to stay in a consistent state of having old data than to act // like we have new data but then suddenly fall back to old data when the cache expires. However, // if the cache TTL is infinite, then it makes sense to update the cache always. if (!_caching.IsInfiniteTtl) { throw; } failure = e; } if (_itemCache != null) { _itemCache.Set(new CacheKey(kind, item.Key), newState); } if (_allCache != null) { // If the cache has a finite TTL, then we should remove the "all items" cache entry to force // a reread the next time All is called. However, if it's an infinite TTL, we need to just // update the item within the existing "all items" entry (since we want things to still work // even if the underlying store is unavailable). if (_caching.IsInfiniteTtl) { try { var cachedAll = _allCache.Get(kind); _allCache.Set(kind, cachedAll.SetItem(item.Key, newState)); } catch (Exception) { } // An exception here means that we did not have a cached value for All, so it tried to query // the underlying store, which failed (not surprisingly since it just failed a moment ago // when we tried to do an update). This should not happen in infinite-cache mode, but if it // does happen, there isn't really anything we can do. } else { _allCache.Remove(kind); } } if (failure != null) { throw failure; } }
/// <summary> /// <see cref="IFeatureStore.Upsert"/> /// </summary> public void Upsert <T>(VersionedDataKind <T> kind, T item) where T : IVersionedData { IVersionedData newState = _core.UpsertInternal(kind, item); if (_itemCache != null) { _itemCache.Set(new CacheKey(kind, item.Key), newState); } if (_allCache != null) { _allCache.Remove(kind); } }
/// <inheritdoc/> public T Get <T>(VersionedDataKind <T> kind, String key) where T : class, IVersionedData { T item; if (_itemCache != null) { item = (T)_itemCache.Get(new CacheKey(kind, key)); } else { item = (T)_core.GetInternal(kind, key); } return((item == null || item.Deleted) ? null : item); }
/// <inheritdoc/> public void Delete <T>(VersionedDataKind <T> kind, string key, int version) where T : IVersionedData { Upsert(kind, kind.MakeDeletedItem(key, version)); }