public void MoveObjectCallBack(object state) { Node targetNode = (Node)state; string nodeKeyHash = Hasher.GetHash(targetNode.EndPoint.ToString()); string previousNodeHash = Hasher.GetHash(_nodeResolver.GetPreviousItemInCircle(targetNode.EndPoint.ToString())); //if self is B, typical scenarios -> A-newnode-MID-B, MID-A-newnode-B-C //A being the previous node, B being the current node and newnode being the new node. string lowerBound = previousNodeHash; string upperBound = nodeKeyHash; IEnumerable<KeyValuePair<string, ServerCacheItem>> candidateList = _cache.Where<KeyValuePair<string, ServerCacheItem>>(x => ((x.Value.Hash.CompareTo(upperBound) < 0) && (x.Value.Hash.CompareTo(lowerBound) > 0))); //special case: A-MID-newnode-B if (lowerBound.CompareTo(upperBound) > 0) { candidateList = _cache.Where<KeyValuePair<string, ServerCacheItem>>(x => ((x.Value.Hash.CompareTo(upperBound) < 0) || (x.Value.Hash.CompareTo(lowerBound) > 0))); } if (candidateList.Count() == 0) return; Node self = new Node() { EndPoint = TcpHelper.SelfIPAddress, NodeState= NodeState.Active}; //prepare the connection string endPoint = string.Format("net.tcp://{0}:{1}/HoCCacheService", targetNode.EndPoint.ToString(), targetNode.ServicePort); CacheServiceReference.CacheServiceClient nodeService = new CacheServiceReference.CacheServiceClient(new NetTcpBinding(SecurityMode.None), new EndpointAddress(endPoint)); try { //move each of the object to the other node async foreach (KeyValuePair<string, ServerCacheItem> valuePair in candidateList) { nodeService.DoInterNodeObjectTransfer(self, valuePair.Key, valuePair.Value); valuePair.Value.ItemState = CacheItemState.Moved; valuePair.Value.RelocatedTo = targetNode; }; nodeService.EndInterNodeObjectTransfer(self); Thread.Sleep(2000);//wait the current thread - note that this is not the main thread RemoveOrResetMovedItems(targetNode); //note that any object update that happens during this time is handled by the CacheService. //basically it copies the update to the new node too. } catch { ResetMovedObjectState(); //in case of any issues revert back to normal state. } }
public void StoreCacheItem(string key, ClientCacheItem value) { ServerCacheItem cacheItemWrapped; if (!_localCache.TryGetValue(key, out cacheItemWrapped)) cacheItemWrapped = new ServerCacheItem() { ItemState = CacheItemState.None }; cacheItemWrapped.Hash = Hasher.GetHash(key); cacheItemWrapped.Value = value; Func<string, ServerCacheItem, ServerCacheItem> updateValueFactory = ((x, y) => (cacheItemWrapped)); _localCache.AddOrUpdate(key, cacheItemWrapped, updateValueFactory); //has the item been moved to another node? if (cacheItemWrapped.ItemState == CacheItemState.Moved) { Debug.Assert(cacheItemWrapped.RelocatedTo != null); Node self = new Node() { EndPoint = TcpHelper.SelfIPAddress, NodeState = NodeState.Active }; //prepare the connection string endPoint = string.Format("net.tcp://{0}:{1}/HoCCacheService", cacheItemWrapped.RelocatedTo.EndPoint.ToString(), cacheItemWrapped.RelocatedTo.ServicePort); CacheServiceReference.CacheServiceClient nodeService = new CacheServiceReference.CacheServiceClient(new NetTcpBinding(SecurityMode.None), new EndpointAddress(endPoint)); //update to the target node. nodeService.StoreCacheItem(key, value); } }
public void PerformShutdownMove() { //targetnode is the one which comes next in the circle, effectively returned by GetObjectLocation Node targetNode = _nodeResolver.GetObjectLocation(TcpHelper.SelfIPAddress.ToString()); //is targetnode self? (am I the only node in the circle?) if (targetNode.EndPoint.ToString().CompareTo(TcpHelper.SelfIPAddress.ToString()) == 0) return; string endPoint = string.Format("net.tcp://{0}:{1}/HoCCacheService", targetNode.EndPoint.ToString(), targetNode.ServicePort); CacheServiceReference.CacheServiceClient nodeService = new CacheServiceReference.CacheServiceClient(new NetTcpBinding(SecurityMode.None), new EndpointAddress(endPoint)); Node self = new Node() { EndPoint = TcpHelper.SelfIPAddress, NodeState= NodeState.Active}; //move the objects to the nearest node async Parallel.ForEach<KeyValuePair<string, ServerCacheItem>>(_cache, valuePair => { nodeService.DoInterNodeObjectTransfer(self, valuePair.Key, valuePair.Value); valuePair.Value.ItemState = CacheItemState.Moved; valuePair.Value.RelocatedTo = targetNode; }); }