Performance

Virtual Method Performance Penalty, Revisited

18 commentsWritten on December 17th, 2010 by
Categories: C#, Performance

I wrote a post about a year ago which discussed a test of the performance difference between calling virtual methods and non-virtual methods. This morning, someone added the following comment to that post:

if you have 100 subclasses of class A, and they all override a method a, it will take a lot longer for it to figure out which version of a to call. Think of it as a switch statement with one case label verses a switch statement with 100 case labels. Since you’re just testing it with one method it’s not surprising that the cost is negligible.

My Bullshit-detector started beeping while reading that, so i just had to see if the number of subclasses indeed had an impact. I didn't go all the way up to 100 subclasses, but i went with 15. If there is indeed a performance penalty that grows with the number of subclasses in play, then surely i'd have to see some difference when using 15 subclasses over just 1, right?

In the original test, i had the following 2 classes:

    public class MyClass
    {
        public long someLong;

        public void IncreaseLong()
        {
            someLong++;
        }

        public virtual void VirtualIncreaseLong()
        {
            someLong++;
        }
    }

    public class MyDerivedClass : MyClass
    {
        public override void VirtualIncreaseLong()
        {
            someLong += 2;
        }
    }

Now, i wasn't quite sure whether the commenter meant having a bunch of classes that inherited directly from MyClass, or having a set of inheriting classes in a deep inheritance tree. Just to be sure, i tested both cases.

In the first case, i have classes like MyDerivedClass1, MyDerivedClass2, ... , MyDerivedClass15 that all inherit directly from MyClass. In the second case, MyDerivedClass1 inherits from MyClass, MyDerivedClass2 inherits from MyDerivedClass1, ... , and MyDerivedClass15 inherits from MyDerivedClass14.

The code of the test is still largely the same as it was in the previous post, with just some minor modifications to make sure that more of the code to be executed has been JIT'ed prior to the actual test-run:

    class Program
    {
        const int iterations = 1000000000;

        static void Main(string[] args)
        {
            var myObject = new MyClass();
            var myDerivedObject = new MyDerivedClass15();

            // we do this so there's no first-time performance cost while timing
            EnsureThatEverythingHasBeenJitted(myObject);
            EnsureThatEverythingHasBeenJitted(myDerivedObject);

            TestNormalIncreaseMethod(myObject, iterations);
            TestVirtualIncreaseMethod(myObject, iterations);

            TestNormalIncreaseMethod(myDerivedObject, iterations);
            TestVirtualIncreaseMethod(myDerivedObject, iterations);

            Console.ReadLine();
        }

        static void EnsureThatEverythingHasBeenJitted(MyClass theObject)
        {
            theObject.IncreaseLong();
            theObject.VirtualIncreaseLong();
            TestNormalIncreaseMethod(theObject, 1, false);
            TestVirtualIncreaseMethod(theObject, 1, false);
        }

        static void TestNormalIncreaseMethod(MyClass theObject, int numberOfTimes, bool printToConsole = true)
        {
            if (printToConsole) Console.WriteLine(string.Format("calling the IncreaseLong method of type {0} {1} times", theObject.GetType().Name, numberOfTimes));
            
            var stopwatch = Stopwatch.StartNew();
            for (var i = 0; i < numberOfTimes; i++)
            {
                theObject.IncreaseLong();
            }
            stopwatch.Stop();

            if (printToConsole) Console.WriteLine("Elapsed milliseconds: " + stopwatch.ElapsedMilliseconds);
        }

        static void TestVirtualIncreaseMethod(MyClass theObject, int numberOfTimes, bool printToConsole = true)
        {
            if (printToConsole) Console.WriteLine(string.Format("calling the VirtualIncreaseLong method of type {0} {1} times", theObject.GetType().Name, numberOfTimes));

            var stopwatch = Stopwatch.StartNew();
            for (var i = 0; i < numberOfTimes; i++)
            {
                theObject.VirtualIncreaseLong();
            }
            stopwatch.Stop();

            if (printToConsole) Console.WriteLine("Elapsed milliseconds: " + stopwatch.ElapsedMilliseconds);
        }
    }

