private void AddItem(IDictionary <IVersionedDataKind, IDictionary <string, IVersionedData> > allData, IVersionedDataKind kind, IVersionedData item) { IDictionary <string, IVersionedData> items; if (!allData.TryGetValue(kind, out items)) { items = new Dictionary <string, IVersionedData>(); allData[kind] = items; } if (items.ContainsKey(item.Key)) { switch (_duplicateKeysHandling) { case DuplicateKeysHandling.Throw: throw new System.Exception("in \"" + kind.GetNamespace() + "\", key \"" + item.Key + "\" was already defined"); case DuplicateKeysHandling.Ignore: break; default: throw new NotImplementedException("Unknown duplicate keys handling: " + _duplicateKeysHandling); } } else { items[item.Key] = item; } }
private static IDictionary <string, IVersionedData> SortCollection(IVersionedDataKind kind, IDictionary <string, IVersionedData> input) { var ordering = kind as IVersionedDataOrdering; if (ordering == null) { return(input); } IDictionary <string, IVersionedData> remainingItems = new Dictionary <string, IVersionedData>(input); var outputOrdering = new OutputOrdering(); while (remainingItems.Count > 0) { // pick a random item that hasn't been updated yet foreach (var entry in remainingItems) { AddWithDependenciesFirst(entry.Value, remainingItems, ordering, outputOrdering); break; } } return(new SortedDictionary <string, IVersionedData>(input, outputOrdering)); }
public void ForceRemove(IVersionedDataKind kind, string key) { if (Data.ContainsKey(kind)) { Data[kind].Remove(key); } }
public IDictionary <string, IVersionedData> GetAllInternal(IVersionedDataKind kind) { if (Data.TryGetValue(kind, out var items)) { return(new Dictionary <string, IVersionedData>(items)); } return(new Dictionary <string, IVersionedData>()); }
public void UnmarshalAsGeneralType() { var jsonStr = "{\"key\":\"flag\",\"on\":false}"; IVersionedDataKind kind = VersionedDataKind.Features; var flag = FeatureStoreHelpers.UnmarshalJson(kind, jsonStr); Assert.Equal("flag", flag.Key); }
public void ForceSet(IVersionedDataKind kind, IVersionedData item) { if (!Data.ContainsKey(kind)) { Data[kind] = new Dictionary <string, IVersionedData>(); } Data[kind][item.Key] = item; }
private bool GetKeyFromPath(string path, IVersionedDataKind kind, out string key) { if (path.StartsWith(kind.GetStreamApiPath())) { key = path.Substring(kind.GetStreamApiPath().Length); return(true); } key = null; return(false); }
public IVersionedData GetInternal(IVersionedDataKind kind, string key) { if (Data.TryGetValue(kind, out var items)) { if (items.TryGetValue(key, out var item)) { return(item); } } return(null); }
/// <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. /// /// This is the same as the other UnmarshalJson method, except that it returns an /// <see cref="IVersionedData"/> rather than a more specific type. This is more likely /// to be useful if you are implementing <see cref="IFeatureStoreCore"/>. /// </summary> /// <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 IVersionedData UnmarshalJson(IVersionedDataKind kind, string data) { try { return((IVersionedData)JsonConvert.DeserializeObject(data, kind.GetItemType())); } catch (JsonException e) { throw new UnmarshalException("Unable to unmarshal " + kind.GetItemType().Name, e); } }
/// <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. /// /// This is the same as the other UnmarshalJson method, except that it returns an /// <see cref="IVersionedData"/> rather than a more specific type. This is more likely /// to be useful if you are implementing <see cref="IFeatureStoreCore"/>. /// </summary> /// <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 IVersionedData UnmarshalJson(IVersionedDataKind kind, string data) { try { return((IVersionedData)JsonUtil.DecodeJson(data, kind.GetItemType())); } catch (JsonException e) { throw new UnmarshalException("Unable to unmarshal " + kind.GetItemType().Name, e); } }
public IVersionedData GetInternal(IVersionedDataKind kind, string key) { IDatabase db = _redis.GetDatabase(); string json = db.HashGet(ItemsKey(kind), key); if (json == null) { Log.DebugFormat("[get] Key: {0} not found in \"{1}\"", key, kind.GetNamespace()); return(null); } return(FeatureStoreHelpers.UnmarshalJson(kind, json)); }
public IDictionary <string, IVersionedData> GetAllInternal(IVersionedDataKind kind) { IDatabase db = _redis.GetDatabase(); HashEntry[] allEntries = db.HashGetAll(ItemsKey(kind)); Dictionary <string, IVersionedData> result = new Dictionary <string, IVersionedData>(); foreach (HashEntry entry in allEntries) { IVersionedData item = FeatureStoreHelpers.UnmarshalJson(kind, entry.Value); result[item.Key] = item; } return(result); }
public DataBuilder Add(IVersionedDataKind kind, params IVersionedData[] items) { IDictionary <String, IVersionedData> itemsDict; if (!_data.TryGetValue(kind, out itemsDict)) { itemsDict = new Dictionary <String, IVersionedData>(); _data[kind] = itemsDict; } foreach (var item in items) { itemsDict[item.Key] = item; } return(this); }
public IVersionedData UpsertInternal(IVersionedDataKind kind, IVersionedData item) { if (!Data.ContainsKey(kind)) { Data[kind] = new Dictionary <string, IVersionedData>(); } if (Data[kind].TryGetValue(item.Key, out var oldItem)) { if (oldItem.Version >= item.Version) { return(oldItem); } } Data[kind][item.Key] = item; return(item); }
private void AddItem(IDictionary <IVersionedDataKind, IDictionary <string, IVersionedData> > allData, IVersionedDataKind kind, IVersionedData item) { IDictionary <string, IVersionedData> items; if (!allData.TryGetValue(kind, out items)) { items = new Dictionary <string, IVersionedData>(); allData[kind] = items; } if (items.ContainsKey(item.Key)) { throw new System.Exception("in \"" + kind.GetNamespace() + "\", key \"" + item.Key + "\" was already defined"); } items[item.Key] = item; }
public IDictionary <string, IVersionedData> GetAllInternal(IVersionedDataKind kind) { return(WaitSafely(() => _coreAsync.GetAllInternalAsync(kind))); }
private ImmutableDictionary <string, IVersionedData> GetAllForCache(IVersionedDataKind kind) { return(_core.GetAllInternal(kind).ToImmutableDictionary()); }
public CacheKey(IVersionedDataKind kind, string key) { Kind = kind; Key = key; }
public async Task <IVersionedData> UpsertInternalAsync(IVersionedDataKind kind, IVersionedData item) { await ArbitraryTask(); return(UpsertInternal(kind, item)); }
private string ItemsKey(IVersionedDataKind kind) { return(_prefix + ":" + kind.GetNamespace()); }
public IVersionedData UpsertInternal(IVersionedDataKind kind, IVersionedData newItem) { IDatabase db = _redis.GetDatabase(); string baseKey = ItemsKey(kind); while (true) { string oldJson; try { oldJson = db.HashGet(baseKey, newItem.Key); } catch (RedisTimeoutException e) { Log.ErrorFormat("Timeout in update when reading {0} from {1}: {2}", newItem.Key, baseKey, e.ToString()); throw; } IVersionedData oldItem = (oldJson == null) ? null : FeatureStoreHelpers.UnmarshalJson(kind, oldJson); int oldVersion = (oldJson == null) ? -1 : oldItem.Version; if (oldVersion >= newItem.Version) { Log.DebugFormat("Attempted to {0} key: {1} version: {2} with a version that is" + " the same or older: {3} in \"{4}\"", newItem.Deleted ? "delete" : "update", newItem.Key, oldVersion, newItem.Version, kind.GetNamespace()); return(oldItem); } // This hook is used only in unit tests _updateHook?.Invoke(); // Note that transactions work a bit differently in StackExchange.Redis than in other // Redis clients. The same Redis connection is shared across all threads, so it can't // set a WATCH at the moment we start the transaction. Instead, it saves up all of // the actions we send during the transaction, and replays them all within a MULTI // when the transaction. AddCondition() is this client's way of doing a WATCH, and it // can only refer to the whole value, not to a JSON property of the value; that's why // we kept track of the whole value in "oldJson". ITransaction txn = db.CreateTransaction(); txn.AddCondition(oldJson == null ? Condition.HashNotExists(baseKey, newItem.Key) : Condition.HashEqual(baseKey, newItem.Key, oldJson)); txn.HashSetAsync(baseKey, newItem.Key, JsonConvert.SerializeObject(newItem)); try { bool success = txn.Execute(); if (!success) { // The watch was triggered, we should retry Log.Debug("Concurrent modification detected, retrying"); continue; } } catch (RedisTimeoutException e) { Log.ErrorFormat("Timeout on update of {0} in {1}: {2}", newItem.Key, baseKey, e.ToString()); throw; } return(newItem); } }
public IVersionedData GetInternal(IVersionedDataKind kind, string key) { return(WaitSafely(() => _coreAsync.GetInternalAsync(kind, key))); }
public async Task <IDictionary <string, IVersionedData> > GetAllInternalAsync(IVersionedDataKind kind) { await ArbitraryTask(); return(GetAllInternal(kind)); }
public IVersionedData UpsertInternal(IVersionedDataKind kind, IVersionedData item) { return(WaitSafely(() => _coreAsync.UpsertInternalAsync(kind, item))); }
public async Task <IVersionedData> GetInternalAsync(IVersionedDataKind kind, string key) { await ArbitraryTask(); return(GetInternal(kind, key)); }