multithreadinghibernategrailstransactionsgrails-2.5

Grails 2.5: Complex “findOrCreate” and synchronisation between threads (HTTP sessions)


In a Grails application we have an interface that accepts a path-like 3-level structure to be created from parameters in a single request like

level1/level2/document

Object level2 references level1 and document references level2.

Multiple objects using the same level1/level2 subpath can be uploaded in parallel and therefore synchronisation between the sessions needs to be implemented. Each of the accounts can have its own structure.

In essence, the logic is like an advanced findOrCreate that has to be synchronised between multiple concurrent requests.

My idea was to implement something like this inside a service method:

Doc d
synchronised(currentUser) {
    Dir.withNewTransaction {
       Dir l1 = findFirstLevel(level1) // (A)
       if (!l1) {
           l1 = new Dir(name: level1)
           l1.save()
       }
       Dir l2 = findSecondLevel(l1, level2)
       if (!l2) {
           l2 = new Dir(name: level2, parent: l1)
           l2.save()
       }
       d = new Doc(name: docName, parent: l2)
       d.save()
    } // (B)
} // (C)
saveDocumentContent(d, content)

I used withNewTransaction to ensure that the records would be saved before the end of synchronised section to make sure that the same structure is properly created only once also for parallel uploads.

However, the data is not persisted until the service function running in thread T1 completes. That causes that the query marked by (A) returns null in thread T2 that was blocked by synchronisation block and entered it before T1 finished executing service method. This leads to a structure like this:

D1/D2/D3
D1/D2/D4

Instead of

D1/D2/D3
     /D4

My assumption was that in (B) at the end of withNewTransaction data will be persisted and then parallel session, running in T2 would get the data using the query.

However this does not happen.

What did I miss?

EDIT: Clearing the session at the beginning and flushing at end of synchronised section has no effect.

EDIT 2: Hibernate 3.6 is used with Grails. Could that be the source of the problem?


Solution

  • The problem was that one of the attributes used in the queries was modified outside the synchronization block. The logic otherwise worked properly.