In the first test (multiple direct subclasses of MyClass) i got the following result:

fifteen subclasses

(note: for this test, i used MyDerivedClass1 instead of MyDerivedClass15 as in the listed code)

In the second test (inheritance tree) i got the following result:

fifteen nested subclasses

As you can once again see, the difference is completely negligible. So here's what i propose: until someone actually shows a case where a clear-cut performance penalty is shown that is even slightly relevant to real-world usage, we should just drop the whole "virtual methods are expensive!"-thing.

Performance Of NHibernate With Ruby Objects Compared To Traditional C# Objects

3 commentsWritten on October 19th, 2010 by
Categories: IronRuby, NHibernate, Performance, Ruby

I recently showed how you can use NHibernate to persist and query Ruby objects through IronRuby. We've continued the experiment (though we've already done some big optimizations in the code based on the first results of these tests) and we recently had to decide whether or not the performance difference between using NHibernate with regular static C# code and using it with dynamic Ruby objects was acceptable. So we ran a set of tests, and compared all of the numbers. Note that we don't claim that these benchmarks are scientifically correct in any way, but we do think they give us a good idea on what we can reasonably expect. I want to share the results with you, and would appreciate any feedback you guys have on this... particularly on whether or not we missed something obvious in our tests or whether or not we should trust these numbers. After all, we're not professional benchmarkers so our approach might very well just suck :)

We have a scenario which consists of 15 'actions'. For these actions, we use some tables from the Chinook database, basically just Artist/Album/Track/Genre/MediaType. The actions are the following:

  1. Retrieve single track without joins, and access each non-reference property
  2. Retrieve single track with joins, and access all properties, including references
  3. Retrieve single track without joins, and access all properties, including references (triggers lazy-loading)
  4. Create and persist object graph: one artist with two albums with 13 tracks each
  5. Retrieve created artist from nr 4, add a new album with another 13 tracks, change the title of the first album from nr 4, and remove the second album from nr 4 including its tracks
  6. Retrieve created artist from nr 4 and delete its entire graph
  7. Create a single track
  8. Retrieve single track from step 7 and update it
  9. Retrieve single track from step 7 and update the name of one of its referenced properties
  10. Retrieve single track from step 7 and change one of the reference properties so it references a different instance
  11. Delete the track from step 7
  12. Retrieve 100 tracks and access each non-reference property
  13. Retrieve 200 tracks and access each non-reference property
  14. Retrieve 100 tracks without joins and access all properties, including references (triggers lazy-loading)
  15. Retrieve 100 tracks with joins and access all properties, including references

Note: when i say we access reference properties to trigger lazy loading, i mean that we access a non-id property of the referenced property to make sure it indeed hits the database.

The scenario is ran 500 times with regular C# objects, and 500 times with Ruby objects. We keep track of the average time of each action in the scenario, as well as the total duration of the scenario. Also, keep in mind that we ran these tests on a local database.

The following graph shows the average duration of each action in milliseconds on the Y axis, and the number of the action on the X axis:

(you can click on the graph to watch it in its full size)

Before i'll discuss these results, i'd also like to show the following graph which shows the average difference in milliseconds between the static and the dynamic execution of each action:

Two actions immediately stand out: the last two which both deal with fetching a set of items and accessing all of their properties. They're both about 6ms slower than their static counterparts, which is a performance penalty of 71% for action 14, and 87% for action 15. That deals with a part of code that we can't really optimize any more. Well, it probably is possible but we've already done a lot of work on that, and this is the best we can come up with so far.

Now, those 2 actions are things we avoid as much as possible in real code anyway, so maybe they aren't that big of an issue. The other 2 actions where there is a noticable difference (though it actually means an increase in average execution time of 1.1ms using a local database) is the creation and persistance of an object graph (step 4), and the retrieval/modification/persistence of that same graph (step 5). Most other actions don't have a noticeable difference, and in some cases the dynamic version is actually faster than the static one, no doubt because NHibernate has in some cases less work to do when using the Map EntityMode (which we rely on for the dynamic stuff) compared to the Poco EntityMode.

