Ph: 11000000
MaximDim
Dmitri Maximovich's notebook
20071122 Thursday November 22, 2007

Monitoring JVM with MRTG, part II

After previous post about monitoring JVM memory with MRTG I've got few comments suggesting that it should be possible to do the same thing via SNMP protocol, support for which is built in into JVM at least since version 1.5. It seems like a better approach, at least from system load prospective (no need to run jstat/jps every few minutes) and apparently enabling SNMP agent in the JVM suppose to have very negligible impact on JVM performance.

Indeed, it turned out that it's surprisingly simple to do if you know what you're doing ;) Big thanks goes to Daniel Fuchs from Sun, for providing very useful comments and adding to my (quite limited) understanding of SNMP protocol. So here is how I done it:

First of all, you need to create 'snmp.acl' file. Very good documented sample comes right with JDK/JRE (usually in '/jre/lib/management/snmp.acl.template'). You can modify it to suit your security model and either copy it into the same directory under 'snmp.acl' name and then it will be used by default, or copy it anywhere else and specify location in the JVM command line. Below is 'snmp.acl' I'm using:

acl = {
  {
    communities = public
    access = read-only
    managers = 127.0.0.1
  }
}

As you see it gives read-only access to the community named 'public' from the interface 127.0.0.1 (localhost). Note that, at lest on Unix systems, 'snmp.acl' file should be given read permissions only to the JVM process owner and nobody else (chmod '600'), otherwise JVM would complain upon startup.

To actually enable SNMP agent in JVM you need to define following system variables, for example on the JVM command line:

-Dcom.sun.management.snmp.interface=127.0.0.1
-Dcom.sun.management.snmp.port=16666
-Dcom.sun.management.snmp.acl=true
-Dcom.sun.management.snmp.acl.file=/path/to/your/snmp.acl

Note that interface name generally should be the same as defined in snmp.acl and unless your JVM is running under 'root' account don't specify ports below 1024 on Unix system. You can also disable acl check for SNMP calls altogether by specifying '-Dcom.sun.management.snmp.acl=false' but obviously it's not recommended. After JVM startup it's good to check it's log files and/or sdout/stderr for any errors.

To make sure everything is configured properly you can use, for example, 'snmpwalk' utility on Unix to query various JVM parameters via SNMP. For example following command should return number of live threads in JVM (43 in this case):

$ snmpwalk -c public -v 2c 127.0.0.1:16666 1.3.6.1.4.1.42.2.145.3.163.1.1.3.1.0
SNMPv2-SMI::enterprises.42.2.145.3.163.1.1.3.1.0 = Gauge32: 43

Note that you should specify correct community name ('public') and ip address (127.0.0.1) as defined in 'snmp.acl' and port (16666) as defined in JVM system variable. The big number passed as last parameter to 'snmpwalk' is so called OID - an unique identifier for SNMP propery you want to read. It comes from JVM-MANAGEMENT-MIB.mib published by Sun. Since it's a bit cumbersome to read MIB file directly I found free MIB Browser utility quite handy.

Now you can get creative of which values to plot using MRTG. Some of them could be plotted directly, such as above mentioned number of threads:

WorkDir: /mrtg/work/dir
NoMib2: Yes

Target[localhost.jvm_snmp_threads]:1.3.6.1.4.1.42.2.145.3.163.1.1.3.1.0&1.3.6.1.4.1.42.2.145.3.163.1.1.3.2.0:public@127.0.0.1:16666
PageTop[localhost.jvm_snmp_threads]: <H1>JVM Thread count</H1>
Options[localhost.jvm_snmp_threads]: nopercent,growright,gauge,noinfo
Title[localhost.jvm_snmp_threads]: JVM Thread count
MaxBytes[localhost.jvm_snmp_threads]: 1000
YLegend[localhost.jvm_snmp_threads]: count
ShortLegend[localhost.jvm_snmp_threads]: count
LegendI[localhost.jvm_snmp_threads]: user
LegendO[localhost.jvm_snmp_threads]: daemon

MRTG config above will produce charts of JVM user/daemon threads count. Note that MRTG requires two OIDs specified (separated by '&' sign). Note also 'NoMib2' parameter which should be specified.

A bit more tricky is to chart memory for various JVM memory pools as that data exposed as 'SNMP table' (not sure about proper terminology) and therefore you need to look up index in the table assigned to particular JVM memory pool first. Not spending much time on this I just created simple shell script which does the trick:

