Technical Blog

3 Posts authored by: Yanko Zhivkov

Why is memory never enough?

 

Our customer project has a few dozens of integration JUnit tests.  Those are tests coded as JUnit tests loading the core application Spring context to verify the correct behavior of certain parts of our application. They have been pretty useful proving us right and a lot of  times wrong after we have committed something into our source code repository.

 

The only problem that we were facing was that the tests were really slow. They would take 6, 8, even 12 hours sometimes in a Hudson build. That was a little suspicious and by taking a closer look at one of the integration test runs using Visual VM we  managed to find out that we were having a memory leak. The max heap size  would reach 1.5GB and because of the huge overload of garbage collection our tests were taking a lot more time than they should have. The JVM was trying hard to collect whatever it could to fit the tests into this pretty big heap.

 

One interesting thing was that after moving the project from JDK 5 to JDK 6 the tests started failing much quicker with an OutOfMemoryError and they were taking 2 hours less in total. The error would print the mysterious

java.lang.OutOfMemoryError: GC overhead limit exceeded.

 

It was the first time I had seen such an error and after some googling it turned out that JDK 6 has this new feature to fail the JVM with an out of memory error sooner rather than later.
They also added an option to suppress/enable that feature by adding -XX:-UseGCOverheadLimit to the JVM arguments.

 

After  adding the option -XX:+HeapDumpOnOutOfMemoryError the JVM produced  valuable heap dumps on an out of memory errors. Using the Memory  Analyzer Tool (MAT) we were able to see where the memory went.

Surprisingly,  the JVM was always crashing on two particular test suites. Both of them having 40+ test cases. The biggest heap consumer was an array of objects pointing to instances of either of the test suite classes.

 

Here's what was uncovered after some investigation:

  • JUnit creates a new instance of the test suite class every time a new test case is launched
  • JUnit will not invoke TestCase.tearDown() if an exception occurs in TestCase.setUp()
  • JUnit keeps reference to all test cases in a test suite until the test suite completes
  • Having fields in your test suite class can hold reference to objects that otherwise would be due for garbage collection

 

tearDown() or rather tearDownHappyCase()

 

Because our tests had a few fields holding reference to various services and the test application context (based on Spring  application context) this was making JUnit overload the memory with  ~40MB per test case. Until a test suite would complete we were ending up with 40 test cases x 40MB = ~1.6GB of RAM.

 

The most  obvious way of fixing that was to make sure all the fields in the test class were nullified so that the objects referenced would be garbage collected.

In JUnit tearDown() is the best location for that. The problem was that in case while setting up a test case an error occurs  JUnit will continue with the next test case without even bothering invoke tearDown(). This was causing even more troubles with the test cases memory footprint.

Our setUp() method was modified to look as follows:

 

public void setUp() throws Exception {
    try {
        super.setUp();
    } catch (Throwable exc) {
          tearDown();
          throw exc;
   }
}

 

And the tearDown() method looked like:

public void tearDown() {
   this.productService = null;
   this.productSkuService = null;
...
 
}

 

Even though not so beautiful this allowed us to get the overall memory usage to reasonable levels and sped up our test cases quite a bit.

 

JUnit 4

 

Interestingly enough the test workflow in JUnit 4 is different. There are the @Before and @After annotations to be used on methods in your test case. Even if the method(s) annotated with @Before throw any error JUnit 4 will still execute all the @After annotated methods.

This means the the above mentioned problem will not occur in JUnit 4 test cases.

It's good to know things have been improved...

2 Comments Permalink

Overview

 

'A picture is worth a thousand words' is a really good saying and it proves to be true in many situations. At Elastic Path, we use a tool called OpenJPA Grapher that helps us build a complex graph of entities that are part of the Elastic Path Commerce platform. Having a tool like this can help you visualize the relationships between your entities and keep you up to date with the multiple changes that occur in a fast-paced development environment.

 

How does it work?

 

OpenJPA enhances all the unenhanced entity classes at build time. When the entities are being enhanced, OpenJPA collects all the metadata it needs. The metadata consists of the type of relationship between two entities, the cascade type supported, and various other properties.

In the attached openjpa-grapher-0.0.1-SNAPSHOT-sources.jar, you will find a class (Grapher.java) that hooks to the OpenJPA enhancer. For every entity that goes through the OpenJPA enhancer, Grapher.java reads the metadata and builds a link between that entity and any other referenced entities. The class uses the notion of an AuxiliaryEnhancer, provided by the OpenJPA library.

The resulting graph file is in text format and includes the entities and their type of relationship. You will see something like 'orderInternal M  R' where the first part of the string is the field name in the class and the letters are denoting the cascade type that could be M - Merge, R - Refresh, D - Delete, P - Persist.

 

Let's look into how to set up the OpenJPA Grapher and generate a visual graph.

 

Building GraphViz graph

 

GraphViz, as you can tell by the name, is a visualization tool that helps you build different graphs and diagrams to help you represent certain information in a more user-friendly format.