We also wanted to see whether the performance difference would get worse when spreading the workload evenly over a set of threads, or even a 'pool' of IronRuby engines. I was pretty happy to see that it didn't really lead to a noticeable difference.

The following graph shows the average duration of the entire scenario in a couple of different situations:

I do have to mention that the numbers shown in this graph aren't averages, but the result from running the scenario once in each situation. We did however ran the scenarios in each situation more than once, and while we didn't list the averages, the numbers are representative of each testrun... we didn't see any really noticeable differences over multiple runs. The percentage difference for each situation is shown in this graph:

As you can see, the performance penalty of the entire scenario in each situation varies between 15% and 26%.

Now, considering the fact that we prefer to avoid loading 'large' sets of data through NHibernate into entities (we prefer to use projections instead for that) we wanted to see what the difference would be for the entire duration of the scenario in each situation, without the final 4 actions. Basically, just the typical CRUD scenarios:

Now the difference varies between 6% and 15%.

Now, suppose that we have a compelling reason to actually go ahead with using this approach (we do actually, but i'm not gonna get into that here), do you think we can trust these numbers? Is there anything else we're missing? Are we complete idiots for testing the performance difference like this? Do you have any feedback whatsoever? Then please leave a comment :)

Think Twice Before You Map Entities To DTOs

21 commentsWritten on September 1st, 2010 by
Categories: NHibernate, Performance

One thing that i see a lot, and that i have largely started to avoid, is that people fetch entities with NHibernate, only to transform them to DTO's so you can send them back to the client so they can be displayed in a a grid or some kind of list or whatever. This is usually pretty easy to do, especially if you already have a DTO mapper or are using something like Automapper. But this comes with a bit of overhead (both performance and memory) that you can often avoid quite easily.

Suppose i have a screen where i need to display entries based on the following DTO class:

    public class AuthorizationDto
    {
        public long Id { get; set; }
        public Guid ApplicationId { get; set; }
        public string ApplicationName { get; set; }
        public Guid? UserGroupId { get; set; }
        public string UserGroupName { get; set; }
        public Guid? UserId { get; set; }
        public string Username { get; set; }
        public Guid PermissionId { get; set; }
        public string PermissionName { get; set; }
        public string PermissionDescription { get; set; }
    }

This DTO basically contains data from 4 entities: Application, UserGroup, User and Permission. I could easily do something like this with NHibernate:

            var items = Session.CreateCriteria<Authorization>()
                .CreateAlias("Application", "a", JoinType.InnerJoin)
                .CreateAlias("User", "u", JoinType.LeftOuterJoin)
                .CreateAlias("UserGroup", "g", JoinType.LeftOuterJoin)
                .CreateAlias("Permission", "p", JoinType.InnerJoin)
                .Future<Authorization>();

            var dtos = new AuthorizationDtoMapper().ToDtos(items);

As you can see, that's very easy to do. Unfortunately, this code really does a lot of stuff that you might not realize. For starters, it retrieves all of the Authorization instances with its related Application, User, UserGroup and Permission instances. It also fetches those entities in their entirety, which means it's retrieving all of their properties while i only need their Id and Name properties really. And finally, NHibernate will set up all of the things that enable its magic for all of these entity instances. That takes a few more CPU cycles and uses more memory than you truly need for the scenario of fetching entities merely to return DTO's. This extra cost obviously becomes worse depending on the size of the resultset that you're fetching.

A better way to do this, is to simply let NHibernate fetch only the data (columns) that you need, and to let it populate the DTO's itself. You can easily do this using projections and the AliasToBeanResultTransformer class. The code would look like this:

            var dtos = Session.CreateCriteria<Authorization>()
                .CreateAlias("Application", "a", JoinType.InnerJoin)
                .CreateAlias("User", "u", JoinType.LeftOuterJoin)
                .CreateAlias("UserGroup", "g", JoinType.LeftOuterJoin)
                .CreateAlias("Permission", "p", JoinType.InnerJoin)
                .SetProjection(Projections.ProjectionList()
                    .Add(Projections.Id(), "Id")
                    .Add(Projections.Property("a.Id"), "ApplicationId")
                    .Add(Projections.Property("a.Name"), "ApplicationName")
                    .Add(Projections.Property("u.Id"), "UserId")
                    .Add(Projections.Property("u.UserName"), "Username")
                    .Add(Projections.Property("g.Id"), "UserGroupId")
                    .Add(Projections.Property("g.Name"), "UserGroupName")
                    .Add(Projections.Property("p.Id"), "PermissionId")
                    .Add(Projections.Property("p.Name"), "PermissionName")
                    .Add(Projections.Property("p.Description"), "PermissionDescription"))
                .SetResultTransformer(new AliasToBeanResultTransformer(typeof(AuthorizationDto)))
                .Future<AuthorizationDto>();