#!/bin/sh
SNMPWALK="/usr/bin/snmpwalk -c public -v 2c 127.0.0.1:16666"
OID_ROOT=".1.3.6.1.4.1.42.2.145.3.163"
OID_POOL_ID="$OID_ROOT.1.1.2.110.1.2"
OID_MEM_POOL_USED="$OID_ROOT.1.1.2.110.1.11"
OID_MEM_POOL_COMMITTED="$OID_ROOT.1.1.2.110.1.12"

POOL_ID=`$SNMPWALK $OID_POOL_ID | grep -i $1 | awk '{print $1}' | awk 'BEGIN { FS = "." } ; { print $13 }'`
#echo $POOL_ID

USED=`$SNMPWALK $OID_MEM_POOL_USED.$POOL_ID | awk 'BEGIN { FS = ":" } ; { print $4 }'`
COMMITTED=`$SNMPWALK $OID_MEM_POOL_COMMITTED.$POOL_ID | awk 'BEGIN { FS = ":" } ; { print $4 }'`

echo $COMMITTED
echo $USED
echo $1
echo "localhost"

Running above script specifying JVM pool names as a single parameter should produce output similar to the following:

$ ./jvm_snmp.sh eden
53739520
14807720
eden
localhost

You can get names for JVM pools available by querying following OID:

$ snmpwalk -c public -v 2c 127.0.0.1:16101 .1.3.6.1.4.1.42.2.145.3.163.1.1.2.110.1.2
SNMPv2-SMI::enterprises.42.2.145.3.163.1.1.2.110.1.2.1 = STRING: "Code Cache"
SNMPv2-SMI::enterprises.42.2.145.3.163.1.1.2.110.1.2.2 = STRING: "Par Eden Space"
SNMPv2-SMI::enterprises.42.2.145.3.163.1.1.2.110.1.2.3 = STRING: "Par Survivor Space"
SNMPv2-SMI::enterprises.42.2.145.3.163.1.1.2.110.1.2.4 = STRING: "CMS Old Gen"
SNMPv2-SMI::enterprises.42.2.145.3.163.1.1.2.110.1.2.5 = STRING: "CMS Perm Gen"

Above shell script could be plugged into MRTG as usual:

WorkDir: /mrtg/work/dir

Target[localhost.jvm_gc_eden]:`/path/to/jvm_snmp.sh eden`
PageTop[localhost.jvm_gc_eden]: <H1>JVM Edem space</H1>
Options[localhost.jvm_gc_eden]: nopercent,growright,gauge,noinfo
Title[localhost.jvm_gc_eden]: JVM Edem
MaxBytes[localhost.jvm_gc_eden]: 100000000
YLegend[localhost.jvm_gc_eden]: mem
ShortLegend[localhost.jvm_gc_eden]: Mb
kMG[localhost.jvm_gc_eden]:,,M,G,T,P
LegendI[localhost.jvm_gc_eden]: capacity
LegendO[localhost.jvm_gc_eden]: utilization

Of course, you're not limited by MRTG for your monitoring needs. SNMP being widely accepted standard pretty much any network monitoring utility should support it. OpenView anyone?

Happy monitoring!

( Nov 22 2007, 01:02:09 PM EST ) Permalink Comments [3]

 

20071114 Wednesday November 14, 2007

Oracle, Java, Timezones and fun with invalid Dates.

I recently run into simple yet peculiar problem while working with our Oracle database which holds some legacy data. One of the tables in Oracle has a 'date of birth' column defined as Oracle's DATE type and I noticed (accidentally) that when I'm querying that table and working with result in Java, sometimes I'm getting dates which are not the same as in database. Dates of birth are stored in that column without time portion, but since there are no such type in Oracle as 'Date without time' time is still stored as 00:00:00. Now let's say we have following row in the table:

select to_char(birth_dt, 'DD/MM/YYYY HH24:MI:SS') from table_a;
------------------------------
24/04/1949 00:00:00

Looks like quite normal date at first sight, but when you fetch this row into Java using standard JDBC operation, similar to:

PreparedStatement ps = conn.prepareStatement("select birth_dt from table_a");
ResultSet rs = ps.executeQuery();
rs.next();

SimpleDateFormat f = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
System.out.println("Date: "+f.format(rs.getDate(1)));

And if you happen to be in the 'Canada/Eastern' timezone (you can execute above code with '-Duser.timezone=Canada/Eastern' JVM argument) the result will be:

