Posts Tagged ‘Java’

Creating Transactional Proxy Classes

Saturday, July 10th, 2010

One of the frequent patterns I make use of for Java backend systems are transactional code blocks, and not transactional in the sense of JPA, Hibernate, Databases, etc. I mean generic transactional blocks in which you have to wrap a piece of code with a begin and end block. For example, JPA is just one style in which you invoke:

try {
    em.getTransaction().begin();
    // invoke code
} finally {
    em.getTransaction().end();
}

Another common example is using pools in which you must borrow and return objects such as:

Object data = null;
try {
    data = pool.borrowObject();
    // do something
} finally {
    pool.returnObject(data);
}

These are just common examples. Often times, I have my own type of transactional block that references some other type of system that must maintain a begin and end state. However, even as simple as

try { begin(); } finally { end(); }

is, it can easily be screwed up. For example, a common mistake is forgetting to put the end() in a finally block to ensure it runs. Further, it violates the DRY (don’t repeat yourself) principle such that if you need to change the processing a bit, you would need to change every invocation of begin/end. That creates a possible maintenance issue.

So, how do we avoid using transactional blocks? The easiest solution is something that most modern libraries such as Spring or Java EE already do, which is creating proxy classes to invoke the blocks automatically. If you are already using Spring or Java EE, you prolly already do this with the @Transactional annotation. However, this post will help demonstrate a simple and easy method of achieving this same behavior for custom transactional blocks.

The first step is creating a marker annotation that will be used on classes and methods to denote a transactional block of code. For example:

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public static @interface Transactional {
    // annotation specific values
}

This annotation allows us to mark either a class or a method. This is basically what the Spring/Java EE Transactional annotation does. The next thing we need to do is actually mark methods as transactional. We can do this either at the class level meaning every method in the class will be transactional or at the method level. The choice is completely a personal preference. However, if you mark the class, then you can ensure that every method will be transactional even if you add a new method. That will help reduce the accidental likelihood of adding a new method but forgetting the transaction annotation. However, if you do not want certain methods to be wrapped in a transactional block, then you will need to annotate at the method level one by one. Here is an example:

@Transactional
public class Test1 {
     public void method1() {
          // this will be invoked in transactional block
     }
 
     public void method2() {
          // so will this
     }
}
 
public class Test2 {
     public void method3() {
          // this will not be transactional
     }
 
     @Transactional
     public void method4() {
          // but this will
     }
}

Now that we have our transactional code we need to create proxy classes to automatically wrap the code. My preferred way of achieving this and the purpose of this blog is to use CGLIB proxy classes. There are several other ways to achieve such as AspectJ. I will leave learning those ways to the reader. Anyways, back to CGLIB. CGLIB provides a proxy creation class called Enhancer. It is very similar to the Proxy class in the standard Java reflection package. However, there is one major difference. The standard Java Proxy class may only use and proxy interfaces, not concrete classes. Enhancer and CGLIB can proxy concrete classes. It is concrete classes that are essential so that we can proxy our existing classes and wrap the methods in transactional code block. Before we can use CGLIB, we must add it to our classpath. The version I am actively using is 2.1_3. You can either download the JARs directly or use the following Maven dependency:

<![CDATA[
        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>2.1_3</version>
        </dependency>
]]>

Once you have added CGLIB, here is the basic way of creating those blocks:

public class Transactions {
        @SuppressWarnings("unchecked")
        public static <T> T proxy(final T object) {
            // check if transactional specified at class level of class or 
            // any parent classes or interfaces
            boolean isTransactional = false;
            Class<?> parent = object.getClass();
            while (!isTransactional && parent != null) {
                if (parent.getAnnotation(Transactional.class) != null) {
                    isTransactional = true;
                }
 
                for (Class<?> ifclass : parent.getInterfaces()) {
                    Class<?> ifparent = ifclass;
                    while (!isTransactional && ifparent != null) {
                        if (ifparent.getAnnotation(Transactional.class) != null) {
                            isTransactional = true;
                        }
 
                        ifparent = ifparent.getSuperclass();
                    }
                }
 
                parent = parent.getSuperclass();
            }
 
            // create proxy class from concrete class
            final boolean transactional = isTransactional;
            return (T) Enhancer.create(object.getClass(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args)
                        throws Throwable {
 
                        // check if transactional at class level or if current method
                        // is transactional.  Note that this ignore overrides.  You
                        // may want to extend this to search for all subclasses and
                        // interfaces defining the method and check those annotatations
                        // as well
                        if (transactional ||
                            method.getAnnotation(Transactional.class) != null) {
                            try {
                                // start transaction block
                                // this could be anything you needed to do such as borrow
                                // from a pool, etc
                                Transactions.begin();
 
                                // invoke method and return its value if provided
                                return method.invoke(object, args);
                            } finally {
                                // finalize the block
                                // this should be the corresponding end block to the begin block
                                Transactions.end();
                            }
                        }
 
                        // not transactional, so invoke as normal
                        else {
                            return method.invoke(object, args);
                        }
                    }
                });
        }
}

