org.piax.gtrans.ov.sg.RQMessage Maven / Gradle / Ivy
Show all versions of piax-compat Show documentation
/*
* RQMessage.java - RQMessage implementation of SkipGraph.
*
* Copyright (c) 2015 Kota Abe / PIAX development team
*
* You can redistribute it and/or modify it under either the terms of
* the AGPLv3 or PIAX binary code license. See the file COPYING
* included in the PIAX package for more in detail.
*
* $Id: MSkipGraph.java 1160 2015-03-15 02:43:20Z teranisi $
*/
package org.piax.gtrans.ov.sg;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.NavigableMap;
import org.piax.common.DdllKey;
import org.piax.common.Endpoint;
import org.piax.common.PeerId;
import org.piax.common.subspace.Range;
import org.piax.gtrans.RemoteValue;
import org.piax.gtrans.TransOptions;
import org.piax.gtrans.TransOptions.ResponseType;
import org.piax.gtrans.ov.Link;
import org.piax.gtrans.ov.sg.SGMessagingFramework.SGReplyMessage;
import org.piax.gtrans.ov.sg.SGMessagingFramework.SGRequestMessage;
import org.piax.gtrans.ov.sg.SkipGraph.QueryId;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* a class representing a message used for propagating range queries.
*
* this class contains various data that are required to be transmitted to the
* target nodes. this class also contains failedLinks field, which
* represents a set of failed nodes that are found while processing the range
* query.
*
* this class also manages (partial) results returned from child nodes (
* rqRet).
*
* @author k-abe
*/
public class RQMessage extends SGRequestMessage {
/*--- logger ---*/
private static final Logger logger = LoggerFactory
.getLogger(RQMessage.class);
private static final long serialVersionUID = 1L;
/** true if you want to record all the intermediate nodes */
public final static boolean TRACE = true;
/** subranges, split by the range query algorithm */
final Collection> subRanges;
/** query id */
final QueryId qid;
/* query contents */
final Object query;
/** hop counter for gathering statistics */
final int hops;
transient RQReturn rqRet;
/**
* failed links. this field is used for avoiding and repairing dead links.
*/
final List failedLinks;
/** cached allLinks for retransmission */
transient NavigableMap cachedAllLinks;
/** intermediate nodes along with query path */
List trace;
public static RQMessage newRQMessage4Root(
SGMessagingFramework sgmf, Collection> subRanges,
QueryId qid, Object query, int expire, TransOptions opts) {
RQMessage msg;
// XXX opts should be on the message
if (TransOptions.responseType(opts) != ResponseType.DIRECT) {
msg = new RQMessage(sgmf, true, false, null,
SGMessagingFramework.DUMMY_MSGID, subRanges, qid, query,
expire, 0);
} else {
msg = new RQMessage(sgmf, true, true, sgmf.myLocator,
SGMessagingFramework.DUMMY_MSGID, subRanges, qid, query,
expire, 0);
}
return msg;
}
/**
* create an instance of RQMessage.
*
* @param sgmf the SGMessagingFramework managing this message
* @param isRoot true if this instance is used at the root node
* @param isDirectReturn true if reply messages should be directly sent to
* the root node
* @param replyTo the node that the reply message for this message should be
* sent to
* @param replyId the ID to distinguish queries at the replyTo node
* @param subRanges set of query ranges
* @param qid QueryId to uniquely distinguish this message
* @param query an object sent to all the nodes within the query ranges
* @param expire expiration time.
* @param hops a hop count from the root node
*/
private RQMessage(SGMessagingFramework sgmf, boolean isRoot,
boolean isDirectReturn, E replyTo, int replyId,
Collection> subRanges, QueryId qid, Object query,
int expire, int hops) {
/*
* ignored if replyTo == null
*/
super(sgmf, isRoot, isDirectReturn, replyTo, replyId, expire);
this.subRanges = subRanges;
this.qid = qid;
this.query = query;
this.hops = hops;
this.failedLinks = new ArrayList();
if (TRACE) {
trace = new ArrayList();
}
}
/**
* create an instance of RQMessage whose subRange is replaced.
*
* @param newSubRanges new subranges to be replaced to
* @return an instance of RQMessage
*/
public RQMessage newInstanceSubrangesChanged(
Collection> newSubRanges) {
RQMessage newMsg = new RQMessage(this, newSubRanges);
newMsg.rqRet = rqRet;
return newMsg;
}
private RQMessage(RQMessage msgSrc, Collection> newSubRanges) {
super(msgSrc);
this.subRanges = newSubRanges;
this.qid = msgSrc.qid;
this.query = msgSrc.query;
this.hops = msgSrc.hops;
this.failedLinks = new ArrayList(msgSrc.failedLinks);
if (TRACE) {
trace = new ArrayList(msgSrc.trace);
}
}
/**
* create a child RQMessage from this instance.
*
* this method is used at intermediate nodes.
*
* @param newSubRange new subrange for the child RQMessage
* @param reason commentary string for debugging
* @return a instance of child RQMessage
*/
public RQMessage newChildInstance(Collection> newSubRange,
String reason) {
RQMessage newMsg;
if (isDirectReturn) {
newMsg = new RQMessage(sgmf, false, true, replyTo, replyId,
newSubRange, qid, query, expire, hops + 1);
} else {
newMsg = new RQMessage(sgmf, false, false, null,
SGMessagingFramework.DUMMY_MSGID, newSubRange, qid, query,
expire, hops + 1);
}
newMsg.rqRet = rqRet;
assert rqRet != null;
newMsg.addFailedLinks(failedLinks);
newMsg.addTrace(trace);
newMsg.addTrace(reason);
return newMsg;
}
@Override
public String toString() {
return "RQMsg[sender=" + sender + ", receiver=" + receiver + ", msgId="
+ msgId + ", replyTo=" + replyTo + ", replyId=" + replyId
+ ", subRanges=" + subRanges + ", rqRet=" + rqRet
+ ", failedLinks=" + failedLinks + "]";
}
void addFailedLinks(Collection links) {
failedLinks.addAll(links);
}
void addTrace(Collection locs) {
if (TRACE) {
trace.addAll(locs);
}
}
void addTrace(String loc) {
if (TRACE) {
trace.add(loc);
}
}
@Override
public void execute(SkipGraph sg) {
sg.rqDisseminate(this);
}
@Override
public boolean onReceivingReply(SkipGraph sg, SGReplyMessage reply0) {
RQReplyMessage reply = (RQReplyMessage) reply0;
logger.debug("onReceivingReply: reply={}, this={}", reply, this);
sg.rqSetReturnValue(rqRet, reply.senderId, reply.vals, reply.hops);
if (isDirectReturn) {
assert isRoot;
return rqRet.isCompleted();
} else {
return reply.isFinal;
}
}
@Override
public synchronized void onTimeOut(SkipGraph sg) {
logger.debug("onTimeout: {}, {}", sg.toStringShort(), this);
synchronized (rqRet) {
// このメッセージのACKタイムアウトの契機で,同時に送ったメッセージで
// タイムアウトしているものがないか調べる.
Collection failedNodes = new HashSet();
Collection> ranges = new HashSet>();
for (RQMessage msg : rqRet.childMsgs.values()) {
if (msg.isAckTimedOut()) {
msg.ackReceived = true; // XXX: fake fake fake
failedNodes.add(msg.receiver);
ranges.addAll(msg.subRanges);
}
}
logger.debug("onTimeout: failedNodes = {}", failedNodes);
if (!failedNodes.isEmpty()) {
sg.fixRoutingTables(failedNodes, rqRet.parentMsg, ranges);
}
/*
* org.piax.gtrans.sg.fixRoutingTable(failedNodes, null,
* rqRet.parentMsg, ranges);
*/
}
}
/**
* a class representing a reply message against {@link RQMessage},
* containing range query results.
*/
public static class RQReplyMessage extends SGReplyMessage {
private static final long serialVersionUID = 1L;
final PeerId senderId;
final Collection>> vals;
/** is final reply? */
final boolean isFinal;
final int hops;
/**
* constructor.
*
* @param sg skip graph
* @param replyTo the RQMessage for which the reply message is created
* @param vals return values
* @param isFinal true if this reply message is the final message and no
* more reply message will be sent
* @param hops max hop count observed by this node (maybe)
*/
public RQReplyMessage(SkipGraph sg, RQMessage replyTo,
Collection>> vals, boolean isFinal,
int hops) {
super(sg, replyTo);
this.senderId = sg.peerId;
this.vals = vals;
this.isFinal = isFinal;
this.hops = hops;
}
}
}