Comments
Richard Davies wrote: The UK has a good crop of technology pioneers in cloud computing - for example ElasticHosts, FlexiScale, Flexiant, OnApp - and also some strong government initiatives such as G-Cloud. We will have to see whether this kind of technical leadership converts into swift mass-market adoption or not.
Cloud Expo on Google News

SYS-CON.TV
Cloud Expo & Virtualization 2009 East
PLATINUM SPONSORS:
IBM
Smarter Business Solutions Through Dynamic Infrastructure
IBM
Smarter Insights: How the CIO Becomes a Hero Again
Microsoft
Windows Azure
GOLD SPONSORS:
Appsense
Why VDI?
CA
Maximizing the Business Value of Virtualization in Enterprise and Cloud Computing Environments
ExactTarget
Messaging in the Cloud - Email, SMS and Voice
Freedom OSS
Stairway to the Cloud
Sun
Sun's Incubation Platform: Helping Startups Serve the Enterprise
POWER PANELS:
Cloud Computing & Enterprise IT: Cost & Operational Benefits
How and Why is a Flexible IT Infrastructure the Key To the Future?
Click For 2008 West
Event Webcasts
Resource Pooling In Java
Resource Pooling In Java

All major and minor application server vendors heavily advertise the connection pooling functionality of their respective offerings. In this article I examine what's involved in developing resource pooling features from the perspective of a Java developer. I feel the subject is both greatly overhyped and underrepresented in technical literature.

The Problem
First, I'll try to describe the problem in very general terms. I'll rely more on practical considerations rather than scientific completeness:

  • A set of resources has one common characteristic: there's a limited supply. Usually the supply limitation isn't related to the scarcity of the resource, but to the difficulty of obtaining it. For example, it's possible to open a database connection for each query, but it's a time-consuming operation.
  • It's assumed that these resources will be needed by different parts of an application that will "compete" for them according to some application logic.
  • Each individual resource can be used an unlimited number of times.

    Translating plain English into Java, it looks like a collection of resources that:

  • Contain a pool of resources to be managed
  • Supply the needed resource on demand
  • Deny the resource if none is available
  • Exercise some policy on resource availability including queuing, waiting, and so on
Java's threading model lends itself nicely to shared access to resources. In this article I assume that resources are shared among concurrent threads, not among the operating system's processes. The implementation described below can be easily adapted for a multiprocess situation by developing an interprocess communication layer on top of it.

Generic Implementation
The generic implementation is provided in the form of the class Pool (see Listing 1).

Theoretically speaking, the Pool class can be a Stack; for example, Pool can extend Stack with the Pool.pop(long time) method, override Stack.pop() and used (semantically) in place of tryPop(). Nevertheless, I've chosen delegation over inheritance and the reasons are:

  • The Stack.pop(), and Pool.pop() methods have different semantics. The former doesn't really "try" to pop it; it's quite unconditional in its attempt to pop the object and will throw an exception if unable to do so.
  • The other methods of the generic Stack class will violate the integrity of the pool. For example, Stack.peek() will deliver a potentially shared object to anybody who asks; Vector.clear(), inherited from the superclass, will destroy a stack-based Pool altogether. You can also "mute" all of Stack's methods that Pool doesn't need, but it will confuse the class's users even further.

Let's consider how the Pool class can be used. First, an application must create a Pool object, usually a static one. Second, the Pool must be populated with the resources to be managed. After that the Pool is ready to use (see Listing 2).