Now that we have that code in place, we can create proxy classes and invoke the methods without worrying about the transactional blocks. Going back to our initial test class, we could invoke via:

    Test1 test = Transactions.proxy(new Test1());
    test.method2(); // this will be invoked in a transactional block

That’s all there is to it.

Simple Performance Improvement with Large Ehcache Disk Store Data Sets

Thursday, April 29th, 2010

One of my applications has several millions cacheable entries.  In order to cache as much as possible without going back to the database I use both a  memory store and a disk store in my Ehcache configuration.  Loading a serialized item from disk is still faster than loading from a database generally.  That being said I was running into performance issues due to the constant reads and writes to and from the disk store.   Due to the serialized nature of the data file it would block on subsequent accesses resulting in lag and performance issues.  So, how did I address it?  I decided to partition the single cache into multiple caches.  So, rather than using something like:

ehcache.getRegion(CONSTANT).get(id);

I now use:

ehcache.getRegion(CONSTANT + (id % 10));

I now have 10 different cache regions resulting in less concurrent access and better performance.  A very simple trick when you have extremely large data sets.  Remember, partitioning is always your friend regardless of what type of data you use.

UPDATE: This is being done in Ehcache 1.5.0…I understand there are better improvements in Ehcache 2.x, so please consult the documentation for more information.

OneToOne with Hibernate

Wednesday, October 7th, 2009

I have a use case within my database schema that involves a one-to-one relationship. Typically, I map most of my tables with an automatic auto-incrementing primary key. The relationship table then has a single foreign key to its single relationship. This works great within Hiberante and HQL without issue. That is until you begin to use Hibernate’s second level cache. Hibernate’s second level cache works by caching all the individual properties and the ids of the foreign key relationships. In other words, it does not store the actual instances themselves. When requested from the cache, Hibernate hydrates the properties into the object form. It then loads the relationships by retrieving from the session (or second level cache) with the foreign key. When you have a OneToOne mapped by a join column such as:

@Entity
public class Person
{
    @Id
    @Column(name="id")
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Integer id;
 
    @OneToOne(fetch=FetchType.LAZY, mappedBy="person")
    private PersonDetails personDetails;
}
 
@Entity
public class PersonDetails
{
    @Id
    @Column(name="id")
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Integer id;
 
    @OneToOne(fetch=FetchType.LAZY)
    @JoinColumn(name="person_id")
    private Person person;
}

In this case, Hibernate will cache the person details table with [ id, person_id ]. When it hydrates the cache entry, it knows how to lookup Person based on the person_id cache value. However, when person is cached, it only caches [ id ] since there is no foreign key from person to person_details. As such, Hibernate can only lookup the person_details by using “from person_details where person_id = :id”. You are prolly wondering where I am going with all of this. The point is that even though you are caching both Person and PersonDetails in the cache (or query cache), Hibernate will always invoke a SQL statement whenever person.getPersonDetails() is invoked. This is due to the fact that Person does not have the foreign key relationship forcing Hibernate to issue a query to find it. That can basically kill your database and cache performance.

So what is the proper way to avoid this type of issue? The answer is to use the same key for both tables. Thus, you have a identity auto incrementing primary key on person and then a manual primary key on person_details that is also the foreign key back to person. In the end, they will both always have the same id. When this is done, Hibernate will always know how to go between Person and PersonDetails since the cache value and foreign key relationship is always its own primary key. Hibernate can optimize this and HQL statements as well. To properly do this, you would have the following entities:

