/*
* 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.atomic;
import java.io.Externalizable;
import java.nio.ByteBuffer;
import java.util.UUID;
import javax.cache.processor.EntryProcessor;
import org.apache.ignite.IgniteLogger;
import org.apache.ignite.cache.CacheWriteSynchronizationMode;
import org.apache.ignite.internal.GridDirectTransient;
import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion;
import org.apache.ignite.internal.processors.cache.CacheObject;
import org.apache.ignite.internal.processors.cache.GridCacheDeployable;
import org.apache.ignite.internal.processors.cache.GridCacheMessage;
import org.apache.ignite.internal.processors.cache.GridCacheSharedContext;
import org.apache.ignite.internal.processors.cache.KeyCacheObject;
import org.apache.ignite.internal.processors.cache.version.GridCacheVersion;
import org.apache.ignite.internal.util.typedef.internal.S;
import org.apache.ignite.plugin.extensions.communication.MessageReader;
import org.apache.ignite.plugin.extensions.communication.MessageWriter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
*
*/
public abstract class GridDhtAtomicAbstractUpdateRequest extends GridCacheMessage implements GridCacheDeployable {
/** Skip store flag bit mask. */
private static final int DHT_ATOMIC_SKIP_STORE_FLAG_MASK = 0x01;
/** Keep binary flag. */
private static final int DHT_ATOMIC_KEEP_BINARY_FLAG_MASK = 0x02;
/** Near cache key flag. */
private static final int DHT_ATOMIC_NEAR_FLAG_MASK = 0x04;
/** */
static final int DHT_ATOMIC_HAS_RESULT_MASK = 0x08;
/** */
private static final int DHT_ATOMIC_REPLY_WITHOUT_DELAY = 0x10;
/** */
protected static final int DHT_ATOMIC_OBSOLETE_NEAR_KEY_FLAG_MASK = 0x20;
/** Message index. */
public static final int CACHE_MSG_IDX = nextIndexId();
/** Future ID on primary. */
protected long futId;
/** Write version. */
protected GridCacheVersion writeVer;
/** Write synchronization mode. */
protected CacheWriteSynchronizationMode syncMode;
/** Topology version. */
protected AffinityTopologyVersion topVer;
/** Subject ID. */
protected UUID subjId;
/** Task name hash. */
protected int taskNameHash;
/** Node ID. */
@GridDirectTransient
protected UUID nodeId;
/** On response flag. Access should be synced on future. */
@GridDirectTransient
private boolean onRes;
/** */
private UUID nearNodeId;
/** */
private long nearFutId;
/** Additional flags. */
protected byte flags;
/**
* Empty constructor required by {@link Externalizable}.
*/
protected GridDhtAtomicAbstractUpdateRequest() {
// N-op.
}
/**
* Constructor.
*
* @param cacheId Cache ID.
* @param nodeId Node ID.
*/
protected GridDhtAtomicAbstractUpdateRequest(int cacheId,
UUID nodeId,
long futId,
GridCacheVersion writeVer,
CacheWriteSynchronizationMode syncMode,
@NotNull AffinityTopologyVersion topVer,
UUID subjId,
int taskNameHash,
boolean addDepInfo,
boolean keepBinary,
boolean skipStore
) {
this.cacheId = cacheId;
this.nodeId = nodeId;
this.futId = futId;
this.writeVer = writeVer;
this.syncMode = syncMode;
this.topVer = topVer;
this.subjId = subjId;
this.taskNameHash = taskNameHash;
this.addDepInfo = addDepInfo;
if (skipStore)
setFlag(true, DHT_ATOMIC_SKIP_STORE_FLAG_MASK);
if (keepBinary)
setFlag(true, DHT_ATOMIC_KEEP_BINARY_FLAG_MASK);
}
/** {@inheritDoc} */
@Override public final AffinityTopologyVersion topologyVersion() {
return topVer;
}
/**
* @param nearNodeId Near node ID.
* @param nearFutId Future ID on near node.
*/
void nearReplyInfo(UUID nearNodeId, long nearFutId) {
assert nearNodeId != null;
this.nearNodeId = nearNodeId;
this.nearFutId = nearFutId;
}
/**
* @return {@code True} if backups should reply immediately.
*/
boolean replyWithoutDelay() {
return isFlag(DHT_ATOMIC_REPLY_WITHOUT_DELAY);
}
/**
* @param replyWithoutDelay {@code True} if backups should reply immediately.
*/
void replyWithoutDelay(boolean replyWithoutDelay) {
setFlag(replyWithoutDelay, DHT_ATOMIC_REPLY_WITHOUT_DELAY);
}
/**
* @param res Result flag.
*/
void hasResult(boolean res) {
setFlag(res, DHT_ATOMIC_HAS_RESULT_MASK);
}
/**
* @return Result flag.
*/
private boolean hasResult() {
return isFlag(DHT_ATOMIC_HAS_RESULT_MASK);
}
/**
* @return Near node ID.
*/
public UUID nearNodeId() {
return nearNodeId;
}
/** {@inheritDoc} */
@Override public int lookupIndex() {
return CACHE_MSG_IDX;
}
/**
* @return Node ID.
*/
public UUID nodeId() {
return nodeId;
}
/**
* @return Flags.
*/
public final byte flags() {
return flags;
}
/**
* @return Keep binary flag.
*/
public final boolean keepBinary() {
return isFlag(DHT_ATOMIC_KEEP_BINARY_FLAG_MASK);
}
/**
* @return Skip write-through to a persistent storage.
*/
public final boolean skipStore() {
return isFlag(DHT_ATOMIC_SKIP_STORE_FLAG_MASK);
}
/**
* @return {@code True} if on response flag changed.
*/
public boolean onResponse() {
return !onRes && (onRes = true);
}
/**
* @return {@code True} if response was received.
*/
boolean hasResponse() {
return onRes;
}
/** {@inheritDoc} */
@Override public boolean addDeploymentInfo() {
return addDepInfo;
}
/**
* @return Force transform backups flag.
*/
public abstract boolean forceTransformBackups();
/** {@inheritDoc} */
@Override public IgniteLogger messageLogger(GridCacheSharedContext ctx) {
return ctx.atomicMessageLogger();
}
/** {@inheritDoc} */
@Override public void onAckReceived() {
cleanup();
}
/**
* @param key Key to add.
* @param val Value, {@code null} if should be removed.
* @param entryProcessor Entry processor.
* @param ttl TTL (optional).
* @param conflictExpireTime Conflict expire time (optional).
* @param conflictVer Conflict version (optional).
* @param addPrevVal If {@code true} adds previous value.
* @param prevVal Previous value.
* @param updateCntr Update counter.
*/
public abstract void addWriteValue(KeyCacheObject key,
@Nullable CacheObject val,
EntryProcessor<Object, Object, Object> entryProcessor,
long ttl,
long conflictExpireTime,
@Nullable GridCacheVersion conflictVer,
boolean addPrevVal,
@Nullable CacheObject prevVal,
long updateCntr
);
/**
* @param key Key to add.
* @param val Value, {@code null} if should be removed.
* @param entryProcessor Entry processor.
* @param ttl TTL.
* @param expireTime Expire time.
*/
public abstract void addNearWriteValue(KeyCacheObject key,
@Nullable CacheObject val,
EntryProcessor<Object, Object, Object> entryProcessor,
long ttl,
long expireTime);
/**
* Cleanup values not needed after message was sent.
*/
protected abstract void cleanup();
/**
* @return Subject ID.
*/
public final UUID subjectId() {
return subjId;
}
/**
* @return Task name.
*/
public final int taskNameHash() {
return taskNameHash;
}
/**
* @return Future ID on primary node.
*/
public final long futureId() {
return futId;
}
/**
* @return Future ID on near node.
*/
public final long nearFutureId() {
return nearFutId;
}
/**
* @return Write version.
*/
public final GridCacheVersion writeVersion() {
return writeVer;
}
/**
* @return Cache write synchronization mode.
*/
public final CacheWriteSynchronizationMode writeSynchronizationMode() {
return syncMode;
}
/**
* @return Keys size.
*/
public abstract int size();
/**
* @return Keys size.
*/
public abstract int nearSize();
/**
* @param key Key to check.
* @return {@code true} if request keys contain key.
*/
public abstract boolean hasKey(KeyCacheObject key);
/**
* @param idx Key index.
* @return Key.
*/
public abstract KeyCacheObject key(int idx);
/**
* @return Obsolete near cache keys size.
*/
public abstract int obsoleteNearKeysSize();
/**
* @param idx Obsolete near cache key index.
* @return Obsolete near cache key.
*/
public abstract KeyCacheObject obsoleteNearKey(int idx);
/**
* @param updCntr Update counter.
* @return Update counter.
*/
public abstract Long updateCounter(int updCntr);
/**
* @param idx Near key index.
* @return Key.
*/
public abstract KeyCacheObject nearKey(int idx);
/**
* @param idx Key index.
* @return Value.
*/
@Nullable public abstract CacheObject value(int idx);
/**
* @param idx Key index.
* @return Value.
*/
@Nullable public abstract CacheObject previousValue(int idx);
/**
* @param idx Key index.
* @return Entry processor.
*/
@Nullable public abstract EntryProcessor<Object, Object, Object> entryProcessor(int idx);
/**
* @param idx Near key index.
* @return Value.
*/
@Nullable public abstract CacheObject nearValue(int idx);
/**
* @param idx Key index.
* @return Transform closure.
*/
@Nullable public abstract EntryProcessor<Object, Object, Object> nearEntryProcessor(int idx);
/**
* @param idx Index.
* @return Conflict version.
*/
@Nullable public abstract GridCacheVersion conflictVersion(int idx);
/**
* @param idx Index.
* @return TTL.
*/
public abstract long ttl(int idx);
/**
* @param idx Index.
* @return TTL for near cache update.
*/
public abstract long nearTtl(int idx);
/**
* @param idx Index.
* @return Conflict expire time.
*/
public abstract long conflictExpireTime(int idx);
/**
* @param idx Index.
* @return Expire time for near cache update.
*/
public abstract long nearExpireTime(int idx);
/**
* @return Optional arguments for entry processor.
*/
@Nullable public abstract Object[] invokeArguments();
/**
* @return {@code True} if near cache update request.
*/
protected final boolean near() {
return isFlag(DHT_ATOMIC_NEAR_FLAG_MASK);
}
/**
* @param near Near cache update flag.
*/
protected final void near(boolean near) {
setFlag(near, DHT_ATOMIC_NEAR_FLAG_MASK);
}
/**
* Sets flag mask.
*
* @param flag Set or clear.
* @param mask Mask.
*/
protected final void setFlag(boolean flag, int mask) {
flags = flag ? (byte)(flags | mask) : (byte)(flags & ~mask);
}
/**
* Reags flag mask.
*
* @param mask Mask to read.
* @return Flag value.
*/
final boolean isFlag(int mask) {
return (flags & mask) != 0;
}
/** {@inheritDoc} */
@Override public byte fieldsCount() {
return 12;
}
/** {@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 3:
if (!writer.writeByte("flags", flags))
return false;
writer.incrementState();
case 4:
if (!writer.writeLong("futId", futId))
return false;
writer.incrementState();
case 5:
if (!writer.writeLong("nearFutId", nearFutId))
return false;
writer.incrementState();
case 6:
if (!writer.writeUuid("nearNodeId", nearNodeId))
return false;
writer.incrementState();
case 7:
if (!writer.writeUuid("subjId", subjId))
return false;
writer.incrementState();
case 8:
if (!writer.writeByte("syncMode", syncMode != null ? (byte)syncMode.ordinal() : -1))
return false;
writer.incrementState();
case 9:
if (!writer.writeInt("taskNameHash", taskNameHash))
return false;
writer.incrementState();
case 10:
if (!writer.writeMessage("topVer", topVer))
return false;
writer.incrementState();
case 11:
if (!writer.writeMessage("writeVer", writeVer))
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 3:
flags = reader.readByte("flags");
if (!reader.isLastRead())
return false;
reader.incrementState();
case 4:
futId = reader.readLong("futId");
if (!reader.isLastRead())
return false;
reader.incrementState();
case 5:
nearFutId = reader.readLong("nearFutId");
if (!reader.isLastRead())
return false;
reader.incrementState();
case 6:
nearNodeId = reader.readUuid("nearNodeId");
if (!reader.isLastRead())
return false;
reader.incrementState();
case 7:
subjId = reader.readUuid("subjId");
if (!reader.isLastRead())
return false;
reader.incrementState();
case 8:
byte syncModeOrd;
syncModeOrd = reader.readByte("syncMode");
if (!reader.isLastRead())
return false;
syncMode = CacheWriteSynchronizationMode.fromOrdinal(syncModeOrd);
reader.incrementState();
case 9:
taskNameHash = reader.readInt("taskNameHash");
if (!reader.isLastRead())
return false;
reader.incrementState();
case 10:
topVer = reader.readMessage("topVer");
if (!reader.isLastRead())
return false;
reader.incrementState();
case 11:
writeVer = reader.readMessage("writeVer");
if (!reader.isLastRead())
return false;
reader.incrementState();
}
return reader.afterMessageRead(GridDhtAtomicAbstractUpdateRequest.class);
}
/** {@inheritDoc} */
@Override public String toString() {
StringBuilder flags = new StringBuilder();
if (skipStore())
appendFlag(flags, "skipStore");
if (keepBinary())
appendFlag(flags, "keepBinary");
if (near())
appendFlag(flags, "near");
if (hasResult())
appendFlag(flags, "hasRes");
if (replyWithoutDelay())
appendFlag(flags, "resNoDelay");
return S.toString(GridDhtAtomicAbstractUpdateRequest.class, this,
"flags", flags.toString());
}
}