/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.ignite.internal.processors.cache.binary;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import javax.cache.CacheException;
import org.apache.ignite.IgniteBinary;
import org.apache.ignite.IgniteCheckedException;
import org.apache.ignite.IgniteException;
import org.apache.ignite.binary.BinaryField;
import org.apache.ignite.binary.BinaryObject;
import org.apache.ignite.binary.BinaryObjectBuilder;
import org.apache.ignite.binary.BinaryObjectException;
import org.apache.ignite.binary.BinaryType;
import org.apache.ignite.binary.BinaryTypeConfiguration;
import org.apache.ignite.cluster.ClusterNode;
import org.apache.ignite.configuration.BinaryConfiguration;
import org.apache.ignite.configuration.CacheConfiguration;
import org.apache.ignite.events.Event;
import org.apache.ignite.internal.GridKernalContext;
import org.apache.ignite.internal.IgniteNodeAttributes;
import org.apache.ignite.internal.binary.BinaryContext;
import org.apache.ignite.internal.binary.BinaryEnumObjectImpl;
import org.apache.ignite.internal.binary.BinaryFieldMetadata;
import org.apache.ignite.internal.binary.BinaryMarshaller;
import org.apache.ignite.internal.binary.BinaryMetadata;
import org.apache.ignite.internal.binary.BinaryMetadataHandler;
import org.apache.ignite.internal.binary.BinaryObjectEx;
import org.apache.ignite.internal.binary.BinaryObjectImpl;
import org.apache.ignite.internal.binary.BinaryObjectOffheapImpl;
import org.apache.ignite.internal.binary.BinaryTypeImpl;
import org.apache.ignite.internal.binary.BinaryUtils;
import org.apache.ignite.internal.binary.GridBinaryMarshaller;
import org.apache.ignite.internal.binary.builder.BinaryObjectBuilderImpl;
import org.apache.ignite.internal.binary.streams.BinaryInputStream;
import org.apache.ignite.internal.binary.streams.BinaryOffheapInputStream;
import org.apache.ignite.internal.managers.eventstorage.GridLocalEventListener;
import org.apache.ignite.internal.processors.cache.CacheObject;
import org.apache.ignite.internal.processors.cache.CacheObjectContext;
import org.apache.ignite.internal.processors.cache.GridCacheContext;
import org.apache.ignite.internal.processors.cache.GridCacheUtils;
import org.apache.ignite.internal.processors.cache.KeyCacheObject;
import org.apache.ignite.internal.processors.cacheobject.IgniteCacheObjectProcessorImpl;
import org.apache.ignite.internal.util.GridUnsafe;
import org.apache.ignite.internal.util.IgniteUtils;
import org.apache.ignite.internal.util.future.GridFutureAdapter;
import org.apache.ignite.internal.util.lang.GridMapEntry;
import org.apache.ignite.internal.util.tostring.GridToStringExclude;
import org.apache.ignite.internal.util.typedef.F;
import org.apache.ignite.internal.util.typedef.T1;
import org.apache.ignite.internal.util.typedef.T2;
import org.apache.ignite.internal.util.typedef.internal.U;
import org.apache.ignite.lang.IgniteBiTuple;
import org.apache.ignite.lang.IgniteClosure;
import org.apache.ignite.lang.IgniteFuture;
import org.apache.ignite.marshaller.Marshaller;
import org.apache.ignite.spi.IgniteNodeValidationResult;
import org.apache.ignite.spi.discovery.DiscoveryDataBag;
import org.apache.ignite.spi.discovery.DiscoveryDataBag.GridDiscoveryData;
import org.jetbrains.annotations.Nullable;
import org.jsr166.ConcurrentHashMap8;
import static org.apache.ignite.IgniteSystemProperties.IGNITE_SKIP_CONFIGURATION_CONSISTENCY_CHECK;
import static org.apache.ignite.IgniteSystemProperties.getBoolean;
import static org.apache.ignite.events.EventType.EVT_CLIENT_NODE_DISCONNECTED;
import static org.apache.ignite.internal.GridComponent.DiscoveryDataExchangeType.BINARY_PROC;
/**
* Binary processor implementation.
*/
public class CacheObjectBinaryProcessorImpl extends IgniteCacheObjectProcessorImpl implements
CacheObjectBinaryProcessor {
/** */
private volatile boolean discoveryStarted;
/** */
private BinaryContext binaryCtx;
/** */
private Marshaller marsh;
/** */
private GridBinaryMarshaller binaryMarsh;
/** */
@GridToStringExclude
private IgniteBinary binaries;
/** Listener removes all registered binary schemas after the local client reconnected. */
private final GridLocalEventListener clientDisconLsnr = new GridLocalEventListener() {
@Override public void onEvent(Event evt) {
binaryContext().unregisterBinarySchemas();
metadataLocCache.clear();
}
};
/** Locally cached metadata. This local cache is managed by exchanging discovery custom events. */
private final ConcurrentMap<Integer, BinaryMetadataHolder> metadataLocCache = new ConcurrentHashMap8<>();
/** */
private BinaryMetadataTransport transport;
/** Cached affinity key field names. */
private final ConcurrentHashMap<Integer, T1<BinaryField>> affKeyFields = new ConcurrentHashMap<>();
/**
* @param ctx Kernal context.
*/
public CacheObjectBinaryProcessorImpl(GridKernalContext ctx) {
super(ctx);
marsh = ctx.grid().configuration().getMarshaller();
}
/** {@inheritDoc} */
@Override public void start(boolean activeOnStart) throws IgniteCheckedException {
if (marsh instanceof BinaryMarshaller) {
if (ctx.clientNode())
ctx.event().addLocalEventListener(clientDisconLsnr, EVT_CLIENT_NODE_DISCONNECTED);
transport = new BinaryMetadataTransport(metadataLocCache, ctx, log);
BinaryMetadataHandler metaHnd = new BinaryMetadataHandler() {
@Override public void addMeta(int typeId, BinaryType newMeta) throws BinaryObjectException {
assert newMeta != null;
assert newMeta instanceof BinaryTypeImpl;
if (!discoveryStarted) {
BinaryMetadataHolder holder = metadataLocCache.get(typeId);
BinaryMetadata oldMeta = holder != null ? holder.metadata() : null;
BinaryMetadata mergedMeta = BinaryUtils.mergeMetadata(oldMeta, ((BinaryTypeImpl)newMeta).metadata());
if (oldMeta != mergedMeta)
metadataLocCache.putIfAbsent(typeId, new BinaryMetadataHolder(mergedMeta, 0, 0));
return;
}
BinaryMetadata newMeta0 = ((BinaryTypeImpl)newMeta).metadata();
CacheObjectBinaryProcessorImpl.this.addMeta(typeId, newMeta0.wrap(binaryCtx));
}
@Override public BinaryType metadata(int typeId) throws BinaryObjectException {
return CacheObjectBinaryProcessorImpl.this.metadata(typeId);
}
@Override public BinaryType metadata(int typeId, int schemaId) throws BinaryObjectException {
return CacheObjectBinaryProcessorImpl.this.metadata(typeId, schemaId);
}
};
BinaryMarshaller bMarsh0 = (BinaryMarshaller)marsh;
binaryCtx = new BinaryContext(metaHnd, ctx.config(), ctx.log(BinaryContext.class));
IgniteUtils.invoke(BinaryMarshaller.class, bMarsh0, "setBinaryContext", binaryCtx, ctx.config());
binaryMarsh = new GridBinaryMarshaller(binaryCtx);
binaries = new IgniteBinaryImpl(ctx, this);
if (!getBoolean(IGNITE_SKIP_CONFIGURATION_CONSISTENCY_CHECK)) {
BinaryConfiguration bCfg = ctx.config().getBinaryConfiguration();
if (bCfg != null) {
Map<String, Object> map = new HashMap<>();
map.put("globIdMapper", bCfg.getIdMapper() != null ? bCfg.getIdMapper().getClass().getName() : null);
map.put("globSerializer", bCfg.getSerializer() != null ? bCfg.getSerializer().getClass() : null);
map.put("compactFooter", bCfg.isCompactFooter());
if (bCfg.getTypeConfigurations() != null) {
Map<Object, Object> typeCfgsMap = new HashMap<>();
for (BinaryTypeConfiguration c : bCfg.getTypeConfigurations()) {
typeCfgsMap.put(
c.getTypeName() != null,
Arrays.asList(
c.getIdMapper() != null ? c.getIdMapper().getClass() : null,
c.getSerializer() != null ? c.getSerializer().getClass() : null,
c.isEnum()
)
);
}
map.put("typeCfgs", typeCfgsMap);
}
ctx.addNodeAttribute(IgniteNodeAttributes.ATTR_BINARY_CONFIGURATION, map);
}
}
}
}
/**
* @param lsnr Listener.
*/
public void addBinaryMetadataUpdateListener(BinaryMetadataUpdatedListener lsnr) {
if (transport != null)
transport.addBinaryMetadataUpdateListener(lsnr);
}
/** {@inheritDoc} */
@Override public void stop(boolean cancel) {
if (ctx.clientNode())
ctx.event().removeLocalEventListener(clientDisconLsnr);
if (transport != null)
transport.stop();
}
/** {@inheritDoc} */
@Override public void onDisconnected(IgniteFuture<?> reconnectFut) throws IgniteCheckedException {
if (transport != null)
transport.onDisconnected();
}
/** {@inheritDoc} */
@Override public void onKernalStart(boolean activeOnStart) throws IgniteCheckedException {
super.onKernalStart(activeOnStart);
discoveryStarted = true;
}
/** {@inheritDoc} */
@Override public int typeId(String typeName) {
if (binaryCtx == null)
return super.typeId(typeName);
return binaryCtx.typeId(typeName);
}
/**
* @param obj Object.
* @return Bytes.
* @throws BinaryObjectException If failed.
*/
public byte[] marshal(@Nullable Object obj) throws BinaryObjectException {
byte[] arr = binaryMarsh.marshal(obj);
assert arr.length > 0;
return arr;
}
/**
* @param ptr Off-heap pointer.
* @param forceHeap If {@code true} creates heap-based object.
* @return Object.
* @throws BinaryObjectException If failed.
*/
public Object unmarshal(long ptr, boolean forceHeap) throws BinaryObjectException {
assert ptr > 0 : ptr;
int size = GridUnsafe.getInt(ptr);
ptr += 4;
byte type = GridUnsafe.getByte(ptr++);
if (type != CacheObject.TYPE_BYTE_ARR) {
assert size > 0 : size;
BinaryInputStream in = new BinaryOffheapInputStream(ptr, size, forceHeap);
return binaryMarsh.unmarshal(in);
}
else
return U.copyMemory(ptr, size);
}
/** {@inheritDoc} */
@SuppressWarnings("unchecked")
@Override public Object marshalToBinary(@Nullable Object obj) throws BinaryObjectException {
if (obj == null)
return null;
if (BinaryUtils.isBinaryType(obj.getClass()))
return obj;
if (obj instanceof Object[]) {
Object[] arr = (Object[])obj;
Object[] pArr = new Object[arr.length];
for (int i = 0; i < arr.length; i++)
pArr[i] = marshalToBinary(arr[i]);
return pArr;
}
if (obj instanceof IgniteBiTuple) {
IgniteBiTuple tup = (IgniteBiTuple)obj;
if (obj instanceof T2)
return new T2<>(marshalToBinary(tup.get1()), marshalToBinary(tup.get2()));
return new IgniteBiTuple<>(marshalToBinary(tup.get1()), marshalToBinary(tup.get2()));
}
{
Collection<Object> pCol = BinaryUtils.newKnownCollection(obj);
if (pCol != null) {
Collection<?> col = (Collection<?>)obj;
for (Object item : col)
pCol.add(marshalToBinary(item));
return pCol;
}
}
{
Map<Object, Object> pMap = BinaryUtils.newKnownMap(obj);
if (pMap != null) {
Map<?, ?> map = (Map<?, ?>)obj;
for (Map.Entry<?, ?> e : map.entrySet())
pMap.put(marshalToBinary(e.getKey()), marshalToBinary(e.getValue()));
return pMap;
}
}
if (obj instanceof Map.Entry) {
Map.Entry<?, ?> e = (Map.Entry<?, ?>)obj;
return new GridMapEntry<>(marshalToBinary(e.getKey()), marshalToBinary(e.getValue()));
}
if (binaryMarsh.mustDeserialize(obj))
return obj; // No need to go through marshal-unmarshal because result will be the same as initial object.
byte[] arr = binaryMarsh.marshal(obj);
assert arr.length > 0;
Object obj0 = binaryMarsh.unmarshal(arr, null);
// Possible if a class has writeObject method.
if (obj0 instanceof BinaryObjectImpl)
((BinaryObjectImpl)obj0).detachAllowed(true);
return obj0;
}
/**
* @return Marshaller.
*/
public GridBinaryMarshaller marshaller() {
return binaryMarsh;
}
/** {@inheritDoc} */
@Override public String affinityField(String keyType) {
if (binaryCtx == null)
return null;
return binaryCtx.affinityKeyFieldName(typeId(keyType));
}
/** {@inheritDoc} */
@Override public BinaryObjectBuilder builder(String clsName) {
return new BinaryObjectBuilderImpl(binaryCtx, clsName);
}
/** {@inheritDoc} */
@Override public BinaryObjectBuilder builder(BinaryObject binaryObj) {
return BinaryObjectBuilderImpl.wrap(binaryObj);
}
/** {@inheritDoc} */
@Override public void updateMetadata(int typeId, String typeName, @Nullable String affKeyFieldName,
Map<String, BinaryFieldMetadata> fieldTypeIds, boolean isEnum) throws BinaryObjectException {
BinaryMetadata meta = new BinaryMetadata(typeId, typeName, fieldTypeIds, affKeyFieldName, null, isEnum);
binaryCtx.updateMetadata(typeId, meta);
}
/** {@inheritDoc} */
@Override public void addMeta(final int typeId, final BinaryType newMeta) throws BinaryObjectException {
assert newMeta != null;
assert newMeta instanceof BinaryTypeImpl;
BinaryMetadata newMeta0 = ((BinaryTypeImpl)newMeta).metadata();
try {
BinaryMetadataHolder metaHolder = metadataLocCache.get(typeId);
BinaryMetadata oldMeta = metaHolder != null ? metaHolder.metadata() : null;
BinaryMetadata mergedMeta = BinaryUtils.mergeMetadata(oldMeta, newMeta0);
MetadataUpdateResult res = transport.requestMetadataUpdate(mergedMeta).get();
assert res != null;
if (res.rejected())
throw res.error();
}
catch (IgniteCheckedException e) {
throw new BinaryObjectException("Failed to update meta data for type: " + newMeta.typeName(), e);
}
}
/** {@inheritDoc} */
@Nullable @Override public BinaryType metadata(final int typeId) {
BinaryMetadataHolder holder = metadataLocCache.get(typeId);
if (holder == null) {
if (ctx.clientNode()) {
try {
transport.requestUpToDateMetadata(typeId).get();
holder = metadataLocCache.get(typeId);
}
catch (IgniteCheckedException ignored) {
// No-op.
}
}
}
if (holder != null) {
if (holder.pendingVersion() - holder.acceptedVersion() > 0) {
GridFutureAdapter<MetadataUpdateResult> fut = transport.awaitMetadataUpdate(typeId, holder.pendingVersion());
if (log.isDebugEnabled() && !fut.isDone())
log.debug("Waiting for update for" +
" [typeId=" + typeId +
", pendingVer=" + holder.pendingVersion() +
", acceptedVer=" + holder.acceptedVersion() + "]");
try {
fut.get();
}
catch (IgniteCheckedException ignored) {
// No-op.
}
}
return holder.metadata().wrap(binaryCtx);
}
else
return null;
}
/** {@inheritDoc} */
@Nullable @Override public BinaryType metadata(final int typeId, final int schemaId) {
BinaryMetadataHolder holder = metadataLocCache.get(typeId);
if (ctx.clientNode()) {
if (holder == null || (holder != null && !holder.metadata().hasSchema(schemaId))) {
try {
transport.requestUpToDateMetadata(typeId).get();
holder = metadataLocCache.get(typeId);
}
catch (IgniteCheckedException ignored) {
// No-op.
}
}
}
else {
if (holder.pendingVersion() - holder.acceptedVersion() > 0) {
GridFutureAdapter<MetadataUpdateResult> fut = transport.awaitMetadataUpdate(
typeId,
holder.pendingVersion());
if (log.isDebugEnabled() && !fut.isDone())
log.debug("Waiting for update for" +
" [typeId=" + typeId
+ ", schemaId=" + schemaId
+ ", pendingVer=" + holder.pendingVersion()
+ ", acceptedVer=" + holder.acceptedVersion() + "]");
try {
fut.get();
}
catch (IgniteCheckedException ignored) {
// No-op.
}
holder = metadataLocCache.get(typeId);
}
}
return holder != null ? holder.metadata().wrap(binaryCtx) : null;
}
/** {@inheritDoc} */
@Override public Map<Integer, BinaryType> metadata(Collection<Integer> typeIds)
throws BinaryObjectException {
try {
Collection<BinaryMetadataKey> keys = new ArrayList<>(typeIds.size());
for (Integer typeId : typeIds)
keys.add(new BinaryMetadataKey(typeId));
Map<Integer, BinaryType> res = U.newHashMap(metadataLocCache.size());
for (Map.Entry<Integer, BinaryMetadataHolder> e : metadataLocCache.entrySet())
res.put(e.getKey(), e.getValue().metadata().wrap(binaryCtx));
return res;
}
catch (CacheException e) {
throw new BinaryObjectException(e);
}
}
/** {@inheritDoc} */
@SuppressWarnings("unchecked")
@Override public Collection<BinaryType> metadata() throws BinaryObjectException {
return F.viewReadOnly(metadataLocCache.values(), new IgniteClosure<BinaryMetadataHolder, BinaryType>() {
@Override public BinaryType apply(BinaryMetadataHolder metaHolder) {
return metaHolder.metadata().wrap(binaryCtx);
}
});
}
/** {@inheritDoc} */
@Override public BinaryObject buildEnum(String typeName, int ord) throws IgniteException {
int typeId = binaryCtx.typeId(typeName);
typeName = binaryCtx.userTypeName(typeName);
updateMetadata(typeId, typeName, null, null, true);
return new BinaryEnumObjectImpl(binaryCtx, typeId, null, ord);
}
/** {@inheritDoc} */
@Override public IgniteBinary binary() throws IgniteException {
return binaries;
}
/** {@inheritDoc} */
@Override public boolean isBinaryObject(Object obj) {
return obj instanceof BinaryObject;
}
/** {@inheritDoc} */
@Override public boolean isBinaryEnabled(CacheConfiguration<?, ?> ccfg) {
return marsh instanceof BinaryMarshaller;
}
/**
* @param po Binary object.
* @return Affinity key.
*/
public Object affinityKey(BinaryObject po) {
// Fast path for already cached field.
if (po instanceof BinaryObjectEx) {
int typeId = ((BinaryObjectEx)po).typeId();
T1<BinaryField> fieldHolder = affKeyFields.get(typeId);
if (fieldHolder != null) {
BinaryField field = fieldHolder.get();
return field != null ? field.value(po) : po;
}
}
// Slow path if affinity field is not cached yet.
try {
BinaryType meta = po instanceof BinaryObjectEx ? ((BinaryObjectEx)po).rawType() : po.type();
if (meta != null) {
String name = meta.affinityKeyFieldName();
if (name != null) {
BinaryField field = meta.field(name);
affKeyFields.putIfAbsent(meta.typeId(), new T1<>(field));
return field.value(po);
}
else
affKeyFields.putIfAbsent(meta.typeId(), new T1<BinaryField>(null));
}
else if (po instanceof BinaryObjectEx) {
int typeId = ((BinaryObjectEx)po).typeId();
String name = binaryCtx.affinityKeyFieldName(typeId);
if (name != null)
return po.field(name);
}
}
catch (BinaryObjectException e) {
U.error(log, "Failed to get affinity field from binary object: " + po, e);
}
return po;
}
/** {@inheritDoc} */
@Override public int typeId(Object obj) {
if (obj == null)
return 0;
return isBinaryObject(obj) ? ((BinaryObjectEx)obj).typeId() : typeId(obj.getClass().getSimpleName());
}
/** {@inheritDoc} */
@Override public Object field(Object obj, String fieldName) {
if (obj == null)
return null;
return isBinaryObject(obj) ? ((BinaryObject)obj).field(fieldName) : super.field(obj, fieldName);
}
/** {@inheritDoc} */
@Override public boolean hasField(Object obj, String fieldName) {
return obj != null && ((BinaryObject)obj).hasField(fieldName);
}
/**
* @return Binary context.
*/
public BinaryContext binaryContext() {
return binaryCtx;
}
/** {@inheritDoc} */
@Override public CacheObjectContext contextForCache(CacheConfiguration cfg) throws IgniteCheckedException {
assert cfg != null;
boolean binaryEnabled = marsh instanceof BinaryMarshaller && !GridCacheUtils.isSystemCache(cfg.getName()) &&
!GridCacheUtils.isIgfsCache(ctx.config(), cfg.getName());
CacheObjectContext ctx0 = super.contextForCache(cfg);
CacheObjectContext res = new CacheObjectBinaryContext(ctx,
cfg.getName(),
ctx0.copyOnGet(),
ctx0.storeValue(),
binaryEnabled,
ctx0.addDeploymentInfo());
ctx.resource().injectGeneric(res.defaultAffMapper());
return res;
}
/** {@inheritDoc} */
@Override public byte[] marshal(CacheObjectContext ctx, Object val) throws IgniteCheckedException {
if (!((CacheObjectBinaryContext)ctx).binaryEnabled() || binaryMarsh == null)
return super.marshal(ctx, val);
byte[] arr = binaryMarsh.marshal(val);
assert arr.length > 0;
return arr;
}
/** {@inheritDoc} */
@Override public Object unmarshal(CacheObjectContext ctx, byte[] bytes, ClassLoader clsLdr)
throws IgniteCheckedException {
if (!((CacheObjectBinaryContext)ctx).binaryEnabled() || binaryMarsh == null)
return super.unmarshal(ctx, bytes, clsLdr);
return binaryMarsh.unmarshal(bytes, clsLdr);
}
/** {@inheritDoc} */
@Override public KeyCacheObject toCacheKeyObject(
CacheObjectContext ctx,
@Nullable GridCacheContext cctx,
Object obj,
boolean userObj
) {
if (!((CacheObjectBinaryContext)ctx).binaryEnabled())
return super.toCacheKeyObject(ctx, cctx, obj, userObj);
if (obj instanceof KeyCacheObject) {
KeyCacheObject key = (KeyCacheObject)obj;
if (key instanceof BinaryObjectImpl) {
// Need to create a copy because the key can be reused at the application layer after that (IGNITE-3505).
key = key.copy(partition(ctx, cctx, key));
}
else if (key.partition() == -1)
// Assume others KeyCacheObjects can not be reused for another cache.
key.partition(partition(ctx, cctx, key));
return key;
}
obj = toBinary(obj);
if (obj instanceof BinaryObjectImpl) {
((BinaryObjectImpl)obj).partition(partition(ctx, cctx, obj));
return (KeyCacheObject)obj;
}
return toCacheKeyObject0(ctx, cctx, obj, userObj);
}
/** {@inheritDoc} */
@Nullable @Override public CacheObject toCacheObject(CacheObjectContext ctx, @Nullable Object obj,
boolean userObj) {
if (!((CacheObjectBinaryContext)ctx).binaryEnabled())
return super.toCacheObject(ctx, obj, userObj);
if (obj == null || obj instanceof CacheObject)
return (CacheObject)obj;
obj = toBinary(obj);
if (obj instanceof CacheObject)
return (CacheObject)obj;
return toCacheObject0(obj, userObj);
}
/** {@inheritDoc} */
@Override public CacheObject toCacheObject(CacheObjectContext ctx, byte type, byte[] bytes) {
if (type == BinaryObjectImpl.TYPE_BINARY)
return new BinaryObjectImpl(binaryContext(), bytes, 0);
else if (type == BinaryObjectImpl.TYPE_BINARY_ENUM)
return new BinaryEnumObjectImpl(binaryContext(), bytes);
return super.toCacheObject(ctx, type, bytes);
}
/** {@inheritDoc} */
@Override public KeyCacheObject toKeyCacheObject(CacheObjectContext ctx, byte type, byte[] bytes) throws IgniteCheckedException {
if (type == BinaryObjectImpl.TYPE_BINARY)
return new BinaryObjectImpl(binaryContext(), bytes, 0);
return super.toKeyCacheObject(ctx, type, bytes);
}
/** {@inheritDoc} */
@Override public Object unwrapTemporary(GridCacheContext ctx, Object obj) throws BinaryObjectException {
if (!((CacheObjectBinaryContext)ctx.cacheObjectContext()).binaryEnabled())
return obj;
if (obj instanceof BinaryObjectOffheapImpl)
return ((BinaryObjectOffheapImpl)obj).heapCopy();
return obj;
}
/**
* @param obj Object.
* @return Binary object.
* @throws IgniteException In case of error.
*/
@Nullable public Object toBinary(@Nullable Object obj) throws IgniteException {
if (obj == null)
return null;
if (isBinaryObject(obj))
return obj;
return marshalToBinary(obj);
}
/** {@inheritDoc} */
@Nullable @Override public IgniteNodeValidationResult validateNode(ClusterNode rmtNode) {
IgniteNodeValidationResult res = super.validateNode(rmtNode);
if (res != null)
return res;
if (getBoolean(IGNITE_SKIP_CONFIGURATION_CONSISTENCY_CHECK) || !(marsh instanceof BinaryMarshaller))
return null;
Object rmtBinaryCfg = rmtNode.attribute(IgniteNodeAttributes.ATTR_BINARY_CONFIGURATION);
ClusterNode locNode = ctx.discovery().localNode();
Object locBinaryCfg = locNode.attribute(IgniteNodeAttributes.ATTR_BINARY_CONFIGURATION);
if (!F.eq(locBinaryCfg, rmtBinaryCfg)) {
String msg = "Local node's binary configuration is not equal to remote node's binary configuration " +
"[locNodeId=%s, rmtNodeId=%s, locBinaryCfg=%s, rmtBinaryCfg=%s]";
return new IgniteNodeValidationResult(rmtNode.id(),
String.format(msg, locNode.id(), rmtNode.id(), locBinaryCfg, rmtBinaryCfg),
String.format(msg, rmtNode.id(), locNode.id(), rmtBinaryCfg, locBinaryCfg));
}
return null;
}
/** {@inheritDoc} */
@Nullable @Override public DiscoveryDataExchangeType discoveryDataType() {
return BINARY_PROC;
}
/** {@inheritDoc} */
@Override public void collectGridNodeData(DiscoveryDataBag dataBag) {
if (!dataBag.commonDataCollectedFor(BINARY_PROC.ordinal())) {
Map<Integer, BinaryMetadataHolder> res = U.newHashMap(metadataLocCache.size());
for (Map.Entry<Integer,BinaryMetadataHolder> e : metadataLocCache.entrySet())
res.put(e.getKey(), e.getValue());
dataBag.addGridCommonData(BINARY_PROC.ordinal(), (Serializable) res);
}
}
/** {@inheritDoc} */
@Override public void onGridDataReceived(GridDiscoveryData data) {
Map<Integer, BinaryMetadataHolder> receivedData = (Map<Integer, BinaryMetadataHolder>) data.commonData();
if (receivedData != null) {
for (Map.Entry<Integer, BinaryMetadataHolder> e : receivedData.entrySet()) {
BinaryMetadataHolder holder = e.getValue();
BinaryMetadataHolder localHolder = new BinaryMetadataHolder(holder.metadata(),
holder.pendingVersion(),
holder.pendingVersion());
if (log.isDebugEnabled())
log.debug("Received metadata on join: " + localHolder);
metadataLocCache.put(e.getKey(), localHolder);
}
}
}
}