<div dir="ltr"><br><div class="gmail_extra"><br><br><div class="gmail_quote">On Tue, Jul 15, 2014 at 5:49 PM, Sanne Grinovero <span dir="ltr">&lt;<a href="mailto:sanne@infinispan.org" target="_blank">sanne@infinispan.org</a>&gt;</span> wrote:<br>

<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div class=""><div class="h5">On 15 July 2014 14:15, Dan Berindei &lt;<a href="mailto:dan.berindei@gmail.com">dan.berindei@gmail.com</a>&gt; wrote:<br>


&gt;<br>
&gt;<br>
&gt;<br>
&gt; On Tue, Jul 15, 2014 at 12:51 AM, Sanne Grinovero &lt;<a href="mailto:sanne@infinispan.org">sanne@infinispan.org</a>&gt;<br>
&gt; wrote:<br>
&gt;&gt;<br>
&gt;&gt; Hi all,<br>
&gt;&gt; I was toying with a custom CacheStore experiment, and am having some<br>
&gt;&gt; friction with some of the new SPIs.<br>
&gt;&gt;<br>
&gt;&gt; So interface org.infinispan.marshall.core.MarshalledEntryFactory&lt;K, V&gt;<br>
&gt;&gt; is an helper to use in the CacheStorei implementation, which exposes<br>
&gt;&gt; three methods:<br>
&gt;&gt;<br>
&gt;&gt;    MarshalledEntry&lt;K,V&gt; newMarshalledEntry(ByteBuffer key, ByteBuffer<br>
&gt;&gt; valueBytes, ByteBuffer metadataBytes);<br>
&gt;&gt;    MarshalledEntry&lt;K,V&gt; newMarshalledEntry(Object key, ByteBuffer<br>
&gt;&gt; valueBytes, ByteBuffer metadataBytes);<br>
&gt;&gt;    MarshalledEntry&lt;K,V&gt; newMarshalledEntry(Object key, Object value,<br>
&gt;&gt; InternalMetadata im);<br>
&gt;&gt;<br>
&gt;&gt; In my CacheStore - and I suspect most efficiency minded<br>
&gt;&gt; implementations - I don&#39;t care about the value Object but I express a<br>
&gt;&gt; specific physical layout for the metadata, so to run for example an<br>
&gt;&gt; efficient &quot;purge expired&quot; task.<br>
&gt;&gt; So, the key is given, the value Object needs to be serialized, but the<br>
&gt;&gt; InternalMetadata I can map to specific fields.<br>
&gt;&gt;<br>
&gt;&gt; Problem is at read time: I don&#39;t have a marshalled version of the<br>
&gt;&gt; Metadata but I need to unmarshall the value.. there is no helper to<br>
&gt;&gt; cover for this case.<br>
&gt;&gt;<br>
&gt;&gt; Wouldn&#39;t this interface be more practical if it had:<br>
&gt;&gt;<br>
&gt;&gt; Object unMarshallKey(ByteBuffer);<br>
&gt;&gt; Object unMarshallValue(ByteBuffer);<br>
&gt;&gt; InternalMetadata unMarshallMetadata(ByteBuffer);<br>
&gt;&gt; MarshalledEntry newMarshalledEntry(Object key, Object value,<br>
&gt;&gt; InternalMetadata im);<br>
&gt;<br>
&gt;<br>
&gt; I guess the idea was that MarshalledEntry unmarshalls the key, value, and<br>
&gt; metadata lazily. Even a purge listener may only be interested in the key,<br>
&gt; and in that case case we can avoid unmarshalling the value.<br>
&gt;<br>
&gt; I think you can do what you want by stuffing the bytes for everything in the<br>
&gt; MarshalledEntry, and unmarshalling the data via<br>
&gt; MarshalledEntry.getMetadata().<br>
<br>
<br>
</div></div>That&#39;s what I did but it&#39;s far from optimal, so I&#39;m proposing the improvement.<br></blockquote><div><br></div><div>Could you expand a bit on why this is suboptimal? The way I see it, you have to support any custom Metadata implementation anyway, so you have to either read and deserialize the entire metadata, or store a duplicate of the expiration timestamp somewhere else.</div>

<div><br></div><div>In LevelDB we store the timestamps in a separate DB, doing 2 LevelDB writes for every store write (with expiration), and I would be very interested in an alternative solution that only wrote to 1 DB.</div>

<div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div class="">
<br>
&gt;&gt; Also, I&#39;d get rid of generics. They are not helping at all, I can<br>
&gt;&gt; hardly couple my custom CacheStore implementation to the end user&#39;s<br>
&gt;&gt; domain model, right?<br>
&gt;<br>
&gt;<br>
&gt; I can see the user writing a custom JDBC store that stores the object&#39;s<br>
&gt; properties into separate columns and thus supporting a single type. But it&#39;s<br>
&gt; a pretty specialized case, and the user can very well do the casts himself.<br>
<br>
</div>Exactly<br>
<div class=""><br>
&gt;<br>
&gt; Maybe Paul and Will have more stuff to add here, they been discussing about<br>
&gt; generics in the cache store SPIs around<br>
&gt; <a href="https://github.com/infinispan/infinispan/pull/2705" target="_blank">https://github.com/infinispan/infinispan/pull/2705</a><br>
&gt;<br>
&gt;&gt;<br>
&gt;&gt; I was also quite surprised that other existing CacheStore<br>
&gt;&gt; implementations don&#39;t have this limitation; peeking in the<br>
&gt;&gt; JDBCCacheStore to see how this is supposed to work, it seems that<br>
&gt;&gt; essentially it duplicates the data by serializazing the<br>
&gt;&gt; InternalMetadata in the BLOB but also stored an Expiry column to query<br>
&gt;&gt; via SQL. I was interested to see how the Purge method could be<br>
&gt;&gt; implemented efficiently, and found a &quot;TODO notify listeners&quot; ;-)<br>
&gt;<br>
&gt;<br>
&gt; I believe the reason why we don&#39;t support purge listeners in the JDBC store<br>
&gt; is that we don&#39;t want to fetch the entries from the database at all. We<br>
&gt; can&#39;t ask CacheNotifier whether there are any listeners registered ATM, we<br>
&gt; need that to avoid the overhead when there are no listeners.<br>
<br>
</div>I understand the reason, still it&#39;s wrong isn&#39;t it ;-)<br>
Having to load each entry for the &quot;maybe there&#39;s a listener&quot; case is<br>
definitely silly, we should inform the CacheStore instance if<br>
notifications are needed or not, and if they need just the key or the<br>
whole entry, no need for metadata.<br>
And for CacheStore instances which don&#39;t respect this we should at<br>
least document the limitation, or open a JIRA to get it done. Would<br>
you agree if I opened issues for each weirdness I&#39;m finding in the<br>
existing CacheStore implementations? I&#39;ve hit some more in the<br>
meantime.<br>
<span class=""><font color="#888888"><br></font></span></blockquote><div><br></div><div>Sure. I&#39;m not too enthusiastic about changing the persistence SPI, but we should at least have a discussion on the pros and cons of the choices we are making there.</div>

<div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><span class=""><font color="#888888"></font></span><div class="">

<div class="h5"><br>
&gt;<br>
&gt;&gt;<br>
&gt;&gt; All other JDBC based stores serialize buckets in groups, REST store<br>
&gt;&gt; doesn&#39;t do purging, LevelDB also does duplication for the metadata,<br>
&gt;&gt; Cassandra is outdated and doesn&#39;t do events on expiry.<br></div></div></blockquote><div> <br></div></div></div></div>