Date: 23/04/1949 23:00:00

As you see, date got shifted one hour (if you're using really old JDK or JDK w/o DST patch you might not see this). So why this is happening with this (and some others, but not all) particular dates? It turned out that this particular time point '24/04/1949 00:00:00' didn't existed in 'Canada/Eastern' timezone as there was a switch to Daylight Savings Time exactly at midnight of April 24, 1949 so after 23:59:59 on April 23, 1949 there was 01:00:00 of April 24, 1949. You can confirm this, for example, by querying OS TZ data - on Solaris you can use 'zdump' command:

bash-2.03$ zdump -v $TZ | grep 1949
Canada/Eastern  Sun Apr 24 04:59:59 1949 UTC = Sat Apr 23 23:59:59 1949 EST isdst=0
Canada/Eastern  Sun Apr 24 05:00:00 1949 UTC = Sun Apr 24 01:00:00 1949 EDT isdst=1
Canada/Eastern  Sun Nov 27 03:59:59 1949 UTC = Sat Nov 26 23:59:59 1949 EDT isdst=1
Canada/Eastern  Sun Nov 27 04:00:00 1949 UTC = Sat Nov 26 23:00:00 1949 EST isdst=0

All modern JDKs with correct TZ info knows that this is invalid date and would not allow you to construct such date, so if you try to run following code in the 'Canada/Eastern' TZ:

Calendar calendar = Calendar.getInstance();
calendar.setLenient(false);
calendar.set(Calendar.YEAR, 1949);
calendar.set(Calendar.MONTH, Calendar.APRIL);
calendar.set(Calendar.DAY_OF_MONTH, 24);
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
System.out.println(calendar.getTime());

result would be:

java.lang.IllegalArgumentException: HOUR_OF_DAY

So the origin of the problem seems to be is that when legacy table was initially created nobody was thinking about timezones, and they wanted to store only date for a date of birth anyway. Now when we're selecting this date in Java, assuming particular timezone, if the date happens to fall within those gaps caused by DST switch we're potentially going to get unexpected date, not the same as apparently stored in our database. Actually I'm not sure why date is shifted backwards in the scenario above, I think it should have been shifted forward instead, so at least day would be the same.

Does anyone had similar problem in their practice?

( Nov 14 2007, 11:43:32 AM EST ) Permalink Comments [2]

 

20070904 Tuesday September 04, 2007

Monitoring JVM memory with MRTG

I'm a big fan of MRTG tool and using it to monitor almost all aspects of my system (CPU, memory, disk activity, network traffic etc). While MRTG was initially designed to monitor network traffic from routers and the like over SNMP, it can be easily adjusted to pick up output from almost any program or shell script. Below are simple script and config file for MRTG which I use to monitor JVM's memory allocation in Eden, Old and Permanent generation memory spaces.

First, how do get information about memory. All modern JDKs (I think starting from Sun's 1.4) comes with Java Virtual Machine Statistics Monitoring Tool called jstat which could produce a lot of interesting information about running Java process once supplied with valid Virtual machine identifier ('vmid'). Vmid could be obtained by running another handy utility included in JDK - Java Virtual Machine Process Status Tool, or jps. Combining these two together, and throwing a bit of grep and awk should give you the output string with information about your specific process:

sudo jstat -gc `sudo jps -lv | grep resin | awk '{print $1}'` | grep -v S0C

It should give you output similar to the one below:

1600.0 1600.0 1600.0  0.0   13184.0  11115.9   87764.0    70535.6   53400.0 32142.0   1210   52.830  38      1.722   54.552

Read jsp and jstat documentation and adjust it to your taste. sudo is usually needed as you won't see information about processes run under different user accounts on Unix. First grep is filtering only 'resin' process which I'm interested in (you may want to change it), last 'grep -v S0C' needed to strip header information from the output.

Information I'm interested in is in columns 5 to 10 (Eden space capacity and utilization and same for Old and Permanent spaces). So I have a simple script which wraps command above and takes memory space as a parameter ('eden', 'old' or 'perm'):

#!/bin/sh
JAVA_HOME=/usr/local/jdk
PID=`sudo $JAVA_HOME/bin/jps -lv | grep resin | awk '{print $1}'`
DATA=`sudo $JAVA_HOME/bin/jstat -gc $PID | grep -v S0C`

EC=`echo $DATA | awk '{print $5}'`
EU=`echo $DATA | awk '{print $6}'`
OC=`echo $DATA | awk '{print $7}'`
OU=`echo $DATA | awk '{print $8}'`
PC=`echo $DATA | awk '{print $9}'`
PU=`echo $DATA | awk '{print $10}'`

case "$1" in
  eden)
     echo $EC
     echo $EU
  ;;
  old)
     echo $OC
     echo $OU
  ;;
  perm)
     echo $PC
     echo $PU
