New method: getOrSet() Allow caching a snippet of code with a single provider method via a closure or udf
Description
Attachments
Gliffy Diagrams
Activity
Luis Majano November 15, 2013 at 10:53 PM
I think getOrSet is catchy(), I don’t want to modify the get() as it will modify the interface and this is extra functionality a provider can implement or not.
Luis Majano
CEO
Ortus Solutions, Corp
www.ortussolutions.com (http://www.ortussolutions.com/)
P/F: 1-888-557-8057
Direct: (909) 248-3408
ColdBox Platform: http://www.coldbox.org (http://www.coldbox.org/)
ContentBox Platform: http://www.gocontentbox.org (http://www.gocontentbox.org/)
Linked In: http://www.linkedin.com/pub/3/731/483
Social: twitter.com/ortussolutions (http://twitter.com/ortussolutions) | twitter.com/coldbox (http://twitter.com/coldbox) | twitter.com/lmajano (http://twitter.com/lmajano) | twitter.com/gocontentbox (http://twitter.com/gocontentbox)

Brad Wood November 15, 2013 at 10:32 PM
Would it be possible to actually just override the regular get() method so you could pass in the closure necessary to create and set the data if it didn't exist?
The only issue I can think of with getOrSet() is that it implies only one of those operations will happen, and technically I supposed that might be true, but from the outside perspective of the method, it can set AND return the data. What about setAndGet()? Hmm, I don't really like that one either. We could call it something like guaranteedGet() other than the fact that's way to long and hard to spell
Luis Majano November 15, 2013 at 10:02 PM
Brad, how about a method name called getOrSet()

Brad Wood July 19, 2013 at 7:31 PMEdited
Yes, I'm aware that the code sample has a potential race condition. I thought about it when I write it, but it was orthogonal to the point since I was just trying get the idea across so I left it. I'll update it so it's not confusing.
Regarding the memory issues-- I don't think we're on the same page. Firstly, I'm not suggesting we persist the closure anywhere-- it is only passed along to be executed if the item is not found in the cache. After the method is finished executing, the closure would be destroyed and not persisted anywhere. The vision was not that this method would be a "one time" thing you would call and then you would only need to do a get-- instead every call to the cache would pass along the closure, but the closure would only be used if the item didn't exist in the cache on that call.
That means There is no inherent memory leak potential. Whether or not the code is executed in its original environment or inside a closure should have no impact on memory.
Luis Majano July 19, 2013 at 7:11 PM
Few comments.
Passing a closure is a nice idea but the issue is memory leaks. Closures will bring with them their entire environment scope. So if I cache the closure alongside the key in the provider so I can do callbacks, then I am caching everything the closure's environment is coming from. So in theory it is a good idea, but not a memory sensitive one. So I feel maybe registering a simple callback could be an alternative.
Second.
The code below is not good:
Because of the lookup. The cache cannot guarantee the results after the lookup. For best practices, you have to retrieve and validate.
The following boilerplate is common in code:
Implement a new provider method to allow this to be accomplished in a "one-liner". This example suggests a new method name of "cacheResult", though I don't really like that method name.
Or even more simply:
The method cacheResult (or whatever we call it) would perform the get and set as necessary inside it return the value after ensuring its in the cache.
The new method would also need to accept timeout, lastAccessTimeout, and extra as well for setting.
We should probably also offer some sort of standard locking mechanism to handle the following sort of scenarios where the logic producing the cached object needs to be single threaded.
I'm not sure if we should have an argument where the developer can pass in the name of the lock if they want creating to be locked, or if we should just have a boolean singleThreadCreation flag and use the cacheID & providerName & key as the lock name.