Wednesday, June 23, 2010

Hibernate Caches

Background
Hibernate comes with three different caching mechanisms - first level, second level and query cache. Truly understanding how the Hibernate caches work and interact with each other is important when you need to increase performance - just enabling caching in your entity with an annotation (or in classic .hbm.xml mapping file) is easy. But understanding what and how things happens behind the scenes is not. You might even end up with a less performing system if you do not know what you are doing.

SessionFactory and Session
The purpose of the Hibernate SessionFactory (called EntityManager in JEE) is to create Sessions, initialize JDBC connections and pool them (using a pluggable provider like C3P0). A SessionFactory is immutable and built from a Configuration holding mapping information, cache information and a lot of other information usually provided by means of a hibernate.cfg.cml file or through a Spring bean configuration.
A Session is a unit of work at its lowest level - representing a transaction in database lingua. When a Session is created and operations are done on Hibernate entities, e.g. setting an attribute of an entity, Hibernate does not go of and update the underlying table immediately. Instead Hibernate keeps track of the state of an entity, whether it is dirty or not, and flushes (commits) updates at the end at the end of a unit of work. This is what Hibernate calls the first level cache.

The 1st level cache
Definition: The first level cache is where Hibernate keeps track of the possible dirty states of the ongoing Session's loaded and touched entities. The ongoing Session represents a unit of work and is always used and can not be turned of. The purpose of the first level cache is to hinder to many SQL queries or updates beeing made to the database, and instead batch them together at the end of the Session. When you think about the 1st level cache think Session.




The 2nd level cache
The 2nd level cache is a process scoped cache that is associated with one SessionFactory. It will survive Sessions and can be reused in new Session by same SessionFactory (which usually is one per application). By default the 2nd level cache is not enabled.
The hibernate cache does not store instances of an entity - instead Hibernate uses something called dehydrated state. A dehydrated state can be thought of as a deserialized entity where the dehydrated state is like an array of strings, integers etc and the id of the entity is the pointer to the dehydrated entity. Conceptually you can think of it as a Map which contains the id as key and an array as value. Or something like below for a cache region:

{ id -> { atribute1, attribute2, attribute3 } }
{ 1 -> { "a name", 20, null } }
{ 2 -> { "another name", 30, 4 } }

If the entity holds a collection of other entities then the other entity also needs to be cached. In this case it could look something like:

{ id -> { atribute1, attribute2, attribute3, Set{item1..n} } }
{ 1 -> { "a name", 20, null , {1,2,5} } }
{ 2 -> { "another name", 30, 4 {4,8}} }

The actual implementation of the 2nd level cache is not done by Hibernate (there is a simple Hashtable cache available, not aimed for production though). Hibernate instead has a plugin concept for caching providers which is used by e.g. EHCache.

Enabling the 2nd level cache and EHCache
To get the 2nd level cache working you need to do 2 things:
1 Cache Strategy. Enable a cache strategy for your Hibernate entity - either in the class with an annotation or in the hibernate mapping xml file if you are stuck with pre java5. This can be done for an entity by providing this little snippet into your hbm.xml file (a better place is to store the cache setting strategy in hibernate.cg.xml file )





or using an annotation for your entity (if you are on java5 or greater)

@Entity
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Router { ... }
And as mentioned above if you want to cache collections of an entity you need to specify caching on collection level:





...


Hibernate has something called a cache region which by default will be the full qualified name of your Java class. And if you like me are a fan of convention over configuration you will use the default region for an entity. A cache region will also be needed for the collection using the full qualified name of the Java class plus the name of the collection name (i.e. org.grouter.domain.entities.Router.nodes)

2 Cache provider. Setting up the physical caching for a cache provider. If you are using EHCache - which is the most common choice i dear to say - then you will need to specify some settings for the cache regions of your entities in a file called ehcache.xml. The EHCache will look for this file in the classpath and if not found it will fallback to ehcache-failsafe.xml which resides in the ehcache.jar library A typical sample for an EHCache configuration could look like (see mind map below for explanations):


and