@Entity
public class Person
{
    @Id
    @Column(name="id")
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Integer id;
 
    @PrimaryKeyJoinColumn
    @OneToOne(fetch=FetchType.LAZY)
    private PersonDetails personDetails;
}
 
@Entity
public class PersonDetails
{
    @Id
    @Column(name="id")
    @GeneratedValue(generator="foreign")
    @GenericGenerator(name="foreign", strategy="foreign", 
                                  parameters={ @Parameter(name="property", value="person") })
    private Integer id;
 
    @PrimaryKeyJoinColumn
    @OneToOne(fetch=FetchType.LAZY)
    private Person person;
}

That tells Hibernate that the relationships are controlled by the primary key. It also tells Hibernate to use the auto-incrementing identity primary key from the database for person and then to use that person’s primary key as the id of the person_details. So, the following statement:

Person p = new Person();
PersonDetails pd = new PersonDetails();
p.setPersonDetails(pd);
pd.setPerson(p);
getEntityManager().persist(p);

would result in the following SQL:

INSERT INTO person (...) VALUES (?, ?, ...);
-- this returns the assigned primary key
INSERT INTO person_details (..., id) VALUES (?, ?, ..., X)
-- X here would be the assigned primary key of the prior insert statement

So, IMO you should always use OneToOne with PrimaryKeyJoinColumn and ensure the foreign keys are the same as the primary keys. This will improve your cache results and simplify your functionality.

Using “use index” With Hibernate/MySQL

Wednesday, October 7th, 2009

MySQL has the notion of specifying a specific index to use when invoking queries in order to override the default provided by MySQL. Typically, MySQL selects the most optimized index based on the query. However, in some cases, it fails to pick properly reducing performance. In those cases, you need to use the keyword “use index” to select the index. For example:

SELECT [FIELDS] FROM my_table TABLE USE INDEX (my_index) WHERE [predicate]

The problem with this is when moving to an ORM-solution such as Hibernate. Being provider-independent, there is no capability natively within Hibernate and HQL to use provider-specific features such as “use index”. However, Hibernate does allow extension points to do everything from adding provider-specific functions to completely rewriting the SQL statements themselves. In this article, I will demonstrate the capability to semi-add “use index” to hibernate.

Before reading take note that this is, IMO, a really ugly hack to make this work. Unfortunately, in my use case, I had the desire to keep my query caches within HQL in line with the timestamps cache created by hibernate for table updates. The easiest way to actually utilize “use index” is to use a native SQL query rather than HQL. Native SQL queries within hibernate can contain any vendor-specific functionality. Further, there may be better ways at doing this, but I had not found any. Thus, this is my hack and so without further ado, let’s get to it.

Hibernate has two extension points that we will use to provide this functionality. The first is a custom dialect used to add specific functions, keywords, etc. The second is an interceptor to intercept various functionality such as preparing SQL statements. When I initially went down this path, I tried to just create and register a custom function in a custom dialect and then invoke it such as:

SELECT [FIELDS] FROM MyTable TABLE useindex(my_index)

However, from what I understand, you may only use custom functions within the where, group, and order clauses, not the from clause. So, I decided to try the interceptor and modify the SQL before getting added to the SQL statement. Unfortuately, Hibernate only passes in the SQL so there is no way to know whether the specified query wanted an index or not. So, I decided to mix the two by using a custom function within a where statement that I could then find in the SQL in order to inject the proper syntax.

The first step here is to create a custom dialect to register our custom function. The easiest way to do this is to just extend the dialect you are already using so that you merely add functionality to your existing dialect. For example, in my persistence.xml file (NOTE: I am using JPA with Hibernate, but this would work with plain Hibernate and session factory configuration as well), I specify my dialect via:

<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect" />

So, I just need to create a new class and extend that MySQL5InnoDBDialect. Within the constructor, I just need to register the simple useindex marker function. The result is:

package com.znet.hibernate.dialect;
 
import org.hibernate.Hibernate;
import org.hibernate.dialect.function.StandardSQLFunction;
 
public class MySQL5InnoDBDialect extends org.hibernate.dialect.MySQL5InnoDBDialect
{
    public MySQL5InnoDBDialect()
    {
        super();
        registerFunction("useindex", new StandardSQLFunction("useindex", Hibernate.BOOLEAN));
    }
}

