Server Caching

Server caching can speed dynamic pages to near-static speeds. Many pages created by database queries only change every 15 minutes or so, e.g. CNN or Slashdot. Resin can cache the results and serve them like static pages. Resin’s caching will work for any servlet, including JSP and XTP pages. It depends only on the headers the servlet returns in the response.

By default, pages are not cached. To cache, a page must set a HTTP caching header.

Resin’s caching operates like a proxy cache. It’s controlled by the same HTTP headers as any proxy cache. Every user shares the same cached page.

  1. Cache-Control: max-age
  2. Debugging caching
  3. Expires
  4. If-Modified
  5. Servlets
  6. Sessions and Cookies
  7. Included Pages
  8. Vary
  9. Caching Anonymous Users
  10. Experimental Anonymous Caching
  11. cache-mapping
Cache-Control: max-age

Setting the max-age header will cache the results for a specified time. For heavily loaded pages, even setting short expires times can significantly improve performance.

Note, pages using sessions should not be cached, although more sophisticated headers like “Cache-Control: private” can specify caching only for the session’s browser.

The following example sets expiration for 15 seconds. So the counter should update slowly.

Expires
<%@ page session="false" %>
<%! int counter; %>
<%
response.addHeader("Cache-Control", "max-age=15");
%>
Count: <%= counter++ %>

max-age is useful for database generated pages which are continuously, but slowly updated. To cache based on something with a known modified date, like a file, you can use If-Modified.

Debugging caching

When designing and testing your cached page, it’s important to see how Resin is caching the page. To turn on logging for caching, you’ll add the following to your resin.conf:

adding caching log
<log name="com.caucho.server.cache"
     path="log/cache.log"
     level="fine"/>

The output will look something like the following:

[10:18:11.369] caching: /images/caucho-white.jpg etag="AAAAPbkEyoA" length=6190
[10:18:11.377] caching: /images/logo.gif etag="AAAAOQ9zLeQ" length=571
[10:18:11.393] caching: /css/default.css etag="AAAANzMooDY" length=1665
[10:18:11.524] caching: /images/pixel.gif etag="AAAANpcE4pY" length=61

...

[2003/09/12 10:18:49.303] using cache: /css/default.css
[2003/09/12 10:18:49.346] using cache: /images/pixel.gif
[2003/09/12 10:18:49.348] using cache: /images/caucho-white.jpg
[2003/09/12 10:18:49.362] using cache: /images/logo.gif
Expires

An application can also set the Expires header to enable caching, when the expiration date is a specific time instead of an interval. For heavily loaded pages, even setting short expires times can significantly improve performance. Sessions should be disabled for caching.

The following example sets expiration for 15 seconds. So the counter should update slowly.

Expires
<%@ page session="false" %>
<%! int counter; %>
<%
long now = System.currentTimeMillis();
response.setDateHeader("Expires", now + 15000);
%>
Count: <%= counter++ %>

Expires is useful for database generated pages which are continuously, but slowly updated. To cache based on something with a known modified date, like a file, you can use If-Modified.

If-Modified

The If-Modified headers let you cache based on an underlying change date. For example, the page may only change when an underlying source page changes. Resin lets you easily use If-Modified by overriding methods in HttpServlet or in a JSP page.

The following page only changes when the underlying ‘test.xml’ page changes.

<%@ page session="false" %>
<%!
int counter;

public long getLastModified(HttpServletRequest req)
{
  String path = req.getRealPath("test.xml");
  return new File(path).lastModified();
}
%>
Count: <%= counter++ %>

If-Modified pages are useful in combination with the cache-mapping configuration.

Servlets

Caching servlets is exactly like caching JSP pages (or XTP or static files.) Resin’s caching mechanism works like a proxy cache: it don’t care how the page is generated; as long as the proper caching headers are set, the page will be cached.

package test;

import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;

public class TestServlet extends HttpServlet {
  int counter;

  public long getLastModified(HttpServletRequest req)
  {
    String path = req.getRealPath("test.xml");
    return new File(path).lastModified();
  }

  public void doGet(HttpServletRequest req,
                    HttpServletResponse res)
    throws IOException, ServletException
  {
    PrintWriter out = res.getWriter();

    out.println("Count: " + counter++);
  }
}
Sessions and Cookies

Because Resin follows the HTTP caching spec, setting caching on a page which relies on sessions will make the page cacheable. You can test this by hitting the following page with separate browsers.

caching session information
<% response.addHeader("Cache-Control", "max-age=3600"); %>

session id <%= session.getId() %>

Normally, this behavior is not what you want. Instead, you may want the browser to cache the page, but not let other browsers see the same page. To do that, you’ll set the “Cache-Control: private” header. You’ll need to use addHeader, not setHeader, so the browser will get both “Cache-Control” directives.

private(browser) caching
<%
  response.addHeader("Cache-Control", "max-age=3600");
  response.addHeader("Cache-Control", "private");
%>

session id <%= session.getId() %>
Included Pages

Resin can cache subpages even when the top page can’t be cached. Sites allowing user personalization will often design pages with jsp:include subpages. Some subpages are user-specific and can’t be cached. Others are common to everybody and can be cached.

