示例#1
0
        /// <summary>
        ///     Add a new object or update an existent one.The object may be excluded from eviction.
        ///     This feature is useful for the loader components which pre load data into the cache
        /// </summary>
        /// <param name="item"></param>
        /// <param name="excludeFromEviction">if true, the item will never be automatically evicted </param>
        public void Put <T>(T item, bool excludeFromEviction = false)
        {
            if (item == null)
            {
                throw new ArgumentNullException(nameof(item));
            }

            var description = RegisterTypeIfNeeded(typeof(T));

            var packedItem = CachedObject.Pack(item, description);

            var request = new PutRequest(typeof(T))
            {
                ExcludeFromEviction = excludeFromEviction
            };

            request.Items.Add(packedItem);

            var response = Channel.SendRequest(request);

            if (response is ExceptionResponse exResponse)
            {
                throw new CacheException("Error while writing an object to the cache", exResponse.Message,
                                         exResponse.CallStack);
            }
        }
示例#2
0
        /// <summary>
        ///     Transactionally add or replace a collection of objects of the same type
        ///     This method needs to lock the cache during the update. Do not use for large collections
        ///     (for example while pre-loading data to a cache) Use <see cref="FeedMany{T}(IEnumerable{T},bool)" /> instead
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="items"></param>
        /// <param name="excludeFromEviction"></param>
        public void PutMany <T>(IEnumerable <T> items, bool excludeFromEviction)
        {
            if (items == null)
            {
                throw new ArgumentNullException(nameof(items));
            }

            var description = RegisterTypeIfNeeded(typeof(T));

            var request = new PutRequest(typeof(T));

            foreach (var item in items)
            {
                var packedItem = CachedObject.Pack(item, description);
                request.Items.Add(packedItem);
            }


            request.ExcludeFromEviction = excludeFromEviction;

            var response = Channel.SendRequest(request);

            if (response is ExceptionResponse exResponse)
            {
                throw new CacheException("Error while writing an object ", exResponse.Message,
                                         exResponse.CallStack);
            }
        }
示例#3
0
        public void UpdateIf <T>(T newValue, OrQuery testAsQuery)
        {
            var description = RegisterTypeIfNeeded(typeof(T));
            var packedItem  = CachedObject.Pack(newValue, description);

            var node = WhichNode(packedItem);

            CacheClients[node].UpdateIf(newValue, testAsQuery);
        }
示例#4
0
        public bool TryAdd <T>(T item)
        {
            var description = RegisterTypeIfNeeded(typeof(T));
            var packedItem  = CachedObject.Pack(item, description);

            var node = WhichNode(packedItem);

            return(CacheClients[node].TryAdd(item));
        }
示例#5
0
        //public IFeedSession BeginFeed(TypeDescriptionConfig typeDescription, int packetSize, bool excludeFromEviction)
        //{
        //    //RegisterTypeIfNeeded()


        //    //return new FeedSession<TItem>(packetSize, excludeFromEviction);

        //    throw new NotImplementedException();
        //}

        /// <summary>
        ///     As an alternative to <see cref="FeedMany{T}(IEnumerable{T},bool,int)" /> you can use
        ///     <see cref="BeginFeed{TItem}" /> <see cref="Add{TItem}" /> <see cref="EndFeed{TItem}" />
        /// </summary>
        /// <typeparam name="TItem"></typeparam>
        /// <param name="session"></param>
        /// <param name="item"></param>
        public void Add <TItem>(IFeedSession session, TItem item) where TItem : class
        {
            var sessionImplementation = (FeedSession <TItem>)session;

            if (sessionImplementation.IsClosed)
            {
                throw new CacheException("The feed session is closed");
            }

            var description = RegisterTypeIfNeeded(typeof(TItem));

            var packedItem = CachedObject.Pack(item, description);

            sessionImplementation.Request.Items.Add(packedItem);

            if (sessionImplementation.Request.Items.Count == sessionImplementation.PacketSize)
            {
                var request = sessionImplementation.Request;
                sessionImplementation.Request = null;

                // only one packet at a time is fed asynchronously. If the previous send is still pending wait fot it to finish
                sessionImplementation.WaitForAsyncCompletion();


                ThreadPool.QueueUserWorkItem(state =>
                {
                    try
                    {
                        var rq = (Request)state;

                        sessionImplementation.StartAsync();

                        var response = Channel.SendRequest(rq);
                        if (response is ExceptionResponse exResponse)
                        {
                            sessionImplementation.EndAsync(
                                new CacheException(
                                    "Error while writing an object to the cache",
                                    exResponse.Message, exResponse.CallStack));
                        }
                        else
                        {
                            sessionImplementation.EndAsync(null);
                        }
                    }
                    catch (Exception e)
                    {
                        sessionImplementation.EndAsync(e);
                    }
                }, request);


                // prepare a new empty put request that will receive new items
                sessionImplementation.Request = new PutRequest(typeof(TItem));
            }
        }
