Pages

Tuesday, March 29, 2011

Comparing different cache products

My app. relies heavily on cache to function. Although I use cache on the view, I use it mostly as Hibernate 2nd level cache. Here are some of the products I used and what I think about them.
Ehcache
I think this was used to be called Easy Hibernate Cache and Hibernate people promoted it's use. Now it's owned by Terracotta. I used this quite for a while, it's light, fast and mostly easy to use. However it didn't worked that good as a distributed cache environment.
It has multicast support for peer discovery which works pretty well for most of the time. Except it didn't worked on our prod environment where we have 10 nodes across the network. Some of the nodes just didn't connect to each other which is unacceptable.
It also has manual peer discovery, which needs different ehcache.xml's which would point to other nodes. I think you could tell hibernate, which xml to use at persistence.xml file.
Still I had hard time tracking which node joined to the cluster and which failed to.
Memcached
Main reason I tried memcached was, its use at facebook, wikipedia and such. Memcached is designed a bit different from the ehcache. This is written in 'C', had to be build and run as a daemon process. Cache clients can connect to it through telnet and perform. First problem I ran into was building it. Although It build easily on a Linux environment It required some editing to headers on a HP-UX in order to compile. Second and greater problem is, it doesn't have support for Hibernate. I used the library here http://code.google.com/p/hibernate-memcached/ which is not being actively developed anymore. It also has some nasty bugs...
Hazelcast
Hazelcast is what I use now. At first look it's design looks similar to ehcache but this one is made distribution in mind. It's distributed by default. I have enabled back-up reads, and near-cache settings for better performance.
It comes whit a decent monitoring app. which you can monitor your cluster and see the active nodes.
It's much easier to configure especially compared whit ehcache.

Wednesday, December 29, 2010

Hibernate Id Generation and Oracle Sequences