;;
esac

echo "unknown"
echo "localhost"

Last two echos needed for MRTG as it expects for lines from the script - first two for actual data graphs and last two for some information I don't care about - like system uptime or location. Now we just need to plug this script (saved as 'jvm.sh') into MRTG config:

WorkDir: /path/to/your/mrtg/data/dir

Target[localhost.jvm_gc_eden]:`jvm.sh eden`
PageTop[localhost.jvm_gc_eden]: JVM Eden space
Options[localhost.jvm_gc_eden]: nopercent,growright,gauge,noinfo
Title[localhost.jvm_gc_eden]: JVM Eden
MaxBytes[localhost.jvm_gc_eden]: 1000000
YLegend[localhost.jvm_gc_eden]: mem
ShortLegend[localhost.jvm_gc_eden]: Mb
kMG[localhost.jvm_gc_eden]:,,M,G,T,P
LegendI[localhost.jvm_gc_eden]: capacity
LegendO[localhost.jvm_gc_eden]: utilization

Target[localhost.jvm_gc_old]:`jvm.sh old`
PageTop[localhost.jvm_gc_old]: JVM Old space
Options[localhost.jvm_gc_old]: nopercent,growright,gauge,noinfo
Title[localhost.jvm_gc_old]: JVM Old
MaxBytes[localhost.jvm_gc_old]: 1000000
YLegend[localhost.jvm_gc_old]: mem
ShortLegend[localhost.jvm_gc_old]: Mb
kMG[localhost.jvm_gc_old]:,,M,G,T,P
LegendI[localhost.jvm_gc_old]: capacity
LegendO[localhost.jvm_gc_old]: utilization

Target[localhost.jvm_gc_perm]:`jvm.sh perm`
PageTop[localhost.jvm_gc_perm]: JVM Perm space
Options[localhost.jvm_gc_perm]: nopercent,growright,gauge,noinfo
Title[localhost.jvm_gc_perm]: JVM Perm
MaxBytes[localhost.jvm_gc_perm]: 1000000
YLegend[localhost.jvm_gc_perm]: mem
ShortLegend[localhost.jvm_gc_perm]: Mb
kMG[localhost.jvm_gc_perm]:,,M,G,T,P
LegendI[localhost.jvm_gc_perm]: capacity
LegendO[localhost.jvm_gc_perm]: utilization

Note how our script with parameter is referenced from 'Target' line. That's it. Below are samples of MRTG graphs produced with above configuration.

[image]
[image]
[image]

( Sep 04 2007, 12:02:20 PM EDT ) Permalink Comments [5]

 

20060530 Tuesday May 30, 2006

Installing Mac OS 10.4 Tiger on iMac G3

As I posted in previous entry, my iMac doesn't have a DVD drive, just a CD-ROM and Tiger ships only on DVD. Luckely, my iMac has FireWire ports, so it should be possible to boot from external FireWire DVD drive, at least theoretically. But prior to that I wanted to upgrade hard drive, because old one is just too noisy to use and just 6 Gb size.

Looking at some instructions available on the net process seems really complicated, no less than 12 steps! But actually I managed to do with less ;-) (In my particular model?) it's not necessary to remove CD carrier as hard drive mount accessible almost right after you open EMI cover. I installed new Seagate 7200 RMP 80 Gb EIDE hard drive in about 15 minutes from start to finish so it's not that complicated as it seems at first. What a difference, I almost couldn't hear the new hard drive working and the fact that iMac doesn't have any fans at al makes really quet computer indeed. Also new hard drive is faster being 7200 RPM versus old one which I believe is just 4400 or so.