示例#6
0
        /// <summary>
        ///     Transactionally update or insert multiple objects
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="items"></param>
        /// <param name="excludeFromEviction"></param>
        public void PutMany <T>(IEnumerable <T> items, bool excludeFromEviction = false)
        {
            if (items == null)
            {
                throw new ArgumentNullException(nameof(items));
            }

            var itemType = typeof(T);

            var description = RegisterTypeIfNeeded(itemType);

            // initialize one request per node
            var requests = new PutRequest[CacheClients.Count];

            for (var i = 0; i < CacheClients.Count; i++)
            {
                requests[i] = new PutRequest(itemType)
                {
                    ExcludeFromEviction = excludeFromEviction
                }
            }
            ;

            foreach (var item in items)
            {
                var packedItem = CachedObject.Pack(item, description);
                var node       = WhichNode(packedItem);
                requests[node].Items.Add(packedItem);
            }


            try
            {
                Parallel.For(0, CacheClients.Count, i =>
                {
                    var response =
                        CacheClients[i].Channel.SendRequest(requests[i]);

                    if (response is ExceptionResponse exResponse)
                    {
                        throw new CacheException(
                            "Error while writing an object to the cache",
                            exResponse.Message, exResponse.CallStack);
                    }
                });
            }
            catch (AggregateException e)
            {
                if (e.InnerException != null)
                {
                    throw e.InnerException;
                }
            }
        }
示例#7
0
        public bool TryAdd <T>(T item)
        {
            if (item == null)
            {
                throw new ArgumentNullException(nameof(item));
            }

            CachedObject packedItem;

            if (typeof(T) == typeof(CachedObject))
            {
                packedItem = item as CachedObject;
            }
            else
            {
                var description = RegisterTypeIfNeeded(typeof(T));

                packedItem = CachedObject.Pack(item, description);
            }


            var request = new PutRequest(typeof(T))
            {
                ExcludeFromEviction = true, OnlyIfNew = true
            };

            request.Items.Add(packedItem);

            var response = Channel.SendRequest(request);

            if (response is ExceptionResponse exResponse)
            {
                throw new CacheException("Error while writing an object to the cache", exResponse.Message,
                                         exResponse.CallStack);
            }

            if (response is ItemsCountResponse count)
            {
                return(count.ItemsCount > 0);
            }

            throw new NotSupportedException($"Unknown answer type received in TryAdd:{response.GetType()}");
        }
示例#8
0
        /// <summary>
        ///     Add an element to the cache during a fill session. Items are effectively send to the server in fixed size packets
        /// </summary>
        /// <typeparam name="TItem"></typeparam>
        /// <param name="session"></param>
        /// <param name="item"></param>
        public void Add <TItem>(IFeedSession session, TItem item) where TItem : class
        {
            var sessionImplementation = (ParallelFeedSession <TItem>)session;

            if (sessionImplementation.IsClosed)
            {
                throw new CacheException("The feed session is closed");
            }

            var description = RegisterTypeIfNeeded(typeof(TItem));

            var packedItem = CachedObject.Pack(item, description);

            var node = WhichNode(packedItem);

            var request = sessionImplementation.Requests[node];

            request.Items.Add(packedItem);

            // for each node fill a packet of fixed size and send it to the server only when completed
            if (request.Items.Count == sessionImplementation.PacketSize)
            {
                // create a new empty one for the future objects
                sessionImplementation.Requests[node] = new PutRequest(typeof(TItem));

                var task = Task.Factory.StartNew(re =>
                {
                    var response = CacheClients[node].Channel.SendRequest((Request)re);
                    if (response is ExceptionResponse exResponse)
                    {
                        throw new CacheException(
                            "Error while writing an object to the cache",
                            exResponse.Message, exResponse.CallStack);
                    }
                }, request);

                sessionImplementation.AddTask(task);
            }
        }
示例#9
0
        public void UpdateIf <T>(T newValue, OrQuery testAsQuery)
        {
            if (newValue == null)
            {
                throw new ArgumentNullException(nameof(newValue));
            }

            CachedObject packedItem;

            if (typeof(T) == typeof(CachedObject))
            {
                packedItem = newValue as CachedObject;
            }
            else
            {
                var description = RegisterTypeIfNeeded(typeof(T));

                packedItem = CachedObject.Pack(newValue, description);
            }


            var request = new PutRequest(typeof(T))
            {
                ExcludeFromEviction = true, Predicate = testAsQuery
            };

            request.Items.Add(packedItem);

            var response = Channel.SendRequest(request);

            if (response is ExceptionResponse exResponse)
            {
                throw new CacheException("Error while writing an object to the cache", exResponse.Message,
                                         exResponse.CallStack);
            }
        }
