Thread Safe Library Update

As always, my life revolves around threading.  So I have a few classes that I use frequently for these purposes.  Now, fortunately, .NET 4.0 will include much of this functionality in PFX, but for now, we have this.

ThreadSafeLibrary

AutoProcessingQueue: This is a queue that as you add things to it, will automatically begin dispatching on a seperate thread and begin calling a specified delegate to process the items.

Batch: This is a class that is similar to a queue except that it allows you to do work in batches.  Set the max & minimum sizes, and start adding items to it.  When it reaches a certain size it will attempt to close the batch and will fire an event that will allow you to wire in code for processing the data in the batch.  It also has a timer that can be enabled if you'd prefer to allow the batch to be closed at a certain interval.  This is great for database calls and bulk inserts.  Say I want to send a series of messages, but i don't want to send them one at a time.  I would like to send the messages when the batch reaches 100 items, or every 5 seconds.  I use this class alot for messaging.

Dispatcher:  This is the class that does the heavy lifting for the majority of things in this library.  You give it a maximum number of threads to work with, and as you add workers to it's queue, it will begin spawning threads to process them(carefully re-using them whenever possible)

ResourcePool:  The dispatcher uses this internally to store & manage it's threads.  Though it can be used for any object type.  One case where i use this frequently is to pool connections to webservices.  To save the time required to open and close connections constantly, i set up a pool, give it a threshold(so as to not flood the service i'm calling) and ask it to get the resource for you via the delegate you provide.

ThreadSafeDictionary<K,V>:  The classic threadsafe implementation of a dictionary, with several added methods to support atomic operations.

ThreadSafeQueue<T>:  The classic Queue implementation of a dictionary, with several added methods to support atomic operations.

ThreadSafeHashSet<T>:  The classic HashSet implementation of a dictionary, with several added methods to support atomic operations.

ThreadSafeStackList<T>:  This is similar to a stack, without alot of the limitations.  Multi-level peek, unwind, etc.

AsyncBlock:
This is a class that allows you to wrap async work into serial action for the purposes of simplicity.  If you need have a function that needs to run numerous asynchronous calls, and then return only when they are all finished, this is your class.

You can use it like so:

     public class AsyncSample
    {
        private Dispatcher Dispatcher;


        public AsyncSample()
        {
            //init a dispatcher that uses 5 threads and doesn't carry execution context
            Dispatcher = new Dispatcher(5, false);
        }


        public void ExecuteParallel<T>(IList<T> work)
        {
            var workers = ConstructParallelWorkers(work);


            //the async block will pause this thread until all workers finish
            using (AsyncBlock block = new AsyncBlock(this.Dispatcher, 10))
            {
                foreach (var worker in workers)
                {
                    block.AddToQueue(worker);
                }
            }
        }


        private IList<AnyWorkerBee<T>> ConstructParallelWorkers<T>(IList<T> work)
        {
            var workers = new List<AnyWorkerBee<T>>();


            foreach (var workUnit in work)
                workers.Add(new AnyWorkerBee<T>() { WorkUnit = workUnit });


            return workers;
        }
    }

 

Posted by Brian Rudolph | with no comments
Filed under: , , ,

HashSet Deserialization Oddities

So, yesterday was a fun day.  I spent all day trying to debug a state in which one of your QA web servers' worker processes would go into an infinite loop and peg a core on the CPU.  After many hours, and finally installing the remote debugging tools on the server, I eventually found the problem - removing an item from a HashSet. ?!?

So let me set the scenario up.  I have a website that runs in a farm, so I utilize SQL for state management.  As you probably already know, all objects that go into state are binary serialized, forwarded to the SQL server, and then fetched and deserialized upon request after the next page load.  

I have a state object that is placed in to session state.  It contains some state that is a HashSet<Guid> object.  The first time this object is put into state, it is empty.  I then retrieve it and place a few guids into it.  This is where it gets odd.  If i browse the object after I add the guids to it, it appears that some of them go in to the set as Empty Guids, regardless of their value when i actually added them.  This is after the set has been deserialized from state empty, then values added to it. 

Interestingly enough, it actually adds multiple duplicate keys to the set, which is natively not permissable.  Under normal circumstances, were I to add Guid.Empty into a hashset 3 times, it will only appear in the set once.  Not in this case.  It appears that the set is checking for uniqueness with the real value being passed in, detects that the value is unique, yet after the value is added it is actually added as Guid.Empty.  So this would be crazy enough... but thats not where the story ends. 

Now, a few methods away I am tearing through the values in the set, and removing ones that meet a certain condition.  Except that since I am receiving empty guids back for most of the items i put in the set, these are always meeting my removal condition.  Aside from the craziness, this shouldn't be a huge problem, except that when i go to remove one of the empty guids from the set, within framework code it gets stuck in an infinite loop.  I have not Reflected this to see where, but i would guess that it is not pleased having duplicate keys internally.  Interestingly enough, if i replace the hashset with a List<Guid>, all is well.

So here's the kicker.  This is not reproducible on my development box, only on this QA server.  The possible reasons are many.  For instance, my dev box runs .Net 3.5 SP1, while the server is running without SP1.  My dev box is running Vista x64 hosting under cassini, while the server is running Server 2008 x64 hosting under IIS 7.  My guess for the culprit would be the former.  I am upgrading the server to SP1 today to see if that resolves the issue. 

I will update this post with the results.

Posted by Brian Rudolph | with no comments

Inline Asynchronous UI Coding using IDisposable in C# .NET

I recently watched this video on the PowerThreading library: http://blogs.msdn.com/charlie/archive/2008/12/03/jeff-richter-video-on-asynchronous-programming-and-his-power-threading-library.aspx

This is very interesting as Jeff Richter utilizes a strange behavior in the way the C# compiler works with IEnumerables to make a useful and easy-to-use async library.  His primary goal was to allow a website\service yield processing during I/O operations, which can provide for better scalability in your app tier. 

While this is quite interesting, I personally would avoid using strange compilation patterns to my advantage in an application.  Specifically because you have no assurance that the compiler will always do this as the language and subsequent compilers evolve.  What I was interested in was the mechanism for including asynchronous calls into code without using a complex series of callbacks. 

Now, to be quite fair, Jeff's implementation was an attempt to limit thread spawning, and context switches.  I am not going to account for this.  I am more interested in parrallel processing.

Let me give you an example.  Take for instance a series of objects that the UI is going to take cues from and make subsequent database calls to retrieve extra data for.  A simple example is a treeview.  If I have a bunch of nodes in a tree and the UI requires that I display the child node or items count for each of these nodes. What you would generally do is loop through the objects and call the DB to retrieve the data, and assign the UI components in one serial block of code.  The problem with this is that the database is more than likely capable of servicing the request for numerous nodes simultaneously, but in the UI we are implementing this serially.  If the tree structure is complex, and you are showing more than just a node count, it is plausible that each of these requests will take upward of 50ms.  If you have several dozen nodes being displayed this can easily add seconds to your response time.

A serial block of code might look like this:

TreeNodeCollection nodes = new TreeNodeCollection();
foreach (TreeNode node in nodes)
{
     int objectCount = database.DoSomething((MyObject)node.Tag); //call the database
     node.Text = String.Format("{0} ({1})", node.Text, objectCount); //update the UI
 }

 Simple and clean, but slow. 

Why not do all of these calls asynchronously, wait for all of the results to filter in, and then update the UI?  This should surely be faster than a serial operation.  Let's say, we spawn Math.Min(nodes.Count, 10) threads to accomplish this task.  So at a maximum, we will use 10 threads to do the work. If we have 20 nodes, it should take at the longest 2 times as long as the longest running call. 