Resin treats subpages as independent requests, so they can be cached independent of the top-level page. Try the following, use the first expires counter example as the included page. Create a top-level page that looks like:

<% if (! session.isNew()) { %>

Welcome back!

<% } %> <jsp:include page="expires.jsp"/>
Vary

In some cases, you’ll want to have separate cached pages for the same URL depending on the capabilities of the browser. Using gzip compression is the most important example. Browsers which can understand gzip-compressed files receive the compressed page while simple browsers will see the uncompressed page. Using the “Vary” header, Resin can cache different versions of that page.

caching based on gzip
<%
  response.addHeader("Cache-Control", "max-age=3600");
  response.addHeader("Vary", "Accept-Encoding");
%>

Accept-Encoding: <%= request.getHeader("Accept-Encoding") %>
Caching Anonymous Users

In many cases, logged in users get specialized pages, but anonymous users all see the same page. In this case, you can still take advantage of Resin’s caching, but you’ll need to do a little work in your design.

First, you’ll need to create an include() subpage that contains the common page. The top page can’t be cached because it depends on whether a user is logged in or not.

You must use include() because forward() is cached just like the top page. The top page isn’t cacheable because of the user login, so the forwarded page isn’t cacheable either.

Here’s what a sample subpage might look like:

<%@ page session=false %>
<%! int counter; %>
<%
long now = System.currentTimeMillis();
response.setDateHeader("Expires", now + 15000);

String user = request.getParameter("user");
%>
User: <%= user %> <%= counter++ %>

The top page slightly trickier because it needs to pass the user to the subpage. You need to pass a unique id. If you pass a boolean logged-in parameter, all logged in users will see the same page.

<%@ page session=true %>
<%
String user = getSomeSortOfUniqueUserId();
if (user == null)
  user = "Anonymous";
%>

...

Of course, the top-level page could also be a servlet:

...

String user = getSomeSortOfUniqueUserId(request);
if (user == null)
  user = "Anonymous";

RequestDispatcher disp;
disp = request.getRequestDispatcher("/cachedpage.jsp?user=" + user);

disp.include(request, response);
Experimental Anonymous Caching

Resin includes an anonymous user caching feature. If a user is not logged in, she will get a cached page. If she’s logged in, she’ll get her own page. This feature will not work if anonymous users are assigned cookies for tracking purposes.

To make anonymous caching work, you must set the Cache-Control: x-anonymous header. If you omit the x-anonymous header, Resin will use the Expires to cache the same page for every user.

<%@ page session="false" %>
<%! int counter; %>
<%
response.addHeader("Cache-Control", "max-age=15");
response.addHeader("Cache-Control", "x-anonymous");

String user = request.getParameter("user");
%>
User: <%= user %> <%= counter++ %>

The top page must still set the Expires or If-Modified header, but Resin will take care of deciding if the page is cacheable or not. If the request has any cookies, Resin will not cache it or use the cached page. If it has no cookies, Resin will use the cached page.

When using x-anonymous, user tracking cookies will make the page uncacheable even if the page is the same for all users. Resin chooses to cache or not based on the existence of any cookies in the request, whether they’re used or not.

cache-mapping

cache-mapping assigns a max-age and Expires to an If-Modified cacheable page. It does not affect max-age or Expires cached pages. The FileServlet takes advantage of cache-mapping because it’s an If-Modified servlet.

Often, you want a long Expires time for a page to a browser. For example, any gif will not change for 24 hours. That keeps browsers from asking for the same gif every five seconds; that’s especially important for tiny formatting gifs. However, as soon as that page or gif changes, you want the change immediately available to any new browser or to a browser using reload.

Here’s how you would set the Expires to 24 hours for a gif, based on the default FileServlet.

<web-app id='/'>
  <cache-mapping url-pattern='*.gif'
                 expires='24h'/>
</web-app>

The cache-mapping automatically generates the Expires header. It only works for cacheable pages setting If-Modified or ETag. It will not affect pages explicily setting Expires or non-cacheable pages. So it’s safe to create a cache-mapping for *.jsp even if only some are cacheable.

Source: http://www.caucho.com/

What’s new in Java 1.7?

First thing first. To determine what set of small language changes should be added to JDK 7, a project has been set up called Project Coin. The final five changes (bit more than 5) are described on the following blog entry of Joseph D. Darcy.

So what made it through is the following:

  • Strings in switch
  • Automatic Resource Management
  • Improved Type Inference for Generic Instance Creation (diamond)
  • Simplified Varargs Method Invocation
  • An omnibus proposal for better integral literals
  • Language support for Collections
  • Language support for JSR 292

There is a list of other features available on the OpenJDK 7 features page.

These features are divided in different categories:

VM

  • Compressed 64-bit object pointers
  • Garbage-First GC (G1)
  • JSR 292: VM support for non-Java languages (InvokeDynamic)

lang

  • SR 294: Language and VM support for modular programming
  • JSR 308: Annotations on Java types
  • JSR TBD: Small language enhancements (the Project Coin I was talking about)
  • JSR TBD: Project Lambda