The tool supports different formats. We have been using the 'dot' format for directed graphs.

 

 

   1.  Installing the grapher component

      Place the attached com.elasticpath.openjpa.grapher.jar and pom files into your local maven repository.

mvn install:install-file -Dfile=com.elasticpath.grapher-0.0.1-SNAPSHOT.jar -DpomFile=com.elasticpath.grapher.pom
    2. Adding a dependency to the grapher in com.elasticpath.core/pom.xml

      This allows the grapher to hook to the OpenJPA Enhancer. The dependency jar file contains a class name in META-INF/services, which is the way it gets plugged in.

      Add the following to the dependencies section in com.elasticpath.core/pom.xml

    <dependency>
      <groupId>com.elasticpath</groupId>
      <artifactId>openjpa-grapher</artifactId>
      <version>0.0.1-SNAPSHOT</version>
      <scope>compile</scope>
    </dependency>

 

     3. Generating the openjpagrapher.dot file

        Run the following commands to generate the dot file:

     > cd com.elasticpath.core
     > ant clean compile

 

     The openjpagraph.dot file is saved in the com.elasticpath.core folder.

    Note that you must call clean when building the graph, otherwise only classes modified after the last enhance are added to the graph.

 

     4. Installing the GraphViz library and generating the SVG file

       GraphViz converts the dot format into a scalable vector graphics (SVG) format. You can find a GraphViz installation information for your OS on their download page.

       After you have installed it, run the following command:

     > dot -Tsvg openjpagraph.dot -odomain-relations.svg

 

How to view the graph

 

In a Browser

The easiest way is to open the file domain-relations.svg in a browser like Safari. Here's how it looks like:

SVGinBrowser.png

As you can see the graph is quite big and cannot be easily browsed.

 

Standalone ZGRVIewer

ZGRViewer is an open source project that allows you to easily view and browse graphs generated with GraphViz. You can download ZGRVIewer from this page.

I used SVN to download the latest trunk version of the tool as described on the download page. ZGRVIewer is a maven project so it can be easily built using mvn package.

Now that you have the tool built, you can go to the target folder and run the viewer with:

> cd zgrviewer/trunk/target
> java -jar zgrviewer-0.9.0-SNAPSHOT.jar

Here's what you should see.

ZGRViewerStandalone.pngZGRViewerStandaloneOverview.png

The main advantage of ZGRViewer is that the graph is zoomable and you can choose from a few tools to actually see the graph relationships in a better way.

 

ZGRViewer as an Applet

A good feature of the ZGRViewer is that you can run it as a Java Applet in a browser thus giving you the best of both worlds - zoomable graph browsing and having the graph viewable without having to download the standalone tool.

In order to do that, we can create a simple web page with the applet embedded.

 

<html>
  <body>
    <div id="main">
      <applet code="net.claribole.zgrviewer.ZGRApplet.class"
              archive="zvtm-core-0.11-SNAPSHOT.jar,zvtm-svg-0.2.0-SNAPSHOT.jar,zgrviewer-0.9.0-SNAPSHOT.jar,timingframework-1.0.jar"
              width="720" height="480">
        <param name="type" value="application/x-java-applet;version=1.5" />
        <param name="scriptable" value="false" />
        <param name="width" value="720" />
        <param name="height" value="480" />

        <param name="svgURL" value="/~yzhivkov/openjpa/domain-relations.svg" />
        <param name="showNavControls" value="true" />
        <param name="showFCPalette" value="true" />
        <param name="title" value="Domain Object Graph" />
        <param name="appletBackgroundColor" value="#DDD" />
        <param name="graphBackgroundColor" value="#DDD" />
        <param name="highlightColor" value="red" />
        <param name="displayOverview" value="true" />
        <param name="focusNodeMagFactor" value="2.0" />
      </applet>
    </div>
  </body>
</html>

The most important parameter here is svgURL that must point to the SVG file.

All you need to do is copy the jars into an http server folder along with the above code as an html page (e.g. openjpa.html).

The listing of your folder should be similar to the following:

antlr-2.7.7.jar
domain-relations.svg
jcip-annotations-1.0.jar
junit-3.8.1.jar
openjpa.html
timingframework-1.0.jar
xercesImpl-2.8.1.jar
xml-apis-1.3.03.jar
xmlParserAPIs-2.6.2.jar
zgrviewer-0.9.0-SNAPSHOT-sources.jar
zgrviewer-0.9.0-SNAPSHOT.jar
zvtm-core-0.11.0-SNAPSHOT.jar
zvtm-svg-0.2.0-SNAPSHOT.jar

You can use Apache Web Server (httpd) to run the example like I did, but in general any web server should do.

The result would be a web page with the applet running on it.

ZGRViewerApplet.png

Conclusion

The OpenJPA grapher can give you a good overview of your domain model in terms of what entities exist in your application.