示例#10
0
        public void FeedMany <T>(IEnumerable <T> items, bool excludeFromEviction, int packetSize)
        {
            if (items == null)
            {
                throw new ArgumentNullException(nameof(items));
            }

            var itemType = typeof(T);

            ClientSideTypeDescription description = null;
            var    needPack = itemType != typeof(CachedObject);
            string typeName = null;

            var sessionId = Guid.NewGuid().ToString();

            if (needPack)
            {
                description = RegisterTypeIfNeeded(itemType);
                typeName    = description.FullTypeName;
            }


            using (var enumerator = items.GetEnumerator())
            {
                var endLoop = false;

                while (!endLoop)
                {
                    var packet = new CachedObject[packetSize];
                    var toPack = new T[packetSize];

                    var count = 0;
                    for (var i = 0; i < packetSize; i++)
                    {
                        if (enumerator.MoveNext())
                        {
                            var item = enumerator.Current;
                            toPack[i] = item;
                            count++;
                        }
                        else
                        {
                            endLoop = true;
                            break;
                        }
                    }


                    Parallel.For(0, count, new ParallelOptions {
                        MaxDegreeOfParallelism = 10
                    }, (i, loopState) =>
                    {
                        var item       = toPack[i];
                        var packedItem = needPack ? CachedObject.Pack(item, description) : item as CachedObject;

                        if (typeName == null)
                        {
                            typeName = packedItem?.FullTypeName;
                        }

                        packet[i] = packedItem;
                    }
                                 );


                    if (typeName != null) // null only for empty collection
                    {
                        var request = new PutRequest(typeName)
                        {
                            ExcludeFromEviction = excludeFromEviction,
                            SessionId           = sessionId,
                            EndOfSession        = endLoop
                        };

                        foreach (var cachedObject in packet)
                        {
                            if (cachedObject != null)
                            {
                                request.Items.Add(cachedObject);
                            }
                        }

                        var response = Channel.SendRequest(request);
                        if (response is ExceptionResponse exResponse)
                        {
                            throw new CacheException("Error while writing an object to the cache", exResponse.Message,
                                                     exResponse.CallStack);
                        }
                    }
                }
            }
        }
示例#11
0
        /// <summary>
        ///     FeedMany is non transactional but it does not lock the cache. To be used for massive feeds
        ///     Can feed with business objects (they will be packed to CachedObject) or directly with CachedObject
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="items"></param>
        /// <param name="excludeFromEviction"></param>
        /// <param name="packetSize"></param>
        public void FeedMany <T>(IEnumerable <T> items, bool excludeFromEviction, int packetSize)
        {
            if (items == null)
            {
                throw new ArgumentNullException(nameof(items));
            }

            // Lazy type registration
            var itemType = typeof(T);

            ClientSideTypeDescription description = null;
            var    needPack = itemType != typeof(CachedObject);
            string typeName = null;

            var sessionId = Guid.NewGuid().ToString();

            if (needPack)
            {
                description = RegisterTypeIfNeeded(itemType);
                typeName    = description.FullTypeName;
            }

            // initialize one request per node
            var requests = new PutRequest[CacheClients.Count];


            // Parallelize both nodes and requests (multiple requests for the same node are executed in parallel if multiple connections are available in the pool)
            var tasks = new List <Task>();

            foreach (var item in items)
            {
                if (typeName == null)
                {
                    typeName = (item as CachedObject)?.FullTypeName;
                }

                var packedItem = needPack ? CachedObject.Pack(item, description) : item as CachedObject;

                var node = WhichNode(packedItem);

                if (requests[node] == null)
                {
                    requests[node] = new PutRequest(typeName)
                    {
                        ExcludeFromEviction = excludeFromEviction,
                        SessionId           = sessionId
                    }
                }
                ;

                var request = requests[node];


                request.Items.Add(packedItem);

                if (request.Items.Count == packetSize)
                {
                    var task = Task.Factory.StartNew(re =>
                    {
                        var put   = (PutRequest)re;
                        var split = put.SplitWithMaxSize();

                        foreach (var putRequest in split)
                        {
                            var response =
                                CacheClients[node].Channel.SendRequest(putRequest);
                            if (response is ExceptionResponse exResponse)
                            {
                                throw new CacheException(
                                    "Error while writing an object to the cache",
                                    exResponse.Message, exResponse.CallStack);
                            }
                        }
                    }, request);


                    tasks.Add(task);
                    requests[node] = new PutRequest(typeName)
                    {
                        ExcludeFromEviction = excludeFromEviction,
                        SessionId           = sessionId
                    };
                }
            }


            //send the last packet left for each node
            for (var node = 0; node < CacheClients.Count; node++)
            {
                var request = requests[node];


                if (request != null)
                {
                    request.EndOfSession = true;

                    var n    = node;
                    var task = Task.Factory.StartNew(re =>
                    {
                        var response = CacheClients[n].Channel.SendRequest((PutRequest)re);
                        if (response is ExceptionResponse exResponse)
                        {
                            throw new CacheException(
                                "Error while writing an object to the cache",
                                exResponse.Message, exResponse.CallStack);
                        }
                    }, request);

                    tasks.Add(task);
                }
            }

            try
            {
                Task.WaitAll(tasks.ToArray());
                Dbg.Trace($"{tasks.Count} tasks finished");
            }
            catch (AggregateException e)
            {
                if (e.InnerException != null)
                {
                    throw e.InnerException;
                }
            }
        }