The usual issue with this is that it requires you to use several call-back methods, do complicated thread monitoring, and subsequently put the UI into a wait state until all of the external threads have finished.  Unfortunately there just is no simple way to do it.

So I got to thinking, what construct can I use to signal an asynchronous block, that would prevent execution beyond it's bounds until all the threads were done.  The answer, IDisposable.  If I created an IDisposable object and wrapped it in a "using" I could prevent the Dispose method from exiting until all the threads have finished.

Utilizing the rest of my Threading objects, this should be fairly simple to accomplish, all I had to do was add a done flag to my workerbee:

public class AsyncBlock : IDisposable
{


        long timeoutMS = 0;
        Dispatcher dispatcher = null;
        bool started = false;

        public AsyncBlock() : this(10) { }

        public AsyncBlock(int timeoutSeconds) : this(timeoutSeconds, 5) { }

        public AsyncBlock(int timeoutSeconds, int threads) : this(new Dispatcher(threads), timeoutSeconds) { }

        public AsyncBlock(Dispatcher dispatcher, int timeoutSeconds)
        {
            this.dispatcher = dispatcher;
            this.timeoutMS = timeoutSeconds * 1000;
            this.WorkQueue = new List<WorkerBee>();
        }


        private IList<WorkerBee> WorkQueue
        {
            get;
            set;
        } 


       public IList<WorkerBee> GetWorkers()        
       {
            return new List<WorkerBee>(this.WorkQueue);
        } 


        public void AddToQueue(WorkerBee bee)
        {
            this.WorkQueue.Add(bee);
            this.dispatcher.AddToQueue(bee);
            started = true;
        }


        public void Start()
        {
            foreach (WorkerBee bee in this.WorkQueue)
                if (!bee.Done)
                    this.dispatcher.AddToQueue(bee);


            started = true;
        }


        public void Dispose()
        {
            if (!started && WorkQueue.Count != 0)
            {
                throw new Exception("Work was never started");
            }


            System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();
            watch.Start();
            bool done = false;

            while (!done)
            {
                done = true;
                foreach (WorkerBee bee in WorkQueue)
                {
                    if (!(done = done && bee.Done))
                        break;
                }
 


                if (watch.ElapsedMilliseconds > timeoutMS)
                    throw new TimeoutException("Timeout elapsed");
 
                if (!done)
                    Thread.Sleep(1); // wait 1ms to try again
            }
 
            watch.Stop();
        }
}


public class DatabaseWorkerBee<RefType, ReturnType> : AnyWorkerBee<Delegate>
{
        public delegate ReturnType DBDelegate();
        private DBDelegate dbDelegate;

        public ReturnType ReturnValue
        {
            get;
            set;
        } 


        public RefType ReferenceObject
        {
            get;
            set;
        } 


        public DatabaseWorkerBee(RefType refObject, DBDelegate del)
        {
            this.ReferenceObject = refObject;
            dbDelegate = del;
        } 


        protected override void WorkStart()
        {
            base.WorkStart();
 
            if (dbDelegate != null)
            {
                ReturnValue = dbDelegate();
            }
        }
    }


 

Alright, this is now a fairly simple implementation in  the UI:

  

IList<WorkerBee> workers = null;


using (AsyncBlock block = new AsyncBlock(30, Math.Min(nodes.Count, 10))) // do these async with a 30 second timeout
{
      foreach (TreeNode o in nodes)
      {
          TreeNode node = o; //must declare this in the loop, or you get the same object in every worker, this is a documented closure bug in the framework
          block.AddToQueue(
              new DatabaseWorkerBee<TreeNode, int>( node, delegate { /* Do Database Call Here using the node object*/; }));
       }


      workers = block.GetWorkers()


}//using will not return until all workers have been processed.


foreach (WorkerBee worker in workers)
{
      DatabaseWorkerBee<TreeNode, int> dbworker = worker as DatabaseWorkerBee<TreeNode, int>;
      dbWorker.ReferenceObject.Text = String.Format("{0} ({1})", dbWorker.ReferenceObject.Text, dbWorker.ReturnValue); //update the UI
}


 

Woot!  All of the nodes are executed async, and all of the values are returned properly.  One thing to note, notice I am declaring a redundant TreeNode object inside the loop.  This is necessary, since we are using an anonymous method inside of the loop.  If we were to just reference the "o" in the iterator, we would get the same object passed to each anonymous method. 

My Threading Objects can be found here: ThreadLib.zip

[Edit]
After further review and testing this code works quite well, except in the instance of windows authenticated database connections.  Because we are spawning new threads, and your security context is thread based, all of the subsequent database calls were made using the applications default user.  This isn't a problem in Windows UI's but in Web apps this is not good.  It could be as simple as setting the new threads to the same security context as the spawning thread, but I'm not sure I want that to happen for every thread.  I will work this out and do an update.

I have worked this security context issue out. If anyone is interested in it, email me.

Posted by Brian Rudolph | with no comments
Filed under: , , ,

More Threading Goodness!

Threading - I write about it a lot, even though i would consider myself somewhat of a rookie when it comes to threading complexities.

One of the challenges we often find when trying to incorporate threading into applications is managing work units, thread pools, and queues.  What I've ended up doing is writing a few helpers to accommodate just these things.

To start, we need to manage a pool of available thread resources.  This pool needs to have a limit, and needs to be able to generate threads on the fly if necessary.  However, the need for resource pools is not limited to threading.  Consider the scenario where you have a web service of some sort, being WSE, FTP HTTP whatever.  There is a lot of overhead in opening and handshaking for these connections.  If I had say a list of 100k files I needed to upload, and wanted to do that asynchronously, I wouldn't want to throw away the connection after every upload.  So I need to do simple connection pooling.  But I don't want to open 10 connections immediately if I am only going to need 2 either, so this pool needs to be dynamic. 

To even start writing a pool, we need some sort of queuing class for resource storage, and in the threaded world, this needs to be thread safe.

So a simple wrapper may look something like this:

public class ThreadSafeQueue<T>
    {
        //This is the internal queue that we are wrapping
        Queue<T> queue = new Queue<T>();
 
        [NonSerialized]
        ReaderWriterLockSlim objLock = Locks.GetLockInstance(LockRecursionPolicy.NoRecursion); //setup the lock;
 
        public int Count
        {
            get
            {
                using (new ReadOnlyLock(this.objLock))
                {
                    return this.queue.Count;
                }
            }
        }
 
        public void Clear()
        {
            using (new WriteLock(this.objLock))
            {
                this.queue.Clear(); ;
            }
        }
 
        public bool Contains(T item)
        {
            using (new ReadOnlyLock(this.objLock))
            {
                return this.queue.Contains(item);
            }
        }
 
        public bool TryDequeue(out T obj)
        {
            using (new ReadLock(this.objLock))
            {
                if (this.queue.Count != 0)
                {
                    obj = this.Dequeue();
                    return true;
                }
            }
 
            obj = default(T);
            return false;
        }
 
        public T Dequeue()
        {
            using (new WriteLock(this.objLock))
            {
                return this.queue.Dequeue();
            }
        }
 
        public void Enqueue(T item)
        {
            using (new WriteLock(this.objLock))
            {
                this.queue.Enqueue(item);
            }
        }
 
        public T Peek()
        {
            using (new ReadOnlyLock(this.objLock))
            {
                return this.queue.Peek();
            }
        }
    }


 
Then we can move on to the Resource Pool, which we want to be generic so that it can serve up any kind of resource, be it a thread, a web service connection, a widget of any sort.

