Archive

Archive for December, 2009

An Asynchronous Resource Pool

December 21, 2009 Leave a comment

I was thinking over this last week about creating an efficient Asynchronously driven generic resource pool. My first solution was a bit more complicated than this one. Originally I tied the IASyncResult from the creation method to the IASyncResult that I returned to the caller. This got too complicated. After a good nights rest I was able to see what I was really trying to do and here’s the result.

 

using System;
using System.Collections.Generic;
using System.Threading;

namespace ResourcePool
{
    /// <summary>
    /// Class for highly efficient pool. 
    /// </summary>
    /// <typeparam name="T">A type that is expensive in use or in creation.</typeparam>
    /// <author>jader3rd</author>
    public class ResourcePool<T> : IDisposable where T : class
    {
        /// <summary>
        /// If grabbing both results and pool, grab results before grabbing the pool lock.
        /// </summary>
        private ReaderWriterLockSlim poolLock, resultsLock;
        private Queue<T> free;
        private Func<AsyncCallback, Object, IAsyncResult> beginCreateResource;
        private Func<IAsyncResult, T> endCreateResource;
        private Queue<PoolResult> outstandingResults;
        private Timer drainTimer;
        private bool disposing;
        private TimeSpan drainFreq;

        public TimeSpan DrainFrequency {
            get
            {
                return drainFreq;
            }
            set
            {
                drainFreq = value;
                if (null != drainTimer)
                {
                    drainTimer.Change(value, value);
                }
            }
        }

        /// <summary>
        /// Creates a pool with no objects and a DrainFrequency of thirty seconds.
        /// </summary>
        /// <param name="creationAction">The action to call to create an item. Place any needed item creation error checking in the action.</param>
        public ResourcePool(Func<T> creationAction) : this (new Func<AsyncCallback, Object, IAsyncResult>(creationAction.BeginInvoke), new Func<IAsyncResult, T>(creationAction.EndInvoke))
        {
        }

        /// <summary>
        /// Creates a pool with no objects and a DrainFrequency of thirty seconds.
        /// </summary>
        /// <param name="beginCreateFunc">The APM begin method for creating the resource.</param>
        /// <param name="endCreateFunc">The APM end method for creating the resource.</param>
        public ResourcePool(Func<AsyncCallback, Object, IAsyncResult> beginCreateFunc, Func<IAsyncResult, T> endCreateFunc)
        {
            beginCreateResource = beginCreateFunc;
            endCreateResource = endCreateFunc;
            poolLock = new ReaderWriterLockSlim();
            free = new Queue<T>();
            DrainFrequency = TimeSpan.FromSeconds(30);
            outstandingResults = new Queue<PoolResult>();
            resultsLock = new ReaderWriterLockSlim();
            drainTimer = new Timer(checkFreePool, null, DrainFrequency, DrainFrequency);
            disposing = false;
        }

        /// <summary>
        /// If there is a free object. Grab it. Does not add to the pool.
        /// </summary>
        /// <param name="item">The item</param>
        /// <returns>True if an object is grabbed.</returns>
        public bool TryGet(out T item)
        {
            try
            {
                poolLock.EnterWriteLock();
                if (disposing)
                {
                    throw new ObjectDisposedException(GetType().Name);
                }
                if (0 < free.Count)
                {
                    item = free.Dequeue();
                    return true;
                }
            }
            finally
            {
                if (poolLock.IsWriteLockHeld) poolLock.ExitWriteLock();
            }
            item = null;
            return false;
        }

        /// <summary>
        /// Get an object from the pool.
        /// </summary>
        /// <param name="callback">The method to be called when an object is free from the pool. If there is an object free right away the callback gets called synchronously.</param>
        /// <param name="state">The object to get passed to the callback method in the aync state.</param>
        /// <returns>An IASyncResult that references the get.</returns>
        public IAsyncResult BeginGet(AsyncCallback callback, Object state)
        {
            T item;
            if (TryGet(out item))
            {
                PoolResult result = new ResourcePool<T>.PoolResult(callback, state, item);
                if (null != callback)
                {
                    callback.Invoke(result);
                }
                return result;
            }
            else
            {
                PoolResult result = new ResourcePool<T>.PoolResult(
                    callback,
                    state,
                    null);
                try
                {
                    resultsLock.EnterWriteLock();
                    outstandingResults.Enqueue(result);
                }
                finally
                {
                    if (resultsLock.IsWriteLockHeld) resultsLock.ExitWriteLock();
                }
                beginCreateResource.Invoke(endCreate, null);
                return result;
            }
        }