I picked Memorex DVD RWN16 USB 2.0 & FireWire External DVD Recorder in my local computer store for about $60 CAD, plugged it into FireWire port on iMac and rebooted holding Option key. Drive was recognized without any problems and couple hours later Tiger was up and running ;-). Although installation wasn't without troubles as installer complained that I should upgrade firmware to the latest version. Not a problem I thought, but if you look at Apple's support page you'd notice that firmware upgrade cannot be installed from Mac OS X, only from previous versions of Mac OS. What to do if my iMac already was running OS X - Apple doesn't give you any clue. Luckily, after plugging old hard drive back I found that it had Mac OS 9.2 on it and after couple reboots firmware was upgraded. I don't really understand why users should jump through these loops, but Apple is another world I suppose.

Next step is to upgrade memory to 1Gb, it seems that it takes old 168 pin PC100 or PC133 DIMM modules, and there are two slots for it. It's time to visit eBay!

( May 30 2006, 11:51:58 AM EDT ) Permalink Comments [0]

 

20060526 Friday May 26, 2006

Unlocking user account on Mac OS X

After all long years of denial I finally got my hands on Macintosh computer. Not a new shiny Intel based, but old 400 MHz PowerPC G3 iMac with CRT monitor. I can't complain because I paid nothing for it and bacically need it for some testing and playing. Still decent machine, with 512Mb memory installed it runs Mac OS X 10.3 (Panther I think it called) pretty good, at least Firefox and Thunderbird ;-)

Anyway, when I got it it was set up in a way not to log user automatically upon boot but to ask for username and password first. Well, I didn't know any. No worries I figured, it's Unix after all, I'll just boot into single user mode and hopefully will be able to run passwd from there. Great, just reboot holding Command-S and in a couple minutes I'm in familiar BSD-like command line. Quick glimpse through /etc/passwd reveal that there are no users defined beside some system accounts.

Apparently it's not that simple with Mac, quick search on google and now I know that regular Unix system files are not used when Mac OS X operates properly, they're replaced by NetInfo database and daemon. Nice, but how do I work with it? After some more googling I finally found how to work with NetInfo from command line:

Verify that you can read the netinfo database:

nicl -raw /var/db/netinfo/local.nidb -list /users

Reset password. This will allow user to login without specifying any password ('joe' is the user you want ot reset password for).

nicl -raw /var/db/netinfo/local.nidb -destroyprop /users/joe passwd

Viola, reboot and I'm in.

Next step is to upgrade hard drive (the one currently there is way too noisy to use comfortably and just 6Gb or so) and try to install Tiger (10.4) on it. I've got a DVD but it's going to be a challenge because my iMac only has CD-ROM ;-). I'll try my luck with external FireWire DVD I guess.

( May 26 2006, 11:48:53 AM EDT ) Permalink Comments [2]

 

20060524 Wednesday May 24, 2006

Importance of Optimistic Locking - GData API

You know that Optimistic locking got into mainstream (and into mind of average developer) when there are not only more and more APIs where it's possible to enable and use it (like, for example, in Hibernate) but APIs where it's not possible not to use it.

Looking at GData API recently I noticed that they have Optimistic locking built in every call which changes the data. It could be confusing at first, if you don't read documentation ;-), why following code failing with com.google.gdata.util.InvalidEntryException on the last line:

URL url = new URL("http://www.google.com/calendar/feeds/xxx@gmail.com/private/full");
CalendarService calendarService = new CalendarService("exampleCo-exampleApp-1");
calendarService.setUserCredentials("xxx@gmail.com", "xxx");

EventEntry entry = new EventEntry();
entry.setTitle(new PlainTextConstruct("Test"));

When eventTimes = new When();
eventTimes.setStartTime(new DateTime(new Date()));
eventTimes.setEndTime(new DateTime(new Date().getTime()+1000*60*60)); // 1hr
entry.addTime(eventTimes);
        
// add to Calendar
EventEntry insertedEntry = calendarService.insert(url, entry);
String id = insertedEntry.getSelfLink().getHref();
System.out.println("Entry created. id="+id);
        
// now try to remove it
calendarService.delete(new URL(id));

In Google Calendar API every Entry has unique id (URL) obtainable via entry.getSelfLink().getHref() but it's not going to work if you want to update or delete entry, instead entry.getEditLink().getHref() must be used, which is identical to URL obtained from getSelfLink() but with version string appended at the end. The version string will change after every update so if you send a delete or update with an old version number, the operation will fail.

Good thing is that when operation fail because of Optimistic Concurrency exception new EditLink URL could be obtained from error response as well as the current state of the Entry so it should be simple for a client to resubmit request. I don't think this information is available in their Java API though, at least not in this version.