Granted, you need to write a bit more code. But that code will do far less than the first version.

Why You Shouldn’t Expose Your Entities Through Your Services

27 commentsWritten on May 17th, 2010 by
Categories: Architecture, Code Quality, Opinions, Performance, WCF

I sometimes still get questions from people who want to expose their entities through their WCF Services.  Regardless of whether these are entities that are populated through NHibernate or any other ORM, this is just not a good thing to do.  Many people prefer to accept and return entities through their services because they believe this is an easier programming model.  They believe that it takes less work than mapping to DTO’s and that as a whole, this solution is much more manageable.  Rest assured that this is a fallacy.  Any perceived benefit that you’ll get from exposing entities outside of your service layer will only last a very short time and will quickly be dwarfed by added complexity, increased maintenance overhead and a performance overhead which must not be ignored. 

In this post, i’d like to take the chance to explain the downsides to exposing entities through services.  Though i’ll probably miss quite a few of the downsides (feel free to add to the list through comments), the ones i will mention are IMO important enough to take note of.

Exposing entities to clients means your clients are very tightly coupled to your service(s)

Entities are a part of your domain.  These entities in your domain can change for various reasons.  Sometimes because functional changes are required, but quite often also for optimizations (whether they are for performance reasons or to improve the clarity and maintainability of your domain).  Functional changes can impact your clients, though that is not necessarily the case.  Optimizations hardly ever have an impact on your clients (other than possibly improved response times from your service calls obviously).  If your service layer accepts and returns domain entities, each possible change is highly likely to have an impact on your clients.  And this impact is not cheap.  In the best case scenario, it means updating your service contracts, regenerating your service proxies and redeploying your clients.  In the worst case scenario, it means making actual changes to the code of your clients.  And for what? Because of changes that shouldn’t have impacted your clients in the first place?

Ideally, your clients are as dumb as they can be.  They should know as little as possible about the actual implementation of the domain because that implementation is simply not relevant to them.  They should present users with data and give them the option to modify that data, to trigger actions and to perform certain tasks.  They should focus squarely on those tasks and pretty much everything else is typically better suited to be done behind your service layer.  If you build your clients with no real knowledge of the actual domain model, but of DTO’s and possible actions to be performed then you can reduce the level of coupling between your clients and your services substantially.

Many of the people who prefer to expose entities often claim that going for the DTO approach introduces too much extra work and too many extra, seemingly unnecessary classes.  For starters, they don’t want to write code that maps entities to DTO’s.  First of all, the amount of code that this requires is in reality very small, not to mention very easy.  Secondly, you can just as well use a library such as AutoMapper to take that pain away from you.  And contrary to what you might think, there is a big performance gain to be had from returning DTO’s over entities, but i’ll get to that in the next section.

Entities are hardly ever the most optimal representation of data

I think we can safely say that most applications need to show data in the following 3 ways:

  • In a grid view, either as a total listing of all instances of a certain type of data or the result of a search query or some kind of filtering action
  • In dropdown controls or anything else that lets users select pieces of data
  • In edit screens where a piece of data needs to be displayed in its entirety, perhaps even to be modified by the user

There are undoubtedly more ways in which data can be presented to the user but i think it’s safe to say that most business applications will certainly rely on the following 3 ways quite heavily.