The name maps to the name of the cache region of your entity. The attribute maxelementsInMemory needs to be set so that Hibernate does not have to swap in and out elements from the cache. A good choice for a read only cache would be as many entities there are in the database table the entity represents. The attribute eternal, if set to true means that any time outs specified will be ignored and entities put into the cache from Hibernate will live for ever.
Below is a mindmap for the second level cache and how it relates to the SessionFactory and the 1st level cache.
The Query cache
The Query cache of Hibernate is not on by default. It uses two cache regions called org.hibernate.cache.StandardQueryCache and org.hibernate.cache.UpdateTimestampsCache. The first one stores the query along with the parameters to the query as a key into the cache and the last one keeps track of stale query results. If an entity part of a cached query is updated the the query cache evicts the query and its cached result from the query cache. Of course to utilize the Query cache the returned and used entities must be set using a cache strategy as discussed previously. A simple load( id ) will not use the query cache but instead if you have a query like:

Query query = session.createQuery("from Router as r where r.created = :creationDate");

query.setParameter("creationDate", new Date());
query.setCacheable(true);
List l = query.list(); // will return one instance with id 4321

Hibernate will cache using as key the query and the parameters the value of the if of the entity.
{ query,{parameters}} ---> {id of cached entity}
{"from Router as r where r.id= :id and r.created = :creationDate", [ new Date() ] } ----> [ 4321 ] ]

Pragmatic approach to the 2nd level cache
How do you now if you are hitting the cache or not? One way is using Hibernates SessionFactory to get statistics for cache hits. In your SessionFactory configuration you can enable the cache statistics by:

true
true
true
true
true
true
true

The you might want to write a unit test to verify that you indeed are hitting the cache. Below is some sample code where the unit test is extending Springs excellent AbstractTransactionalDataSourceSpringContextTests

public class MessageDAOTest extends AbstractDAOTests  // which extends AbstractTransactionalDataSourceSpringContextTests

{
public void testCache()
{
long numberOfMessages = jdbcTemplate.queryForInt("SELECT count(*) FROM message ");
System.out.println("Number of rows :" + numberOfMessages);
final String cacheRegion = Message.class.getCanonicalName();
SecondLevelCacheStatistics settingsStatistics = sessionFactory.getStatistics().
getSecondLevelCacheStatistics(cacheRegion);
StopWatch stopWatch = new StopWatch();
for (int i = 0; i < 10; i++)
{
stopWatch.start();
messageDAO.findAllMessages();
stopWatch.stop();
System.out.println("Query time : " + stopWatch.getTime());
assertEquals(0, settingsStatistics.getMissCount());
assertEquals(numberOfMessages * i, settingsStatistics.getHitCount());
stopWatch.reset();
System.out.println(settingsStatistics);
endTransaction();

// spring creates a transaction when test starts - so we first end it then start a new in the loop
startNewTransaction();
}
}

}

The output could looke something like:

30 Jan 08 23:37:14  INFO org.springframework.test.AbstractTransactionalSpringContextTests:323 - Began transaction (1):

transaction manager [org.springframework.orm.hibernate3.HibernateTransactionManager@ced32d]; default rollback = true
Number of rows :6
Query time : 562
SecondLevelCacheStatistics[hitCount=0,missCount=0,putCount=6,elementCountInMemory=6,elementCountOnDisk=0,sizeInMemory=8814]
30 Jan 08 23:37:15 INFO org.springframework.test.AbstractTransactionalSpringContextTests:290 - Rolled back transaction
after test execution
30 Jan 08 23:37:15 INFO org.springframework.test.AbstractTransactionalSpringContextTests:323 - Began transaction (2):
transaction manager [org.springframework.orm.hibernate3.HibernateTransactionManager@ced32d]; default rollback = true
Query time : 8
SecondLevelCacheStatistics[hitCount=6,missCount=0,putCount=6,elementCountInMemory=6,elementCountOnDisk=0,sizeInMemory=8814]
30 Jan 08 23:37:15 INFO org.springframework.test.AbstractTransactionalSpringContextTests:290 - Rolled back transaction
after test execution
30 Jan 08 23:37:15 INFO org.springframework.test.AbstractTransactionalSpringContextTests:323 - Began transaction (3):
transaction manager [org.springframework.orm.hibernate3.HibernateTransactionManager@ced32d]; default rollback = true
Query time : 11

Another way to spy on what Hibernate is doing is to proxy the jdbc driver used by a proxy driver. One excellent one I use is p6spy which will show you exactly what is issued over a JDBC connection to the actual backend database. For other tips have a look below in the mindmap.

Wednesday, June 9, 2010

Load Balancing and Clustering Liferay