        /// <summary>
        /// Actualy get an object from the pool.
        /// </summary>
        /// <param name="result">The result object tied to this call.</param>
        /// <returns>An item from the pool.</returns>
        public T EndGet(IAsyncResult result)
        {
            PoolResult res = (PoolResult)result;
            T returnee = null;
            if (null == res.Picked)
            {
                res.AsyncWaitHandle.WaitOne();
                if (disposing)
                {
                    throw new ObjectDisposedException(GetType().Name);
                }
            }
            returnee = res.Picked;

            return returnee;
        }

        /// <summary>
        /// Put an item no longer in use back in the pool.
        /// </summary>
        /// <param name="item">The item to place in the pool.</param>
        public void Put(T item)
        {
            try
            {
                poolLock.EnterWriteLock();
                if (disposing)
                {
                    throw new ObjectDisposedException(GetType().Name);
                }
                free.Enqueue(item);
            }
            finally
            {
                if (poolLock.IsWriteLockHeld) poolLock.ExitWriteLock();
            }
            ThreadPool.QueueUserWorkItem(checkOutstandingResults);
        }

        /// <summary>
        /// The callback for the create method. Put the item in the free pool.
        /// </summary>
        /// <param name="result">The result to pass to EndInvoke.</param>
        private void endCreate(IAsyncResult result)
        {
            T item = endCreateResource.Invoke(result);
            if (disposing) return;
            Put(item);
        }

        /// <summary>
        /// Dispose of resources, drain the pool, and if the pool items are IDisposable, dispose them.
        /// </summary>
        public void Dispose()
        {
            disposing = true;
            try
            {
                resultsLock.EnterWriteLock();
                while (0 < outstandingResults.Count)
                {
                    PoolResult result = outstandingResults.Dequeue();
                    ((EventWaitHandle)result.AsyncWaitHandle).Set();
                }
            }
            finally
            {
                if (resultsLock.IsWriteLockHeld) resultsLock.EnterWriteLock();
            }
            try
            {
                poolLock.EnterWriteLock();
                while (0 < free.Count)
                {
                    T item = free.Dequeue();
                    if (item is IDisposable)
                    {
                        ((IDisposable)item).Dispose();
                    }
                }
            }
            finally
            {
                if (poolLock.IsWriteLockHeld) poolLock.ExitWriteLock();
            }
            poolLock.Dispose();
            resultsLock.Dispose();
            drainTimer.Dispose();
        }

        /// <summary>
        /// Called by the pool draining timer to empty the pool
        /// </summary>
        /// <param name="state"></param>
        private void checkFreePool(Object state)
        {
            T item = null;
            if (disposing) return;
            try
            {
                resultsLock.EnterReadLock();
                // only drain if there are no outstanding results
                if (0 == outstandingResults.Count)
                {
                    try
                    {
                        poolLock.EnterWriteLock();
                        if (disposing) return;
                        if (1 < free.Count)
                        {
                            item = free.Dequeue();
                        }
                    }
                    finally
                    {
                        if (poolLock.IsWriteLockHeld) poolLock.ExitWriteLock();
                    }
                }
            }
            finally
            {
                if (resultsLock.IsReadLockHeld) resultsLock.ExitReadLock();
            }
            if (disposing) return;
            if (item != null && item is IDisposable)
            {
                ((IDisposable)item).Dispose();
            }
        }