In the case of a grid view, you’re frequently showing data that is related to more than one entity.  You’ll often need to include the name or the description of some associated entities.  So what exactly is it that you want to do in this situation?  Do you want to return a list of the main entities of the grid view, which all have their required association properties filled in so you can display the columns that you need in the grid view?  Do you actually need all of the properties of these entities (for both the main entities and the associated entities)?  Odds are high that you’re going to be returning a lot more data to the client than you actually need.  And that is what is realistically going to hurt the performance of your system.  Any piece of unnecessary data that you transmit to your clients has a cost associated with it.  The unnecessary data is retrieved from the database.  The entities are then serialized at the service end.  Then they are transmitted to the client.  Then they are deserialized by your client.  All of this is pretty costly, so the more unnecessary data that is included in this operation, the more your performance and the responsiveness of your client (not to mention your database and your server) is impacted negatively.

In the case of dropdown controls or anything else that lets users select pieces of data, you typically only need very few of the properties of that piece of data.  In many cases, the primary key and a name or a description are sufficient.  Do you really need to transmit the entire entity every time for usages like this? Again, keep in mind that all of that extra data that will never be used by your client needs to be retrieved, serialized, transmitted and deserialized again.  Surely, this is an awful waste, no? 

And then there’s the case where a piece of data needs to be displayed in its entirety.  In these cases, you will almost always need all of the properties of the entity that is displayed, but you’ll most often also need to show other data (things that can be selected, or linked to the main entity).  This other data will in most cases fall into the previous category where you’ll only need very little information about the actual entity.  If you’re smart, you’ve chosen the DTO approach to retrieve this data for the data that can be selected, and in that case, you already have all of the infrastructural code in place to project entities or data into DTO’s.  So you might as well reuse it for the main entity as well since you already have the capability to do this.

Always keep in mind that your entities will frequently either contain more data than needed, or less data than needed.  As such, it just doesn’t make much sense to expose entities to your clients since they are hardly ever optimal for client-side usage.  If you really want to think about performance, stop worrying about the supposed cost of mapping to DTO’s (which is truly negligible) and start focusing on what your actually sending to and from your service because this is far more costly than any kind of DTO-mapping really is.

Must your data really come from entities?

If you are displaying data to your user, does that data really need to come from your domain model?  Does it really need to be retrieved by populating a collection of entities to then return them to the client?  Again, keep the form of the data in mind when thinking about this.  In many cases, as i mentioned above, an entity is not the most optimal form of the data that your client needs.  So why even retrieve it through entities? Sure, asking your ORM to retrieve a set of entities based on a set of criteria is often the easiest thing to do, but if the easiest path were the best path, the overall quality of software projects wouldn’t be in the sad state that it’s in today.  If the form of the required data is not identical to the structure of an entity, it’s often far more optimal to simply populate a DTO directly from the data.  With NHibernate, you can easily do this by adding a list of projections to your query and then using a ResultTransformer to populate the DTO’s based on the direct output of the query.  In this case, no entity instance ever needs to be created when you’re just retrieving data, and no extra mapping between the entity and the DTO’s needs to be performed.  Your data access code simply retrieves the resulting data from a query, and puts that data directly in your DTO’s.  There’s no reason why usage of an ORM should prevent you from doing this.   Once again, this approach will offer far more performance benefits than avoiding DTO mapping at all costs ever can.

What about the behavior of your entities?

Do your entities have any behavior in them?  If not, they are already more of a DTO than a true entity.  In fact, if your entities have no behavior at all, you could even wonder why you’re using an ORM in the first place.  Now, behavior can mean many things.  It could mean lazy loading of associations.  It could mean actual business logic.  Obviously, lazy-loading doesn’t (and shouldn’t!) work client-side, but what about your business logic? Do you have business logic that can be executed client-side? Or is it business logic that should only be executed behind the service layer? If so, how do you make the distinction between this to prevent client-side usage from these entities? Whatever you do, you’re pretty much opening up a can of worms that really is better avoided in the first place.

How are you going to deal with technical issues?