There are two ways of Clustering Liferay on Tomcat
1. Sticky Session
User request will always goes to same Liferay instance
2. Session Replication
User request can go to any tomcat in cluster and his session is copied on entire cluster




Lets get started for Sticky Session based clustering and load balancing.


Use-Case
Setting up two tomcat Liferay along with apache on same windows machine.


Pre-requirements
1. install Apche 2.x
2. download Liferay5.x and make an extra copy


Steps 1. open httpd.conf from apache_home/conf/ and add these lines at the end



BalancerMember ajp://localhost:8009/ route=tomcatA smax=15 max=50 loadfactor=20
BalancerMember ajp://localhost:8010/ route=tomcatB smax=15 max=50 loadfactor=20




ProxyPass balancer://mycluster/ stickysession=JSESSIONID




SetHandler balancer-manager
Order Deny,Allow
Deny from all
Allow from localhost



Step 2.


uncomment the following four lines on httpd.conf


LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_ajp_module modules/mod_proxy_ajp.so
LoadModule proxy_balancer_module modules/mod_proxy_balancer.so
LoadModule status_module modules/mod_status.so


Step 3.


open liferay/tomcat_home_1/conf/server.xml and add jvmRoute="tomcatA" to the following line


Engine name="Catalina" defaultHost="localhost"


so it should look like this
Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcatA"


Step 4.


open liferay/tomcat_home_2/conf/server.xml and add jvmRoute="tomcatB" to the following line


Engine name="Catalina" defaultHost="localhost"


so it should look like this
Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcatB


also change the following port nos




Server port="8006" shutdown="SHUTDOWN"


Connector port="8081" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8444"


Connector port="8010" protocol="AJP/1.3" redirectPort="8444"


Thats It!


start apache, tomcatA, tomcatB and


navigate to http://localhost/
also checkout balancer-manager
http://localhost/balancer-manager


for more configuration and understanding checkout the following link
http://httpd.apache.org/docs/2.2/mod/mod_proxy.html





If your tomcats run on different server make sure you change index directory to some central place (e.g /common-dir/liferay ) i.e resource.repositories.root=/common-dir/liferay in portal-ext.properties


An Important Liferay article

http://www.liferay.com/web/guest/community/wiki/-/wiki/Main/Clustering

Wednesday, April 28, 2010

liferay performance tuning


Performance Improvement ways in liferay

a) Memory - garbage collection thru Admin interface

b) Parameters to JVM while starting tomcat
-Xms128m -Xmx1024m -XX:MaxPermSize=128m

c) DBCP instances - increase it in ROOT.xml

d) Properties file changes
last.modified.check=false
theme.css.fast.load=true
javascript.fast.load=true

e) Servlet Filters

Total of 15 filters. Disable the ones that are not required. eg.

CompressionFilter
StripFilter

Open web.xml and comment the entries for these filters.

Similarly for,

CASFilter
NtlmFilter
VirtualHostFilter

The fewer servlet filters you are running, the less processing power is needed.

f) Portlet

Edit the following files to disable certain portlets from getting deployed to the portal server.

portlet.xml
liferay-portlet.xml

Restart the server

g) Database design

Ensure all the search colums are indiced properly.
Do periodic house-keeping on the database indices.
Proper design of the database tables keeping in mind the normalization techniques.

h) Get the cache-ing enabled for database objects.

By default only the User_ table is cached. Cache other tables as well that will be frequenly accessed.

Refer to the place where you can do this setting.

i) Application Layer

Write your code in such a way that you make lesser database / hibernate calls.

Remember, every call to the persistence layer is going to take time. So be very careful using them. Never use persistence layer calls inside loops.

Write optimized queries when you put them in custom-sql files.

j) UI design

place fewer portlets on a portal page.

when you use images / flash objects make sure that they are very small.

If you write custom css / javascript compress them using YUI compressor so that they get downloaded to the browser pretty fast.

Replace Tinymce in the place of FCKEditor.

k) Setting logging mode to ERROR.

Tuesday, February 10, 2009

Creating and importing properties into java file

step 1)

create a property file with name Conn.Properties having example property
bvmc.LoginURL=manish
bvdb.url = jdbc:oracle:thin:



step 2)
write the following java code

private static final Properties CONNPRP = new Properties();

static {

try {

FileInputStream fileInputStream = new FileInputStream(
"config/Conn.Properties");
CONNPRP.load(fileInputStream);

} catch (Exception e)
{
throw new RuntimeException(e);
}
}


