/*
* 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.distributed.dht.preloader;
import java.util.Map;
import java.util.HashMap;
import java.nio.ByteBuffer;
import java.util.Collections;
import java.io.Externalizable;
import org.apache.ignite.IgniteCheckedException;
import org.apache.ignite.internal.GridDirectMap;
import org.apache.ignite.internal.GridDirectTransient;
import org.apache.ignite.internal.processors.cache.GridCacheSharedContext;
import org.apache.ignite.internal.processors.cache.distributed.dht.GridDhtPartitionState;
import org.apache.ignite.internal.processors.cache.version.GridCacheVersion;
import org.apache.ignite.internal.util.tostring.GridToStringInclude;
import org.apache.ignite.internal.util.typedef.F;
import org.apache.ignite.internal.util.typedef.T2;
import org.apache.ignite.internal.util.typedef.internal.S;
import org.apache.ignite.internal.util.typedef.internal.U;
import org.apache.ignite.plugin.extensions.communication.MessageCollectionItemType;
import org.apache.ignite.plugin.extensions.communication.MessageReader;
import org.apache.ignite.plugin.extensions.communication.MessageWriter;
import org.jetbrains.annotations.Nullable;
/**
* Information about partitions of a single node.
*/
public class GridDhtPartitionsSingleMessage extends GridDhtPartitionsAbstractMessage {
/** */
private static final long serialVersionUID = 0L;
/** Local partitions. */
@GridToStringInclude
@GridDirectTransient
private Map<Integer, GridDhtPartitionMap> parts;
/** */
@GridDirectMap(keyType = Integer.class, valueType = Integer.class)
private Map<Integer, Integer> dupPartsData;
/** Serialized partitions. */
private byte[] partsBytes;
/** Partitions update counters. */
@GridToStringInclude
@GridDirectTransient
private Map<Integer, Map<Integer, T2<Long, Long>>> partCntrs;
/** Serialized partitions counters. */
private byte[] partCntrsBytes;
/** Exception. */
@GridToStringInclude
@GridDirectTransient
private Exception ex;
/** */
private byte[] exBytes;
/** */
private boolean client;
/** */
@GridDirectTransient
private transient boolean compress;
/**
* Required by {@link Externalizable}.
*/
public GridDhtPartitionsSingleMessage() {
// No-op.
}
/**
* @param exchId Exchange ID.
* @param client Client message flag.
* @param lastVer Last version.
* @param compress {@code True} if it is possible to use compression for message.
*/
public GridDhtPartitionsSingleMessage(GridDhtPartitionExchangeId exchId,
boolean client,
@Nullable GridCacheVersion lastVer,
boolean compress) {
super(exchId, lastVer);
this.client = client;
this.compress = compress;
}
/**
* @return {@code True} if sent from client node.
*/
public boolean client() {
return client;
}
/**
* @param cacheId Cache ID to add local partition for.
* @param locMap Local partition map.
* @param dupDataCache Optional ID of cache with the same partition state map.
*/
public void addLocalPartitionMap(int cacheId, GridDhtPartitionMap locMap, @Nullable Integer dupDataCache) {
if (parts == null)
parts = new HashMap<>();
parts.put(cacheId, locMap);
if (dupDataCache != null) {
assert compress;
assert F.isEmpty(locMap.map());
assert parts.containsKey(dupDataCache);
if (dupPartsData == null)
dupPartsData = new HashMap<>();
dupPartsData.put(cacheId, dupDataCache);
}
}
/**
* @param cacheId Cache ID.
* @param cntrMap Partition update counters.
*/
public void partitionUpdateCounters(int cacheId, Map<Integer, T2<Long, Long>> cntrMap) {
if (partCntrs == null)
partCntrs = new HashMap<>();
partCntrs.put(cacheId, cntrMap);
}
/**
* @param cacheId Cache ID.
* @return Partition update counters.
*/
@Override public Map<Integer, T2<Long, Long>> partitionUpdateCounters(int cacheId) {
if (partCntrs != null) {
Map<Integer, T2<Long, Long>> res = partCntrs.get(cacheId);
return res != null ? res : Collections.<Integer, T2<Long, Long>>emptyMap();
}
return Collections.emptyMap();
}
/**
* @return Local partitions.
*/
public Map<Integer, GridDhtPartitionMap> partitions() {
if (parts == null)
parts = new HashMap<>();
return parts;
}
/**
* @param ex Exception.
*/
public void setException(Exception ex) {
this.ex = ex;
}
/**
*
*/
public Exception getException() {
return ex;
}
/** {@inheritDoc}
* @param ctx*/
@Override public void prepareMarshal(GridCacheSharedContext ctx) throws IgniteCheckedException {
super.prepareMarshal(ctx);
boolean marshal = (parts != null && partsBytes == null) ||
(partCntrs != null && partCntrsBytes == null) ||
(ex != null && exBytes == null);
if (marshal) {
byte[] partsBytes0 = null;
byte[] partCntrsBytes0 = null;
byte[] exBytes0 = null;
if (parts != null && partsBytes == null)
partsBytes0 = U.marshal(ctx, parts);
if (partCntrs != null && partCntrsBytes == null)
partCntrsBytes0 = U.marshal(ctx, partCntrs);
if (ex != null && exBytes == null)
exBytes0 = U.marshal(ctx, ex);
if (compress) {
assert !compressed();
try {
byte[] partsBytesZip = U.zip(partsBytes0);
byte[] partCntrsBytesZip = U.zip(partCntrsBytes0);
byte[] exBytesZip = U.zip(exBytes0);
partsBytes0 = partsBytesZip;
partCntrsBytes0 = partCntrsBytesZip;
exBytes0 = exBytesZip;
compressed(true);
}
catch (IgniteCheckedException e) {
U.error(ctx.logger(getClass()), "Failed to compress partitions data: " + e, e);
}
}
partsBytes = partsBytes0;
partCntrsBytes = partCntrsBytes0;
exBytes = exBytes0;
}
}
/** {@inheritDoc} */
@Override public void finishUnmarshal(GridCacheSharedContext ctx, ClassLoader ldr) throws IgniteCheckedException {
super.finishUnmarshal(ctx, ldr);
if (partsBytes != null && parts == null) {
if (compressed())
parts = U.unmarshalZip(ctx.marshaller(), partsBytes, U.resolveClassLoader(ldr, ctx.gridConfig()));
else
parts = U.unmarshal(ctx, partsBytes, U.resolveClassLoader(ldr, ctx.gridConfig()));
}
if (partCntrsBytes != null && partCntrs == null) {
if (compressed())
partCntrs = U.unmarshalZip(ctx.marshaller(), partCntrsBytes, U.resolveClassLoader(ldr, ctx.gridConfig()));
else
partCntrs = U.unmarshal(ctx, partCntrsBytes, U.resolveClassLoader(ldr, ctx.gridConfig()));
}
if (exBytes != null && ex == null) {
if (compressed())
ex = U.unmarshalZip(ctx.marshaller(), exBytes, U.resolveClassLoader(ldr, ctx.gridConfig()));
else
ex = U.unmarshal(ctx, exBytes, U.resolveClassLoader(ldr, ctx.gridConfig()));
}
if (dupPartsData != null) {
assert parts != null;
for (Map.Entry<Integer, Integer> e : dupPartsData.entrySet()) {
GridDhtPartitionMap map1 = parts.get(e.getKey());
assert map1 != null : e.getKey();
assert F.isEmpty(map1.map());
assert !map1.hasMovingPartitions();
GridDhtPartitionMap map2 = parts.get(e.getValue());
assert map2 != null : e.getValue();
assert map2.map() != null;
for (Map.Entry<Integer, GridDhtPartitionState> e0 : map2.map().entrySet())
map1.put(e0.getKey(), e0.getValue());
}
}
}
/** {@inheritDoc} */
@Override public boolean writeTo(ByteBuffer buf, MessageWriter writer) {
writer.setBuffer(buf);
if (!super.writeTo(buf, writer))
return false;
if (!writer.isHeaderWritten()) {
if (!writer.writeHeader(directType(), fieldsCount()))
return false;
writer.onHeaderWritten();
}
switch (writer.state()) {
case 6:
if (!writer.writeBoolean("client", client))
return false;
writer.incrementState();
case 7:
if (!writer.writeMap("dupPartsData", dupPartsData, MessageCollectionItemType.INT, MessageCollectionItemType.INT))
return false;
writer.incrementState();
case 8:
if (!writer.writeByteArray("exBytes", exBytes))
return false;
writer.incrementState();
case 9:
if (!writer.writeByteArray("partCntrsBytes", partCntrsBytes))
return false;
writer.incrementState();
case 10:
if (!writer.writeByteArray("partsBytes", partsBytes))
return false;
writer.incrementState();
}
return true;
}
/** {@inheritDoc} */
@Override public boolean readFrom(ByteBuffer buf, MessageReader reader) {
reader.setBuffer(buf);
if (!reader.beforeMessageRead())
return false;
if (!super.readFrom(buf, reader))
return false;
switch (reader.state()) {
case 6:
client = reader.readBoolean("client");
if (!reader.isLastRead())
return false;
reader.incrementState();
case 7:
dupPartsData = reader.readMap("dupPartsData", MessageCollectionItemType.INT, MessageCollectionItemType.INT, false);
if (!reader.isLastRead())
return false;
reader.incrementState();
case 8:
exBytes = reader.readByteArray("exBytes");
if (!reader.isLastRead())
return false;
reader.incrementState();
case 9:
partCntrsBytes = reader.readByteArray("partCntrsBytes");
if (!reader.isLastRead())
return false;
reader.incrementState();
case 10:
partsBytes = reader.readByteArray("partsBytes");
if (!reader.isLastRead())
return false;
reader.incrementState();
}
return reader.afterMessageRead(GridDhtPartitionsSingleMessage.class);
}
/** {@inheritDoc} */
@Override public short directType() {
return 47;
}
//todo add ex
/** {@inheritDoc} */
@Override public byte fieldsCount() {
return 11;
}
/** {@inheritDoc} */
@Override public String toString() {
return S.toString(GridDhtPartitionsSingleMessage.class, this, super.toString());
}
}