public class ResourcePool<T> : IDisposable
        where T : class
    {
 
        public event EventHandler CreatedResource;
        public delegate T CreateResourceDelegate();
        public delegate bool CanReuseResourceDelegate(T obj);
 
        public ResourcePool(CreateResourceDelegate creatorDelegate, CanReuseResourceDelegate checkerDelegate)
        {
            this.MaxResourceCount = 10;
            this.IterationTimeout = 5;
            this.MaxRetry = 100;
            this.Creator = creatorDelegate;
            this.CheckResource = checkerDelegate;
        }
 
        private CreateResourceDelegate Creator { get; set; }
 
        private CanReuseResourceDelegate CheckResource { get; set; }
 
        /// <summary>
        /// Retreives a resource from the pool.
        /// </summary>
        /// <returns></returns>
        public T Get()
        {
            T obj = null;
            try
            {
                int tries = 0;
                while (obj == null && (this.MaxRetry == 0 || tries++ <= this.MaxRetry))
                {
                    if (Queue.Count == 0)
                    {
                        if (this.MaxResourceCount == 0 || (this.MaxResourceCount > this.ActiveResourceCount))
                        {
                            if (this.Creator == null)
                                throw new NullReferenceException("Unable to create new Resource Instance");
 
                            obj = this.Creator();
                            FireEvent(ref this.CreatedResource);
                        }
                        else
                        {
                            Thread.Sleep(this.IterationTimeout); // wait for one to become available if we can't create one.
                        }
                    }
                    else
                    {
                        obj = Queue.Dequeue();
                    }
                }
            }
            finally
            {
                Interlocked.Increment(ref this._ActiveResourceCount);
            }
 
            if (obj == null)
                throw new NullReferenceException("Unable to retrieve Resource Instance");
 
            return obj;
        }
 
        /// <summary>
        /// Returns a resource to the pool.
        /// </summary>
        /// <param name="obj"></param>
        public void Release(T obj)
        {
            try
            {
                if (this.MaxResourceCount == 0 || Queue.Count < this.MaxResourceCount)
                {
                    if (this.CheckResource == null || this.CheckResource(obj))
                    {
                        Queue.Enqueue(obj);
                    }
                }
            }
            finally
            {
               Interlocked.Decrement(ref this._ActiveResourceCount); //decrement counter so we know we can reuse the resource.
            }
        }
 
        private int _ActiveResourceCount;
         
        /// <summary>
        /// This is the maximum number of resources the pool will hold and subsequently attempt to create.  Default is 10.
        /// Set to 0 enables no limit.
        /// </summary>
        public int MaxResourceCount { get; set; }
 
        /// <summary>
        /// This is the maximum number of times the pool will look for or attempt to create a resource.  Default is 100.
        /// Set to 0 enables no limit.
        /// </summary>
        public int MaxRetry { get; set; }
 
        /// <summary>
        /// This is the length of time(in milliseconds) that the pool will wait between tries to get a resource. Default is 5ms.
        /// </summary>
        public int IterationTimeout { get; set; }
 
        private ThreadSafeQueue<T> Queue
        {
            get { return this._Queue; }
        }readonly ThreadSafeQueue<T> _Queue = new ThreadSafeQueue<T>();
 
        private void FireEvent(ref EventHandler targetEvent)
        {
            Eventing.FireEvent(ref targetEvent, this);
        }
 
        public void Dispose(bool disposing)
        {
            if (disposing)
            {
                this.Queue.Clear();
            }
        }
 
        public void Dispose()
        {
            this.Dispose(true);
        }
    }


 
 
I know I am tearing through this quickly, but it's a lot to explain.
 
Now we need to have some sort of managed work unit that the thread can work on.  We want it's work unit to be generic and should be easily derived from:
 

public abstract class WorkerBee
    {
        public WorkerBee() { }
 
        public abstract void Start();
    }
 
    public abstract class WorkerBee<T> : WorkerBee
    {
        public T WorkUnit { get; set; }
    }
 
    /// <summary>
    /// This worker can be used as it.  Subscribe to the WorkBegan and WorkFinished events to inject logic.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class AnyWorkerBee<T> : WorkerBee<T>
    {
        public delegate void WorkerEventHandler(WorkerBee<T> sender);
        public event WorkerEventHandler WorkBegan;
        public event WorkerEventHandler WorkFinished;
 
        protected virtual void OnWorkBegan()
        {
            if (this.WorkBegan != null)
                this.WorkBegan(this);
        }
 
        protected virtual void OnWorkFinished()
        {
            if (this.WorkFinished != null)
                this.WorkFinished(this);
        }
 
        protected virtual void WorkStart()
        {
            this.OnWorkBegan();
        }
 
        protected virtual void WorkFinish()
        {
            this.OnWorkBegan();
        }
 
        public virtual void DoWork() { }
 
        public override void Start()
        {
            this.WorkStart();
            this.DoWork();
            this.WorkFinish();
        }
    }


 
Now we can look at the actual dispatcher, we need some way to add work to a queue, have it spawn a thread if it has any left, and then execute the work.  One of the tricky things was to make sure the dispatcher thread was not ALWAYS running.  It would start itself up anytime work was added, continue running and waiting until it's work queue was empty, then shut down.  Every subsequent addition to the queue would ensure that the dispatcher was still running.
 

 
public class Dispatcher : IDisposable
    {
        public Dispatcher(int maxThreadCount)
        {
            this.Threads = new ResourcePool<Thread>(
                new ResourcePool<Thread>.CreateResourceDelegate(this.CreateThread),
                new ResourcePool<Thread>.CanReuseResourceDelegate(this.ValidateThread));
 
            this.Threads.MaxRetry = 0;
 
            this.WorkQueue = new ThreadSafeQueue<WorkerBee>();
 
            this.Threads.MaxResourceCount = maxThreadCount;
            this.EnsureDispatch(false); // setup the dispatcher
        }
 
        /// <summary>
        /// Call this to stop the dispatcher
        /// </summary>
        public void Abort()
        {
            this.AbortDispatch = true;
        }
 
        /// <summary>
        /// Call this to pause the dispatcher
        /// </summary>
        public void Pause()
        {
            this.AbortDispatch = true;
        }
 
        /// <summary>
        /// Call this to resume the dispatcher
        /// </summary>
        public void Resume()
        {
            if (this.AbortDispatch)
            {
                this.AbortDispatch = false;
                this.EnsureDispatch();
            }
        }
 
        /// <summary>
        /// Set this to prevent the dispatcher from spawning threads.
        /// </summary>
        private bool AbortDispatch
        {
            get;
            set;
        }
 
        /// <summary>
        /// This is the thread that will dispatch work to other threads.
        /// </summary>
        private Thread DispatchThread
        {
            get;
            set;
        }object _DispatcherLock = new Object();
 
        /// <summary>
        /// This will make sure that the Dispatcher is active and running.
        /// </summary>
        private void EnsureDispatch()
        {
            this.EnsureDispatch(true);
        }
 
        /// <summary>
        /// This will make sure that the Dispatcher is active and running.
        /// </summary>
        private void EnsureDispatch(bool start)
        {
            lock (this._DispatcherLock)
            {
                if (this.DispatchThread == null || this.DispatchThread.ThreadState == ThreadState.Stopped)
                {
                    this.DispatchThread = new Thread(new ThreadStart(this.FireThread));
                    this.DispatchThread.IsBackground = true;
                }
 
                if (start && ((this.DispatchThread.ThreadState | ThreadState.Unstarted) == this.DispatchThread.ThreadState))
                    this.DispatchThread.Start();
            }
        }
 
        /// <summary>
        /// This is a required callback for the Resource pool.
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        private bool ValidateThread(Thread obj)
        {
            return false; //never reuse threads
        }
 
        /// <summary>
        /// This is the method that the resource pool will call to get a new thread to work with.
        /// </summary>
        /// <returns></returns>
        private Thread CreateThread()
        {
            return new Thread(new ParameterizedThreadStart(this.DispatchWork));
        }
 
        /// <summary>
        /// The function starts the work on a new thread.
        /// </summary>
        private void DispatchWork(object state)
        {
            try
            {
                WorkerBee work = state as WorkerBee;
 
                if (work != null)
                    work.Start();
            }
            finally
            {
                //Give the thread back.
                this.Threads.Release(Thread.CurrentThread);
            }
        }
 
        /// <summary>
        /// This puts work on the queue and starts the dispatcher
        /// </summary>
        /// <param name="obj"></param>
        public void AddToQueue(WorkerBee obj)
        {
            this.WorkQueue.Enqueue(obj);
            this.EnsureDispatch();
        }
 
        private int GetQueueLength()
        {
            return this.WorkQueue.Count;
        }
 
        /// <summary>
        /// This is the callback that the dispatcher thread calls.
        /// It will initialize a new thread from the pool and start work
        /// </summary>
        private void FireThread()
        {
            WorkerBee work = null;
            while (!AbortDispatch && this.WorkQueue.TryDequeue(out work))
            {
                if (work != null)
                {
                    Thread thread = this.Threads.Get();
                    
                    if (!AbortDispatch) // check again
                        thread.Start(work);
                    else
                        this.Threads.Release(Thread.CurrentThread);
                }
            }
        }
 
        /// <summary>
        /// This is the queue of stuff to be done.
        /// </summary>
        private ThreadSafeQueue<WorkerBee> WorkQueue
        {
            get;
            set;
        }
 
        /// <summary>
        /// Simple resource pool filled with threads
        /// </summary>
        private ResourcePool<Thread> Threads
        {
            get;
            set;
        }
 
        public void Dispose(bool disposing)
        {
            if (disposing)
            {
                this.WorkQueue.Clear();
                this.Threads.Dispose();
            }
        }
 
        public void Dispose()
        {
            this.Dispose(true);
        }
    }