We use the org.hibernate.dialect.function.StandardSQLFunction class to create a quick function that expects the specified function name and expects a return type of boolean. To use this dialect, just update the configuration to specify the newly created class.

<property name="hibernate.dialect" value="com.znet.hibernate.dialect.MySQL5InnoDBDialect" />

This function will in the end take two parameters. The first parameter will denote the table to associate the index to. The second parameter will denote the actual index [eg: useindex(table, my_index)]. This will allow us to mark the resultant SQL with both the index and associated table. Thus, we can properly restructure the generated SQL accordingly. We could now use this function within HQL such as:

String hql1 = "select table from MyTable table where useindex(table, my_index) is true and table.feature is not null";
// result: select [omitted] from my_table table where useindex(table.id, my_index)=1 and table.feature is not null";
// note that hibernate automatically resolves table into table.id within the function

Now that we know what the SQL gets generated as, let’s build an interceptor to transform the SQL. org.hibernate.Interceptors can perform all types of functionality within Hibernate. For our case, we just care about transforming the SQL via the onPrepareStatement(String sql) method. The first step is to create our interceptor. The easiest way is to just extend EmptyInterceptor and merely override the methods you care about. EmptyInterceptor provides empty stubs for all implemented methods.

package com.znet.hibernate.interceptor;
 
import org.hibernate.EmptyInterceptor;
 
public class IndexInterceptor extends EmptyInterceptor
{
    private static final long serialVersionUID = 1L;
 
    @Override
    public String onPrepareStatement(String sql)
    {
        while (true)
        {
            // check if function specified
            int idx = sql.indexOf("useindex(");
            if (idx < 0) { break; }
 
            // find end of function
            int endidx = sql.indexOf(")=1", idx);
            if (endidx < idx) 
            { 
                throwError("expected useindex(table, index) is true"); 
            }
 
            // get both parameters
            String[] params = sql.substring(idx + 9, endidx).split(",");
            if (params.length != 2) 
            {
                throwError("expected 2 parameters to useindex(table, index)");
            }
 
            // trim parameters and verify
            String tableId = params[0].trim(); 
            String indexHint = params[1].trim();
            if (tableId.length() == 0 || indexHint.length() == 0)
            {
                throwError("invalid parameters to useindex(table, index)");
            }
 
            // find actual table name minus id
            int dotIdx = tableId.indexOf('.');
            if (dotIdx < 0)
            {
                throwError("invalid table name in useindex(table, index)");
            }
 
            // find table name within declaration
            String tableName = tableId.substring(0, dotIdx);
            int tableIdx = sql.indexOf(" " + tableName + " ");
            if (tableIdx < 0)
            {
                throwError("unknown table name in useindex(table, index)");
            }
 
            // remove useindex function from predicate
            String predicate = sql.substring(endidx + 3);
            if (predicate.startsWith(" and ")) 
            { 
                predicate = predicate.substring(5); 
            }
 
            // inject use index after table declaration
            sql = sql.substring(0, tableIdx + 2 + tableName.length()) +
                  "use index (" + indexHint + ") " + 
                  sql.substring(tableIdx + 2 + tableName.length(), idx) +
                  predicate;
        }
 
        return sql;
    }
 
    protected void throwError(String message)
    {
        throw new IllegalStateException(message);
    }
}

There is quite a bit of logic there to go into depth, but the general idea is that it searches for each useindex(table, index)=1 declaration within the SQL statement. For each instance, it tracks back to the table declaration (via from or join) and appends the “use index(index)” statement to the table declaration. Finally, it removes the function from the where statement. So, going back to our example above, we end up with:

String hql1 = "select table from MyTable table where useindex(table, my_index) is true and table.feature is not null";
// before interceptor: select [omitted] from my_table table where useindex(table.id, my_index)=1 and table.feature is not null";
// after interceptor:  select [omitted] from my_table table use index (my_index) where table.feature is not null

Before that will actually work, though, we need to register the interceptor with Hibernate. There are multiple ways to do this depending on whether you are using straight Hibernate, Hibernate with Spring, JPA with Hibernate, etc. I will demonstate JPA with Hibernate via persistence.xml, but for other examples, see this article.

