So... I quickly discussed the possibility of re-rolling the Cache API on top the k/v interface with @pounard on IRC. @catch You also mentioned that idea briefly over at #1175054: Add a storage (API) for persistent non-configuration state. What's your opinion now? Currently, the only incompatibility is ->getAll() which might be troublesome for some backends?! We wouldn't really gain much from this other than consistent APIs. And I think the foundation for both APIs actually IS identical.

Also, the KeyValueStore has an $options argument in the constructor. We currently don't have that in the CacheBackenInterface. However, I think that could actually make sense.

Comments

It makes some sort of sense looking at the implementation details, but it doesn't really in term of interfaces, because the business is different.

Today, the interface and business being different, we could possibly plan to use the k/v as hidden backend inside a defautl implementation, for example. This way would make sense. But I have some red flags raising in my head.

The situation today is that the cache backends are mature (long term mature, 2 major versions they exists) and contrib backends are efficient. I'd like to keep that until the k/v matures itself a bit more before thinking of using the k/v as backend for our default implementations.

Plus, there is another red flag here, native backends targeted are not the same, both needs being conceptually different. For example, memcache is a volatile storage, k/v is designed to store persistent and coherent data (coherent as data consistency is maintained): memcache itself is not a target for the k/v store. This means that in the mid term, there will be two great families of cache backends: the one that k/v supports, and the others, but I might think both will be as big in term of backend numbers.

Another big concern is that cache has some added features (right now I'm thinking of flush and wildcard operation, even if the later may disappear, the former won't): those features are not supported by k/v as it is today, which means that we just cannot use a k/v interface, but we'd end up by extending the existing ones, which defies a bit the purpose of having a default implementation. Therefore we would end up with a database cache implementation extending the k/v database store, have an array based cache implement extending the array based k/v and so on... plus all implementing cache, instead of having a standalone, unique and sufficient "k/v based cache" implementation accepting any k/v backend per composition. This raise a great warning which is that code sharing won't be perfect, extension will ofuscate the code and make it harder to maintain.

Considering the point above, this also means that if k/v derivates, evolves (or cache) fixing the extending implementation will be even harder, because we'll probably face spaguetti code in that specific implementation.

Another big concern is about edge features that one of cache and k/v has but the other has not: those needless features for the cache might imply heavy design concerns on the k/v store: this would mean that, for example, a Redis cache backend using the k/v implementation could be blocked because of the way k/v uses Redis, which could prevent missing methods to be implemented. Keeping it separated in this case is the wizer thing to do.

Another concern is pure optimization, both k/v and cache may look the same, but they don't have the same use case. For example, cache must be extremelly fast at read operations, while k/v can be optimized of both read and writes. Consensus is uneasy and if we think in term of raw performances, merging both is definitely not a good idea.

Although, I'm not definitely closed to this question, but I think we need the k/v to mature before thinking of it. Right now, k/v is used for non cache use cases, and it we need to extract more core use cases, make it evolve to be efficient for those use case, and after that see if it fits for cache. Cache backends are simple (really, very simple) to implement, and even if some pieces of code might look the same as k/v, it's small enough to be maintained alone. At this level (database cache backend is less that 300 lines of code, comments included) I think that extension, merge, abstraction would cause more problems than it would solve: this would be a leaky abstraction and make it harder to maintain.

So @pounard, I guess you are voting to 'punt" until a later date.

I think what @fubhy has raised is a valid idea. I also think we should explore this idea further. Maybe it it is too early, but there is a good possibility what is proposed makes sense.

@Lars Toomre Just in case, this is not a post bombing, I actually described a set of concerns that may be tackled. Please read them.

More inconsistencies (as of writing this):

  • KeyValueStoreInterface::get() returns NULL if it fails to find an entry with a particular key. CacheBackendInterface::get() returns FALSE. Considering that we are returning an object if we find something it doesn't really matter what we return... It's just a minor nit-pick.
  • KeyValueStoreInterface::getMultiple() currently doesn't accept the $keys by reference and suggests a different behavior in that regard.