ThreadingDemo.zip


Download the code and test project and try it for yourself.  I will say that this is fairly experimental, although I have been using it for quite a few things and have experienced no issues.  One of the major things I have used it for is the cache scavenger in my Factory caching model and it seems to work great.

 

Posted by Brian Rudolph | with no comments
Filed under: ,

Work Harder

Work Harder!  That is a statement I find myself repeating daily.  People often wonder what makes one person better at a certain task than others.  There is a truly simple answer, practice. 

Natural ability is a myth.  With the exception of physical limitations, all ability is gained through practice.  No infant is born with the innate ability to walk.  No musician picks up an instrument for the first time and performs a flawless number.  Everything ‘great' is preceded by countless not-so-great attempts. 

The human race is a term that to some is a simple definition of our status as homosapiens.  To me, it is a bit more literal.  I recognize that there are billions of people in this world, all of whom want the same things I do.  What sets certain individuals apart from the pack is their willingness to work harder than the rest.  So for me, it's the race of humans.  Who wants to work harder?  Who wants to spend that extra effort day after day to be the best at what they do.  Someone who doesn't work as hard as I do does not deserve the same things I deserve, just as I do not deserve the same benefits of the people who work harder than I am willing to. 

I hear complaints from people about the state of their lives, every argument of which never focuses on their lack of effort.  It is always the result of some innocuous outside influence.  Bunk.  People who work hard, achieve more.  Good things happen to good people who work hard.  Being good isn't enough.  There are lots of "good" people, if the definition of "good" can be simplified to "not being bad".  Spend a few more hours with your face buried in a book rather than a pint of beer.  Unless, of course, your goal is to be the best drinker on earth.    

Everything that has gone right in my life happened to me when I went the extra mile.  Every real accomplishment didn't come from the 8 to 5 daily grind.  Good things happened during the hundred-hour weeks of work.  Times when 8 to 5 wouldn't have been enough to get the job done, allowing the opportunity to pass right by. 

There have been many times I have explained to people that epiphanies have come to me in my sleep.  Though I was not lying, this is not a result of me having some abnormal super power.  It is a result of me wrapping my mind so deeply around a problem that I am consumed by it even during my few hours of sleep. 

I like to think that everything that has happened to me in my life, I've earned.  This, of course, includes all of the bad things.  For many years my interests were simply in having fun, so my career took a nose-dive.  Then I focused entirely on work which destroyed countless relationships, as well as my physical health. So while balance has become important, I have recognized that every decision comes with consequences; consequences which I hope to never complain about.

People make choices in their lives.  If your choice is to pursue a career or path in your life that will never financially stabilize, you have no right to complain about finances.  You have chosen to sacrifice financial success for your love or interest in what it is you do.  It is not society's responsibility to fill in for your financial woes.  If you choose to sacrifice your personal life for professional glory, then do not cry about your lack of intimacy.  You chose that path.  Just realize that everything requires hard work.  Even if an individual's goal in life is to be the best parent their child could have, then they must work for it. 

This is not to say that I am better or worse than anyone else in this world.  What I am attempting to say is that I take responsibility for what happens in my life.  I will not give up, I will not rest until I am the best I can be at what I do, regardless of what this life throws at me.  The best I can be at anything will require a lifetime of effort.  So I suppose it is a valid assumption to say that I will only achieve this in the moment immediately before my death. 

I truly wish more people would take responsibility for their lives.

Thread Safe Dictionary Update

 

For those of you that have read my post about the Thread Safe Dictionary, I have a few updates. 

In recent months, I have done a ridiculous amount of multi-threaded work.  This has forced me to expand my threading libraries.  One of the primary objects that required changes\fixes was my dictionary. 

 

The dictionary uses ReaderWriterLockSlim locks.  These are clean, lightweight locks that MS has provided.  Most importantly, they allow upgradeable read locks.  I now use simple IDisposable locking wrappers.  This allows us to use the "using" syntax to ensure lock releases.

It is important to note that no safe dictionary can provide safe inserts without the caller forcing a lock.  This is because by the time you check for the existence of an object and then insert it, it may have been inserted by another thread.  The only way to prevent this is by doing a "blind" merge.  The reason I call it blind, is that when you do a merge, we check for existence, and do a replace\insert within the scope of a single write lock.  This means you cannot control which objects get replaced in the dictionary.  This is rarely important in caching situations.

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


public interface IThreadSafeDictionary<TKey, TValue> : IDictionary<TKey, TValue>
{
    /// <summary>
    /// Merge is similar to the SQL merge or upsert statement.  
    /// </summary>
    /// <param name="key">Key to lookup</param>
    /// <param name="newValue">New Value</param>
    void MergeSafe(TKey key, TValue newValue);


    /// <summary>
    /// This is a blind remove. Prevents the need to check for existence first.
    /// </summary>
    /// <param name="key">Key to Remove</param>
    void RemoveSafe(TKey key);
}


[Serializable]
public class ThreadSafeDictionary<TKey, TValue> : IThreadSafeDictionary<TKey, TValue>
{
    //This is the internal dictionary that we are wrapping
    IDictionary<TKey, TValue> dict = new Dictionary<TKey, TValue>();


    [NonSerialized]
    ReaderWriterLockSlim dictionaryLock = Locks.GetLockInstance(LockRecursionPolicy.NoRecursion); //setup the lock;


    /// <summary>
    /// This is a blind remove. Prevents the need to check for existence first.
    /// </summary>
    /// <param name="key">Key to remove</param>
    public void RemoveSafe(TKey key)
    {
        using (new ReadLock(this.dictionaryLock))
        {
            if (this.dict.ContainsKey(key))
            {
                using (new WriteLock(this.dictionaryLock))
                {
                    this.dict.Remove(key);
                }
            }
        }
    }