Accepting and returning entities from services introduces a host of technical issues that can be quite substantial.  Serialization and deserialization specifically are issues that you need to be worried about.  If you’re using an ORM which does lazy-loading of associations, this will certainly cause serialization issues that you need to work around.  You can either disable lazy loading, or you can make sure that your entities are always fully initialized (as in: always have their associations fully loaded) before they are sent back to the client.  Disabling lazy-loading will cause performance problems in your service layer, either in places where you don’t expect them to be or in places that you haven’t thought of before it’s too late.  Fully loading your entities and their associates before returning them is another performance nightmare waiting to happen so that’s really not an ideal solution either.  You can try to hook into the serialization process or even the lazy-loading features of your ORM but whatever you do in that case will be a hack that will cause issues sooner or later.  And again, all of these problems can very easily be avoided with a solution which, i hope you realize by now, offers plenty more benefits than any solution where you accept/return entities in your service.

Conclusion

Every single downside to exposing entities through services are issues that i have myself encountered in past projects, either ones i’ve worked on myself, or ones that i’ve seen other people work on.  If that’s not enough for you, then maybe you’ll find it interesting to know that some of the brightest and most respected people (like Udi Dahan and Ayende for instance) in the .NET community also actively recommend against exposing entities through services because of the same downsides that i mentioned, though they could probably give you even more downsides that i forgot to cover in this post.  These downsides are not figments of anyone’s imagination.  They are very real, and you really, really ought to think twice before dismissing this advice. 

Using Copy-On-Write In Multithreaded Code To Reduce Locking Overhead

5 commentsWritten on March 8th, 2010 by
Categories: Multithreading, Performance

I recently posted some code that i asked you to review.  When i posted it, the code had never even executed (that’s right, not even through a test) and i only thought it would do what i needed it to do.  I consider the actual implementation non-obvious (at least for those who don’t know the copy-on-write approach to avoid traditional locking) so i just wanted to hear some reactions to the code from people who didn’t knew the context.  I promised to do a follow-up post to discuss the code in its entirety so here it is.

First, i’ll show the whole class again:

    public class TenantSessionFactoryManager : ITenantSessionFactoryManager

    {

        private readonly ITenantContext tenantContext;

        private readonly ITenantInfoHolder tenantInfoHolder;

        private readonly string mappingAssemblyName;

 

        private readonly object writeLock = new object();

        private Dictionary<Guid, ISessionFactory> sessionFactories;

 

        public TenantSessionFactoryManager(ITenantContext tenantContext, ITenantInfoHolder tenantInfoHolder, string mappingAssemblyName)

        {

            this.tenantContext = tenantContext;

            this.tenantInfoHolder = tenantInfoHolder;

            this.mappingAssemblyName = mappingAssemblyName;

            sessionFactories = new Dictionary<Guid, ISessionFactory>();

        }

 

        public ISession CreateSessionForCurrentTenant()

        {

            var tenantId = tenantContext.CurrentTenantId;

 

            if (!sessionFactories.ContainsKey(tenantId))

            {

                CreateSessionFactoryForCurrentTenant();

            }

 

            return sessionFactories[tenantId].OpenSession();

        }

 

        private void CreateSessionFactoryForCurrentTenant()

        {

            lock (writeLock)

            {

                var tenantId = tenantContext.CurrentTenantId;

 

                if (!sessionFactories.ContainsKey(tenantId))

                {

                    var connectionString = tenantInfoHolder.GetDatabaseConnectionString(tenantId);

 

                    var sessionFactory = new Configuration()

                        .Configure()

                        .AddProperties(new Dictionary<string, string>

                                {

                                    { "connection.connection_string", connectionString },

                                    { "cache.region_prefix", "Tenant_" + tenantId }

                                })

                        .AddAssembly(mappingAssemblyName)

                        .BuildSessionFactory();

 

                    var newDictionary = new Dictionary<Guid, ISessionFactory>(sessionFactories);

                    newDictionary[tenantId] = sessionFactory;

                    sessionFactories = newDictionary;

                }

            }

        }

 

        public void RemoveSessionFactoryForTenant(Guid tenantId)

        {

            if (!sessionFactories.ContainsKey(tenantId))

            {

                return;

            }

 

            lock (writeLock)

            {

                if (!sessionFactories.ContainsKey(tenantId))

                {

                    return;

                }

 

                var sessionFactory = sessionFactories[tenantId];

                var newDictionary = new Dictionary<Guid, ISessionFactory>(sessionFactories);

                newDictionary.Remove(tenantId);

                sessionFactories = newDictionary;

 

                sessionFactory.Dispose();

            }

        }

    }

 