<property name="hibernate.ejb.interceptor" value="com.znet.hibernate.interceptor.IndexInterceptor" />

That’s it. You can now force the “use index” declaration within any HQL by simply adding useindex(table, index) is true to the where statement. Note that it should be the first statement in the where statement. In theory, although I have not tested this very much, the following complex example should work too:

String  hql = "select table from MyTable table " +
                     "inner join table.relative relative, " +
                    "OtherTable other " +
                     "where useindex(table,table_index) is true and " +
                     "useindex(relative,relative_index) is true and " +
                     "useindex(other, other_index) is true and " +
                     "relative.feature1 = other.feature2";

As I stated, this is just an example that I am using and I have in no way tested it to a large extent outside simple examples. If you do take an attempt to use it and find issues, feel free to post a comment and I will look into fixing or helping. Otherwise feel free to use this in any way that helps you.

Eclipse Galileo (3.5) Released - My Favorite Features

Wednesday, June 24th, 2009

Eclipse Galileo has officially been released and with it comes multitudes of changes. Below are my favorites from the Platform, JDT, and Web Tools projects.

For more information, including screenshots, see:

Mac OSX Builds Use Cocoa and Sheets

The platform now uses native cocoa-build SWT widgets, rather than the obsolete Carbon. This brings the platform more in line with current Mac OSX technologies. Further, it uses Sheets for most popup dialogs to follow the OSX user interface guidelines.

Comparing Microsoft Word Documents

Comparing Microsoft Word documents in Eclipse now uses the native Microsoft Word compare support to show changes between versions. For any project that stores Word documents in source control, this feature may be nice to compare changes between versions…especially in terms of merging updates.

Open Resource Dialog

The Open Resource Dialog now allows the choice of what editor to use by right clicking to the context menu. This is a huge, yet small, benefit. Often times you may want to use a different editor than the default. This new change makes that much easier. For example, if you have custom named configuration files in XML that have an official editor (ie: JSF), you can right click to select the specific editor rather than the default XML editor.

Improved Installation/Plugin Management

Eclipse has greatly improved how plugins are added and managed, especially when adding new plugin sites.

Open Implementation Hyperlink

An Open Implementation hyperlink has been added for overridable methods, which directly opens the implementation in case there’s only one, or shows all the concrete implementations for that method in the hierarchy of its declaring type, using the quick type hierarchy. By default, the hyperlink appears when you hold down the Ctrl key while hovering over an overridable method. You can configure the modifier for this hyperlink on the General > Editors > Text Editors > Hyperlinking preference page.

This feature is a huge bonus, especially when you are navigating through source files trying to process the flow. If the class declares a type as an interface (which is usually the case), then normally you wil ctrl+click to the interface, which is obviously not what you want. This new feature allows you to pick the concrete class that you want to jump to making debugging easier.

Javadoc Viewer and Hover

The Javadoc view and hovers now support the {@inheritDoc} tag and add links to overridden methods (like the Javadoc tool). Moreover, the message for deprecated elements now shows up on top, and relative links are supported (for example, to embed images from the “doc-files” directory or to link to {@docRoot}).

This feature should make viewing javadoc inline when hovering an element easier to follow to click through to.

New JPA Entity Generation from Tables

Dali has a new Entity Generation wizard via a contribution from Oracle. This functionality includes a new wizard that offers additional configuration options.

This makes setting up JPA projects, tables, and entities much easier.

XSLT Source Editing

Content assistance is now available for the XSLT mode attribute. This attribute is on the xsl:template and xsl:apply-templates elements. The assistance will find all available modes that have been defined in the current stylesheet as well as any imported or included stylesheets.

Content Assistance is available for the name attribute on the xsl:call-template element. This will provide proposals of available named templates that can be called. This searches the current stylesheet as well as any imported or included stylesheets.

Content assistance is available for the href attribute on xsl:include and xsl:import elements. This will search the current project for any XSLT stylesheet that is available, and provide it as a possible proposal. It is limited in scope to the current project.

The XSL Tools Editor now supports the Templates View. This allows for drag and drop support of XPath templates into the editor. Users may also use this view to create and maintain new or existing templates.

XSLT Debugger