( May 24 2006, 02:24:13 PM EDT ) Permalink

 

20060425 Tuesday April 25, 2006

Re: Spring: recovering from database concurrency failures

Recent post in Peter Veentjer's blog cached my attention in Eric's linkblog. Named 'Spring: recovering from database concurrency failures' author claims that Multi Version Concurrency Control (MVCC) works effectively in the same way, from application prospective, as Optimistic Locking, by throwing exception back to application when two concurrent updates happens in the same moment.

This means that transactions can fail with multiversioning databases while they would have been completed successfully with databases that use locks.

He even proposes solution to retry update operations in application untill it succeed eventually.

I beg to differ Peter. Maybe this is how things are in MySQL but certainly this is not the case with more mature databases. For example, below is quick test in Oracle 9i, which doesn't throw any exception no matter from how many applications you execute it simultaneously:

SQL> connect maxim@dev
Connected.

SQL> create table test(id integer not null, value integer not null);

Table created.

SQL> insert into test(id, value) values (1,1);

1 row created.

SQL> select * from test;

        ID      VALUE
---------- ----------
         1          1

SQL> -- open couple sqlplus windows and execute the procedure below
SQL> -- from all of them concurrently

SQL> begin
  2  for c in 1..1000000 loop
  3  update test set value=value+1 where id=1;
  4  commit;
  5  end loop;
  6  end;
  7  /

PL/SQL procedure successfully completed.

Good news is that

...this doesn’t mean that multiversioning databases are bad.

Indeed, may be it's just MySQL?

( Apr 25 2006, 02:17:08 PM EDT ) Permalink Comments [13]

 

20060201 Wednesday February 01, 2006

High Performance Message Processing with BMT Message-Driven Beans and Spring

[image] Article High Performance Message Processing with BMT Message-Driven Beans and Spring I wrote together with Eugene has been published today on BEA dev2dev.

We're discussing arhitecture of non-transactional messages consumption with XA-like 'one-and-only-one' quality of service but without overhead of distributed transaction (in most cases).

Your comments are always welcome.


( Feb 01 2006, 09:59:08 AM EST ) Permalink

 

20060122 Sunday January 22, 2006

Passing data between advices in Spring

Spring version 1.2.6 added very useful new method getUserAttributes() into ReflectiveMethodInvocation class (Spring's implementation of AOP Alliance MethodInvocation interface) which provides invocation-bound alternative to a ThreadLocal and allows passing data between advices in call chain.

I don't want to argue with purists who say that each advice should be totally independent from each other. In real world application it's almost always beneficial to be able to pass some data between interceptors either because it's expensive to recreate every time or because data computed in one interceptor should be accessible to next interceptor(s) in chain. Spring's implementation uses lazy initialized Map and therefore there is zero performance impact if your code is not calling this method.

public class AdviceA implements MethodInterceptor {
  public Object invoke(MethodInvocation invocation) throws Throwable {
    System.out.println("AdviceA");
                
    ReflectiveMethodInvocation mi = (ReflectiveMethodInvocation)invocation;
                
    String data = "Now is "+new Date();
    mi.getUserAttributes().put("data", data);

    return invocation.proceed();
}
...
// another advice somewhere down the call chain:
public class AdviceB implements MethodInterceptor {
  public Object invoke(MethodInvocation invocation) throws Throwable {

    ReflectiveMethodInvocation mi = (ReflectiveMethodInvocation)invocation;
    String data = (String)mi.getUserAttributes().get("data");
    System.out.println("AdviceB :"+data);

    return invocation.proceed();
}
( Jan 22 2006, 10:02:38 PM EST ) Permalink

 

20051116 Wednesday November 16, 2005

Peak performance tuning of CMP Entity beans

[image] My article about CMP Beans performance tuning has been published on BEA dev2dev.

Although not as sexy as AOP on Rails ;-) Entity beans still used widely and amazingly not all developers ultimately familiar or even heard about many advanced features available in any leading J2EE server. This article tries to cover different concurrency strategies and gives some recommendation how and when to use it. Your comments are welcome.


( Nov 16 2005, 10:18:15 AM EST ) Permalink Comments [7]

 

20051102 Wednesday November 02, 2005

And free Oracle for all...

I've been skeptical about new versions of PostgreSql and MySql with enterprise features support, but I guess competition is a good thing after all as Oracle just released 10g Express Edition (XE) (beta) for Windows and Linux, which is free to develop, deploy, and distribute.

At quick glance all features of 10g release 2 supported in XE, including Oracle Text for full text indexing. Maximum DB size is limited by 4Gb and XE will use only one CPU. I guess it's fair limitations for entry level, pilot and even for many medium-sized applications.

Nice move, Oracle. Why would I want to use MySql now? ;-)

( Nov 02 2005, 12:41:42 PM EST ) Permalink Comments [2]

 

20051026 Wednesday October 26, 2005

MySQL 5 and support for XA transactions

MySQL 5 RC had been released recently with lots of new major features. Among the others is support for XA transactions announced as well.

Although it's good to see that open source DBMSs getting closer feature wise to major databases, one should be careful when considering throwing away his Oracle and migrating to MySQL. I recently posted my thoughts about it in dev2dev blog and Jason Carreira also shared his opinion on the state of open source transaction monitors.

So let's take a look at some limitations of current 'support' of XA transactions in MySQL 5 RC. For example:

For XA START, the JOIN and RESUME clauses are not supported For XA END the SUSPEND [FOR MIGRATE] clause is not supported

So what does it mean and what impact it could have on your J2EE application? Well, if you're using Session Beans (or Spring's JTATransactionManager wrapper for that matter) you better be careful with Not Supported and Requires New transaction attributes. J2EE server should execute XAResource.end(xid, TM_SUSPEND) on all resources which was enlisted in transaction which is being suspended and if it's not clear how it's going to work in MySQL. To prevent some comments, sure 'there are workarounds': for example JDBC driver implementation could create new connection to the database to handle work done in new transaction without actually 'suspending' previous transaction in MySQL, but this would lead to extra connections and complexity in JDBC driver code (== more bugs). Again it's interesting question what would happen if something (DB, Tx monitor or client) would crash in that time, will they be able to recover? Af far as I know, XAResource doesn't need to persist information about XA transaction state before prepare or suspend is called.

