Use XMLs not groovy scripts with db migration plugin!

I have 48 domain classes in my Grails 2.1 project and I use Grails Database Migration Plugin 1.2 for a database management. Recently I’ve noticed that it becomes terribly slow when running application, even if there are no changes to be applied. I swit…

I have 48 domain classes in my Grails 2.1 project and I use Grails Database Migration Plugin 1.2 for a database management. Recently I’ve noticed that it becomes terribly slow when running application, even if there are no changes to be applied.

I switched do debug logging level for liquibase package and I found that it takes about 15 seconds to parse changelog.groovy and 20 files that were included in it!

Prepare benchmark

I couldn’t belive it so I’ve created two new clean changelogs:

$ grails dbm-generate-changelog changelog.groovy
$ grails dbm-generate-changelog changelog.xml

Both of these changelogs contain 229 change sets. It is enough that you can benchmark parsers for them. Two parsers in question are:

  • grails.plugin.databasemigration.GrailsChangeLogParser
  • liquibase.parser.core.xml.XMLChangeLogSAXParser

I need to modify a line in my Config.groovy and switch changelog.groovy with changelog.xml for a second test:

grails.plugin.databasemigration.updateOnStart = true
grails.plugin.databasemigration.updateOnStartFileNames = ["changelog.groovy"]
// grails.plugin.databasemigration.updateOnStartFileNames = ["changelog.xml"] grails.plugin.databasemigration.updateOnStart = true
grails.plugin.databasemigration.updateOnStartFileNames = ["changelog-all.groovy"]
// grails.plugin.databasemigration.updateOnStartFileNames = ["changelog-all.xml"]

Profile with JProfiler

I want to profile execution time. I use JProfiler from ej-technologies to measure execution times. Please notice that I don’t want to benchmark SQL queries performed by liquibase. I am only focused on parse method of these two classes.

Here’s how I set up JProfiler:

I switch to CPU Views – Method statistics and I click “Record”. Here are results for both parsers:

Results for changelog.groovy

Results for changelog.xml

Analysis

My assumptions were correct: 8 339 ms vs 139 ms. Parsing XML is 60 times faster! I want to jump and sing: “I switch to XML now!”, but I have some concerns. I have a production database that I need to be compatible with. And I should rewrite my all groovy changelog files by hand. So it’s not so trivial and it’s a time consuming and error prone task.

So as much as I want to switch to XML now, I won’t. But if you start your adventure with database migration plugin today I have an advice for you: use XML if you start from scratch.

For now I’ve just submitted a new JIRA issue – GrailsChangeLogParser – parse method is very slow and I hope it can be greatly improved.

You May Also Like

Grails render as JSON catch

One of a reasons your controller doesn't render a proper response in JSON format might be wrong package name that you use. It is easy to overlook. Import are on top of a file, you look at your code and everything seems to be fine. Except response is still not in JSON format.

Consider this simple controller:

class RestJsonCatchController {
def grailsJson() {
render([first: 'foo', second: 5] as grails.converters.JSON)
}

def netSfJson() {
render([first: 'foo', second: 5] as net.sf.json.JSON)
}
}

And now, with finger crossed... We have a winner!

$ curl localhost:8080/example/restJsonCatch/grailsJson
{"first":"foo","second":5}
$ curl localhost:8080/example/restJsonCatch/netSfJson
{first=foo, second=5}

As you can see only grails.converters.JSON converts your response to JSON format. There is no such converter for net.sf.json.JSON, so Grails has no converter to apply and it renders Map normally.

Conclusion: always carefully look at your imports if you're working with JSON in Grails!

Edit: Burt suggested that this is a bug. I've submitted JIRA issue here: GRAILS-9622 render as class that is not a codec should throw exception

Tomcat: Problemy z requestami zawierającymi polskie znaki diakrytyczne


Jeśli jest problem z pobieraniem plików z polskimi znakami diakrytycznymi, to trzeba dopisać kodowanie do connectora w tomcat/conf/server.xml

URIEncoding="UTF-8"

Typowa konfiguracja connectora będzie wyglądała tak

<Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" URIEncoding="UTF-8" />