Basically, the purpose of this class is to hold a set of ISessionFactory instances, each of which belongs to a particular tenant in a multi-tenant application.  Tenants can be added on the fly (without restarting the application) and when an ISessionFactory doesn’t exist yet for a particular tenant, it must be created when the first request for an ISession for that tenant comes in.  Obviously, access to the sessionFactories dictionary must be thread-safe since multiple threads will be reading from the dictionary as well as occasionally writing to it.

I considered 3 options to make sure access to the dictionary would be thread-safe:

  1. Traditional locking (through the lock statement or the Monitor class)
  2. Using the ReadWriterLockSlim class
  3. Using the copy-on-write pattern

Traditional locking was quickly scratched from the list because that would require me to lock for every read of the dictionary as well as every write.  Now, pretty much every single request requires an NHibernate session which means that pretty much every single request results in a lookup in the sessionFactories dictionary.  If i need to lock for every read, this significantly hurts overall throughput of the system. 

The ReadWriterLockSlim might be a good solution here… after all, the short description of this class in MSDN says this:

Represents a lock that is used to manage access to a resource, allowing multiple threads for reading or exclusive access for writing.

Sounds like what i need, right?  But the thing is, i’ve never used the ReadWriterLockSlim class before and it hasn’t really gained my trust yet.  I know that’s a terrible excuse for not using it, but here me out.  While the ReadWriterLockSlim likely reduces locking overhead over traditional locking substantially, there still has to be some overhead for read operations, even if it is small.  In most situations, that small overhead wouldn’t bother me but in this case, that little overhead would be added to pretty much every single request in the system.  Now, writing to a dictionary implies that a new tenant has been added to the system.  In the context of this system, that’s not even gonna happen on a daily basis.  Hell, once a week is probably a best-case estimation and even that is highly optimistic.  So i really don’t want any kind of overhead on read operations when the write operation is only going to happen very occasionally.

That leaves the copy-on-write pattern.  I’ve used it before with success (though at the time, i didn’t know it was a known pattern) so this approach has already gained my trust.  It basically implies that we don’t do any locking on the read operations, but whenever a write operation occurs we copy the original set of objects, perform the write on the newly copied set and then set the reference of the original set to the newly created and modified instance.  During this whole time, every single read is safe.  Successive reads within the same logical operation however aren’t, so the following code would not be thread-safe:

            if (sessionFactories.ContainsKey(tenantId))

            {

                return sessionFactories[tenantId].OpenSession();

            }

 

Because there’s no locking on the reads, the code within the if-block could fail because the sessionFactories reference could be pointing to a new dictionary which no longer contains the element for that key. 

Of course, if you have frequent writes, the overhead of copying the set of objects every time you need to add/remove one might be bigger than you want, so this isn’t a pattern that you should use whenever you need to protect access to a shared resource. For this situation however, i think it’s ideal… though i’d obviously like to hear about better solutions :)

Now, let’s take a closer look at the pieces of code that perform the write operations.  First, adding a new ISessionFactory to the dictionary:

        private void CreateSessionFactoryForCurrentTenant()

        {

            lock (writeLock)

            {

                var tenantId = tenantContext.CurrentTenantId;

 

                if (!sessionFactories.ContainsKey(tenantId))

                {

                    var connectionString = tenantInfoHolder.GetDatabaseConnectionString(tenantId);

 

                    var sessionFactory = new Configuration()

                        .Configure()

                        .AddProperties(new Dictionary<string, string>

                                {

                                    { "connection.connection_string", connectionString },

                                    { "cache.region_prefix", "Tenant_" + tenantId }

                                })

                        .AddAssembly(mappingAssemblyName)

                        .BuildSessionFactory();

 

                    var newDictionary = new Dictionary<Guid, ISessionFactory>(sessionFactories);

                    newDictionary[tenantId] = sessionFactory;

                    sessionFactories = newDictionary;

                }

            }

        }

 