    /// <summary>
    /// Merge does a blind remove, and then add.  Basically a blind Upsert.  
    /// </summary>
    /// <param name="key">Key to lookup</param>
    /// <param name="newValue">New Value</param>
    public void MergeSafe(TKey key, TValue newValue)
    {
        using (new WriteLock(this.dictionaryLock)) // take a writelock immediately since we will always be writing
        {
            if (this.dict.ContainsKey(key))
            {
                this.dict.Remove(key);
            }


            this.dict.Add(key, newValue);
        }
    }


    public virtual bool Remove(TKey key)
    {
        using (new WriteLock(this.dictionaryLock))
        {
            return this.dict.Remove(key);
        }
    }


    public virtual bool ContainsKey(TKey key)
    {
        using (new ReadOnlyLock(this.dictionaryLock))
        {
            return this.dict.ContainsKey(key);
        }
    }


    public virtual bool TryGetValue(TKey key, out TValue value)
    {
        using (new ReadOnlyLock(this.dictionaryLock))
        {
            return this.dict.TryGetValue(key, out value);
        }
    }


    public virtual TValue this[TKey key]
    {
        get
        {
            using (new ReadOnlyLock(this.dictionaryLock))
            {
                return this.dict[key];
            }
        }
        set
        {
            using (new WriteLock(this.dictionaryLock))
            {
                this.dict[key] = value;
            }
        }
    }


    public virtual ICollection<TKey> Keys
    {
        get
        {
            using (new ReadOnlyLock(this.dictionaryLock))
            {
                return new List<TKey>(this.dict.Keys);
            }
        }
    }


    public virtual ICollection<TValue> Values
    {
        get
        {
            using (new ReadOnlyLock(this.dictionaryLock))
            {
                return new List<TValue>(this.dict.Values);
            }
        }
    }


    public virtual void Clear()
    {
        using (new WriteLock(this.dictionaryLock))
        {
            this.dict.Clear();
        }
    }


    public virtual int Count
    {
        get
        {
            using (new ReadOnlyLock(this.dictionaryLock))
            {
                return this.dict.Count;
            }
        }
    }


    public virtual bool Contains(KeyValuePair<TKey, TValue> item)
    {
        using (new ReadOnlyLock(this.dictionaryLock))
        {
            return this.dict.Contains(item);
        }
    }


    public virtual void Add(KeyValuePair<TKey, TValue> item)
    {
        using (new WriteLock(this.dictionaryLock))
        {
            this.dict.Add(item);
        }
    }


    public virtual void Add(TKey key, TValue value)
    {
        using (new WriteLock(this.dictionaryLock))
        {
            this.dict.Add(key, value);
        }
    }


    public virtual bool Remove(KeyValuePair<TKey, TValue> item)
    {
        using (new WriteLock(this.dictionaryLock))
        {
            return this.dict.Remove(item);
        }
    }


    public virtual void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
    {
        using (new ReadOnlyLock(this.dictionaryLock))
        {
            this.dict.CopyTo(array, arrayIndex);
        }
    }


    public virtual bool IsReadOnly
    {
        get
        {
            using (new ReadOnlyLock(this.dictionaryLock))
            {
                return this.dict.IsReadOnly;
            }
        }
    }


    public virtual IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
    {
        throw new NotSupportedException("Cannot enumerate a threadsafe dictionary.  Instead, enumerate the keys or values collection");
    }


    IEnumerator IEnumerable.GetEnumerator()
    {
        throw new NotSupportedException("Cannot enumerate a threadsafe dictionary.  Instead, enumerate the keys or values collection");
    }
}


public static class Locks
{
    public static void GetReadLock(ReaderWriterLockSlim locks)
    {
        bool lockAcquired = false;
        while (!lockAcquired)
            lockAcquired = locks.TryEnterUpgradeableReadLock(1);
    }


    public static void GetReadOnlyLock(ReaderWriterLockSlim locks)
    {
        bool lockAcquired = false;
        while (!lockAcquired)
            lockAcquired = locks.TryEnterReadLock(1);
    }


    public static void GetWriteLock(ReaderWriterLockSlim locks)
    {
        bool lockAcquired = false;
        while (!lockAcquired)
            lockAcquired = locks.TryEnterWriteLock(1);
    }


    public static void ReleaseReadOnlyLock(ReaderWriterLockSlim locks)
    {
        if (locks.IsReadLockHeld)
            locks.ExitReadLock();
    }


    public static void ReleaseReadLock(ReaderWriterLockSlim locks)
    {
        if (locks.IsUpgradeableReadLockHeld)
            locks.ExitUpgradeableReadLock();
    }


    public static void ReleaseWriteLock(ReaderWriterLockSlim locks)
    {
        if (locks.IsWriteLockHeld)
            locks.ExitWriteLock();
    }


    public static void ReleaseLock(ReaderWriterLockSlim locks)
    {
        ReleaseWriteLock(locks);
        ReleaseReadLock(locks);
        ReleaseReadOnlyLock(locks);
    }


    public static ReaderWriterLockSlim GetLockInstance()
    {
        return GetLockInstance(LockRecursionPolicy.SupportsRecursion);
    }


    public static ReaderWriterLockSlim GetLockInstance(LockRecursionPolicy recursionPolicy)
    {
        return new ReaderWriterLockSlim(recursionPolicy);
    }
}


public abstract class BaseLock : IDisposable
{
    protected ReaderWriterLockSlim _Locks;


    public BaseLock(ReaderWriterLockSlim locks)
    {
        _Locks = locks;
    }


    public abstract void Dispose();
}


public class ReadLock : BaseLock
{
    public ReadLock(ReaderWriterLockSlim locks)
        : base(locks)
    {
        Locks.GetReadLock(this._Locks);
    }


    public override void Dispose()
    {
        Locks.ReleaseReadLock(this._Locks);
    }
}


public class ReadOnlyLock : BaseLock
{
    public ReadOnlyLock(ReaderWriterLockSlim locks)
        : base(locks)
    {
        Locks.GetReadOnlyLock(this._Locks);
    }


    public override void Dispose()
    {
        Locks.ReleaseReadOnlyLock(this._Locks);
    }
}


public class WriteLock : BaseLock
{
    public WriteLock(ReaderWriterLockSlim locks)
        : base(locks)
    {
        Locks.GetWriteLock(this._Locks);
    }


    public override void Dispose()
    {
        Locks.ReleaseWriteLock(this._Locks);
    }
}

 

Posted by Brian Rudolph | 16 comment(s)
Filed under: ,

Thread Safe Dictionary in .NET with ReaderWriterLockSlim

Since MS has decided to not include a thread-safe dictionary in the .NET framework, many of us have been forced to implement our own.  What MS has done now with .NET 3.5 is given us a newer locking mechanism which makes this task easier. 

Previously, we had 2 lock mechanisms, neither of which worked very well for my uses.  The first is the Lock statement.  While this method is effective, it causes serious contention issues with simultaneous reads\writes.  Since it is generally safe to execute multiple concurrent reads from a dictionary, this was a huge performance flaw as the Lock statement was forcing us to perform all actions against the object in a serial fashion.

So that left ReaderWriterLock, which would allow us to take out Reader & Writer locks independently.  This seemed to be the answer.  Unfortunately, after further testing and review, MS and the dev communities warned against this lock type as it could have unintended consequences in certain situations.  The explanations for these I will not go in to, a simple Google search will answer those questions.  For the most part, I don't have the mental capacity to understand, much less explain the failures.  I will tell you that I have tested this method, and ran in to some issues, and subsequently abandoned the approach.

