Lior Rozner Blog

The .NET era
Deadlocks and Enterprise Services

   

The big picture - my team (Ayelet Nisan, Saar Carmi and me) is currently writing the framework for a large scale .NET project.

The problem - a few days ago while debugging our new batch framework version (a lot of working with threads, enterprise services and SWC) we have encountered a strange deadlock.

Finding the solution - being familiar with such problems our first assumption was that our applicative locks (ReaderWriterLock) was causing the problem, after a few hours we ruled it out. Our second assumption was that somehow the DB locks in conjunction with the applicative locks are causing this but while trying to debug it we saw that the actual lock is caused while the thread is creating a new instance of a class that derives from a ServicedComponent. After a few retries on different computers we were sure that we are on the problem but we could not figure what exactly is causing it. Here we stopped and did some reality check, first we know that it is always happening (sometime after 2 seconds and sometime after 30 seconds) and second (like with a lot of other locking problems) the same creation of ServicedComponent seems to have worked most of the time. To make the next major step we needed to find where exactly we are being locked inside the constructor of our ServiceComponent for that we used the debugger call stack and the Reflector tool, we were being locked inside the method Proxy.RevokeObject called from the ServicedComponentProxy.CleanupQueues and here it is


internal
static void CleanupQueues(bool bGit)
{
     
object obj1;

      if (!ServicedComponentProxy._asyncFinalizeEnabled)
      {

            return;

      }

      if (bGit && (ServicedComponentProxy._gitQueue.Count > 0))

      {

            obj1 = ServicedComponentProxy._gitQueue.Pop();

            if (obj1 != null)

            {

                  int num1 = (int) obj1;

                  try

                  {

                        Proxy.RevokeObject(num1);

                  }

                  catch

                  {

                  }

            }

      }

      if (ServicedComponentProxy._ctxQueue.Count <= 0)

      {

            return;

      }

      obj1 = ServicedComponentProxy._ctxQueue.Pop();

      if (obj1 == null)

      {

            return;

      }

      if (!Util.ExtendedLifetime)

      {

            ContextTrackerContainer container1 = (ContextTrackerContainer) obj1;

            container1.Release();

      }

      else

      {

            ServicedComponentProxy proxy1 = (ServicedComponentProxy) obj1;

            proxy1.SendDestructionEvents(false);

            proxy1.ReleaseContext();

      }

}

 

The next thing was to try and googlize our already well know methods\problem, there are not so many people that have encounter our problem further more none of them gave us a real solution to our problem.

Finally searching in the MSDN we found a clue to our problem while using GIT keyword which is mentioned a couple of times in code. The clue was in the form of KB298014 FIX: COM+ application that uses the Global Interface Table (GIT) may deadlock, following the instructions in the KB and adding two registry keys fixed our problem(the dispose solution did not seemed to be working to us).

Yet another last look at the first lines of code in the previous method

if (!ServicedComponentProxy._asyncFinalizeEnabled)

{

    return;

}

seems magically linked to the registry key we just added DisableAsyncFinalization

 

Oh yes one last important thing, the problem was only reproduced on XP sp2 machines while not in windows 2003 servers.

.   

 

 

ADO.NET 2.0 Feature Matrix

A must read article about ADO.NET 2.0 Feature Matrix, top 9 features are:

  • ADO.NET:
    • ADO.NET 2.0 does not use the Microsoft Data Access Components (MDAC).
    • You can clear a connection pool by using the static method SqlConnection.ClearPool.
    • Built-in SqlCommand methods that provide asynchronous execution.
    • And finally SqlClient contains a new class called SqlBulkCopy, for inserting many rows into the database from a client in one round-trip
  • SQL Server 200:
    • MARS - multiple active result sets .
    • SqlDependency - Registering for notifications for DB changes.
    • Promotable transactions - the new System.Transactions namespace, enabling a behavior that can automatically detect multi-instance access and "promote" a transaction from local to multi-instance (distributed).
    • "hot spare" capability through database mirroring. If a SQL Server instance fails, the work can be shifted over to the backup server automatically.
    • And of course support for user-defined types and native XML data type and better large data support

 

You are all welcome to come to our (yosi and me) session about Enterprise Services.
The session will be at the 9th 17:30, in Microsoft Israel.

BaseCodeGenerrators goes internal

Yet another change I have encountered while migrating our environment to the VS.NET 2003 and the 1.1 Framework is the change of the class BaseCodeGeneratorWithSite from public to internal.

For those of u who did not encounter it I can just say that it is used for building custom tools, and a sample can be found in the MSDN magazine.

Those of u who already used it (like me) will have to face the fact that Microsoft has decided that the class is to be internal in the VS.NET 2003, so u can’t use it any more that way, but, a small search in got dot net revealed a little magic - The full source code of the class for the developers who have been using the class in the previous version.

 

 

 

HttpServerUtility.Transfer change in Framework 1.1

A week ago while I tried the new 1.1 framework on our web project, I have encounter a strange unexplainable behavior.
Thou I could not explain it exactly; it was definitely a change of behavior between the 1.0 and the 1.1 framework.

A few breakpoints and some call stacks after, I discovered that a call to HttpServerUtility.Transfer(string path) is translated in 1.0 to HttpServerUtility.Transfer(string path, bool perserveForm = false) and in 1.1 to HttpServerUtility.Transfer(string path, bool perserveForm = true).

With a little help of Anakrino(www.saurik.com) u can see the difference more easily

Framework 1.0
public void Transfer(string path)

{

      bool local0;

      Page local1;

 

      local0 = true;

      local1 = this._context.Handler as Page;

      if (local1 != null && local1.IsPostBack)

            local0 = false;

      this.Transfer(path, local0);

}
Framework 1.1

public void Transfer(string path)

{

      this.Transfer(path, true);

}

 

 

 

More Posts