I thought that @SequenceGenerator allocationSize attribute defined the number to increment the sequence. The API says that anyway... If you forget the fact that, you can't increment the Oracle Sequences more or less than the number you specified while you created them, you may find your self in a trap.
By default you create your sequences with an increment of 1. This becomes a problem if your app. does bulk inserts. Every insert will need a select to the sequence to generate an id which in turn will hinder the performance of app.
One of the ways Hibernate tries to overcome this problem is using a simple strategy called HiLo. Basically Hibernate uses the allocationSize attribute as a multiplier to sequence value. If the sequence is 'x' Hibernate uses id's from '(x-1)*allocationSize' to 'x*allocationSize' to following inserts after a single select and an increment to the sequence.
While I think this is a feasible approach, down side is all the apps. using this sequence will have to use this algorithm to generate the id's, dealing with the fixed allocationSize, or the generated id's may collide with each other.
Instead of using sequences, using a table which stores id's is much better since you can define the increment size to the amount that you actually require. Using the following annotation and the optimizer, causes a simpler and similar behavior that API actually states. Here is the annotation;
1:    @GeneratedValue(strategy = GenerationType.TABLE, generator = "genFooTable")
2: @GenericGenerator(name = "genFooTable",
3: strategy = "org.hibernate.id.enhanced.TableGenerator",
4: parameters = {
5: @Parameter(name = "table_name", value = "SEQUENCES"),
6: @Parameter(name = "value_column_name", value = "NEXTVALUE"),
7: @Parameter(name = "segment_column_name", value = "NAME"),
8: @Parameter(name = "segment_value", value = "genFooTable"),
9: @Parameter(name = "increment_size", value = "10"),
10: @Parameter(name = "optimizer", value = "org.mca.PooledIdOptimizer")
11: })
The optimizer :
1:  public class PooledIdOptimizer extends org.hibernate.id.enhanced.OptimizerFactory.OptimizerSupport {
2: private long value;
3: private long hiValue = -1;
4: public synchronized Serializable generate(AccessCallback callback) {
5: if ((hiValue < 0) || (value >= hiValue)) {
6: value = callback.getNextValue();
7: hiValue = value + incrementSize;
8: }
9: return make(value++);
10: }
I made a little editing with the Hibernate's original pooled optimizer since I didn't like the way it work.
Cheers!

Monday, December 27, 2010

Friday, November 26, 2010

About JSF

I have been using JSF for at least 5 years I think. And here I am thinking how can I make my menu item, which is a JSF component, to open up its link on a new window. I know I should check the reference document and there is probably an attribute for it but that seems too much hassle. I could have set the target attribute on a standard html anchor.
There is always an answer with JSF but it's not always as simple as it should be. Like validating (or not validating) a component could be a problem. Is it immediate ? Which form the component and the button is in ? Is ajax used ? You should consider these or your button may not work or the user may see unrelated validation messages.
I believe JSF is still good for apps where you need to process good amount of input from users, show some fancy ajax UI easily where otherwise you have to deal with JS.
The question is can't these all be simpler ?

Monday, October 25, 2010

JSF Page Fragment Caching

Problem : Our menu took ages to render.
Our application menu had links to various functions of the apps., 400+ nodes, which needed to be authorized based on EL. JSF has to execute certain EL for each node and decide if its to be rendered and than actually render the menu.
Solution : Cache it.
Simplest solution is to cache your menu. Our menu changes when the users roles changes which doesn't happen all that often so JSF doesn't have to do all that computing and since lots of user share same set of roles they can share the cached menus.
How ?
As far as I am aware Seam has a cache component. I didn't used that and I thought I could do simple component to cache with out much hassle. Here is how the tag looks like;
<mca:cache region="menu" key="#{viewUtility.getMenuKey()}">
... menu goes here ...
</mca:cache>
We need a cache region and cache key. Region will be used to specify what you are caching. Key will identify the value. In this case I used the hash code of the user's roles so that same cached will be used for different users as long as they have the same roles.
Much of the work is done on renderer here;
/**
* User: malpay
* Date: 12.Ağu.2010
* Time: 10:53:06
*/
public class CacheRenderer extends Renderer {

private final static Log log = LogFactory.getLog(CacheRenderer.class);

private CacheManager cacheManager;

public CacheManager getCacheManager() {
if (cacheManager == null) {
cacheManager = (CacheManager) FacesContextUtils.getWebApplicationContext(
FacesContext.getCurrentInstance()).getBean("ehCacheManager");
}
return cacheManager;
}


private void replaceResponseWriter(FacesContext context) {
ResponseWriter rw = context.getResponseWriter();
CacheWriter cw = new CacheWriter(rw);
context.setResponseWriter(cw);
}

private boolean cacheNotUptoDate(CacheComponent cc, Cache cache) {
return cache.get(cc.getKey()) == null;
}

@Override
public void encodeBegin(FacesContext context, UIComponent component) throws IOException {
CacheComponent cc = (CacheComponent) component;
Cache cache = getRegion(cc.getRegion());
if (cacheNotUptoDate(cc, cache)) {
replaceResponseWriter(context);
}
}

@Override
public void encodeEnd(FacesContext context, UIComponent component) throws IOException {
CacheComponent cc = (CacheComponent) component;
if (responseWriterReplaced(context)) {
CacheWriter cw = (CacheWriter) context.getResponseWriter();
String value = updateCache(cc, cw);
context.setResponseWriter(cw.getResponseWriter());
context.getResponseWriter().write(value);
}
}

@Override
public void encodeChildren(FacesContext context, UIComponent component) throws IOException {
CacheComponent cc = (CacheComponent) component;
Cache cache = getRegion(cc.getRegion());
if (cacheNotUptoDate(cc, cache)) {
for (UIComponent child : component.getChildren()) {
child.encodeAll(context);
}
} else {
char[] chars = cache.get(cc.getKey()).getValue().toString().toCharArray();
log.info("rendering cache region : " + cc.getRegion() + "" + cc.getKey());
context.getResponseWriter().write(chars, 0, chars.length);
}
}

private String updateCache(CacheComponent cc, CacheWriter cw) {
Cache cache = getRegion(cc.getRegion());
String value = cw.getValue();
cache.put(new Element(cc.getKey(), value));
return value;
}

private boolean responseWriterReplaced(FacesContext context) {
return context.getResponseWriter() instanceof CacheWriter;
}


private Cache getRegion(String region) {
if (getCacheManager().getCache(region) == null) {
getCacheManager().addCache(region);
}
return getCacheManager().getCache(region);
}

@Override
public boolean getRendersChildren() {
return true;
}
}
What it does is check the cache if its up to date, if not render the children as usually but save the rendered portion of the page and update the cache with it. If the cache is up to date don't render the children, simply wrote the cache on the response.
This works well on my scenario but be aware It may require some adjustments for more general use.

Thursday, May 27, 2010

Facelet tip

A quick facelet tip. If you needed an extra attribute on a component you can add and access it easily with facelets. Here I needed to add an node attribute on boolean check box, which is part of rich faces tree.
<h:selectBooleanCheckbox id="tree_cbx" value="#{tree.getNode(item).selected}"
node="#{tree.getNode(item)}">
<a4j:support ajaxSingle="true" event="onchange"
reRender="tree_yetki">
<a4j:ajaxListener
type="tr.com.innova.ortak.tree.node.YetkiNodeListener"/>
</a4j:support>
</h:selectBooleanCheckbox>
You can access the attribute easily once you have the component. Here is my ajaxListener;
public class YetkiNodeListener implements AjaxListener {

@Override
public void processAjax(AjaxEvent event) {
UIComponent holder = (UIComponent) ((UIComponent) event.getSource())
.getParent();
holder.getValueExpression("node").getValue(FacesContext.getCurrentInstance().getELContext());
...
}

Wednesday, May 19, 2010

Status

  • I should have started using Maven earlier. If you want to manage an inhouse repository check out the Artifactory. Ill make better use of it on my next project.
  • Hudson: More capable than CC, easily configurable UI, pluggable, integrates with svn, maven, ant... And don't forget to revert before update.
  • HTML5 Canvas looks cool. 3D Games + Drawing tools + ?. If you haven't already check this out ; http://mrdoob.com/lab/javascript/harmony , he also has 3d engine based on JS. I'll try this out may be do a project.
  • There is the Devoxx @ 15 Nov., Call for papers deadline is 6 Jun.
  • Dynamic reporting with jasper reports. This guy has a clever and basic idea of how to do it. Implemented a similar thing. Plus I added annotations to format and display the data.
  • Single Sign-On/Out with CAS.
  • Our project is still approaching the deadline. A bit tired.