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;
 }
Exemplo n.º 7
0
 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);
 }
Exemplo n.º 9
0
 /// <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);
     }
 }
Exemplo n.º 11
0
        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));
        }
Exemplo n.º 12
0
        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);
 }
Exemplo n.º 15
0
        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;
        }
Exemplo n.º 16
0
 public IDictionary <string, IVersionedData> GetAllInternal(IVersionedDataKind kind)
 {
     return(WaitSafely(() => _coreAsync.GetAllInternalAsync(kind)));
 }
Exemplo n.º 17
0
 private ImmutableDictionary <string, IVersionedData> GetAllForCache(IVersionedDataKind kind)
 {
     return(_core.GetAllInternal(kind).ToImmutableDictionary());
 }
Exemplo n.º 18
0
 public CacheKey(IVersionedDataKind kind, string key)
 {
     Kind = kind;
     Key  = key;
 }
Exemplo n.º 19
0
        public async Task <IVersionedData> UpsertInternalAsync(IVersionedDataKind kind, IVersionedData item)
        {
            await ArbitraryTask();

            return(UpsertInternal(kind, item));
        }
Exemplo n.º 20
0
 private string ItemsKey(IVersionedDataKind kind)
 {
     return(_prefix + ":" + kind.GetNamespace());
 }
Exemplo n.º 21
0
        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);
            }
        }
Exemplo n.º 22
0
 public IVersionedData GetInternal(IVersionedDataKind kind, string key)
 {
     return(WaitSafely(() => _coreAsync.GetInternalAsync(kind, key)));
 }
Exemplo n.º 23
0
        public async Task <IDictionary <string, IVersionedData> > GetAllInternalAsync(IVersionedDataKind kind)
        {
            await ArbitraryTask();

            return(GetAllInternal(kind));
        }
Exemplo n.º 24
0
 public IVersionedData UpsertInternal(IVersionedDataKind kind, IVersionedData item)
 {
     return(WaitSafely(() => _coreAsync.UpsertInternalAsync(kind, item)));
 }
Exemplo n.º 25
0
        public async Task <IVersionedData> GetInternalAsync(IVersionedDataKind kind, string key)
        {
            await ArbitraryTask();

            return(GetInternal(kind, key));
        }