Friday, February 14, 2014

Improved Metrics

A few months back I wrote some code to compute a moving average (well more accurately it's a moving window of a counter). This implementation was functional, yet not particularly efficient. The main problem was it required a thread per metric. Recently I updated the code to share a thread; it is described on github.




Saturday, January 18, 2014

Deploying a Play Framework Application on Raspberry Pi

It's simple to deploy a playframework application, just run 'play dist' and move the appname-version-SNAPSHOT.zip to your server, unzip and run the bin/appname script

However, the script's default memory allocation is 1GB, which more than a Raspberry Pi can support, and leads to the following error:

Error occurred during initialization of VM
Could not reserve enough space for object heap


BTW, I'm running Java 7 for ARM

java -version

java version "1.7.0_10"
Java(TM) SE Embedded Runtime Environment (build 1.7.0_10-b18, headless)
Java HotSpot(TM) Embedded Client VM (build 23.6-b04, mixed mode)

Reading through the script you'll see there are several options you can pass, including a mem option

bin/appname -h 

Usage:  [options]

  -h | -help         print this message
  -v | -verbose      this runner is chattier
  -d | -debug        set sbt log level to debug
  -mem      set memory options (default: , which is -Xms1024m -Xmx1024m -XX:MaxPermSize=256m -XX:ReservedCodeCacheSize=128m)
  -jvm-debug   Turn on JVM debugging, open at the given port.

  # java version (default: java from PATH, currently java version "1.7.0_10")
  -java-home          alternate JAVA_HOME

  # jvm options and output control
  JAVA_OPTS          environment variable, if unset uses ""
  -Dkey=val          pass -Dkey=val directly to the java runtime
  -J-X               pass option -X directly to the java runtime
                     (-J is stripped)

I changed the memory to 32mb and it started just fine

bin/appname -mem 32

bin/appname -mem 32

Play server process ID is 4356

[info] play - datasource [jdbc:postgresql://192.168.1.15:5432/postgres] bound to JNDI as DefaultDS
[info] play - database [default] connected at jdbc:postgresql://192.168.1.15:5432/postgres
[info] application - Application has started
[info] play - Starting application default Akka system.
[info] play - Application started (Prod)
[info] play - Listening for HTTP on /0.0.0.0:900

Wednesday, January 15, 2014

Optimistic Locking and Timestamp Precision with Ebean and Postgres

Lately I've been experimenting with the Play Framework. I'm using Avaje Ebean (JPA), the default ORM for Play Framework, with Postgres. I have an Akka background task that kicks off search jobs. To force a job to run I can simply change the run-at field

update search set next_run_at = now()

But I found this results in an OptimisticLockException when the scheduler runs:

javax.persistence.OptimisticLockException: Data has changed. updated [0] rows sql[update search set next_run_at=?, last_run_at=?, run_count=? where id=? and name is null and search=? and low is null and high is null and exact_match=? and active=? and notify_immediately=? and scheduled=? and frequency_hours=? and search_date is null and next_run_at=? and last_run_at=? and created_at=? and updated_at is null and error_count=? and result_count=? and run_count=? and location=? and account_id=?] bind[null] at com.avaje.ebeaninternal.server.persist.dml.DmlHandler.checkRowCount(DmlHandler.java:95) ~[avaje-ebeanorm.jar:na] at com.avaje.ebeaninternal.server.persist.dml.UpdateHandler.execute(UpdateHandler.java:81) ~[avaje-ebeanorm.jar:na] at com.avaje.ebeaninternal.server.persist.dml.DmlBeanPersister.execute(DmlBeanPersister.java:86) ~[avaje-ebeanorm.jar:na] at com.avaje.ebeaninternal.server.persist.dml.DmlBeanPersister.update(DmlBeanPersister.java:66) ~[avaje-ebeanorm.jar:na] at com.avaje.ebeaninternal.server.persist.DefaultPersistExecute.executeUpdateBean(DefaultPersistExecute.java:82) ~[avaje-ebeanorm.jar:na] at com.avaje.ebeaninternal.server.core.PersistRequestBean.executeNow(PersistRequestBean.java:452) ~[avaje-ebeanorm.jar:na]

It turns out that Ebean uses optimistic locking by default. This works by updating the row only if none of the columns changed since the initial select query. The problem occurs since my POJO uses the Java Date class, which provides only millisecond precision and the Postgres now function provides microsecond precision (an additional 3 digits). This results in a loss of precision and the fields don't match so Ebean thinks another process updated the fields. For example, the Ebean update statement looks like

update table set ... where next_run_at = "2014-01-15 08:18:08.518000"

but the field has microsecond precision: "2014-01-15 08:18: 08.518337" so it fails to update

There are a few solutions to this problem. One solution is to be mindful of SQL updates to timestamps that occur outside of your application and only use only millisecond precision. For this I found the date_trunc Postgres function:

date_trunc('milliseconds', now())

Another option is to set the precision of the timestamp field to milliseconds

ALTER TABLE ... next_run_at timestamp(3)

You might think you'd just turn off optimistic locking if you don't need it, but it appears that it is not possible to do so with Ebean.

Another possible solution is to use the @Version JPA Annotation. With @Version, Ebean will only include the version field to determine perform optimistic locking