Пример #1
0
        /// <summary>
        /// Invoke the passed <see cref="IEntryProcessor"/> against the
        /// entries specified by the passed cache and entries.
        /// </summary>
        /// <remarks>
        /// The invocation is made thread safe by locking the corresponding
        /// keys on the cache. If an attempt to lock all the entries at once
        /// fails, they will be processed individually one-by-one.
        /// </remarks>
        /// <param name="cache">
        /// The <see cref="IConcurrentCache"/> that the
        /// <b>IEntryProcessor</b> works against.
        /// </param>
        /// <param name="entries">
        /// A collection of <see cref="IInvocableCacheEntry"/> objects to
        /// process.
        /// </param>
        /// <param name="agent">
        /// The <b>IEntryProcessor</b> to use to process the specified keys.
        /// </param>
        /// <returns>
        /// An <b>IDictionary</b> containing the results of invoking the
        /// <b>IEntryProcessor</b> against each of the specified entry.
        /// </returns>
        public static IDictionary InvokeAllLocked(IConcurrentCache cache,
                                                  ICollection entries, IEntryProcessor agent)
        {
            ICollection keys = ConverterCollections.GetCollection(entries,
                                                                  ENTRY_TO_KEY_CONVERTER, NullImplementation.GetConverter());

            // try to lock them all at once
            var listLocked = LockAll(cache, keys, 0);

            if (listLocked == null)
            {
                // the attempt failed; do it one-by-one
                var result = new HashDictionary(entries.Count);
                foreach (IInvocableCacheEntry entry in entries)
                {
                    result[entry.Key] = InvokeLocked(cache, entry, agent);
                }
                return(result);
            }
            try
            {
                return(agent.ProcessAll(entries));
            }
            finally
            {
                UnlockAll(cache, listLocked);
            }
        }
Пример #2
0
 /// <summary>
 /// Unlock all the specified keys.
 /// </summary>
 /// <param name="cache">
 /// The <see cref="IConcurrentCache"/> to use.
 /// </param>
 /// <param name="keys">
 /// A collection of keys to unlock.
 /// </param>
 public static void UnlockAll(IConcurrentCache cache, ICollection keys)
 {
     foreach (var key in keys)
     {
         cache.Unlock(key);
     }
 }
Пример #3
0
        /// <summary>
        /// Attempt to lock all the specified keys within a specified period
        /// of time.
        /// </summary>
        /// <param name="cache">
        /// The <see cref="IConcurrentCache"/> to use.
        /// </param>
        /// <param name="keys">
        /// A collection of keys to lock.
        /// </param>
        /// <param name="waitMillis">
        /// The number of milliseconds to continue trying to obtain locks;
        /// pass zero to return immediately; pass -1 to block the calling
        /// thread until the lock could be obtained.
        /// </param>
        /// <returns>
        /// An <b>IList</b> containing all the locked keys in the order
        /// opposite to the locking order (LIFO); <c>null</c> if timeout has
        /// occurred.
        /// </returns>
        public static IList LockAll(IConcurrentCache cache, ICollection keys,
                                    int waitMillis)
        {
            // remove the duplicates
            HashSet setKeys = keys is HashSet ? (HashSet)keys : new HashSet(keys);

            // copy the keys into a list to fully control the iteration order
            var  listKeys   = new ArrayList(setKeys);
            var  listLocked = new ArrayList();
            int  keysCount  = listKeys.Count;
            bool isSuccess  = true;

            do
            {
                int waitNextMillis = waitMillis; // allow blocking wait for the very first key
                for (int i = 0; i < keysCount; i++)
                {
                    var key = listKeys[i];

                    isSuccess = cache.Lock(key, waitNextMillis);
                    if (isSuccess)
                    {
                        // add the last locked item into the front of the locked
                        // list so it behaves as a stack (FILO strategy)
                        listLocked.Insert(0, key);

                        // to prevent a deadlock don't wait afterwards
                        waitNextMillis = 0;
                    }
                    else
                    {
                        if (i == 0)
                        {
                            // the very first key cannot be locked -- timeout
                            return(null);
                        }

                        // unlock all we hold and try again
                        foreach (var o in listLocked)
                        {
                            cache.Unlock(o);
                        }
                        listLocked.Clear();

                        // move the "offending" key to the top of the list
                        // so next iteration we will attempt to lock it first
                        listKeys.RemoveAt(i);
                        listKeys.Insert(0, key);
                    }
                }
            }while (!isSuccess);

            return(listLocked);
        }
Пример #4
0
        /// <summary>
        /// Invoke the passed <see cref="IEntryProcessor"/> against the
        /// specified <see cref="IInvocableCacheEntry"/>.
        /// </summary>
        /// <remarks>
        /// The invocation is made thread safe by locking the corresponding key
        /// on the cache.
        /// </remarks>
        /// <param name="cache">
        /// The <see cref="IConcurrentCache"/> that the
        /// <b>IEntryProcessor</b> works against.
        /// </param>
        /// <param name="entry">
        /// The <b>IInvocableCacheEntry</b> to process; it is not required to
        /// exist within the cache.
        /// </param>
        /// <param name="agent">
        /// The <b>IEntryProcessor</b> to use to process the specified key.
        /// </param>
        /// <returns>
        /// The result of the invocation as returned from the
        /// <b>IEntryProcessor</b>.
        /// </returns>
        public static object InvokeLocked(IConcurrentCache cache,
                                          IInvocableCacheEntry entry, IEntryProcessor agent)
        {
            var key = entry.Key;

            cache.Lock(key, -1);
            try
            {
                return(agent.Process(entry));
            }
            finally
            {
                cache.Unlock(key);
            }
        }
        public void ConverterConcurrentCacheTests()
        {
            IConcurrentCache cache = InstantiateCache();
            IConverter       cDown = new ConvertDown();
            IConverter       cUp   = new ConvertUp();

            IConcurrentCache convCache = ConverterCollections.GetConcurrentCache(cache, cUp, cDown, cUp, cDown);

            Assert.IsNotNull(convCache);
            Assert.IsInstanceOf(typeof(ConverterCollections.ConverterConcurrentCache), convCache);
            ConverterCollections.ConverterConcurrentCache cc =
                convCache as ConverterCollections.ConverterConcurrentCache;
            Assert.IsNotNull(cc);
            Assert.AreEqual(cc.ConcurrentCache, cache);
        }
Пример #6
0
 /// <summary>
 /// Creates an instance of RequestProcessor.
 /// </summary>
 /// <param name="cache">The cache from which the requests will be served.</param>
 public RequestProcessor(IConcurrentCache <string, string> cache)
 {
     _cache = cache ?? throw new ArgumentNullException($"{nameof(cache)} cannot be null.");
 }