String loginURL = CONNPRP.getProperty("bvmc.LoginURL");

System.out.println("loginURL :::::: " + loginURL);

***** How to create mail functionality in java *****

We just need mail.jar imported into our Eclipse project for this mail functionality.

package Mail;


import java.util.Properties;

import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

public class MailManager {
private static Properties properties = System.getProperties();

static {
String mailhost = "relay.company.com";

properties.put("mail.smtp.host", mailhost);
properties.put("mail.mime.charset", "utf-8");
}

public static void main(String[] args) throws Throwable {
try {
// System.out.println("Start-----------");
// String userName = "Vikas";
// String from = userName + "@gmail.com";
// String to = "manish.kr.jaiswal@gmail.com";
// String body = "This is the body";
// String subject = "TestSubject";
// sendEmail(from, to, body, subject);
// System.out.println("Start-----------2");
} catch (Throwable th) {
th.printStackTrace();
throw th;

}
}

public static void sendEmail(String from, String to, String body,
String subject) throws MessagingException, AddressException {
Session session = Session.getInstance(properties, null);

Message message = new MimeMessage(session);
message.setFrom(new InternetAddress(from));

message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(
to, false));

message.setSubject(subject);
message.setContent(body, "text/html; charset=utf-8");
// message.setText(body);// , "text/html;
Transport.send(message);
}
}

Sunday, February 8, 2009

**** Using JSON in JavaScript. *****

JSON Simply is a way of representation of data and its access and this is by default supported by javascript

JSON is a subset of the object literal notation of JavaScript. Since JSON is a subset of JavaScript,
it can be used in the language with no muss or fuss.

var myJSONObject = {"bindings": [
{"ircEvent": "PRIVMSG", "method": "newURI", "regex": "^http://.*"},
{"ircEvent": "PRIVMSG", "method": "deleteURI", "regex": "^delete.*"},
{"ircEvent": "PRIVMSG", "method": "randomURI", "regex": "^random.*"}
]
};


Members can be retrieved using dot or subscript operators.

myJSONObject.bindings[0].method // "newURI"

To convert a JSON text into an object, you can use the eval() function. eval() invokes the JavaScript compiler. Since JSON is a proper subset of JavaScript, the compiler will correctly parse the text and produce an object structure. The text must be wrapped in parens to avoid tripping on an ambiguity in JavaScript's syntax.

var myObject = eval('(' + myJSONtext + ')');

Thursday, February 5, 2009

1) Ajax made Simple

Ajax in Simple steps.............ENJOYYYYYYYYY

Basically there are 3 things to be understood in Ajax

1) we have a request state that tells the request state after its being sent from AJAX/javascript code

State Description
0 The request is not initialized
1 The request has been set up
2 The request has been sent
3 The request is in process
4 The request is complete

2) A function is being called at every state of request .

xmlHttp.onreadystatechange=function()
{
if(xmlHttp.readyState==4)
{
// Get the data from the server's response
}
}

4) Get the data from the server's response

xmlHttp.responseText

Now Before all these we need 2 things more

1) get XMLHttpRequest object (its an ActiveXObject ).

2) send the request using
xmlHttp.open("GET","time.asp",true);
xmlHttp.send(null);

2) JOB SCHEDULING USING QUARTZ IN JAVA

An easy example for JOB scheduling

class 1 MainApplication :-




import java.util.Calendar;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

import org.apache.catalina.util.URLEncoder;


class MainApplication {

public static void main(String[] args) {
Timer timer = new Timer();
Calendar date = Calendar.getInstance();
date.set(
Calendar.DAY_OF_WEEK,
Calendar.WEDNESDAY
);
date.set(Calendar.HOUR, 5);
date.set(Calendar.MINUTE,0);
date.set(Calendar.SECOND, 0);
date.set(Calendar.MILLISECOND, 0);

// Schedule to run every Sunday in midnight
timer.schedule(
new ReportGenerator(),
date.getTime(),
1000 * 60 * 60 * 24 * 7
);

}
}


class 2 ReportGenerator :-



import java.util.TimerTask;


public class ReportGenerator extends TimerTask {

public void run() {
System.out.println("This is VIKASSSSSSSSSSSSSSSSSSSSSSSS:: ");
//TODO generate report
}

}

---------------------------------------------------------------