<div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">On Tue, Jul 5, 2016 at 7:14 AM, Roman Mohr <span dir="ltr"><<a href="mailto:rmohr@redhat.com" target="_blank">rmohr@redhat.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="HOEnZb"><div class="h5">On Mon, Jul 4, 2016 at 11:58 PM, Roman Mohr <<a href="mailto:rmohr@redhat.com">rmohr@redhat.com</a>> wrote:<br>
> Hi Everyone,<br>
><br>
> I wanted to discuss a practice which seems to be pretty common in the<br>
> engine which I find very limiting, dangerous and for some things it<br>
> can even be a blocker.<br>
><br>
> There are several places in the engine where we are using maps as<br>
> cache in singletons to avoid reloading data from the database. Two<br>
> prominent ones are the QuotaManager[1] and the MacPoolPerCluster[2].<br>
><br>
> While it looks tempting to just use a map as cache, add some locks<br>
> around it and create an injectable singleton, this has some drawbacks:<br>
><br>
> 1) We have an autoritative source for our data and it offers<br>
> transactions to take care of inconsistencies or parallel updates.<br>
> Doing all that in a service again duplicates this.<br>
> 2) Caching on the service layer is definitely not a good idea. It can<br>
> introduce unwanted side effects when someone invokes the DAOs<br>
> directly.<br>
> 3) The point is more about the question if a cache is really needed:<br>
> Do I just want that cache because I find it convenient to do a<br>
> #getMacPoolForCluster(Guid clusterId) in a loop instead of just<br>
> loading it once before the loop, or do my usage requirements really<br>
> force me to use a cache?<br>
><br>
> If you really need a cache, consider the following:<br>
><br>
> 1) Do the caching on the DAO layer. This guarantees the best<br>
> consistency across the data.<br>
> 2) Yes this means either locking in the DAOs or a transactional cache.<br>
> But before you complain, think about what in [1] and [2] is done. We<br>
> do exactly that there, so the complexity is already introduced anyway.<br>
> 3) Since we are working with transactions, a custom cache should NEVER<br>
> cache writes (really just talking about our use case here). This makes<br>
> checks for existing IDs before adding an entity or similar checks<br>
> unnecessary, don't duplicate constraint checks like in [2].<br>
> 4) There should always be a way to disable the cache (even if it is<br>
> just for testing).<br>
> 5) If I can't convince you to move the cache to the DAO layer, still<br>
> add a way to disable the cache.<br>
><br>
<br>
</div></div>I forgot to mention one thing: There are of course cases where<br>
something is loaded on startup. Mostly things which can have multiple<br>
sources.<br>
For instance for the application configuration itself it is pretty<br>
common, or like in the scheduler the scheduling policies where some<br>
are Java only,<br>
some are coming from other sources. It is still good<br>
<br>
But for normal business entities accessing parts of it through<br>
services and parts of it through services is not the best thing to do<br>
(if constructiong the whole business entity out of multiple daos is<br>
complex, Repositories can help, but the cache should still be in the<br>
dao layer).<br></blockquote><div><br>I do not agree that the caching should be on the DAO layer - that might lead to getting an entity that is built of parts that are not coherent each with another if the different DAO caches are not in sync. <br>I'd put the cache on the Repositories (non-existent currently) or a higher layer, just above the transaction boundaries, so the cache would contain service call results rather than raw data. Then the cache would prevent from the application accessing the DB connection pool for a connection. Yes, different service caches might have same entities duplicated in the memory, but I do not care of that until that's proven as a problem and if it would I'd go to improving cache - making that more capable.<br><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
I hopeĀ you get what I mean.<br>
<div class="HOEnZb"><div class="h5"><br>
> For as long as there is no general caching solution with something<br>
> like ehcache or infinispan, in my eyes such small things matter a lot<br>
> to keep a project maintainable.<br>
><br>
> That are some of the best practices I have seen around caching<br>
> database data. It would be great if we could agree on something like<br>
> that. Maybe there is already an agreement on something and I am just<br>
> not aware of it.<br>
><br>
> Looking forward to hear your feedback.<br>
><br>
> Roman<br>
><br>
> [1] <a href="https://github.com/oVirt/ovirt-engine/blob/master/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/quota/QuotaManager.java" rel="noreferrer" target="_blank">https://github.com/oVirt/ovirt-engine/blob/master/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/quota/QuotaManager.java</a><br>
> [2] <a href="https://github.com/oVirt/ovirt-engine/blob/master/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/network/macpool/MacPoolPerCluster.java" rel="noreferrer" target="_blank">https://github.com/oVirt/ovirt-engine/blob/master/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/network/macpool/MacPoolPerCluster.java</a><br>
_______________________________________________<br>
Devel mailing list<br>
<a href="mailto:Devel@ovirt.org">Devel@ovirt.org</a><br>
<a href="http://lists.ovirt.org/mailman/listinfo/devel" rel="noreferrer" target="_blank">http://lists.ovirt.org/mailman/listinfo/devel</a><br>
</div></div></blockquote></div><br></div></div>