In Listing 2 the method usageExample() uses a static instance of the Pool class (named staticPool) created and initialized elsewhere in the class. The type "Resource" represents any particular type of resource that the application will need. The resource is obtained from the pool via the pop() method that accepts a waiting time parameter (in seconds) (e.g., the Pool class will try for 10 seconds to obtain the resource, if it's not currently available). During that time the pool will check 10 times if some other thread put any of the resources back and will return it if so. If none of the resources become available, the pool will return null and it's up to the application to decide how to proceed further; the example in Listing 2 just gives up and throws an exception.

An important aspect of using pools is that a resource obtained from a pool must be returned after the application is done using it. This is guaranteed by the "finally" clause in the example: if the resource was successfully obtained (not null), then it will be returned (call to the Pool.push() method). Obviously, if anything prevents the return of the resource, it creates a resource leak that will eventually deplete the pool.

The synchronization of the Pool's methods deserves special attention. Since java.util.Stack class is used in implementing the Pool, there's a certain sense of security as far as multithreading is concerned. The Stack class is, in turn, implemented as a java.util.Vector, which is properly synchronized. Unfortunately, this sense of security proves to be a false one and for the following reason: method Pool.tryPop() prevents the possibility of popping the empty stack (with related complications in the form of a nasty runtime EmptyStackException) by checking it via Stack.empty(). The problem arises if the execution path veers off the current thread after the Stack.empty() call and some other thread gets the last resource in the pool, then the current thread does pop an empty stack! It's hard to estimate how often it will happen, but it'll be too late to think about it when exceptions start flying out of your complete and attractively shrink-wrapped product. So we have to synchronize the Pool.tryPop() method; however, the rest of Pool's methods don't need any additional synchronization. Pool.push() is synchronized via its superclass Vector and Pool.pop(long time) does all its magic via Pool.tryPop().

Exercise 1
The pop() method uses a very simple waiting algorithm - it tries to get the resource 10 times per waiting period. The overall performance of the system that uses resource pools can be significantly improved if a more adaptive waiting algorithm is utilized. One such algorithm I'm aware of can be described as follows: start with a very short waiting time (say, 1/100 of the total wait) and double it with each iteration until either the waiting limit is exhausted or a resource is obtained. The effect is that if no resource is available immediately, the pool will try more frequently in the beginning of the wait and less so toward the end; it can be called a "vanishing hope" method. For a system that operates near its performance capacity, it results in better response time during occasional overloads. The implementation of improved waiting schemes is left as an exercise to the reader.

Database Connections
The resource pooling is most frequently used for database connections. Naturally, database connections are presumed to be JDBC connections for the purposes of this discussion. Several specific database issues warrant special consideration with regard to resource pooling:

  • A database connection can and will be broken, in my experience, during the application instance's life span. Some drivers (could be all of them) may not restore connections if their respective database servers are restarted.
  • It's impractical to create all possible database connections during an application's start-up. It takes forever and all these connections may not be needed.

    These issues lead to the following requirements for database connection pooling:

  • Connections should be periodically checked for validity.
  • Connections should be dynamically allocated as needed.
Listing 3 presents an implementation based on a generic Pool class that was discussed in the previous section. Note: A lot of details were omitted for the sake of clarity, namely, initialization, synchronization, and proper exception handling.

The DbConnectionsPool class extends the generic Pool with the following functionality:

  • It can create new database connections. All parameters that are needed to do so (driver, user name and password, maximum number of connections allowed, etc.) are passed to the class constructor and later used by the createConnection() method.
  • Its constructor starts a thread that periodically checks connections for validity and destroys bad ones.
  • The pop() method creates new connections (up to the specified maximum number) when the pool is depleted.
  • isGood() method tries to send a "null-operation" to the database just to make sure it can go to the server and back. Since all the connections to be tested aren't used by any pending transactions, the statement "rollback work" should do nothing (check with your particular database's documentation).
Exercise 2
The run() method removes a connection only when it goes bad. It might be very useful to create an algorithm that will destroy connections according to their usage patterns. For example, the winning strategy might be to create new connections when needed and remove old ones when demand for them is low. It'll reduce memory requirements of the application and may ease up the load on the database server. An implementation of such an algorithm is offered as an exercise. Hint: Compare currentConnections counter with the number of connections in the pool while checking for validity. If these two numbers are close, then connections are underutilized.

CORBA Connections
The CORBA world offers its own set of complications as far as resource pooling is concerned. The good news is that CORBA connections are automatically rebound (that's CORBA-speak for "reconnected") in case of failure (at least, the implementation I use - Inprise's VisiBroker - does this). The bad news is that the CORBA connection pool implementation has to deal with the fact that CORBA connections, unlike JDBC ones, are not created equal. A typical application usually connects to several different CORBA objects that are distinguished by their type and name.

It's quite possible to create separate connection pools for each object type and name combination, but it leads to code bloat and, generally, reduces the reliability and maintainability of an application. Let's see how the situation can be remedied.

