Creating a FTP Connection Pool using Object Pool Pattern in C#

One of my web applications was using FTP to upload photos to a FTP server. A new connection was created every time a user uploaded his photos. The instantiation of a new connection on every upload request was turning out to be a very costly step. So I decided to use the Object Pool Pattern to implement a pool of FTP Connections.

Here's the FtpClientConnectionPool class. This code is based on an example I found on Best-Practice Software Engineering.

1   public class FtpClientConnectionPool
2 {
3 private static volatile FtpClientConnectionPool myInstance;
4 private static object syncRoot = new Object();
5 private List locked, unlocked;
6
7 private FtpClientConnectionPool()
8 {
9 locked = new List();
10 unlocked = new List();
11 }
12
13 public static FtpClientConnectionPool Instance
14 {
15 get
16 {
17 if (myInstance == null)
18 {
19 lock(syncRoot)
20 {
21 if (myInstance == null)
22 myInstance = new FtpClientConnectionPool();
23 }
24 }
25 return myInstance;
26 }
27 }
28
29 public FtpClient CheckOut()
30 {
31 lock(syncRoot)
32 {
33 for (int i = unlocked.Count - 1; i >= 0; i--)
34 {
35 FtpClient f = unlocked[i];
36 unlocked.Remove(f);
37 if (!TimedOut(f))
38 {
39 locked.Add(f);
40 return f;
41 }
42 }
43 // No active instance - create new
44 FtpClient newF = Create();
45 locked.Add(newF);
46 return newF;
47 }
48 }
49
50 public void CheckIn(FtpClient f)
51 {
52 lock(syncRoot)
53 {
54 locked.Remove(f);
55 unlocked.Add(f);
56 }
57 }
58
59 private FtpClient Create()
60 {
61 FtpClient newInstance = new FtpClient(
62 Settings.FTPServer,
63 Settings.FTPUsername,
64 Settings.FTPPassword);
65 newInstance.ChangeDir("/");
66 return newInstance;
67 }
68
69 private Boolean TimedOut(FtpClient f)
70 {
71 try
72 {
73 f.ChangeDir("/");
74 }
75 catch
76 {
77 return true;
78 }
79
80 return false;
81 }
82 }
I have implemented this as a Singleton because I did not want multiple instances of the connection pool floating around. The myInstance variable is declared to be volatile to ensure that assignment to the instance variable completes before the instance variable can be accessed.

To make this work for the multithreaded web scenario, the approach uses a syncRoot instance to lock on, rather than locking on the type itself, to avoid deadlocks.

Note that there is no limit to the number of connections in this implementation. The pool will grow with the number of simultaneous users, and shrink as the connections timeout.

A client will use this connection pool as:
1   FtpClient ftp = FtpClientConnectionPool.Instance.CheckOut();
2 ftp.Upload(file);
3 FtpClientConnectionPool.Instance.CheckIn(ftp);


kick it on DotNetKicks.com

3 comments:

Anonymous said...

Nice article !But where will you close the FTP Connections ?Do we need to do that in the Application_Stop event ?

Anonymous said...

Indeed it looks like this code relies on automatic connection loose by timeout.

There obviously is no active closing: On connection request ("CheckOut"), the pool simply checks all connections still present for the first one still active (and meanwhile cleans up all inactive which are found so far) and automatically creates a new one when no active one is left.

On connection release ("CheckIn"), the connection is simply moved from the "in use" list to the "currently not in use" list, waiting there for better times or the next request.

Thats quite simple but not quite clean and may cause conflicts in restrictive operational environments where rules exist which inhibit idle connection hold.

Thus the problem / question "how to regularly and actively cleanup aged connections" is not addressed here as it seems.

ZipwiZ

Anonymous said...

Sometimes it is helpful to dig deep...

This article refers primarily to:

http://best-practice-software-engineering.ifs.tuwien.ac.at/patterns/objectpool.html

Nice thing. It in turn promarily refers to:

http://www.javaworld.com/javaworld/jw-06-1998/jw-06-object-pool.html

Thats the root source. Looking on page 3 of this article shows that the author in 1998 was aware of the problem:

http://www.javaworld.com/javaworld/jw-06-1998/jw-06-object-pool.html?page=3

Now we have a C# example here, but since the sources are Java based, I dare to refer to:

http://commons.apache.org/pool/

This library seems to cover all problems omitted here for simplicity, including regular cleanup by a separate thread etc. I do not know how simple or complicated it may be to translate this to C# / .NET, but it should be feasible -- and maybe there is already some kind of "Apache commons for .NET" out there. Don't know -- for the Spring lib set, there is...

ZipwiZ

Post a Comment

I am a programmer based in Seattle, WA. This is a space where I put notes from my programming experience, reading and training. To browse the list of all articles on this site please go here. You can contact me at rohit@rohit.cc.