core

  • Modularization (Project Jigsaw)
  • Upgrade class-loader architecture
  • Method to close a URLClassLoader
  • Unicode 5.1
  • Concurrency and collections updates (jsr166y)
  • JSR 203: More new I/O APIs for the Java platform (NIO.2)
  • SCTP (Stream Control Transmission Protocol)
  • SDP (Sockets Direct Protocol)
  • Elliptic-curve cryptography (ECC)

client

  • XRender pipeline for Java 2D
  • Forward-port 6u10 deployment features
  • Create new platform APIs for 6u10 graphics features
  • Nimbus look-and-feel for Swing
  • Swing JLayer component

web

  • Update the XML stack

As you can see there is a lot of stuff. I personally tried the new Garbage Collector (G1) a few months back and was really impressed by the performance. Unfortunately the JVM was crashing every few hours so it couldn’t be used for production. This GC is available in Java 1.6 as well but same thing, it crashes every so often.

I think that’s it for the new features. Maybe it’s a good idea to see some code examples now.

Code examples for new features in Java 1.7

Most of what is below come from the excellent article from Joe Wright on his blog about New language features in Java 7

Language support for collections

This is all about writing less code when you create a List, a Set or a Map. You don’t have to instantiate the Object and then add the element to the Collection. You can now do it in 1 line.

List<String> list = [“item”];
String item = list[0];

Set<String> set = {“item”};

Map<String, Integer> map = {“key” : 1};
int value = map[“key”];

Automatic Resource Management

Annoyed to have verbose code because of try / catch statement. You will love this one.

Indeed, this:

BufferedReader br = new BufferedReader(new FileReader(path));
try {
return br.readLine();
} finally {
br.close();
}

Become this:

try (BufferedReader br = new BufferedReader(new FileReader(path)) {
return br.readLine();
}

Improved Type Inference for Generic Instance Creation (diamond)

Same thing, today you specify the Generic when you declare the interface of your object and then you have to repeat yourself when you instantiate the object. You won’t have to now as you can do:

Map<String, List<String>> map = new HashMap<>();

Underscores in numeric literals

Not sure this one will be useful to lot of people. You can do:

int billion = 1_000_000_000;

Strings in switch

Nothing to explain here, the title says it all.

String availability = “available”;
switch(availability) {
case “available”:
//code
break;

case “unavailable”:
//code
break;

case “merged”:
//code

default:
//code
break;
}

Binary literals

You can create binary literals using the 0b prefix

int binary = 0b1001_1001;

That’s it for the code examples. It would be great if someone can point me on more things. I am sure there are plenty of other cool stuff.

Performance of Java 1.7

I have picked up the tests I ran from an article from Taranfx posted here.

So the tests are the following (my code, not his but I followed the same ideas). I ran all of this on a Macbook Pro running ArchLinux (the one with an Intel(R) Core(TM)2 Duo CPU T7700 @ 2.40GHz. I think 2 years old). I have 2Gb of RAM. I set the Heap Size to 728m (-Xms728m -Xmx728m).

Test 1. Add 1 Million String values to a List (the String is a UUID generated using UUID.randomUUID()).

Test 2. HashMap with 1 million keys, values. Each key, value pair is being calculated via concurrent thread. The key is a UUID and the int is generated using Math.random()

Test 3. Printing 1 million items of ArrayList to number of Files (1000). Writing to different files happening in parallel.

I am just comparing Java 1.6 (1.6.0_19) vs Java 1.7 (b87). I added Java 1.5 to this benchmark following a request in the comments but not Java 1.4 as it is from an other age to me.

So here is the result

Performance benchmark Java 1.5 vs Java 1.6 vs Java 1.7

Java 1.5 Java 1.6 Java 1.7
Test 1 10,698 sec 9,481 sec 9,328 sec
Test 2 69,827 sec 37,935 sec 36,636 sec
Test 3 26,931 sec 30,868 sec 27,383 sec

The difference of performance is clearly not as big as it is in the article of Taranfx. It appears that our implementation of his tests are probably quite different as well as my tests are taking a lot more time than his.

Release date of Java 1.7

In November 2009, it was planned to be in September 2010 as there would be 3 more milestones. Milestone 6 was completed with build 84. b85 was scheduled for the 4th of March 2010, first build of Milestone 7. b87 used in this article has been released the 25th of March 2010. So it looks like a release for September 2010 is more than likely. Though I have been reading an interesting subject on the stackoverflow forum here. You can check the blog of Alex Miller as well. He publishes links to all blog and news items referring to the progress of Java7.

Thanks

http://inebium.com/post/java-7-new-release-performance-code

Zing Chart

Build Flash or HTML5 charts with the latest & greatest features and technologies

  • More than a Dozen Chart Types
  • Handles Massive Data Sets (10,000 points and more)
  • Fly thru Chart Data with Zooming, Scrolling, and Filtering
  • Build Interactive and Drillable Graphs
  • Live Data Feed Support to Update Charts in Realtime

Compare Canvas based charting with Flash one here http://www.zingchart.com/flash-and-html5-canvas/#speedtest

Download free trial @ : http://www.zingchart.com/download/