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