sasa1977 / con_cache

ets based key/value cache with row level isolated writes and ttl support
MIT License
910 stars 71 forks source link

get_or_store for bag types #27

Closed fcevado closed 8 years ago

fcevado commented 8 years ago

As we discussed in the pull request #26 , I'm opening this issue to discuss about the usage of get_or_store for bag types. I'll prepare a summary of what was discussed in the pr about this subject.

fcevado commented 8 years ago

In the discussion was suggested the following behavior for bag types:

ConCache.get_or_store(cache, :a, fn() -> [1, 2, 3] end) == [1, 2, 3]

We pointed out:

I guess this was the relevant points made about this matter on the pull request.

fcevado commented 8 years ago

I was thinking bout this... Since there isn't a related function in ETS for get_or_store , I think the sanest way to deal with it is based on the functions related to it in ConCache. get_or_store behaves as both get and put as applyed together. So, the return possibilities for get_or_store can be a value for set types and a list for bag types as happens to get, but the lambda passed to get_or_store should be handled as the value passed to put finishing with a single value inserted.

In that way, this happens for set types:

ConCache.get_or_store(cache, :a, fn() -> 1 end) == 1
ConCache.get_or_store(cache, :a, fn() -> [1, 2, 3] end) == [1, 2, 3]

And that should happen with bag types:

ConCache.get_or_store(cache, :a, fn() -> 1 end) == [1]
ConCache.get_or_store(cache, :a, fn() -> [1, 2, 3] end) == [[1, 2, 3]]
sasa1977 commented 8 years ago

The interface you propose seems consistent, so that's an improvement. However, in this case a bag basically converges into a set, since there's a single value under a key. Which makes me wonder why would I want to use this over sets?

There is also a bit of asymmetry here. I can store multiple values under a single key using multiple ConCache.put invocations. In this case, get_or_store will return all elements. However, if I'm using get_or_store to actually store something, then I can only store one value, so again a bag becomes a set.

So I guess my overall question is in which scenarios do you see get_or_store with bags useful?

fcevado commented 8 years ago

However, in this case a bag basically converges into a set, since there's a single value under a key. Which makes me wonder why would I want to use this over sets?

I disagree, this is a restriction of how the insertion works(be it with get_or_store or put), you can only store one value at a time. Even with put i can't insert multiple values with a single call to ConCache.

So I guess my overall question is in which scenarios do you see get_or_store with bags useful?

I guess this is the point that we are disagreeing. As I see, the use for get_or_store is to validate if there is a value "binded" to that key before insertion, not to insert multiple values. Sure, if i can insert multiple values why should i validate before inserting? I undertsand that thought, but I'm thinking more about a consistent working/useful functionality. I guess the question to be made is: If there is no real reason to restrict the usage of get_or_store for bag types why should we restrict it?

sasa1977 commented 8 years ago

As I see, the use for get_or_store is to validate if there is a value "binded" to that key before insertion, not to insert multiple values.

I agree with this. That's why I asked in which scenarios do you see bags useful.

I actually wrote original ConCache with this function in mind. In particular, I had a bunch of simultaneous processes which needed to perform some expensive computation. Caching allowed to have only one of them compute it, while others would wait, and then fetch the cached value. So the code of each process would be something like:

ConCache.get_or_store(cache, some_key, fn -> expensive_computation() end)

Now, in this particular case I used only get_or_store to store data to the cache. In fact, I'm not sure I can see in which cases would get_or_store be used alongside put. I'd expect to either use one or the other to store data to the cache.

With this in mind, putting it in the bag context, if only get_or_store is used to store data, and it can store just one value, then a bag is used as a set (one value per key), so why not just use a set?

So given all this, and a lack of specific use-case which we can discuss, I'm not currently convinced that get_or_store should be supported for bags. It feels confusing, adds complexity, and I don't see a concrete use-case. When a concrete scenario appears, I'll be happy to discuss further, and change my mind if good arguments are presented.

fcevado commented 8 years ago

Now, in this particular case I used only get_or_store to store data to the cache. In fact, I'm not sure I can see in which cases would get_or_store be used alongside put. I'd expect to either use one or the other to store data to the cache.

Now I understand your point. Thinking that way I agree with you that would be necessary a more specific use case to allow get_or_store being used with bag types. All the scenarios that I thought could be solved in a easier way usind isolated.