But may be we should not be worrying about scenario described above because of the following 'implementation detail' in MySQL XA support:

If an XA transaction has reached the PREPARED state and the MySQL server dies, the transaction can be continued after the server restarts. That is as it should be. However, if the client connection terminates and the server continues to run, the server rolls back any pending XA transaction, even one that has reached the PREPARED state.

Are you ready for heuristic outcomes?

( Oct 26 2005, 03:50:49 AM EDT ) Permalink Comments [0]

 

20051019 Wednesday October 19, 2005

JMS messaging with Spring...nice but there is no magic

Some gotchas and things to keep in mind when using Spring's JMS support in J2EE server. Read details in my post on dev2dev.

( Oct 19 2005, 01:02:26 PM EDT ) Permalink Comments [0]

 

20050923 Friday September 23, 2005

Google toolbar - what a shame!

I wanted to try the release of google toolbar today, but apparently it doesn't work in Mozilla Deer Park (beta of Firefox 1.5). Although they claim that ...For the extension to work, you must be using version 1.0 or later.

[image]

This is a shame guys, don't you have like extra couple billions dollars to spend? After all, most of the extensions already supports Firefox 1.5, including CruiseControl Monitor. ;-)

( Sep 23 2005, 02:51:01 PM EDT ) Permalink Comments [0]

 

20050919 Monday September 19, 2005

CruiseControl Monitor extension with JMX actions support

New version of CruiseControl Monitor has been released with major functionality update - now JMX actions could be invoked from the Extension's popup menu on any of the project. Of course it works only for Java version of CruiseControl started with JMX console enabled. User should specify URL for JMX console . Projects build statuses still parsed from status page HTML because it's not clear for now how (if possible at all) to get statuses for all projects deployed on CruiseControl server in one HTTP request to JMX. If anybody know how to do that please drop me a line, I'd be interested to learn it. If it's possible, then parsing HTML could be dropped completely.

Deer Park beta (Firefox 1.4) also supported starting from this version.

[image]

Technorati Tags: Java Javascript Mozilla Firefox CruiseControl

( Sep 19 2005, 04:33:12 PM EDT ) Permalink Comments [0]

 

photo
Contact
Projects
Calendar
« February 2012
Sun Mon Tue Wed Thu Fri Sat
     
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
     
             
Recent Comments
Google searches map
Today's unique words: 0
Searches
Today's hits: 41
Translations


You are viewing a mobilized version of this site...
View original page here

Mobilized by Mowser Mowser