With .NET 3.5 comes the brand-spankin-new ReaderWriterLockSlim.  ReaderWriterLockSlim is similar to the ReaderWriterLock in functionality, minus some of the drawbacks.  Of course any new approach will bring on its own consequences, and if you do a little research, you will find that Slim isn't infallible either. 

Many of our applications implement the Factory model.  Factory models are great, they are extensible, and they can be extremely performant.  With that said, any data driven application that uses the Factory model without a caching model, will most likely perform poorly.  So, in our factories, we build in a caching mechanism.  A very simple type and ID based cache that allows us to persist commonly used objects to in-memory cache for a specific amount of time.  I won't go in to the implementation of this model here as every caching implementation has its own needs and wants.

At the heart of this and likely any caching model is inevitably a Dictionary or Dictionary like structure.  MS programmers have spent countless hours fine-tuning the Dictionary class to make it as performant as possible.  I challenge anyone to write a managed Dictionary that performs as well in such a wide variety of scenarios.  I've tried and failed.  Unfortunately, MS has not provided a thread-safe implementation.  Generally when you run into the question of thread-safety, most people have no idea what you are talking about.  The problem with writing truly thread-safe code that can work in any scenario is that you will sacrifice performance.  If you tailor your thread-safe mechanisms to your particular problem, you can generally maintain a higher level of performance.

The reason we need thread-safety is not that we are specifically spawning threads.  In IIS, worker processes are inherently multi-threaded.  Therefore, using static objects in a web-farm generally requires some level of thread safety, otherwise you will get dreaded "An item with the same key has already been added" errors.  This is because between the time you check to see if a key already exists in your dictionary and the time you insert it, some other thread may have inserted this key.  This is especially the case in object factories, because you have multiple threads attempting to access/create objects and subsequently cache them.

This is the code I've written.  Update: This code has been tested, and is working well.  I will keep this post updated with any changes and test results.  I also have not made this class utilize lock escalation, which ReaderWriterLockSlim supports.  As always, please perform your own testing.

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


public interface IThreadSafeDictionary<TKey, TValue> : IDictionary<TKey, TValue>
{
    /// <summary>
    /// Merge is similar to the SQL merge or upsert statement.  
    /// </summary>
    /// <param name="key">Key to lookup</param>
    /// <param name="newValue">New Value</param>
    void MergeSafe(TKey key, TValue newValue);


    /// <summary>
    /// This is a blind remove. Prevents the need to check for existence first.
    /// </summary>
    /// <param name="key">Key to Remove</param>
    void RemoveSafe(TKey key);
}


[Serializable]
public class ThreadSafeDictionary<TKey, TValue> : IThreadSafeDictionary<TKey, TValue>
{
    //This is the internal dictionary that we are wrapping
    IDictionary<TKey, TValue> dict = new Dictionary<TKey, TValue>();


    [NonSerialized]
    ReaderWriterLockSlim dictionaryLock = Locks.GetLockInstance(LockRecursionPolicy.NoRecursion); //setup the lock;


    /// <summary>
    /// This is a blind remove. Prevents the need to check for existence first.
    /// </summary>
    /// <param name="key">Key to remove</param>
    public void RemoveSafe(TKey key)
    {
        using (new ReadLock(this.dictionaryLock))
        {
            if (this.dict.ContainsKey(key))
            {
                using (new WriteLock(this.dictionaryLock))
                {
                    this.dict.Remove(key);
                }
            }
        }
    }


    /// <summary>
    /// Merge does a blind remove, and then add.  Basically a blind Upsert.  
    /// </summary>
    /// <param name="key">Key to lookup</param>
    /// <param name="newValue">New Value</param>
    public void MergeSafe(TKey key, TValue newValue)
    {
        using (new WriteLock(this.dictionaryLock)) // take a writelock immediately since we will always be writing
        {
            if (this.dict.ContainsKey(key))
            {
                this.dict.Remove(key);
            }


            this.dict.Add(key, newValue);
        }
    }


    public virtual bool Remove(TKey key)
    {
        using (new WriteLock(this.dictionaryLock))
        {
            return this.dict.Remove(key);
        }
    }


    public virtual bool ContainsKey(TKey key)
    {
        using (new ReadOnlyLock(this.dictionaryLock))
        {
            return this.dict.ContainsKey(key);
        }
    }


    public virtual bool TryGetValue(TKey key, out TValue value)
    {
        using (new ReadOnlyLock(this.dictionaryLock))
        {
            return this.dict.TryGetValue(key, out value);
        }
    }


    public virtual TValue this[TKey key]
    {
        get
        {
            using (new ReadOnlyLock(this.dictionaryLock))
            {
                return this.dict[key];
            }
        }
        set
        {
            using (new WriteLock(this.dictionaryLock))
            {
                this.dict[key] = value;
            }
        }
    }


    public virtual ICollection<TKey> Keys
    {
        get
        {
            using (new ReadOnlyLock(this.dictionaryLock))
            {
                return new List<TKey>(this.dict.Keys);
            }
        }
    }


    public virtual ICollection<TValue> Values
    {
        get
        {
            using (new ReadOnlyLock(this.dictionaryLock))
            {
                return new List<TValue>(this.dict.Values);
            }
        }
    }


    public virtual void Clear()
    {
        using (new WriteLock(this.dictionaryLock))
        {
            this.dict.Clear();
        }
    }


    public virtual int Count
    {
        get
        {
            using (new ReadOnlyLock(this.dictionaryLock))
            {
                return this.dict.Count;
            }
        }
    }


    public virtual bool Contains(KeyValuePair<TKey, TValue> item)
    {
        using (new ReadOnlyLock(this.dictionaryLock))
        {
            return this.dict.Contains(item);
        }
    }


    public virtual void Add(KeyValuePair<TKey, TValue> item)
    {
        using (new WriteLock(this.dictionaryLock))
        {
            this.dict.Add(item);
        }
    }


    public virtual void Add(TKey key, TValue value)
    {
        using (new WriteLock(this.dictionaryLock))
        {
            this.dict.Add(key, value);
        }
    }


    public virtual bool Remove(KeyValuePair<TKey, TValue> item)
    {
        using (new WriteLock(this.dictionaryLock))
        {
            return this.dict.Remove(item);
        }
    }


    public virtual void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
    {
        using (new ReadOnlyLock(this.dictionaryLock))
        {
            this.dict.CopyTo(array, arrayIndex);
        }
    }


    public virtual bool IsReadOnly
    {
        get
        {
            using (new ReadOnlyLock(this.dictionaryLock))
            {
                return this.dict.IsReadOnly;
            }
        }
    }


    public virtual IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
    {
        throw new NotSupportedException("Cannot enumerate a threadsafe dictionary.  Instead, enumerate the keys or values collection");
    }


    IEnumerator IEnumerable.GetEnumerator()
    {
        throw new NotSupportedException("Cannot enumerate a threadsafe dictionary.  Instead, enumerate the keys or values collection");
    }
}


public static class Locks
{
    public static void GetReadLock(ReaderWriterLockSlim locks)
    {
        bool lockAcquired = false;
        while (!lockAcquired)
            lockAcquired = locks.TryEnterUpgradeableReadLock(1);
    }


    public static void GetReadOnlyLock(ReaderWriterLockSlim locks)
    {
        bool lockAcquired = false;
        while (!lockAcquired)
            lockAcquired = locks.TryEnterReadLock(1);
    }


    public static void GetWriteLock(ReaderWriterLockSlim locks)
    {
        bool lockAcquired = false;
        while (!lockAcquired)
            lockAcquired = locks.TryEnterWriteLock(1);
    }


