5

Is there a standard connection pooling model (or API) similar to that used by the data providers in .net that I could use to implement my own connection pool?

I ask because I have a requirement to implement my own connection pool to a proprietary TCP/IP device that we use in a web service. The current problem is that there are lot of connections (read too many) to the device due to the threaded nature of web services running under IIS. I want to limit the number of these connections using my own connection pool and it seems stupid to reinvent the wheel if there is a standard model I could use to do this.

VinceJS
  • 1,254
  • 3
  • 18
  • 38

3 Answers3

6

Is there a standard connection pooling model

Other than ADO.NET, no. But the ADO.NET model is nice an simple. Construct an object to get a connection from the pool, or created anew, and it is returned to the pool on Close/Dispose/Finalise.

From this one can immediately determine an implementation pattern:

  • The client type is a proxy to the real type, and has a lifetime from creation to Close/…. It is a proxy to the real object. Provides methods and properties which forward to the real connection.
  • The real connection is a long lived instance, created by the pool, given out under a proxy and then returned at the end of the proxy.

There is a choice in the implementation. When an object has been handed out, does the pool need to also keep a reference? If it does the pool needs to track which objects are active and which are pooled; otherwise a simple collection of available objects can be used.

Something like:

internal class MyObjectImpl {
  // The real object that holds the resource
}

internal static class MyObjectPool {
  private static object syncRoot = new object();
  private static Queue<MyObjectImpl> pool = new Queue<MyObject>();
  private static int totalObjects = 0;
  private readonly int maxObjects = 10;

  internal MyObjectImplGet() {
    lock (syncRoot) {
      if (pool.Count > 0) {
        return pool.Dequeue();
      }
      if (totalObjects >= maxObjects) {
        throw new PoolException("No objects available");
      }
      var o = new MyObjectImpl();
      totalObjects++;
      return o;
    }
  }

  internal void Return(MyObjectImpl obj) {
    lock (syncRoot) {
      pool.Enqueue(obj);
    }
  }
}

public class MyObject : IDisposable {
  private MyObjectImpl impl;

  public MyObject() {
    impl = MyObjectPool.Get();
  }

  public void Close() {
    Dispose();
  }

  public void Dispose() {
    MyIObjectPool.Return(impl);
    // Prevent continuing use, as the implementation object instance
    // could now be given out.
    impl = null;
  }

  // Forward API to implement

}

This doesn't cater for instances of MyObject being destroyed. E.g. hold a collection of weak references to allocated MyObject's, and if the pool is empty check for disposed instances. This would also be needed if you cannot rely on client's to Close or dispose of instances, or implement a finaliser on MyObjectImpl1 (and report this as an error in debug builds).

1 This cannot be done on MyObject because by the time MyObject was finalised the MyObjectImpl instance could already have been finalised.

ntrch
  • 76
  • 1
  • 22
Richard
  • 106,783
  • 21
  • 203
  • 265
  • A very interesting idea, thanks! How would one go about making this thread safe? – VinceJS Jul 20 '09 at 09:40
  • The pool as show is thread safe. The pooled objects may or may not be thread safe depending on its implementation. I'll change `MyObject.Dispose` to explicitly free the implementation reference, this will avoid continuing to use `MyObject` instances after returning to the pool. – Richard Jul 20 '09 at 10:17
  • What if I wanted to wait for a certain amount of time until a pooled object becomes available and not immediately throw a "No objects available" exception? How would I do this in a thread safe way? – VinceJS Jul 20 '09 at 12:57
4

Update

Actually now I know more, I think I'd use a feature from my IoC container of choice - Castle Windsor. One of the built-in lifestyles is "pooled", which means that whenever you ask the container for an object that was registered with this lifestyle, it'll give you one of the pooled objects if it can, or else create a new one.

Previously...

I think you want to implement "object pooling". Here's a few things that looked promising:

Of course with your pooled objects, you need to be careful with concurrency and thread synchronisation etc.


For database connections:

You can control the number of connections in the .NET connection pool with an option in the connection string: "max pool size" as described in: http://msdn.microsoft.com/en-us/library/8xx3tyca(VS.71).aspx

Try to avoid implementing your own if you can.

Neil Barnwell
  • 41,080
  • 29
  • 148
  • 220
  • I cannot use any the standard .NET connection pools because I am communicating to a proprietary device via TCP/IP (using a custom protocol) and not to a Oracle of MS/SQL database. – VinceJS Jul 18 '09 at 20:36
  • Oh I SEE. Lol. So basically you want to implement an object pool, rather than a connection pool. I'll update my answer... – Neil Barnwell Jul 18 '09 at 20:40
0

Web service methods are meant to be stateless (i.e. no objects are maintained in existence on the server between calls). What you want to do is maintain a collection of proprietary connection objects on the server between calls, and allocate existing connection objects from this pool to each method call (instead of creating a new connection object in each method).

A simple way to do this is to declare your collection of objects as "private static" within the scope of your web service but outside the scope of any method, like this:

public class Service1 : System.Web.Services.WebService
{
    private static List<CustomConnection> _connections = 
        new List<CustomConnection>();

    [WebMethod]
    public string HelloWorld()
    {
        return "Hello World";
    }
}

and then populate the collection from the web service's startup event (I don't remember what event that is at the moment - I'll be back with it in a second). Any method that needs to use a connection would get a connection object from this list, instead of creating a new one (you'll have to handle the method of allocating connections and marking them as "in use" and so on).

This will work fine if your web service is called frequently (web services usually shut down after 20 minutes of inactivity, which would necessitate rebuilding the connection pool for the next call). If you need to maintain your collection of connections beyond that, check out this article:

http://msdn.microsoft.com/en-us/library/system.web.httpapplicationstate.aspx

MusiGenesis
  • 74,184
  • 40
  • 190
  • 334
  • You may want to read his question again. He's not using SOAP web services. -1. – John Saunders Jul 18 '09 at 22:21
  • You may want to read his question again yourself. All I see is "C#", ".Net", "IIS" and "web service". What did you see in his question that suggests he's not using a web service like my sample code here? – MusiGenesis Jul 19 '09 at 00:41
  • 1
    Yes its a standard .net 2.0 SOAP web service. And thanks for the suggestion however its already (partially) being done this way: the connections are thread static. The problem is that this results in a lot of connections: 20 IIS threads with 5 connections each (to different TCP/IP ports on the same machine) is 100 connections per web server. With 4 web servers, this results in 400 connections to the destination machine. – VinceJS Jul 19 '09 at 08:29
  • @VinceJS: check out the MSDN link in my answer, then. This will let you create your 5 connections once on each web server, which connections can then be shared by every request to that server. It doesn't handle server farms, so you would still have 20 connections total; I don't see how there could be any way of sharing a pool of connections between servers, unless you have only 1 server directly connecting to the destination, and the other servers all talk to the first server. – MusiGenesis Jul 19 '09 at 11:13
  • Upvoted because OP confirmed that it's actually a SOAP web service, and JS downvoted because he thought it wasn't. – estanford Oct 12 '11 at 16:20