/// <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;
 }
Beispiel #2
0
        /// <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;
        }
Beispiel #7
0
 /// <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;
 }