invalidate object cache in circumflex-orm

61 views
Skip to first unread message

sveri

unread,
Apr 22, 2012, 5:33:07 AM4/22/12
to circumfl...@googlegroups.com
Hi again,

in my last post i wrote i try to integrate circumflex-orm into the play framework, which works nice so far.
I can save, delete, fetch and do all kind of things.
But, now i found i problem with the object cache.

I have three sequential actions:
1. the first one lists all Tasks found in the database. This works
2. The second saves a found/edited Task into the database. This still works. (The entries in the database are updated accordingly)
3. Now i refresh the list of tasks and then i still the old state of the Task object.
It seems like the objects are cached, and the cache is not reset on save.

Any Ideas how i can mark the cache invalid for the saved object?

Thanks in Advance,
Sven

sveri

unread,
Apr 22, 2012, 5:41:27 AM4/22/12
to circumfl...@googlegroups.com
Well, sorry, i forgot to provide some code.

This is the select code:
val taskDbObj = Task AS "taskDb"
val tasks = SELECT(taskDbObj.*).FROM(taskDbObj).ORDER_BY(taskDbObj.createdAt DESC).list

and this the save code:
var retVal: Long = 0
    Context.executeInNew {ctx =>
        if (task.name().trim() != "" || task.description().trim() != ""){
            if(task.id.value == None) {
                task.save()
                retVal = task.id().longValue()
            }else{
                task.save()
                println(task.description())
            }
        }
    }

Best Regards,
Sven

Boris Okunskiy

unread,
Apr 22, 2012, 6:12:35 AM4/22/12
to circumfl...@googlegroups.com
Greetings Sven,

The records are only cached within a single transaction (this is the default behavior). I still see the problem with transaction demarcation: since you don't wrap every request (including these which only read from database), your SELECTs "see" the results of a single transaction (which spans from first request). Please consider the filter for transaction-per-request we were talking about earlier.

As for the caches, you do not need to invalidate them manually as long as you use `save`, `INSERT`, `UPDATE` or `DELETE` methods (ActiveRecord-style persistence). You only need to maintain the cache manually if one of the following conditions are met:

1. There are auxiliary database objects (triggers) that  change the data -- and you wish to see the changes in the same transaction.
2. You use custom DML query -- and you wish to see the changes in the same transaction.
3. The data is modified externally -- and you wish to see the changes in the same transaction.
4. You use application-wide cache (e.g. Ehcache) and one of the above conditions are met.

You see, our ORM is all about transactions :) When you are working on a strongly concurrent application (such as any web application), the transaction-per-request seems like the only choice. I am sorry that our documentation is very sparse about transactions, I think I can manage to completely rewrite it some day.

As for now, feel free to post your questions there, in the group.

Best regards,
Boris Okunskiy

sveri

unread,
Apr 22, 2012, 12:56:21 PM4/22/12
to circumfl...@googlegroups.com
Hi Boris,

i was afraid you were pointing me to the transaction management again :D
Thanks anyway, but i have no clue about how to integrate this into the play framework. I was looking for similar code, but couldn't find anything.
They have a GlobalSettings class, but i dont think that this is the right place to integrate them (https://github.com/playframework/Play20/blob/master/framework/src/play/src/main/scala/play/api/Global.scala)

I did raise a question on stackoverflow (http://stackoverflow.com/questions/10269926/integrate-circumflex-orm-in-play-2-0-scala-application-with-correct-servlet-filt).
I'd be happy if you could add some valuable information.

Best Regards,
Sven

sveri

unread,
Apr 23, 2012, 10:24:55 AM4/23/12
to circumfl...@googlegroups.com
Hi,

a nice guy at the irc pointed me at this doc: http://www.playframework.org/documentation/2.0/ScalaActionsComposition
According to what is stated there the following code works for me:

case class ScircumflexOrm[A](action: Action[A]) extends Action[A] {

    def apply(request: Request[A]): Result = {
      Context.executeInNew { ctx =>
        action(request)
      }
    }

    lazy val parser = action.parser
  }
 
  def index = ScircumflexOrm {
    Action {

   
    val taskDbObj = Task AS "taskDb"
    val tasks = SELECT(taskDbObj.*).FROM(taskDbObj).ORDER_BY(taskDbObj.createdAt DESC).list
   
    Ok(html.task.index(tasks))
    }
  }

So every action get's wrapped now with the Context Object. Or at least every action i want to.
What do you think in regards of performance about this?


Best Regards,
Sven

Am Sonntag, 22. April 2012 11:33:07 UTC+2 schrieb sveri:

Boris Okunskiy

unread,
Apr 24, 2012, 4:40:12 AM4/24/12
to circumfl...@googlegroups.com
Hi Sven,

I see nothing performance-critical there, but I'm not sure about the scope of this `Action` wrapper, so I just have to ask a couple of questions to make sure the things are going right.

1. What view technology are you using? Do you pass records to your views? Is there any chance that views can access the associations (both straight and inverse)? If yes, then you need to find a way to surround your view processing in block transaction, too.

2. Is there a chance that the record can be accessed outside the `ScircumflexOrm` block?

P.S. Sorry for being such a paranoid -- I just think it is better to start off the correct transaction boundaries then searching for the reason of leaks when the application grows.

Best regards,
Boris Okunskiy

sveri

unread,
Apr 24, 2012, 11:15:29 AM4/24/12
to circumfl...@googlegroups.com
Hi Boris,

Am Dienstag, 24. April 2012 10:40:12 UTC+2 schrieb Boris Okunskiy:
Hi Sven,

I see nothing performance-critical there, but I'm not sure about the scope of this `Action` wrapper, so I just have to ask a couple of questions to make sure the things are going right.
Well, i am not that sure either, as i still dont have that much insights of the play framework, but i will add my thoughts below.

1. What view technology are you using? Do you pass records to your views? Is there any chance that views can access the associations (both straight and inverse)? If yes, then you need to find a way to surround your view processing in block transaction, too.
That's what i thought too. Right now i do pass results to the view like this:
render(Ok(tasks))
where tasks is a List of object fetched from the database.

In the associated view i can then iterate over it and get the belonging properties. So lets say my task object references another object "user" via foreign key, and i do fetch the user only in the view via task.user().name(), then it possibly will return a wrong/old result?
Do i understand that correct?

2. Is there a chance that the record can be accessed outside the `ScircumflexOrm` block?
See above, right now i dont see any other possibility.

P.S. Sorry for being such a paranoid -- I just think it is better to start off the correct transaction boundaries then searching for the reason of leaks when the application grows.
Dont excuse please, i really do appreciate this. I myself did not think of this view problem until you wrote of it, where as it is obvious, if i look closer at it.

Best regards,
Sven
Reply all
Reply to author
Forward
0 new messages