/// <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); } }
/// <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); } }
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); }
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)); }
//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)); } }
/// <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; } } }
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()}"); }
/// <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); } }
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); } }
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); } } } } }
/// <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; } } }