/// <summary> /// Adds a pair of key and value to the cache. If the specified key already exists /// in the cache; it is updated, otherwise a new item is added to the cache. /// </summary> /// <param name="key">key of the entry.</param> /// <returns>cache entry.</returns> /// <remarks> /// Does an Insert locally, however the generated notification is discarded, since it is /// specially handled in <see cref="Insert"/>. /// </remarks> private CacheInsResultWithEntry Local_Insert(object key, CacheEntry cacheEntry, Address src, bool notify, object lockId, LockAccessType accessType, OperationContext operationContext) { CacheInsResultWithEntry retVal = new CacheInsResultWithEntry(); try { if (_internalCache != null) { retVal = _internalCache.Insert(key, cacheEntry, notify, lockId,accessType, operationContext); } } catch (Exception e) { if (_clusteredExceptions) throw; } return retVal; }
/// <summary> /// Returns the set of nodes where the insertion was performed as an atomic operation. /// </summary> /// <param name="results">responses collected from all members of cluster.</param> /// <returns>list of nodes where the operation succeeded</returns> public static CacheInsResultWithEntry FindAtomicInsertStatusReplicated(RspList results) { int needEvictCount = 0; int timeoutCount = 0; int suspectedCount = 0; int successCount = 0; CacheInsResultWithEntry res = new CacheInsResultWithEntry(); if (results == null) return res; for (int i = 0; i < results.size(); i++) { Rsp rsp = (Rsp)results.elementAt(i); if (!rsp.wasReceived() && !rsp.wasSuspected()) { timeoutCount++; continue; } if (rsp.wasSuspected()) { suspectedCount++; continue; } res = (CacheInsResultWithEntry)((OperationResponse)rsp.Value).SerializablePayload; if (res.Result == CacheInsResult.Success || res.Result == CacheInsResult.SuccessOverwrite) { successCount++; } if (res.Result != CacheInsResult.Success && res.Result != CacheInsResult.SuccessOverwrite && res.Result != CacheInsResult.NeedsEviction) { } /* If all the nodes in the Cluster return NeedsEviction response then we do not need to remove */ if (res.Result == CacheInsResult.NeedsEviction) { needEvictCount++; } } if (needEvictCount == results.size()) { //every node returned the NeedEviction; so we need not remove the item //as data is not corrupted. res.Result = CacheInsResult.NeedsEvictionNotRemove; } if (suspectedCount > 0 && successCount > 0 && (suspectedCount + successCount == results.size())) { //as operation is successfull on all other nodes other than suspected node(s). } if (timeoutCount > 0 && (timeoutCount + successCount == results.size())) { if (successCount > 0) { //operation is not succeeded on some of the nodes; therefore we throw timeout exception. res.Result = CacheInsResult.PartialTimeout; } else { //operation timed out on all of the node; no need to rollback. res.Result = CacheInsResult.FullTimeout; } } if (timeoutCount > 0 && suspectedCount > 0) { if (successCount > 0) { //operation is not succeeded on some of the nodes; therefore we throw timeout exception. res.Result = CacheInsResult.PartialTimeout; } else { //operation timed out on all of the node; no need to rollback. res.Result = CacheInsResult.FullTimeout; } } return res; }
/// <summary> /// Adds a pair of key and value to the cache. If the specified key already exists /// in the cache; it is updated, otherwise a new item is added to the cache. /// </summary> /// <param name="key">key of the entry.</param> /// <param name="cacheEntry">the cache entry.</param> /// <returns>returns the result of operation.</returns> /// <remarks> /// This method invokes <see cref="handleInsert"/> on every server-node in the cluster. If the operation /// fails on any one node the whole operation is considered to have failed and is rolled-back. /// Moreover the node initiating this request (this method) also triggers a cluster-wide /// item-update notificaion. /// </remarks> public override CacheInsResultWithEntry Insert(object key, CacheEntry cacheEntry, bool notify, object lockId, LockAccessType accessType, OperationContext operationContext) { if (ServerMonitor.MonitorActivity) ServerMonitor.LogClientActivity("RepCache.Insert", ""); /// Wait until the object enters any running status _statusLatch.WaitForAny(NodeStatus.Initializing | NodeStatus.Running); if (_internalCache == null) throw new InvalidOperationException(); if (Context.NCacheLog.IsInfoEnabled) Context.NCacheLog.Info("Replicated.Insert()", "Key = " + key); CacheEntry pEntry = null; CacheInsResultWithEntry retVal = new CacheInsResultWithEntry(); Exception thrown = null; try { // We get the actual item to raise custom call back with the item. //Get internally catters for the state-transfer scenarios. pEntry = Get(key, operationContext); retVal.Entry = pEntry; if (pEntry != null) { if (accessType != LockAccessType.IGNORE_LOCK) { if (pEntry.IsItemLocked() && !pEntry.CompareLock(lockId)) { //throw new LockingException("Item is locked."); retVal.Entry = null; retVal.Result = CacheInsResult.ItemLocked; return retVal; } } } if (Cluster.Servers.Count > 1) { // Try to add to the local node and the cluster. retVal = Clustered_Insert(key, cacheEntry, lockId, accessType, operationContext); //muds: //if coordinator has sent the previous entry, use that one... //otherwise send back the localy got previous entry... if (retVal.Entry != null) pEntry = retVal.Entry; else retVal.Entry = pEntry; } else retVal = Local_Insert(key, cacheEntry, Cluster.LocalAddress, true, lockId, accessType, operationContext); } catch (Exception e) { thrown = e; } // Try to insert to the local node and the cluster. if ((retVal.Result == CacheInsResult.NeedsEviction || retVal.Result == CacheInsResult.Failure || retVal.Result == CacheInsResult.FullTimeout || retVal.Result == CacheInsResult.PartialTimeout) || thrown != null) { Context.NCacheLog.Warn("Replicated.Insert()", "rolling back, since result was " + retVal.Result); bool rollback = true; bool timeout = false; if (retVal.Result == CacheInsResult.PartialTimeout) { timeout = true; } else if (retVal.Result == CacheInsResult.FullTimeout) { timeout = true; rollback = false; } if (rollback) { Thread.Sleep(2000); /// failed on the cluster, so remove locally as well. if (Cluster.Servers.Count > 1) { Clustered_Remove(key, ItemRemoveReason.Removed, null, false, null, LockAccessType.IGNORE_LOCK, operationContext); } } if (timeout) { throw new Runtime.Exceptions.TimeoutException("Operation timeout."); } if (thrown != null) throw thrown; } if (notify && retVal.Result == CacheInsResult.SuccessOverwrite) { RemoveUpdateIndexOperation(key); } return retVal; }
private CacheInsResultWithEntry Safe_Clustered_Insert(object key, CacheEntry cacheEntry, out Address targetNode, object lockId, LockAccessType accessType, OperationContext operationContext) { bool suspectedErrorOccured = false; int maxTries = _stats.Nodes.Count > 3 ? 3 : _stats.Nodes.Count - 1; CacheInsResultWithEntry retVal = new CacheInsResultWithEntry(); targetNode = null; do { try { targetNode = GetNextNode(key as string); if (targetNode == null) { throw new Exception("No target node available to accommodate the data."); } if (targetNode.CompareTo(LocalAddress) == 0) { retVal = Local_Insert(key, cacheEntry, Cluster.LocalAddress, true, lockId, accessType, operationContext); } else { retVal = Clustered_Insert(targetNode, key, cacheEntry, lockId, accessType, operationContext); } break; } catch (Alachisoft.NCache.Caching.Exceptions.StateTransferException se) { _distributionMgr.Wait(key); } catch (Runtime.Exceptions.TimeoutException te) { if (NCacheLog.IsInfoEnabled) NCacheLog.Info("PartitionedCache.Safe_Clustered_Insert()", te.ToString()); if (suspectedErrorOccured) { suspectedErrorOccured = false; continue; } else throw; } catch (Runtime.Exceptions.SuspectedException e) { suspectedErrorOccured = true; if (NCacheLog.IsInfoEnabled) NCacheLog.Info("PartitionedCache.Safe_Clustered_Insert()", e.ToString()); if (maxTries == 0) throw; maxTries--; } } while (maxTries > 0); return retVal; }
/// <summary> /// Adds a pair of key and value to the cache. If the specified key already exists /// in the cache; it is updated, otherwise a new item is added to the cache. /// </summary> /// <param name="key">key of the entry.</param> /// <param name="cacheEntry">the cache entry.</param> /// <returns>returns the result of operation.</returns> /// <remarks> /// This method either invokes <see cref="handleInsert"/> on any cluster node or invokes /// <see cref="Local_Insert"/> locally. The choice of the server node is determined by the /// <see cref="LoadBalancer"/>. /// <see cref="Local_Insert"/> triggers either <see cref="OnItemAdded"/> or <see cref="OnItemUpdated"/>, which /// in turn trigger either an item-added or item-updated cluster-wide notification. /// </remarks> public override CacheInsResultWithEntry Insert(object key, CacheEntry cacheEntry, bool notify, object lockId, LockAccessType accessType, OperationContext operationContext) { if (ServerMonitor.MonitorActivity) ServerMonitor.LogClientActivity("PrtCache.Insert", ""); /// Wait until the object enters the running status _statusLatch.WaitForAny(NodeStatus.Running); Address targetNode = null; if (_internalCache == null) throw new InvalidOperationException(); CacheInsResultWithEntry result = new CacheInsResultWithEntry(); result = Safe_Clustered_Insert(key, cacheEntry, out targetNode, lockId, accessType, operationContext); return result; }
/// <summary> /// Updates or Adds the object to the cluster. /// </summary> /// <param name="dest"></param> /// <param name="key">key of the entry.</param> /// <param name="cacheEntry"></param> /// <param name="lockId"></param> /// <param name="accessType"></param> /// <param name="operationContext"></param> /// <returns>cache entry.</returns> /// <remarks> /// This method invokes <see cref="handleInsert"/> on the specified node. /// </remarks> protected CacheInsResultWithEntry Clustered_Insert(Address dest, object key, CacheEntry cacheEntry, object lockId, LockAccessType accessType, OperationContext operationContext) { if (ServerMonitor.MonitorActivity) ServerMonitor.LogClientActivity("PartCacheBase.Insert", ""); CacheInsResultWithEntry retVal = new CacheInsResultWithEntry(); try { Function func = new Function((int)OpCodes.Insert, new object[] { key, cacheEntry.CloneWithoutValue(), lockId, accessType, operationContext }); Array userPayLoad = null; if (cacheEntry.Value is CallbackEntry) { CallbackEntry cbEntry = ((CallbackEntry)cacheEntry.Value); userPayLoad = cbEntry.UserData; } else { userPayLoad = cacheEntry.UserData; } func.UserPayload = userPayLoad; func.ResponseExpected = true; object result = Cluster.SendMessage(dest, func, GroupRequest.GET_FIRST, false); if (result == null) { return retVal; } retVal = (CacheInsResultWithEntry)((OperationResponse)result).SerializablePayload; if (retVal.Entry != null) retVal.Entry.Value = ((OperationResponse)result).UserPayload; } catch (Runtime.Exceptions.SuspectedException se) { throw; } catch (Runtime.Exceptions.TimeoutException te) { throw; } catch (CacheException e) { throw; } catch (Exception e) { throw new GeneralFailureException(e.Message, e); } return retVal; }
/// <summary> /// Adds a pair of key and value to the cache. If the specified key already exists /// in the cache; it is updated, otherwise a new item is added to the cache. /// </summary> /// <param name="key">key of the entry.</param> /// <param name="cacheEntry">the cache entry.</param> /// <returns>returns the result of operation.</returns> public override CacheInsResultWithEntry Insert(object key, CacheEntry cacheEntry, bool notify, object lockId, LockAccessType accessType, OperationContext operationContext) { CacheInsResultWithEntry retVal = new CacheInsResultWithEntry(); if (Internal != null) { retVal = Internal.Insert(key, cacheEntry, notify, lockId, accessType, operationContext); } return retVal; }