Consider the CORBAConnectionsPool presented in Listing 4 (again, many implementation details are omitted). The basic idea is simple: create a separate pool for each object name and automatically open new connections using the same strategy that was used with the DbConnectionsPool class. More details on this approach:

  • We distinguish CORBA objects by specifying their respective names and IDs as parameters in pop(...) methods.
  • The object ID can be omitted if an object inherits from a GenericObject CORBA interface. The CORBAConnectionsPool class is aware of this interface and "knows" how to get its object ID, creating a valid ID to bind to any of its subclasses. The right reference can be obtained by the actual application by narrowing down (CORBA's equivalent of type casting) the reference to the GenericObject retrieved from the pool.
Unfortunately, as with any compromise, these implementation details force the user to exercise some caution regarding what can be safely stored in this pool. The following convention must be observed: an object name must uniquely identify an interface for the purposes of the CORBAConnectionsPool class. For example, if there are two interfaces, Laser and Bubble, that extend the Device interface, and both CORBA services that implement Laser and Bubble are named the same (say, "Printer," or not named at all), the code in Listing 5 would lead to storing an ambiguous reference in the CORBAConnectionsPool that was caused by the polymorphism. The same will happen if we try to manage multiple objects with the same name and completely unrelated types, but for a different reason: the CORBAConnectionsPool class doesn't keep track of object IDs along with object names, which leads directly to Exercise 3.

Exercise 3
Since the above-described implementation distinguishes CORBA objects only by their names, develop a CORBA connection pool that will also account for object IDs.

The overall usage pattern for CORBAConnectionsPool follows the example presented for a generic Pool in Listing 2 with changes dictated by CORBAConnectionsPool method signatures. Again, as always, it's extremely important to guarantee the return of the used connection back to the pool.

The most compelling case for using CORBAConnectionsPool despite its object ID indifference is when an application has to deal with a large number of objects of the same interface, for example, printer services on a network. It's also quite convenient for the CORBA services that are part of a larger system to implement some common generic interfaces, such as GenericObject, in the example above. This interface can be used to implement common interface features that are related to some application group (e.g., for life-cycle management).

Conclusion
As you can see, it's a relatively straightforward task to develop a resource pooling solution in Java, thanks to built-in multithreading. Unfortunately, a developer has to take care of a lot of implementation details (careful synchronization is one example) to produce a resource pool for production-level heavy lifting. Even more unfortunate, domain-specific pools require drastic changes to the interface compared to generic ones. Java development of resource pooling can be taken a bit further by exploring the possibilities of developing a general framework that includes these features:

  • A flexible mechanism for defining resource availability policies that vary depending on the application: For example, a database has different performance characteristics than a Web server and, therefore, these two require different resource strategies including waiting and queuing.
  • Ability to accommodate resources of various types without any resource-specific knowledge on the framework's part: As shown above, a database connection requires different caretaking compared to a CORBA link. It should be possible to provide generic interfaces for resource creation, initialization, and upkeep regardless of the particular type.
  • "Learning" runtime behavior with regard to resource creation and clean up: For example, it should be possible for some applications to predict their demands for a particular resource type and prepare the resource pool accordingly. For example, authentication services are loaded mostly in the morning, printers are at night, and the fax load depends on the long-distance fee schedule.
While exploring future possibilities of resource pooling, it's important to concentrate on the usability of the perspective solution: interfaces that are too general or complex may encourage developers to choose a resource-specific solution.
About Ivan Kiselev
Ivan Kiselev is chief architect at APP Design Group, Inc. His professional interests include applications of reusable frameworks and application servers to electronic commerce systems, development environments, and integration of scripting languages into all of the above.

In order to post a comment you need to be registered and logged in.

Register | Sign-in

Reader Feedback: Page 1 of 1

Latest Cloud Developer Stories
Swisscom, the Swiss telecom, is going into the cloud business. Its subsidiary Swisscom IT Services AG has signed up with Red Hat as a Certified Cloud Provider and launched a public cloud Infrastructure-as-a-Service (IaaS) cloud targeting enterprise-class customers primarily in ...
Apache Deltacloud, the Red Hat-contributed ReSTful API that abstracts differences between clouds so services on any cloud can be managed – provided of course there’s a driver – has graduated from the Apache Foundation’s incubator and is now a full-fledged Top-Level Project (TLP)....
In a surprise move on Tuesday, January 10, Oracle wheeled out its Big Data Appliance. That’s the one it said in October would be ready sometime in the first half. Only nobody believed it meant early in the first half. Heck, it’s not even clear anybody thought Oracle could make ...
Rackspace Hosting, the service leader in cloud computing, on Thursday announced its acquisition of SharePoint911, an industry leader in SharePoint consulting, training, and "JumpStart" services within SharePoint. The unification of both companies provides capabilities to deliver ...
CloudLinux, Inc., on Thursday released CafeFS 3, a virtualized file system for shared hosters that cages each customer within its own virtualized file system. CageFS becomes part of CloudLinux OS at no additional charge. CloudLinux OS, the only commercially-supported Linux OS m...
Subscribe to the World's Most Powerful Newsletters
Subscribe to Our Rss Feeds & Get Your SYS-CON News Live!
Click to Add our RSS Feeds to the Service of Your Choice:
Google Reader or Homepage Add to My Yahoo! Subscribe with Bloglines Subscribe in NewsGator Online
myFeedster Add to My AOL Subscribe in Rojo Add 'Hugg' to Newsburst from CNET News.com Kinja Digest View Additional SYS-CON Feeds
Publish Your Article! Please send it to editorial(at)sys-con.com!

Advertise on this site! Contact advertising(at)sys-con.com! 201 802-3021

SYS-CON Featured Whitepapers
ADS BY GOOGLE

Breaking Cloud Computing News

ANN ARBOR, Mich., Feb. 16, 2012 /PRNewswire-USNewswire/ -- In recognition of a $15 million gift t...