The XSLT debugger now supports a result view. The view will show the output that has been generated to the current break point. As a user steps through code the view will be updated as well.

During debugging of an XSLT Stylesheet, variables that contain NodeSets are now expandable, allowing inspection of the contents of the Nodes carried

Common Java Cookbook

Wednesday, June 3rd, 2009

If you use any popular open source technologies, odds are they use or you have used the Apache Commons libraries.  The following is a free e-book on using those various libraries.

Common Java Cookbook

Using Spring For Dependency Management

Sunday, April 26th, 2009

Spring is often times considered a web application library similar to the EJB 3.x stack.  However, Spring is so much more and can live in standalone applications as well.  Today I am going to touch on using Spring in standalone applications to handle dependency or configuration management.  I do not mean configuration management in the sense of CMS, but in the sense of handling and creating inner-dependencies between business objects, especially in the aspect of singletons.  One of the biggest issues with applications is high coupling by having to have objects create other objects, assign the relationships, and manage those dependencies.  However, one of the primary goals of any application is loose coupling, which in turn reduces maintenance.  Some of the traditional ways of handling these types of scenarios include:

  • Factories that create the instances and setup the dependencies.  While this abstracts the configuration to a factory, it still requires high coupling in the factory to talk to other factories and know about the objects and their inner dependencies.  It also requires static classes for the factories typically, which reduces testability.  My general rule of thumb is to reduce static classes in order to improve pluggability and testability.
  • Custom XML configuration to setup the dependencies and objects.    This pattern abstracts away all the coupling, but requires yet another XML format to be defined, a custom parser to be written, etc.  This can be a tedious operation depending on how fine grained and customizable the format is.

Spring offers a much better approach to this.  It allows you to use either annotations or XML configuration to setup the dependencies.  The difference with Spring’s XML configuration is that it is highly dynamic and flexible and offers several capabilities.  Further, Spring offers other support including AOP in order to separate and handle cross cutting concerns.  For example, you can easily add security or logging around any method invocation without the associated class having to manage that relationship.  In the end, your objects only deal with the objects they must directly deal with resulting in very loose coupling and high testability.

(more…)

Scalable NIO Servers - Part 3 - Features

Monday, April 13th, 2009

We have now analyzed various open source NIO servers for performance and memory consumption.  Per my quick, initial testing, only Grizzly, Mina, and Netty were comparable. Now, let’s analyze features and how each of these frameworks use them.  For my purposes, I am going to be looking into the following features that I personally value most important for my project:

  • Intercepting Pattern (ie: Filters)
  • Access to high level, yet effcient, buffers rather than lower level byte buffers
  • Protocol independence and abstraction
  • Socket independence and abstraction
  • Custom protocol support
  • POJO support for encoding/decoding
  • Custom thread model support
  • HTTP support
  • User documentation (user guide, javadoc, source code, examples

(more…)

Scalable NIO Servers - Part 2 - Memory

Thursday, April 9th, 2009

As my ongoing investigation into picking a suitable and highly scalable server for my future applications, today I will be talking about memory.  Yesterday, we discussed performance and saw in general how Netty and Grizzly compared to one another.  Today, we will further extend that by comparing memory usage footprint at start, over time, and how the memory usage compares as a trend with respect to garbage collection.  As GC is one of the biggest culprits of performance, the more efficient the server at conserving memory, the better the performance.  So, without further ado, let’s get to the testing.

(more…)

Scalable NIO Servers - Part 1 - Performance

Tuesday, April 7th, 2009

As a continuation of evaluating an NIO server for my iPhone game, I started with looking at pure performance. First, the following links provide already existant benchmarks:

I took my own samples and quickly ran some basic tests as well to just get a really rough idea.  Note that these metrics should be taken with a large grain of salt as they do not attempt to optimize any of the test libraries and the clients are all run in traditional threads on non-server class machines alongside the actual servers.  Thus, these tests are quickly CPU bound on the client.  The idea is to just get a very rough estimate to compare alongside the above tests.

That point aside, my test basically creates a echo server and echo client.  It then starts up X simultaneous threads that push a simple ‘testing’ string back and forth to the server as fast as it can.  The end result is the time it takes to send a message and receive the echo in milliseconds.

(more…)