    public static void ReleaseReadOnlyLock(ReaderWriterLockSlim locks)
    {
        if (locks.IsReadLockHeld)
            locks.ExitReadLock();
    }


    public static void ReleaseReadLock(ReaderWriterLockSlim locks)
    {
        if (locks.IsUpgradeableReadLockHeld)
            locks.ExitUpgradeableReadLock();
    }


    public static void ReleaseWriteLock(ReaderWriterLockSlim locks)
    {
        if (locks.IsWriteLockHeld)
            locks.ExitWriteLock();
    }


    public static void ReleaseLock(ReaderWriterLockSlim locks)
    {
        ReleaseWriteLock(locks);
        ReleaseReadLock(locks);
        ReleaseReadOnlyLock(locks);
    }


    public static ReaderWriterLockSlim GetLockInstance()
    {
        return GetLockInstance(LockRecursionPolicy.SupportsRecursion);
    }


    public static ReaderWriterLockSlim GetLockInstance(LockRecursionPolicy recursionPolicy)
    {
        return new ReaderWriterLockSlim(recursionPolicy);
    }
}


public abstract class BaseLock : IDisposable
{
    protected ReaderWriterLockSlim _Locks;


    public BaseLock(ReaderWriterLockSlim locks)
    {
        _Locks = locks;
    }


    public abstract void Dispose();
}


public class ReadLock : BaseLock
{
    public ReadLock(ReaderWriterLockSlim locks)
        : base(locks)
    {
        Locks.GetReadLock(this._Locks);
    }


    public override void Dispose()
    {
        Locks.ReleaseReadLock(this._Locks);
    }
}


public class ReadOnlyLock : BaseLock
{
    public ReadOnlyLock(ReaderWriterLockSlim locks)
        : base(locks)
    {
        Locks.GetReadOnlyLock(this._Locks);
    }


    public override void Dispose()
    {
        Locks.ReleaseReadOnlyLock(this._Locks);
    }
}


public class WriteLock : BaseLock
{
    public WriteLock(ReaderWriterLockSlim locks)
        : base(locks)
    {
        Locks.GetWriteLock(this._Locks);
    }


    public override void Dispose()
    {
        Locks.ReleaseWriteLock(this._Locks);
    }
}


 

[Update]
Through some testing, I found the need to update the ThreadSafe Dictionary.  I changed all of the locking to use IDisposables to ensure lock creation and destruction.

 

Microsoft 2008 Platform Launch - Heroes Happen {Here}

For those of you that live under a rock, the Microsoft 2008 Platform Launch has kicked off.  It is the launch event for Sql Server 2008, Windows Server 2008, and Visual Studio 2008.

The company I work for, Big Hammer, has been featured in the event.  As well of some of my products.

Check out the case study to get an idea of what I do all day.

SQL Server Constants... The Constant Struggle..

Sql Server does not allow for user defined constants.  So we are forced to take other routes like hard-coded values, scalar udf's, settings tables, etc. 

Unfortunately, all methods are not equal.  You need to carefully consider your use of different methods, and test the results as all of these methods result in different approaches by the query optimizer.

We use an object factory that is tightly coupled to database tables.  To simplify data access we have a single view that becomes, in essence, a partitioned table.  We'll call it dbo.Object

This view looks something like this:

1
2
3
4
5
6
7
8
9
10
create view dbo.Object
as
select 1 as ObjectType_ID, ID, Description from dbo.[User]
union all 
select 2 as ObjectType_ID, ID, Description from dbo.object2
union all 
select 3 as ObjectType_ID, ID, Description from dbo.object3
union all 
select 4 as ObjectType_ID, ID, Description from dbo.object4
--etc..

Now to query against that view, you can simply predicate on objecttype.  If you check the IO statistics, it is only looking up against the one table, provided you query it properly.  Don't bother looking at the Query Plan as it does not truly reflect what the server does to fetch the data.

So the idea is, we have a table which directly related concrete types in code to database object types.  This way objects can very simply load themselves from the DB.  Poor coding practices aside, for many applications this is a perfectly legitimate model.

The problem comes in when writing queries against these partitioned views.  We were looking for a way to not have to hard-code type ID's into sprocs or queries.  This is where constants would be a big help.  I could potentially define a constant called @@UserType and equate it to it's corresponding database object type. 

This way when writing a query to extract all user info, I could simply write:

1
Select * from dbo.Object where ObjectType_ID = @@UserType

Here are the multiple ways we have tried to accomplish this, each has it's own unique performance outcomes:

First, turn IO statistics output on for your connection.

1
set statistics io on

This query works properly, unfortunately we are hardcoding the ID, which is what we are trying not to do.  This is the baseline.  We want results identical to this.

1
Select * from dbo.Object where ObjectType_ID = 2

So lets try creating a UDF that returns that ObjectType_ID

1
2
3
4
5
6
create function [ObjectType].[User]()
returns int
as
begin
    return(1) 
end

This query unfortunately evaluates each table, but at least it doesn't scan them

1
2
3
4
declare @objtype int
set @objtype = ObjectType.[User]() -- a udf that returns a value

Select * from dbo.Object where ObjectType_ID = @objtype 

This query is closer, but it is creating a working table and is evaluating for every row

1
Select * from dbo.Object where ObjectType_ID = ObjectType.[User]()

I modified the UDF to take a useless param, in hopes that the deterministic decisions were based on the input param to output, but to no avail.
The results were same as above.

1
Select * from dbo.Object where ObjectType_ID = ObjectType.[User](0)

I changed the UDF to take the string Type name as an input, and a simple CASE or IF statement is user to return the correct ID.
This would be optimal, as it would prevent me from having to create a UDF for each Type.  I also tried it with looking up the value in a table.
Unfortunately we get the same result.

1
Select * from dbo.Object where ObjectType_ID = ObjectType.GetType('User')

Lets try a subquery.
This is the worst, as it scans each table.

1
2
Select * from dbo.Object 
where ObjectType_ID = (Select ObjectType.[User]())

Joining on a settings table is an option, unfortunately as we may be doing multiple joins on tables requiring these constants, we would have to do multiple joins on the settings table, which turns out to be very inefficient.

Chuck Heinzelman pointed out an intersting function to call to check if the UDF is being treated as deterministic:

1
select objectpropertyex(object_id('objecttype.user'), 'isdeterministic') -- returns 0

This returns False

So taking Chuck's advice, I schema bound the function:

1
2
3
4
5
6
7
alter function [ObjectType].[User]()
returns int
with schemabinding
as
begin
return(1) 
end 

Now, we try this again: 