        /// <summary>
        /// Analyze the outstanding results queue and if there's a free item in the pool serve up the result.
        /// </summary>
        /// <param name="state">Not used, just there to satisfy the callback</param>
        private void checkOutstandingResults(object state)
        {
            PoolResult result = null;
            T item = null;
            try
            {
                resultsLock.EnterWriteLock();
                if (0 < outstandingResults.Count)
                {
                    try
                    {
                        poolLock.EnterWriteLock();
                        if (0 < free.Count)
                        {
                            result = outstandingResults.Dequeue();
                            item = free.Dequeue();
                        }
                    }
                    finally
                    {
                        if (poolLock.IsWriteLockHeld) poolLock.ExitWriteLock();
                    }
                }
            }
            finally
            {
                if (resultsLock.IsWriteLockHeld) resultsLock.ExitWriteLock();
            }

            if (null != result)
            {
                result.Picked = item;
                if (null != result.Callback)
                {
                    result.Callback.Invoke(result);
                }
            }
        }

        /// <summary>
        /// The IASyncResult that controls the pool.
        /// </summary>
        private class PoolResult : IAsyncResult
        {
            private AsyncCallback callerCallback;
            private Object callerState;
            private T picked;
            private WaitHandle myHandle;
            private bool compSync, isComp;

            public PoolResult(AsyncCallback callback, Object state, T chosen)
            {
                callerCallback = callback;
                callerState = state;
                picked = chosen;
                if (null == picked)
                {
                    isComp = false;
                    compSync = false;
                }
                else
                {
                    isComp = true;
                    compSync = true;
                }
            }

            public T Picked
            {
                get { return picked; }
                internal set
                {
                    picked = value;
                    isComp = true;
                    compSync = false;
                    if (null == callerCallback)
                    {
                        ((ManualResetEvent)AsyncWaitHandle).Set();
                    }

                }
            }

            public object AsyncState
            {
                get { return callerState; }
            }

            public WaitHandle AsyncWaitHandle
            {
                get 
                {
                    if (null == myHandle)
                    {
                        myHandle = new ManualResetEvent(false);
                    }
                    return myHandle;
                }
            }

            public bool CompletedSynchronously
            {
                get
                {
                    return compSync;
                }
            }

            public bool IsCompleted
            {
                get
                {
                    return isComp;
                }
            }

            internal AsyncCallback Callback
            {
                get
                {
                    return callerCallback;
                }
            }
        }
    }
}

Frozen Seattle Nights

December 15, 2009 2 comments

For all of those who don’t know the Seattle area has gone through two weeks of freezing weather. The temperature has stayed below freezing for most of the two weeks. The sky has been cloudless and there hasn’t been much wind. They kept on predicting snow, but it kept staying too cold for the moisture to move in. I don’t think that any records were broken for how cold it got, but what’s different this time is how long it stayed below freezing. It has been abnormal.

On Saturday night Amanda and I were in bed and just about ready to turn off the light when the fire alarm went off. It is very loud. Poor Isis, our cat, was scared to death. So Amanda took Isis outside. The fire alarm was going off for everyone in our building (16 units). Everybody else was coming outside too about this time, but with their freaked out dogs. Isis was not happy being taken into the cold and being surrounded by dogs. Amanda had to foil her many attempts to flee to a place with no alarm and no dogs.

What had happened was one of the external fire sprinklers had started pouring water, causing the fire alarm to go off. The fire department showed up, turned off the alarm, turned off the water and helped clean up. They said that they cold was causing fire sprinkler heads to freeze and burst. It was their ninth call that night for just the same reason. The buildings around here haven’t seen consecutive cold like this before and it’s showing.

The management company is going to take a few days to get to fixing our building because they are dealing with this all over. We were lucky in that it didn’t affect a unit, only the exterior stair well. I’m sure there are lots of other places where it’s causing burst pipes inside of units.

It made for quite a lot of excitement.

Categories: Uncategorized

Passwords and Windows 7

December 6, 2009 Leave a comment

In two of my recent posts I listed out things which I do not like about Windows 7. Another one cropped up a few days ago. The Windows 7 that I have is Home Premium. Why not? I’m using it at home. I didn’t see any feature that I would want in a more expensive version.

This week I started getting a notice that my password was about to expire. I look, and look and there’s no way in Windows 7 Home Edition to mark a user account with the attribute “Password never Expires”. I even tried opening MMC and adding the Local Users and Groups snapin, but there’s an error saying you can’t load that Snapin in Home Premium. Argh! That’s so stupid! Especially considering the fact that you can have a user with no password. Why am I not allowed to manage my own computer!

Categories: Uncategorized