[ 
https://issues.apache.org/jira/browse/IGNITE-4293?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15751001#comment-15751001
 ] 

Alexandr Kuramshin edited comment on IGNITE-4293 at 12/15/16 10:35 AM:
-----------------------------------------------------------------------

Let's look at the basis with two types: CacheObject and CacheObjectContext.

Because the implementations could be very different, let's think abstract.

Calling CacheObject.value(CacheObjectContext ctx, boolean cpy) we'll get a user 
object independently of underlying storage and implementation.

Supposed that the CacheObject MAY have a cached instance of the user object 
on-heap, and the <cpy> flag is like a hint controlling behaivor of such 
implementations. If it's true, then the copy of the user object MAY be 
returned, if underlying CacheObject have the such internal on-heap instance, 
but if it's false is also possible to retreive a new instance every time 
because of absence of internal field.

Next there is CacheObjectContext controlling the behavior of the caching 
on-heap instance and user objects will be returned. Precisely two methods: 
copyOnGet() and storeValue().

Supposed that copyOnGet() value controls behaviour of CacheObjects with respect 
to <cpy> flag. If copyOnGet() is false, then the cached user object should be 
returned, if the internal on-heap instance is present. And if storeValue() is 
true, then the CacheObject should store the user object upon deserialization, 
if the internal field is present.

It's seems that copyOnGet() and storeValue() are threated independently, but 
it's something wrong. If we'll call every time CacheObject.value(ctx, true) and 
both ctx.copyOnGet() and ctx.storeValue() are true, then the stored value will 
never be used. But relating to common usage of CacheObject.value method it's 
seems that usual value of <cpy> is false, so the problem is virtual.

I'm wondering that nothing of above was written in Javadoc.

Going further, I'm answering myself when the copyOnGet() and storeValue() 
should be true or false?

Definitly they should depend upon user preference 
CacheConfiguration.isCopyOnRead(): copyOnGet() == isCopyOnRead(); storeValue() 
!= isCopyOnRead().

Also we should take in account how indexing are working. Whenever indexing is 
enabled on the cache, some number of GridH2ValueCacheObject are present (up to 
number of cache entries). There is the method 
GridH2ValueCacheObject.compareSecure(Value v, CompareMode mode) which compares 
the two CacheObject or its serialized user objects, depending of the 
CacheObject.isPlatformType() value. So, because compareSecure() method is time 
critical, we should set storeValue() to true, when indexing is enabled AND 
CacheObject.isPlatformType() is true for all entries in the cache, to avoid 
high CPU overhead upon deserializing user object on each compareSecure() 
invocation.

Actual CacheObject type stored in the cache depends on the 
IgniteConfiguration.getMarshaller() value configured. The 
GridQueryProcessor.isEnabled(CacheConfiguration ccfg) doesn't take into account 
what marshaller type is used, but only whether indexing is enabled. It should 
be fixed.

There is another condition IgniteConfiguration.isPeerClassLoadingEnabled() is 
used to determine CacheObjectContext.storeValue(). It is still being discovered.


was (Author: ein):
Let's look at the basis with two types: CacheObject and CacheObjectContext.

Because the implementations could be very different, let's think abstract.

Calling CacheObject.value(CacheObjectContext ctx, boolean cpy) we'll get a user 
object independently of underlying storage and implementation.

Supposed that the CacheObject MAY have a cached instance of the user object 
on-heap, and the {cpy} flag is like a hint controlling behaivor of such 
implementations. If it's true, then the copy of the user object MAY be 
returned, if underlying CacheObject have the such internal on-heap instance, 
but if it's false is also possible to retreive a new instance every time 
because of absence of internal field.

Next there is CacheObjectContext controlling the behavior of the caching 
on-heap instance and user objects will be returned. Precisely two methods: 
copyOnGet() and storeValue().

Supposed that copyOnGet() value controls behaviour of CacheObjects with respect 
to {cpy} flag. If copyOnGet() is false, then the cached user object should be 
returned, if the internal on-heap instance is present. And if storeValue() is 
true, then the CacheObject should store the user object upon deserialization, 
if the internal field is present.

It's seems that copyOnGet() and storeValue() are threated independently, but 
it's something wrong. If we'll call every time CacheObject.value(ctx, true) and 
both ctx.copyOnGet() and ctx.storeValue() are true, then the stored value will 
never be used. But relating to common usage of CacheObject.value method it's 
seems that usual value of {cpy} is false, so the problem is virtual.

I'm wondering that nothing of above was written in Javadoc.

Going further, I'm answering myself when the copyOnGet() and storeValue() 
should be true or false?

Definitly they should depend upon user preference 
CacheConfiguration.isCopyOnRead(): copyOnGet() == isCopyOnRead(); storeValue() 
!= isCopyOnRead().

Also we should take in account how indexing are working. Whenever indexing is 
enabled on the cache, some number of GridH2ValueCacheObject are present (up to 
number of cache entries). There is the method 
GridH2ValueCacheObject.compareSecure(Value v, CompareMode mode) which compares 
the two CacheObject or its serialized user objects, depending of the 
CacheObject.isPlatformType() value. So, because compareSecure() method is time 
critical, we should set storeValue() to true, when indexing is enabled AND 
CacheObject.isPlatformType() is true for all entries in the cache, to avoid 
high CPU overhead upon deserializing user object on each compareSecure() 
invocation.

Actual CacheObject type stored in the cache depends on the 
IgniteConfiguration.getMarshaller() value configured. The 
GridQueryProcessor.isEnabled(CacheConfiguration ccfg) doesn't take into account 
what marshaller type is used, but only whether indexing is enabled. It should 
be fixed.

There is another condition IgniteConfiguration.isPeerClassLoadingEnabled() is 
used to determine CacheObjectContext.storeValue(). It is still being discovered.

> Deserialized value is cached if queries are enabled
> ---------------------------------------------------
>
>                 Key: IGNITE-4293
>                 URL: https://issues.apache.org/jira/browse/IGNITE-4293
>             Project: Ignite
>          Issue Type: Bug
>          Components: cache
>    Affects Versions: 1.7
>            Reporter: Valentin Kulichenko
>            Assignee: Alexandr Kuramshin
>            Priority: Critical
>
> Here is the problematic piece of code in {{IgniteCacheObjectProcessorImpl}}:
> {code}
> boolean storeVal = ctx.config().isPeerClassLoadingEnabled() ||
>     GridQueryProcessor.isEnabled(ccfg) ||
>     !ccfg.isCopyOnRead();
> {code}
> This flag is set to true if queries are enabled even when binary marshaller 
> is used (this condition makes sense to other marshallers though). It is then 
> use in {{BinaryObjectImpl.deserializeValue}}:
> {code}
> if (coCtx != null && coCtx.storeValue())
>     obj = obj0;
> {code}
> As a result, memory consumption doubles.



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)

Reply via email to