private int WhichNode(CachedObject obj) { return(WhichNode(obj.PrimaryKey)); }
/// <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 response = CacheClients[node].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); 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; } } }
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); } } } } }