A good thing about the ZGRViewer Applet is that you can even integrate the whole process with your favorite continuous integration server (Hudson, Jenkins, Bamboo, etc.) and have a consistent, up-to-date visual representation of your entity relationships.

 

References

 

OpenJPA - http://openjpa.apache.org

GraphViz - http://www.graphviz.org

ZGRViewer - http://zvtm.sourceforge.net/zgrviewer.html

Auxiliary Enhancer - http://ivansthunks.com/blog/tag/auxiliaryenhancer/

1 Comments Permalink

       

The search server web application is responsible for providing searching and browsing functionality for both the storefront and the Commerce Manager (CM) client. At its heart is the Solr search engine, which sits on top of the Lucene indexes. If you wanted to leverage Solr's powerful search capabilities, you could use the Solr search APIs. However, these APIs require extensive knowledge of Solr syntax. Another option might be to use JPQL, which is basically an object oriented SQL. But this requires some JPQL specific knowledge to be able to retrieve data from the database.

 

In Elastic Path 6.1, a new set of APIs were created to allow developers to create complex, platform-independent search queries using a familiar syntax, but with the added benefits of an ecommerce domain-specific language.  The new Elastic Path Query Language (EPQL) gives us the ability to be technology independent and makes the system more flexible.

 

The advanced search feature was introduced in Elastic Path Commerce 6.1, with the ability to handle products, categories, and catalogs initially. Its architecture, however, is extensible, and in the future, it will support searching for other types of domain objects, such as price lists, orders, and customers.  The advanced search functionality is currently available within the CM client and the import-export tool. The CM client integration supports only products at this time, while the import-export tool can use advanced search for looking up sets of products, categories, and catalogs.

 

Advanced search is provided as a library that can be used into any application or a standalone program.

 

The syntax of the Elastic Path Query Language (EPQL) resembles the SQL language. A simple query consists of a single expression. An expression has the following form:

 

FIND Product WHERE <field> <operator> <value>

where

  • <field> is the field you are searching. For example, if you want to look for products of a specific brand, you would include the BrandCode field in your query. The supported fields are described in Supported fields further in this article.
  • <operator> is the operator you are using to perform the comparison.
  • <value> is the literal value you want to compare to the field value.

For example, the following query matches the product whose code is 10030205

 

FIND Product WHERE ProductCode =   '10030205'

 

In addition to searching for field values, you can also search for attribute values. To search for a value in an attribute, the expression has the following form:

 

Attribute{<attribute_name>} <operator> <value>

where <attribute_name> is the name of a product attribute or product SKU attribute.

 

For example, the following query matches all products that have the Header / Model attribute set to MX:

 

FIND Product WHERE Attribute{Header /   Model} = 'MX'

 

Here is a more complicated query that finds all Nike and Adidas products that cost less than $200 USD and belong to catalog A:

 

FIND Product WHERE Catalog = 'A'   AND Price{A}[USD] < 200

AND (BrandName [en] = 'Nike' OR BrandName   [en] = 'Adidas')


You can run queries immediately using the CM client's UI. This is convenient for testing, but it doesn't allow you to schedule actions on the query results. Let's say you want to perform a daily action on products that match the criteria in the previous example. To do that, you would need to create a class that retrieves the products using EPQL and sends that information to a third party system for processing.

 

To use the EPQL search APIs, you need to add com.elasticpath.core.jar and com.elasticpath.ql.jar file to your project's classpath.

 

Next, add the required Spring bean definitions. Create a file named serviceEPQL.xml in the project's conf/spring/service folder and add a reference to it from the Spring application-context.xml. For an example, take a look at the com.elasticpath.cmclient.core RCP plugin or the import/export tool.

 

Create a Java class that will be used to retrieve the products using EPQL. The following code shows how to execute an EPQL query:

 

public boolean doDailyTask() {

// get a search engine instance

EpQLSearchEngine searchEngine =

       getElasticPath().getBean("epQLSearchEngine");

// create a query

String searchString = "FIND Product   WHERE Catalog = 'A' " +

       "AND Price{A}[USD] < 200   AND (BrandName [en] = 'Nike' " +

       "OR BrandName [en] =   'Adidas')";

// get a parser and use it to validate the query

EPQueryParser parser = searchEngine.getEpQueryParser();

try {

   parser.verify(query);

}

catch (EpQLParseException   exception){

   LOG.warn(exception);

return false;

}

// if the query is okay, execute it and   get the results

SolrIndexSearchResult result =   searchEngine.search(searchString);

List<Long> productUids =   result.getSearchResults();

// ... Do some processing on the results

return true;

}

 

The EpQLSearchEngine class has a search method that executes a query and returns the results. Before executing a query, you should make sure that it is syntactically valid.

 

The EPQLQueryParser class provides a verify method that takes a query string as an argument. If there's an error in the query, it throws an exception, including a detailed description to help you fix the problem.  The search result set contains the list of UIDs of the objects that matched the query.

0 Comments 0 References Permalink