As you can see, the entire operation is put between a lock on the writeLock object instance.  The downside of this is that creating an ISessionFactory instance is an expensive operation, which means the lock will be held for a long time (could easily be one or more seconds).  Then again, i don’t anticipate this happening frequently so it’s not that big of an issue… especially since reads aren’t being blocked by this anyway.  This approach also prevents the creation of 2 ISessionFactory instances for the same tenant.  Well, unless i missed a bug here :p

Now, once the ISessionFactory instance is created, we create a new Dictionary based on the contents of the old one and then we add the new ISessionFactory instance to it.  After that, we replace the sessionFactories references with the new dictionary and from that point on, every read will use the new dictionary instance.  During this entire operation, no read operation was impacted negatively. 

Now lets take a look at the other write operation, removing an ISessionFactory instance from the dictionary:

        public void RemoveSessionFactoryForTenant(Guid tenantId)

        {

            if (!sessionFactories.ContainsKey(tenantId))

            {

                return;

            }

 

            lock (writeLock)

            {

                if (!sessionFactories.ContainsKey(tenantId))

                {

                    return;

                }

 

                var sessionFactory = sessionFactories[tenantId];

                var newDictionary = new Dictionary<Guid, ISessionFactory>(sessionFactories);

                newDictionary.Remove(tenantId);

                sessionFactories = newDictionary;

 

                sessionFactory.Dispose();

            }

 

The first if-check, which happens outside of the lock is a bug that i missed but that was pointed out in the comments of the original post.  If CreateSessionFactoryForCurrentTenant and RemoveSessionFactoryForTenant would execute concurrently for the same tenant, it’s possible that the ISessionFactory instance of that tenant is never removed from the dictionary (and also never disposed of…) since the check happens outside of the lock and could be executed before the ISessionFactory of the tenant was added to the dictionary.  In that case, the ISessionFactory instance would stay in the dictionary as long as the application stays up.  This is definitely a race condition that you want to avoid in every other situation though in this case, the odds that we’re simultaneously adding and removing the same tenant are slim to none.  Nevertheless, i don’t want to be accused of promoting race conditions so we’ll make the change anyway :)

        public void RemoveSessionFactoryForTenant(Guid tenantId)

        {

            lock (writeLock)

            {

                if (!sessionFactories.ContainsKey(tenantId))

                {

                    return;

                }

 

                var sessionFactory = sessionFactories[tenantId];

                var newDictionary = new Dictionary<Guid, ISessionFactory>(sessionFactories);

                newDictionary.Remove(tenantId);

                sessionFactories = newDictionary;

 

                sessionFactory.Dispose();

            }

        }

 

Now, as you can see we once again create a new dictionary based on the previous one, then remove the ISessionFactory instance for the current tenant and then we overwrite the sessionFactories instance once again.

Finally, there’s the read operation that i specifically didn’t want suffering from locking overhead:

        public ISession CreateSessionForCurrentTenant()

        {

            var tenantId = tenantContext.CurrentTenantId;

 

            if (!sessionFactories.ContainsKey(tenantId))

            {

                CreateSessionFactoryForCurrentTenant();

            }

 

            return sessionFactories[tenantId].OpenSession();

        }

 

The only time this code will block is when a new ISessionFactory for the current tenant needs to be created.  Luckily, that only happens once for each tenant.  As i mentioned earlier in the post, using this pattern doesn’t guarantee that successive reads within the same logical operation are thread safe, so there is a bug in here.  If a tenant already has an ISessionFactory instance, it’s possible that the RemoveSessionFactoryForTenant method has been executed between the if-check and accessing the ISessionFactory based on the tenantId.  In that particular scenario, the ISessionFactory instance is no longer in the dictionary which will cause this code to throw an exception.

That’s a bug that i don’t feel like fixing though… Once a tenant has been removed, they are no longer a paying customer.  If they are no longer paying for the software, there is no reason whatsoever why i should care about any possible exceptions they could get while running the software :)

Seriously though, if the RemoveSessionFactoryForTenant method is called, users of that tenant won’t even have access to the system anymore so it’s really a non-issue.

Anyways, i think i’ve covered the implementation in more detail than you probably cared for.  So, any thoughts? Are there still issues that i haven’t thought of? Is there another approach that you would use for this specific scenario?