1
Select objectpropertyex(object_id('objecttype.user), 'isdeterministic') -- returns 1

Excellent, now it returns True.

Unfortunately, we get almost the same results if we re-run the queries. 
I did not, however, profile it to see if it is truly evaluating the function for every row.  I suspect it is not.  So the use of the UDF may be not so bad if the only result is that it is using a worktable.  Unfortunately, every place i use the UDF in a query, it creates another worktable.

So until we have a better CONST struct in SQL we will be forced to hardcode values for some of our queries.

 

Posted by Brian Rudolph | with no comments
Filed under:

Media Center Woes

So about a year ago i began my quest for the ultimate home media experience.  I have the A/V components(TV's, Projectors, Speakers, Etc.) but i needed to tie all of my installations together.  I have a Projector with a 110+ inch screen in my basement, and a 73" DLP in my great room. I also have flat panel LCD's scattered throughout my home. 

The goal was to provide live TV, recorded TV, music, and DVD access to all stations through one component.  Whether that component was an xbox 360, a Vista Media Center PC, or whatever, i wanted one at each station.  So i sat and chatted with a friend from work, Casey Chesnut who is a former Media Center MVP.  We decided to try a few approaches.

So I started with the primary media center pc.  This was going to be my focal point, my connector to my digital cable, and the center for any DVR.  I did some research and found that the legal jackals at the digital cable companies are ensuring that only qualified (read paid-up) manufacturers can sell media center pc's with digital cable tuner cards.  So after some digging, i made a choice and purchased a s1Digital media center with two digital cable tuner cards.  This thing was flaky as could be for the first few weeks.  After some configuration changes, uninstalling the Intel Viiv garbage, and a firmware update for my the tuner cards, it is finally stable.  The only thing that is left is that the machine has a built-in IR receiver that works only half of the time.  So i was forced to connect an external IR port.  The only problem is that now, half of the time, the machine is registering double button actions from the remote.  This sucks.  So after an hour of looking around in the case for the cable or port to disconnect the built-in IR sensor, i just decided to cover the front face with tape.  Black Gaffers tape is the ultimate visual enhancement for a high-end home A/V setup.  The good news is that the machine is pretty slick.  Lots of processing power, and the video quality from digital cable is incredible. 

Now, on to the second part of this install.  I have somewhere around 500 DVD's that i've acquired over the past years.  I previously had them most of them in a 400 disc changer that was controlled via a pretty slick Escient media interface.  The Escient did all of the cataloging, and only twice did it fail to recognize a DVD.  Unfortunately, i found myself shuttling DVD's from my upstairs to my downstairs or to my bedroom to watch them.  This is a hassle, and since i am a big lazy goon, i'm generally not too careful with them.  So, i decided to rip all of my DVD's to a giant drive array.  So i bought 2 NAS devices, one is a ReadyNAS, and the other is a linksys.  The ReadyNAS is great, and i haven't used the linksys yet, so i have no verdict.  Either way, i have something in the range of 5TB+ of RAID 5 storage.  This is great.  The only pain is that you can't just copy most DVD's to a file structure, as DRM prevents it.  The good news is that Slysoft AnyDVD fixes this problem and strips of all DRM.  I could have converted or compressed the DVD's and saved some space, but i'm one of those people who prefers to have an exact copy of my hard media.

Excellent, so now i have my movies all in one place.  Scratch that.  I will have them in one place once i've finished ripping them all.  Anyways, now i have a huge directory structure with many of my dvd's.  Unfortunately, coming from the Escient, i want a better and prettier interface than a folder structure.  Casey recommended the My Movies plugin for Media Center.  I installed it and it works fairly well.  It's a little buggy, but acceptable for a free community initiative.  This cataloged my DVD's and allowed me to play them on my media center.  Sweet. 

So my Primary TV is mostly set.  Now lets get this lovely media piped to other rooms!  My first plan of attack was an xbox 360.  This worked really well.  I could connect to my media center and watch live and recorded TV through my xbox!  This was awesome, such a simple solution.  Not only are 360 consoles fairly cheap, but they have great video and sound capabilities and i could play a game anywhere in the house.  Excellent, order up 5 xbox consoles right?  Negative.  The 360 console will not allow you to play a DVD format movie from a network share.  They have been recently extended to allow divx though.  Unfortunately at 110" divx looks like crap.  Also, i'll be damned if i'm going to convert and store every movie i have to divx. 

Casey, so intrigued by this debacle, began trying to circumvent this limitation.  Custom media streams, on-the-fly conversions, etc.  Nothing looked or worked very well.  Thanks for the effort though bud.

On to plan B.  A media center PC at every TV.  Sounds like a winner if i can find a cheap enough PC to warrant using just for this purpose.  Enter HP Slimline Refurbs.  It turns out that buy.com was selling these very capable, very nice looking refurbs for just over $300.  Excellent.  Order a couple and give em a shot.  The machines themselves are impressive, great stats for a cheap machine, and they come with Vista Home Premium.   Excellent.  Yes! I can play my dvd's! 

But wait... i can't use a Media Center PC as an extender, just like the xbox?  Nope! MS has failed me again.  The initiave in MS to provide a software based extender has been stalled or flat-out cancelled according to Casey. 

So, on these nice Media Center PC's, i cannot watch live TV or recorded TV from my primary media center.  And because the cable companies won't allow a home-built user to buy and install his own digital cable tuners, I cannot just use them independently.  Even if i play some tricks and share the saved files for recorded TV, the drm prevents me from watching Whose Line at any TV i want. 

 Damn...  So, i'm going to try a few non-MS methods.  There are a few independant Media Center clones out there, even a few open-source ones in C#.  I'll keep you all posted.

 

 

Posted by Brian Rudolph | with no comments
Filed under: ,

MS DTC Configuration for SQL 2005 in a Distance-Cluster on Windows Server 2003 Datacenter IA64

As does everyone from time-to-time, we had a lovely "learn as you go" moment in the middle of a deployment recently.  As it turns out there are some very specific rules for setting up MS DTC in a clustered environment.  As always, individual results may very.

First of all, most DTC changes don't require an operating system restart.  Unfortunately, it would appear, in a clustered environment this is not true.  We did, however, find that if you bring down services in the correct order, you can successfully make changes to DTC without a system restart.

  1. Offline SQL Instances
  2. Offline DTC
  3. Offline Backup Agents(we use SQL Safe from Idera)
  4. Make DTC changes
  5. Restart Server (we discovered this the hard way after numerous attempts)
  6. Online Backup Agents
  7. Online DTC
  8. Online SQL Instances

Now that we have that out of the way, we can get to the settings.  For this example, lets assume we have 3 servers, 2 of them are distance-clustered, the 3rd is not a member of the cluster but will be executing distributed transactions to the cluster itself.

First of all, if you don't know where the DTC settings are they exist in the "Component Services" snap-in for MMC(run:mmc; add snap-in:"Component Services").  For me, I RDP into the console on the server itself, so the default "My Computer" node that appears works, otherwise connect to the appropriate server.  Then, right-click 'Properties" on the server name and you have a window which gives you a tab labeled "MSDTC". 

This tab looks like this:

 

So this screen tells us some things.  First make sure that DTC is started on all the servers involved(unless you brought them offline purposely as described above).  If not, nothing is going to work.  You will probably want to make sure that service starts automatically.  Your cluster group should probably handle this.

Now the fun stuff. Like I said, individual results may vary but these settings worked for us.

Open the Security Configuration dialog:

 

 

This dialog shows the configuration as works for our Server 1 & 2(the clustered servers), "Mutual Authentication Required" will NOT work in a clustered environment. Not sure if "Incoming Caller Authentication Required" works, we couldn't make it work properly.

On the non-clustered server, you must also NOT use "Mutual Authentication Required", however "Incoming Caller Authentication Required" authentication seems to be sufficient for the non-clustered servers.

What this means then is that all servers that will be opening or receiving distributed transactions to or from a clustered environment, must have their DTC settings changed.  We found this out the hard way, as DTC transactions were working in one direction, and not the other.  So it is possible that if your transactions are only being initiated in one direction you may not need to mess with certain servers.  Test it, you'll be glad you took the time.

If you are reading this post, you've probably already seen the DTCPing.exe app that is on the Microsoft site.  It is important to note that DTCPing happily returned no errors even when our authentication settings were jacked.  So, while this utility may help diagnose certain DTC issues, i'm not sure that it helps in this scenario.

Some of this information is outlined very obscurely in this KB article http://support.microsoft.com/kb/899191/

Notes:

  • I am not sure as to the security implications of these settings in an exposed environment.  As our servers are safely sitting in an internal network, I'm not too concerned.  You will have to research and evaluate that decision on your own.
  • I did not have to change any settings on the second machine in the cluster, as cluster manager did it for me when I initiated a test fail-over.  Once again, run your own test.