mirror of https://github.com/apache/cassandra
Lift MessagingService.minimum_version to 40
patch by Mick Semb Wever; reviewed by Andrés de la Peña García, Maxim Muzafarov for CASSANDRA-18314
This commit is contained in:
parent
6ab45971fc
commit
4bbfd64fcd
|
|
@ -1,4 +1,5 @@
|
|||
5.0
|
||||
* Lift MessagingService.minimum_version to 40 (CASSANDRA-18314)
|
||||
* Introduce pluggable crypto providers and default to AmazonCorrettoCryptoProvider (CASSANDRA-18624)
|
||||
* Improved DeletionTime serialization (CASSANDRA-18648)
|
||||
* CEP-7: Storage Attached Indexes (CASSANDRA-16052)
|
||||
|
|
|
|||
|
|
@ -48,8 +48,6 @@ import org.apache.cassandra.utils.*;
|
|||
import org.apache.cassandra.utils.btree.BTreeSet;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.*;
|
||||
import static org.apache.cassandra.net.MessagingService.VERSION_30;
|
||||
import static org.apache.cassandra.net.MessagingService.VERSION_3014;
|
||||
import static org.apache.cassandra.net.MessagingService.VERSION_40;
|
||||
import static org.apache.cassandra.net.MessagingService.VERSION_50;
|
||||
import static org.apache.cassandra.utils.Clock.Global.nanoTime;
|
||||
|
|
@ -332,8 +330,6 @@ public class CounterMutation implements IMutation
|
|||
return DatabaseDescriptor.getCounterWriteRpcTimeout(unit);
|
||||
}
|
||||
|
||||
private int serializedSize30;
|
||||
private int serializedSize3014;
|
||||
private int serializedSize40;
|
||||
private int serializedSize50;
|
||||
|
||||
|
|
@ -341,14 +337,6 @@ public class CounterMutation implements IMutation
|
|||
{
|
||||
switch (version)
|
||||
{
|
||||
case VERSION_30:
|
||||
if (serializedSize30 == 0)
|
||||
serializedSize30 = (int) serializer.serializedSize(this, VERSION_30);
|
||||
return serializedSize30;
|
||||
case VERSION_3014:
|
||||
if (serializedSize3014 == 0)
|
||||
serializedSize3014 = (int) serializer.serializedSize(this, VERSION_3014);
|
||||
return serializedSize3014;
|
||||
case VERSION_40:
|
||||
if (serializedSize40 == 0)
|
||||
serializedSize40 = (int) serializer.serializedSize(this, VERSION_40);
|
||||
|
|
|
|||
|
|
@ -48,8 +48,6 @@ import org.apache.cassandra.service.AbstractWriteResponseHandler;
|
|||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
import org.apache.cassandra.utils.concurrent.Future;
|
||||
|
||||
import static org.apache.cassandra.net.MessagingService.VERSION_30;
|
||||
import static org.apache.cassandra.net.MessagingService.VERSION_3014;
|
||||
import static org.apache.cassandra.net.MessagingService.VERSION_40;
|
||||
import static org.apache.cassandra.net.MessagingService.VERSION_50;
|
||||
import static org.apache.cassandra.utils.MonotonicClock.Global.approxTime;
|
||||
|
|
@ -317,8 +315,6 @@ public class Mutation implements IMutation, Supplier<Mutation>
|
|||
return buff.append("])").toString();
|
||||
}
|
||||
|
||||
private int serializedSize30;
|
||||
private int serializedSize3014;
|
||||
private int serializedSize40;
|
||||
private int serializedSize50;
|
||||
|
||||
|
|
@ -326,14 +322,6 @@ public class Mutation implements IMutation, Supplier<Mutation>
|
|||
{
|
||||
switch (version)
|
||||
{
|
||||
case VERSION_30:
|
||||
if (serializedSize30 == 0)
|
||||
serializedSize30 = (int) serializer.serializedSize(this, VERSION_30);
|
||||
return serializedSize30;
|
||||
case VERSION_3014:
|
||||
if (serializedSize3014 == 0)
|
||||
serializedSize3014 = (int) serializer.serializedSize(this, VERSION_3014);
|
||||
return serializedSize3014;
|
||||
case VERSION_40:
|
||||
if (serializedSize40 == 0)
|
||||
serializedSize40 = (int) serializer.serializedSize(this, VERSION_40);
|
||||
|
|
|
|||
|
|
@ -66,14 +66,13 @@ public class MutationVerbHandler implements IVerbHandler<Mutation>
|
|||
.withParam(ParamType.RESPOND_TO, originalMessage.from())
|
||||
.withoutParam(ParamType.FORWARD_TO);
|
||||
|
||||
boolean useSameMessageID = forwardTo.useSameMessageID(originalMessage.id());
|
||||
// reuse the same Message if all ids are identical (as they will be for 4.0+ node originated messages)
|
||||
Message<Mutation> message = useSameMessageID ? builder.build() : null;
|
||||
Message<Mutation> message = builder.build();
|
||||
|
||||
forwardTo.forEach((id, target) ->
|
||||
{
|
||||
Tracing.trace("Enqueuing forwarded write to {}", target);
|
||||
MessagingService.instance().send(useSameMessageID ? message : builder.withId(id).build(), target);
|
||||
MessagingService.instance().send(message, target);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -298,6 +298,7 @@ public abstract class ReadResponse
|
|||
{
|
||||
public void serialize(ReadResponse response, DataOutputPlus out, int version) throws IOException
|
||||
{
|
||||
assert version >= MessagingService.VERSION_40;
|
||||
boolean isDigest = response instanceof DigestResponse;
|
||||
ByteBuffer digest = isDigest ? ((DigestResponse)response).digest : ByteBufferUtil.EMPTY_BYTE_BUFFER;
|
||||
ByteBufferUtil.writeWithVIntLength(digest, out);
|
||||
|
|
@ -312,12 +313,8 @@ public abstract class ReadResponse
|
|||
// repaired sstables were read (but they might be on other replicas).
|
||||
// If the coordinator did not request this info, the response contains an empty digest
|
||||
// and a true for the isConclusive flag.
|
||||
// If the messaging version is < 4.0, these are omitted altogether.
|
||||
if (version >= MessagingService.VERSION_40)
|
||||
{
|
||||
ByteBufferUtil.writeWithVIntLength(response.repairedDataDigest(), out);
|
||||
out.writeBoolean(response.isRepairedDigestConclusive());
|
||||
}
|
||||
ByteBufferUtil.writeWithVIntLength(response.repairedDataDigest(), out);
|
||||
out.writeBoolean(response.isRepairedDigestConclusive());
|
||||
|
||||
ByteBuffer data = ((DataResponse)response).data;
|
||||
ByteBufferUtil.writeWithVIntLength(data, out);
|
||||
|
|
@ -326,6 +323,7 @@ public abstract class ReadResponse
|
|||
|
||||
public ReadResponse deserialize(DataInputPlus in, int version) throws IOException
|
||||
{
|
||||
assert version >= MessagingService.VERSION_40;
|
||||
ByteBuffer digest = ByteBufferUtil.readWithVIntLength(in);
|
||||
if (digest.hasRemaining())
|
||||
return new DigestResponse(digest);
|
||||
|
|
@ -334,17 +332,8 @@ public abstract class ReadResponse
|
|||
// that comes from the replica's repaired set, along with a flag indicating
|
||||
// whether or not the digest may be influenced by unrepaired/pending
|
||||
// repaired data
|
||||
boolean repairedDigestConclusive;
|
||||
if (version >= MessagingService.VERSION_40)
|
||||
{
|
||||
digest = ByteBufferUtil.readWithVIntLength(in);
|
||||
repairedDigestConclusive = in.readBoolean();
|
||||
}
|
||||
else
|
||||
{
|
||||
digest = ByteBufferUtil.EMPTY_BYTE_BUFFER;
|
||||
repairedDigestConclusive = true;
|
||||
}
|
||||
digest = ByteBufferUtil.readWithVIntLength(in);
|
||||
boolean repairedDigestConclusive = in.readBoolean();
|
||||
|
||||
ByteBuffer data = ByteBufferUtil.readWithVIntLength(in);
|
||||
return new RemoteDataResponse(data, digest, repairedDigestConclusive, version);
|
||||
|
|
@ -352,6 +341,7 @@ public abstract class ReadResponse
|
|||
|
||||
public long serializedSize(ReadResponse response, int version)
|
||||
{
|
||||
assert version >= MessagingService.VERSION_40;
|
||||
boolean isDigest = response instanceof DigestResponse;
|
||||
ByteBuffer digest = isDigest ? ((DigestResponse)response).digest : ByteBufferUtil.EMPTY_BYTE_BUFFER;
|
||||
long size = ByteBufferUtil.serializedSizeWithVIntLength(digest);
|
||||
|
|
@ -360,16 +350,12 @@ public abstract class ReadResponse
|
|||
{
|
||||
// From 4.0, a coordinator may request an additional info about the repaired data
|
||||
// that makes up the response.
|
||||
if (version >= MessagingService.VERSION_40)
|
||||
{
|
||||
size += ByteBufferUtil.serializedSizeWithVIntLength(response.repairedDataDigest());
|
||||
size += 1;
|
||||
}
|
||||
size += ByteBufferUtil.serializedSizeWithVIntLength(response.repairedDataDigest());
|
||||
size += 1;
|
||||
|
||||
// In theory, we should deserialize/re-serialize if the version asked is different from the current
|
||||
// version as the content could have a different serialization format. So far though, we haven't made
|
||||
// change to partition iterators serialization since 3.0 so we skip this.
|
||||
assert version >= MessagingService.VERSION_30;
|
||||
ByteBuffer data = ((DataResponse)response).data;
|
||||
size += ByteBufferUtil.serializedSizeWithVIntLength(data);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,22 +22,17 @@ import java.util.*;
|
|||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.collect.SortedSetMultimap;
|
||||
import com.google.common.collect.TreeMultimap;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.apache.cassandra.cql3.ColumnIdentifier;
|
||||
import org.apache.cassandra.db.*;
|
||||
import org.apache.cassandra.db.rows.CellPath;
|
||||
import org.apache.cassandra.gms.Gossiper;
|
||||
import org.apache.cassandra.io.util.DataInputPlus;
|
||||
import org.apache.cassandra.io.util.DataOutputPlus;
|
||||
import org.apache.cassandra.net.MessagingService;
|
||||
import org.apache.cassandra.schema.ColumnMetadata;
|
||||
import org.apache.cassandra.schema.TableMetadata;
|
||||
import org.apache.cassandra.utils.CassandraVersion;
|
||||
|
||||
/**
|
||||
* Represents which (non-PK) columns (and optionally which sub-part of a column for complex columns) are selected
|
||||
|
|
@ -69,7 +64,6 @@ import org.apache.cassandra.utils.CassandraVersion;
|
|||
*/
|
||||
public abstract class ColumnFilter
|
||||
{
|
||||
private final static Logger logger = LoggerFactory.getLogger(ColumnFilter.class);
|
||||
|
||||
public static final ColumnFilter NONE = selection(RegularAndStaticColumns.NONE);
|
||||
|
||||
|
|
@ -87,10 +81,6 @@ public abstract class ColumnFilter
|
|||
* For queries that have no restrictions on the clustering or regular columns, C* will return some data for
|
||||
* the partition even if it does not contains any row as long as one of the static columns contains data.
|
||||
* To be able to ensure those queries all columns need to be fetched.</p>
|
||||
*
|
||||
* <p>This strategy is also used, instead of the ALL_REGULARS_AND_QUERIED_STATICS_COLUMNS one, in mixed version clusters
|
||||
* where some nodes have a version lower than 4.0. To ensure backward compatibility with those version that interpret the
|
||||
* _fetchAll_ serialization flag as a true fetch all request.</p>
|
||||
*/
|
||||
ALL_COLUMNS
|
||||
{
|
||||
|
|
@ -182,67 +172,6 @@ public abstract class ColumnFilter
|
|||
abstract RegularAndStaticColumns getFetchedColumns(TableMetadata metadata, RegularAndStaticColumns queried);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if there are pre-4.0-rc2 nodes in the cluster, {@code false} otherwise.
|
||||
*
|
||||
* <p>ColumnFilters from 4.0 releases before RC2 wrongly assumed that fetching all regular columns and not
|
||||
* the static columns was enough. That was not the case for queries that needed to return rows for empty partitions.
|
||||
* See CASSANDRA-16686 for more details.</p>
|
||||
*/
|
||||
private static boolean isUpgradingFromVersionLowerThan40RC2()
|
||||
{
|
||||
if (Gossiper.instance.isUpgradingFromVersionLowerThan(CassandraVersion.CASSANDRA_4_0_RC2))
|
||||
{
|
||||
logger.trace("ColumnFilter conversion has been applied so that static columns will not be fetched because there are pre 4.0-rc2 nodes in the cluster");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if there are pre-4.0 nodes in the cluster, {@code false} otherwise.
|
||||
*
|
||||
* <p>If there pre-4.0 nodes in the cluster all static columns should be fetched along with all regular columns.
|
||||
* This is due to the fact that this nodes have a different understanding of the fetchAll serialization flag.
|
||||
* Pre-4.0 the fetchAll flag meant that all the columns regular AND STATIC should be fetched whereas for 4.0
|
||||
* nodes it meant that only the regular columns and the queried static columns should be fetched.</p>
|
||||
*/
|
||||
private static boolean isUpgradingFromVersionLowerThan40()
|
||||
{
|
||||
if (Gossiper.instance.isUpgradingFromVersionLowerThan(CassandraVersion.CASSANDRA_4_0))
|
||||
{
|
||||
logger.trace("ColumnFilter conversion has been applied so that all static columns will be fetched because there are pre 4.0 nodes in the cluster");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if there are pre-3.4 nodes in the cluster, {@code false} otherwise.
|
||||
*
|
||||
* When fetchAll is enabled on pre CASSANDRA-10657 (3.4-), queried columns are not considered at all, and it
|
||||
* is assumed that all columns are queried. CASSANDRA-10657 (3.4+) brings back skipping values of columns
|
||||
* which are not in queried set when fetchAll is enabled. That makes exactly the same filter being
|
||||
* interpreted in a different way on 3.4- and 3.4+.
|
||||
*
|
||||
* Moreover, there is no way to convert the filter with fetchAll and queried != null so that it is
|
||||
* interpreted the same way on 3.4- because that Cassandra version does not support such filtering.
|
||||
*
|
||||
* In order to avoid inconsistencies in data read by 3.4- and 3.4+ we need to avoid creation of incompatible
|
||||
* filters when the cluster contains 3.4- nodes. We need to do that by using a wildcard query.
|
||||
*
|
||||
* see CASSANDRA-10657, CASSANDRA-15833, CASSANDRA-16415
|
||||
*/
|
||||
private static boolean isUpgradingFromVersionLowerThan34()
|
||||
{
|
||||
if (Gossiper.instance.isUpgradingFromVersionLowerThan(CassandraVersion.CASSANDRA_3_4))
|
||||
{
|
||||
logger.trace("ColumnFilter conversion has been applied so that all columns will be queried because there are pre 3.4 nodes in the cluster");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* A filter that includes all columns for the provided table.
|
||||
*/
|
||||
|
|
@ -267,29 +196,13 @@ public abstract class ColumnFilter
|
|||
* A filter that fetches all columns for the provided table, but returns
|
||||
* only the queried ones.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
public static ColumnFilter selection(TableMetadata metadata,
|
||||
RegularAndStaticColumns queried,
|
||||
boolean returnStaticContentOnPartitionWithNoRows)
|
||||
{
|
||||
// pre CASSANDRA-10657 (3.4-), when fetchAll is enabled, queried columns are not considered at all, and it
|
||||
// is assumed that all columns are queried.
|
||||
if (isUpgradingFromVersionLowerThan34())
|
||||
{
|
||||
return new WildCardColumnFilter(metadata.regularAndStaticColumns());
|
||||
}
|
||||
|
||||
// pre CASSANDRA-12768 (4.0-) all static columns should be fetched along with all regular columns.
|
||||
if (isUpgradingFromVersionLowerThan40())
|
||||
{
|
||||
return SelectionColumnFilter.newInstance(FetchingStrategy.ALL_COLUMNS, metadata, queried, null);
|
||||
}
|
||||
|
||||
// pre CASSANDRA-16686 (4.0-RC2-) static columns were not fetched unless queried which led to some wrong
|
||||
// results for some queries
|
||||
if (!returnStaticContentOnPartitionWithNoRows || isUpgradingFromVersionLowerThan40RC2())
|
||||
{
|
||||
if (!returnStaticContentOnPartitionWithNoRows)
|
||||
return SelectionColumnFilter.newInstance(FetchingStrategy.ALL_REGULARS_AND_QUERIED_STATICS_COLUMNS, metadata, queried, null);
|
||||
}
|
||||
|
||||
return SelectionColumnFilter.newInstance(FetchingStrategy.ALL_COLUMNS, metadata, queried, null);
|
||||
}
|
||||
|
|
@ -546,48 +459,26 @@ public abstract class ColumnFilter
|
|||
|
||||
public ColumnFilter build()
|
||||
{
|
||||
boolean isFetchAll = metadata != null;
|
||||
boolean isFetchAllRegulars = metadata != null;
|
||||
|
||||
RegularAndStaticColumns queried = queriedBuilder == null ? null : queriedBuilder.build();
|
||||
|
||||
// It's only ok to have queried == null in ColumnFilter if isFetchAll. So deal with the case of a selectionBuilder
|
||||
// It's only ok to have queried == null in ColumnFilter if isFetchAllRegulars. So deal with the case of a selectionBuilder
|
||||
// with nothing selected (we can at least happen on some backward compatible queries - CASSANDRA-10471).
|
||||
if (!isFetchAll && queried == null)
|
||||
if (!isFetchAllRegulars && queried == null)
|
||||
queried = RegularAndStaticColumns.NONE;
|
||||
|
||||
SortedSetMultimap<ColumnIdentifier, ColumnSubselection> s = buildSubSelections();
|
||||
|
||||
if (isFetchAll)
|
||||
if (isFetchAllRegulars)
|
||||
{
|
||||
// When fetchAll is enabled on pre CASSANDRA-10657 (3.4-), queried columns are not considered at all, and it
|
||||
// is assumed that all columns are queried. CASSANDRA-10657 (3.4+) brings back skipping values of columns
|
||||
// which are not in queried set when fetchAll is enabled. That makes exactly the same filter being
|
||||
// interpreted in a different way on 3.4- and 3.4+.
|
||||
//
|
||||
// Moreover, there is no way to convert the filter with fetchAll and queried != null so that it is
|
||||
// interpreted the same way on 3.4- because that Cassandra version does not support such filtering.
|
||||
//
|
||||
// In order to avoid inconsitencies in data read by 3.4- and 3.4+ we need to avoid creation of incompatible
|
||||
// filters when the cluster contains 3.4- nodes. We do that by forcibly setting queried to null.
|
||||
//
|
||||
// see CASSANDRA-10657, CASSANDRA-15833, CASSANDRA-16415
|
||||
if (queried == null || isUpgradingFromVersionLowerThan34())
|
||||
{
|
||||
// there is no way to convert the filter with fetchAll and queried != null so all columns are queried
|
||||
// see CASSANDRA-10657, CASSANDRA-15833, CASSANDRA-16415
|
||||
if (queried == null)
|
||||
return new WildCardColumnFilter(metadata.regularAndStaticColumns());
|
||||
}
|
||||
|
||||
// pre CASSANDRA-12768 (4.0-) all static columns should be fetched along with all regular columns.
|
||||
if (isUpgradingFromVersionLowerThan40())
|
||||
{
|
||||
return SelectionColumnFilter.newInstance(FetchingStrategy.ALL_COLUMNS, metadata, queried, s);
|
||||
}
|
||||
|
||||
// pre CASSANDRA-16686 (4.0-RC2-) static columns where not fetched unless queried witch lead to some wrong results
|
||||
// for some queries
|
||||
if (!returnStaticContentOnPartitionWithNoRows || isUpgradingFromVersionLowerThan40RC2())
|
||||
{
|
||||
if (!returnStaticContentOnPartitionWithNoRows)
|
||||
return SelectionColumnFilter.newInstance(FetchingStrategy.ALL_REGULARS_AND_QUERIED_STATICS_COLUMNS, metadata, queried, s);
|
||||
}
|
||||
|
||||
return SelectionColumnFilter.newInstance(FetchingStrategy.ALL_COLUMNS, metadata, queried, s);
|
||||
}
|
||||
|
|
@ -948,9 +839,8 @@ public abstract class ColumnFilter
|
|||
|
||||
public static class Serializer
|
||||
{
|
||||
// Prior to 4.0 the FETCH_ALL flag meant fetch all regular and static columns. From 4.0 onward it meant
|
||||
// fetch all regular columns and queried static columns
|
||||
private static final int FETCH_ALL_MASK = 0x01;
|
||||
private static final int FETCH_ALL_REGULARS_MASK = 0x01;
|
||||
private static final int HAS_QUERIED_MASK = 0x02;
|
||||
private static final int HAS_SUB_SELECTIONS_MASK = 0x04;
|
||||
// The FETCH_ALL_STATICS flag was added in CASSANDRA-16686 to allow 4.0 to handle queries that required
|
||||
|
|
@ -959,7 +849,7 @@ public abstract class ColumnFilter
|
|||
|
||||
private static int makeHeaderByte(ColumnFilter selection)
|
||||
{
|
||||
return (selection.fetchesAllColumns(false) ? FETCH_ALL_MASK : 0)
|
||||
return (selection.fetchesAllColumns(false) ? FETCH_ALL_REGULARS_MASK : 0)
|
||||
| (!selection.isWildcard() ? HAS_QUERIED_MASK : 0)
|
||||
| (selection.subSelections() != null ? HAS_SUB_SELECTIONS_MASK : 0)
|
||||
| (selection.fetchesAllColumns(true) ? FETCH_ALL_STATICS_MASK : 0);
|
||||
|
|
@ -969,7 +859,7 @@ public abstract class ColumnFilter
|
|||
{
|
||||
out.writeByte(makeHeaderByte(selection));
|
||||
|
||||
if (version >= MessagingService.VERSION_3014 && selection.fetchesAllColumns(false))
|
||||
if (selection.fetchesAllColumns(false))
|
||||
{
|
||||
serializeRegularAndStaticColumns(selection.fetchedColumns(), out);
|
||||
}
|
||||
|
|
@ -1004,9 +894,7 @@ public abstract class ColumnFilter
|
|||
public ColumnFilter deserialize(DataInputPlus in, int version, TableMetadata metadata) throws IOException
|
||||
{
|
||||
int header = in.readUnsignedByte();
|
||||
// The meaning of isFetchAll is actually different for pre-4.0 versions and for 4.0+ versions
|
||||
// In 4.0+ it meant is fetch all regulars
|
||||
boolean isFetchAll = (header & FETCH_ALL_MASK) != 0;
|
||||
boolean isFetchAllRegulars = (header & FETCH_ALL_REGULARS_MASK) != 0;
|
||||
boolean hasQueried = (header & HAS_QUERIED_MASK) != 0;
|
||||
boolean hasSubSelections = (header & HAS_SUB_SELECTIONS_MASK) != 0;
|
||||
boolean isFetchAllStatics = (header & FETCH_ALL_STATICS_MASK) != 0;
|
||||
|
|
@ -1014,50 +902,23 @@ public abstract class ColumnFilter
|
|||
RegularAndStaticColumns fetched = null;
|
||||
RegularAndStaticColumns queried = null;
|
||||
|
||||
if (isFetchAll)
|
||||
{
|
||||
if (version >= MessagingService.VERSION_3014)
|
||||
{
|
||||
fetched = deserializeRegularAndStaticColumns(in, metadata);
|
||||
}
|
||||
else
|
||||
{
|
||||
fetched = metadata.regularAndStaticColumns();
|
||||
}
|
||||
}
|
||||
if (isFetchAllRegulars)
|
||||
fetched = deserializeRegularAndStaticColumns(in, metadata);
|
||||
|
||||
if (hasQueried)
|
||||
{
|
||||
queried = deserializeRegularAndStaticColumns(in, metadata);
|
||||
}
|
||||
|
||||
SortedSetMultimap<ColumnIdentifier, ColumnSubselection> subSelections = null;
|
||||
if (hasSubSelections)
|
||||
{
|
||||
subSelections = deserializeSubSelection(in, version, metadata);
|
||||
}
|
||||
|
||||
if (isFetchAll)
|
||||
if (isFetchAllRegulars)
|
||||
{
|
||||
// pre CASSANDRA-10657 (3.4-), when fetchAll is enabled, queried columns are not considered at all, and it
|
||||
// is assumed that all columns are queried.
|
||||
if (!hasQueried || isUpgradingFromVersionLowerThan34())
|
||||
{
|
||||
if (!hasQueried)
|
||||
return new WildCardColumnFilter(fetched);
|
||||
}
|
||||
|
||||
// pre CASSANDRA-12768 (4.0-) all static columns should be fetched along with all regular columns.
|
||||
if (isUpgradingFromVersionLowerThan40())
|
||||
{
|
||||
return new SelectionColumnFilter(FetchingStrategy.ALL_COLUMNS, queried, fetched, subSelections);
|
||||
}
|
||||
|
||||
// pre CASSANDRA-16686 (4.0-RC2-) static columns where not fetched unless queried witch lead to some wrong results
|
||||
// for some queries
|
||||
if (!isFetchAllStatics || isUpgradingFromVersionLowerThan40RC2())
|
||||
{
|
||||
if (!isFetchAllStatics)
|
||||
return new SelectionColumnFilter(FetchingStrategy.ALL_REGULARS_AND_QUERIED_STATICS_COLUMNS, queried, fetched, subSelections);
|
||||
}
|
||||
|
||||
return new SelectionColumnFilter(FetchingStrategy.ALL_COLUMNS, queried, fetched, subSelections);
|
||||
}
|
||||
|
|
@ -1091,7 +952,7 @@ public abstract class ColumnFilter
|
|||
{
|
||||
long size = 1; // header byte
|
||||
|
||||
if (version >= MessagingService.VERSION_3014 && selection.fetchesAllColumns(false))
|
||||
if (selection.fetchesAllColumns(false))
|
||||
{
|
||||
size += regularAndStaticColumnsSerializedSize(selection.fetchedColumns());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -97,20 +97,20 @@ public enum RequestFailureReason
|
|||
|
||||
public void serialize(RequestFailureReason reason, DataOutputPlus out, int version) throws IOException
|
||||
{
|
||||
if (version < VERSION_40)
|
||||
out.writeShort(reason.code);
|
||||
else
|
||||
out.writeUnsignedVInt32(reason.code);
|
||||
assert version >= VERSION_40;
|
||||
out.writeUnsignedVInt32(reason.code);
|
||||
}
|
||||
|
||||
public RequestFailureReason deserialize(DataInputPlus in, int version) throws IOException
|
||||
{
|
||||
return fromCode(version < VERSION_40 ? in.readUnsignedShort() : in.readUnsignedVInt32());
|
||||
assert version >= VERSION_40;
|
||||
return fromCode(in.readUnsignedVInt32());
|
||||
}
|
||||
|
||||
public long serializedSize(RequestFailureReason reason, int version)
|
||||
{
|
||||
return version < VERSION_40 ? 2 : VIntCoding.computeVIntSize(reason.code);
|
||||
assert version >= VERSION_40;
|
||||
return VIntCoding.computeVIntSize(reason.code);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,7 +66,6 @@ final class HintsDescriptor
|
|||
{
|
||||
private static final Logger logger = LoggerFactory.getLogger(HintsDescriptor.class);
|
||||
|
||||
static final int VERSION_30 = 1;
|
||||
static final int VERSION_40 = 2;
|
||||
static final int VERSION_50 = 3;
|
||||
static final int CURRENT_VERSION = DatabaseDescriptor.getStorageCompatibilityMode().isBefore(5) ? VERSION_40 : VERSION_50;
|
||||
|
|
@ -231,8 +230,6 @@ final class HintsDescriptor
|
|||
{
|
||||
switch (hintsVersion)
|
||||
{
|
||||
case VERSION_30:
|
||||
return MessagingService.VERSION_30;
|
||||
case VERSION_40:
|
||||
return MessagingService.VERSION_40;
|
||||
case VERSION_50:
|
||||
|
|
|
|||
|
|
@ -55,7 +55,6 @@ import org.apache.cassandra.utils.FastByteOperations;
|
|||
* need to sometimes return a port and sometimes not.
|
||||
*
|
||||
*/
|
||||
@SuppressWarnings("UnstableApiUsage")
|
||||
public final class InetAddressAndPort extends InetSocketAddress implements Comparable<InetAddressAndPort>, Serializable
|
||||
{
|
||||
private static final long serialVersionUID = 0;
|
||||
|
|
@ -319,8 +318,6 @@ public final class InetAddressAndPort extends InetSocketAddress implements Compa
|
|||
|
||||
/**
|
||||
* As of version 4.0 the endpoint description includes a port number as an unsigned short
|
||||
* This serializer matches the 3.0 CompactEndpointSerializationHelper, encoding the number of address bytes
|
||||
* in a single byte before the address itself.
|
||||
*/
|
||||
public static final class Serializer implements IVersionedSerializer<InetAddressAndPort>
|
||||
{
|
||||
|
|
@ -347,17 +344,10 @@ public final class InetAddressAndPort extends InetSocketAddress implements Compa
|
|||
|
||||
void serialize(byte[] address, int port, DataOutputPlus out, int version) throws IOException
|
||||
{
|
||||
if (version >= MessagingService.VERSION_40)
|
||||
{
|
||||
out.writeByte(address.length + 2);
|
||||
out.write(address);
|
||||
out.writeShort(port);
|
||||
}
|
||||
else
|
||||
{
|
||||
out.writeByte(address.length);
|
||||
out.write(address);
|
||||
}
|
||||
assert version >= MessagingService.VERSION_40;
|
||||
out.writeByte(address.length + 2);
|
||||
out.write(address);
|
||||
out.writeShort(port);
|
||||
}
|
||||
|
||||
public InetAddressAndPort deserialize(DataInputPlus in, int version) throws IOException
|
||||
|
|
@ -368,11 +358,7 @@ public final class InetAddressAndPort extends InetSocketAddress implements Compa
|
|||
//The original pre-4.0 serialiation of just an address
|
||||
case 4:
|
||||
case 16:
|
||||
{
|
||||
byte[] bytes = new byte[size];
|
||||
in.readFully(bytes, 0, bytes.length);
|
||||
return getByAddress(bytes);
|
||||
}
|
||||
throw new AssertionError("pre-4.0 serialization size " + size);
|
||||
//Address and one port
|
||||
case 6:
|
||||
case 18:
|
||||
|
|
@ -395,13 +381,7 @@ public final class InetAddressAndPort extends InetSocketAddress implements Compa
|
|||
public InetAddressAndPort extract(ByteBuffer buf, int position) throws IOException
|
||||
{
|
||||
int size = buf.get(position++) & 0xFF;
|
||||
if (size == 4 || size == 16)
|
||||
{
|
||||
byte[] bytes = new byte[size];
|
||||
ByteBufferUtil.copyBytes(buf, position, bytes, 0, size);
|
||||
return getByAddress(bytes);
|
||||
}
|
||||
else if (size == 6 || size == 18)
|
||||
if (size == 6 || size == 18)
|
||||
{
|
||||
byte[] bytes = new byte[size - 2];
|
||||
ByteBufferUtil.copyBytes(buf, position, bytes, 0, size - 2);
|
||||
|
|
@ -420,26 +400,15 @@ public final class InetAddressAndPort extends InetSocketAddress implements Compa
|
|||
|
||||
public long serializedSize(InetSocketAddress from, int version)
|
||||
{
|
||||
//4.0 includes a port number
|
||||
if (version >= MessagingService.VERSION_40)
|
||||
{
|
||||
if (from.getAddress() instanceof Inet4Address)
|
||||
return 1 + 4 + 2;
|
||||
assert from.getAddress() instanceof Inet6Address;
|
||||
return 1 + 16 + 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (from.getAddress() instanceof Inet4Address)
|
||||
return 1 + 4;
|
||||
assert from.getAddress() instanceof Inet6Address;
|
||||
return 1 + 16;
|
||||
}
|
||||
assert version >= MessagingService.VERSION_40;
|
||||
if (from.getAddress() instanceof Inet4Address)
|
||||
return 1 + 4 + 2;
|
||||
assert from.getAddress() instanceof Inet6Address;
|
||||
return 1 + 16 + 2;
|
||||
}
|
||||
}
|
||||
|
||||
/** Serializer for handling FWD_FRM message parameters. Pre-4.0 deserialization is a special
|
||||
* case in the message
|
||||
/** Serializer for handling FWD_FRM message parameters.
|
||||
*/
|
||||
public static final class FwdFrmSerializer implements IVersionedSerializer<InetAddressAndPort>
|
||||
{
|
||||
|
|
@ -448,73 +417,43 @@ public final class InetAddressAndPort extends InetSocketAddress implements Compa
|
|||
|
||||
public void serialize(InetAddressAndPort endpoint, DataOutputPlus out, int version) throws IOException
|
||||
{
|
||||
assert version >= MessagingService.VERSION_40;
|
||||
byte[] buf = endpoint.addressBytes;
|
||||
|
||||
if (version >= MessagingService.VERSION_40)
|
||||
{
|
||||
out.writeByte(buf.length + 2);
|
||||
out.write(buf);
|
||||
out.writeShort(endpoint.getPort());
|
||||
}
|
||||
else
|
||||
{
|
||||
out.write(buf);
|
||||
}
|
||||
out.writeByte(buf.length + 2);
|
||||
out.write(buf);
|
||||
out.writeShort(endpoint.getPort());
|
||||
}
|
||||
|
||||
public long serializedSize(InetAddressAndPort from, int version)
|
||||
{
|
||||
//4.0 includes a port number
|
||||
if (version >= MessagingService.VERSION_40)
|
||||
{
|
||||
if (from.getAddress() instanceof Inet4Address)
|
||||
return 1 + 4 + 2;
|
||||
assert from.getAddress() instanceof Inet6Address;
|
||||
return 1 + 16 + 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (from.getAddress() instanceof Inet4Address)
|
||||
return 4;
|
||||
assert from.getAddress() instanceof Inet6Address;
|
||||
return 16;
|
||||
}
|
||||
assert version >= MessagingService.VERSION_40;
|
||||
if (from.getAddress() instanceof Inet4Address)
|
||||
return 1 + 4 + 2;
|
||||
assert from.getAddress() instanceof Inet6Address;
|
||||
return 1 + 16 + 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InetAddressAndPort deserialize(DataInputPlus in, int version) throws IOException
|
||||
{
|
||||
if (version >= MessagingService.VERSION_40)
|
||||
assert version >= MessagingService.VERSION_40 : "FWD_FRM deserializations should be special-cased pre-4.0";
|
||||
int size = in.readByte() & 0xFF;
|
||||
switch (size)
|
||||
{
|
||||
int size = in.readByte() & 0xFF;
|
||||
switch (size)
|
||||
//Address and one port
|
||||
case 6:
|
||||
case 18:
|
||||
{
|
||||
//Address and one port
|
||||
case 6:
|
||||
case 18:
|
||||
{
|
||||
byte[] bytes = new byte[size - 2];
|
||||
in.readFully(bytes);
|
||||
byte[] bytes = new byte[size - 2];
|
||||
in.readFully(bytes);
|
||||
|
||||
int port = in.readShort() & 0xFFFF;
|
||||
return getByAddressOverrideDefaults(InetAddress.getByAddress(bytes), bytes, port);
|
||||
}
|
||||
default:
|
||||
throw new AssertionError("Unexpected size " + size);
|
||||
int port = in.readShort() & 0xFFFF;
|
||||
return getByAddressOverrideDefaults(InetAddress.getByAddress(bytes), bytes, port);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new IllegalStateException("FWD_FRM deserializations should be special-cased pre-4.0");
|
||||
default:
|
||||
throw new AssertionError("Unexpected size " + size);
|
||||
}
|
||||
}
|
||||
|
||||
public InetAddressAndPort pre40DeserializeWithLength(DataInputPlus in, int version, int length) throws IOException
|
||||
{
|
||||
assert length == 4 || length == 16 : "unexpected length " + length;
|
||||
byte[] from = new byte[length];
|
||||
in.readFully(from, 0, length);
|
||||
return InetAddressAndPort.getByAddress(from);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,8 +18,6 @@
|
|||
package org.apache.cassandra.net;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.primitives.Ints;
|
||||
import org.apache.cassandra.db.TypeSizes;
|
||||
import org.apache.cassandra.io.IVersionedSerializer;
|
||||
import org.apache.cassandra.io.util.DataInputPlus;
|
||||
import org.apache.cassandra.io.util.DataOutputPlus;
|
||||
|
|
@ -39,7 +37,6 @@ import static org.apache.cassandra.utils.vint.VIntCoding.computeUnsignedVIntSize
|
|||
* A container used to store a node -> message_id map for inter-DC write forwarding.
|
||||
* We pick one node in each external DC to forward the message to its local peers.
|
||||
*
|
||||
* TODO: in the next protocol version only serialize peers, message id will become redundant once 3.0 is out of the picture
|
||||
*/
|
||||
public final class ForwardingInfo implements Serializable
|
||||
{
|
||||
|
|
@ -53,19 +50,6 @@ public final class ForwardingInfo implements Serializable
|
|||
this.messageIds = messageIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@code true} if all host are to use the same message id, {@code false} otherwise. Starting with 4.0 and
|
||||
* above, we should be reusing the same id, always, but it won't always be true until 3.0/3.11 are phased out.
|
||||
*/
|
||||
public boolean useSameMessageID(long id)
|
||||
{
|
||||
for (int i = 0; i < messageIds.length; i++)
|
||||
if (id != messageIds[i])
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the provided consumer to all (host, message_id) pairs.
|
||||
*/
|
||||
|
|
@ -79,37 +63,33 @@ public final class ForwardingInfo implements Serializable
|
|||
{
|
||||
public void serialize(ForwardingInfo forwardTo, DataOutputPlus out, int version) throws IOException
|
||||
{
|
||||
assert version >= VERSION_40;
|
||||
long[] ids = forwardTo.messageIds;
|
||||
List<InetAddressAndPort> targets = forwardTo.targets;
|
||||
|
||||
int count = ids.length;
|
||||
if (version >= VERSION_40)
|
||||
out.writeUnsignedVInt32(count);
|
||||
else
|
||||
out.writeInt(count);
|
||||
out.writeUnsignedVInt32(count);
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
inetAddressAndPortSerializer.serialize(targets.get(i), out, version);
|
||||
if (version >= VERSION_40)
|
||||
out.writeUnsignedVInt(ids[i]);
|
||||
else
|
||||
out.writeInt(Ints.checkedCast(ids[i]));
|
||||
out.writeUnsignedVInt(ids[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public long serializedSize(ForwardingInfo forwardTo, int version)
|
||||
{
|
||||
assert version >= VERSION_40;
|
||||
long[] ids = forwardTo.messageIds;
|
||||
List<InetAddressAndPort> targets = forwardTo.targets;
|
||||
|
||||
int count = ids.length;
|
||||
long size = version >= VERSION_40 ? computeUnsignedVIntSize(count) : TypeSizes.sizeof(count);
|
||||
long size = computeUnsignedVIntSize(count);
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
size += inetAddressAndPortSerializer.serializedSize(targets.get(i), version);
|
||||
size += version >= VERSION_40 ? computeUnsignedVIntSize(ids[i]) : 4;
|
||||
size += computeUnsignedVIntSize(ids[i]);
|
||||
}
|
||||
|
||||
return size;
|
||||
|
|
@ -117,7 +97,8 @@ public final class ForwardingInfo implements Serializable
|
|||
|
||||
public ForwardingInfo deserialize(DataInputPlus in, int version) throws IOException
|
||||
{
|
||||
int count = version >= VERSION_40 ? in.readUnsignedVInt32() : in.readInt();
|
||||
assert version >= VERSION_40;
|
||||
int count = in.readUnsignedVInt32();
|
||||
|
||||
long[] ids = new long[count];
|
||||
List<InetAddressAndPort> targets = new ArrayList<>(count);
|
||||
|
|
@ -125,7 +106,7 @@ public final class ForwardingInfo implements Serializable
|
|||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
targets.add(inetAddressAndPortSerializer.deserialize(in, version));
|
||||
ids[i] = version >= VERSION_40 ? in.readUnsignedVInt32() : in.readInt();
|
||||
ids[i] = in.readUnsignedVInt32();
|
||||
}
|
||||
|
||||
return new ForwardingInfo(targets, ids);
|
||||
|
|
|
|||
|
|
@ -51,10 +51,6 @@ import static org.apache.cassandra.utils.ByteBufferUtil.copyBytes;
|
|||
LZ4 compression with custom frame format; payload is protected by CRC32
|
||||
* 3. {@link FrameDecoderUnprotected}:
|
||||
no compression; no integrity protection
|
||||
* 4. {@link FrameDecoderLegacy}:
|
||||
no compression; no integrity protection; turns unframed streams of legacy messages (< 4.0) into frames
|
||||
* 5. {@link FrameDecoderLegacyLZ4}
|
||||
* LZ4 compression using standard LZ4 frame format; groups legacy messages (< 4.0) into frames
|
||||
*/
|
||||
public abstract class FrameDecoder extends ChannelInboundHandlerAdapter
|
||||
{
|
||||
|
|
@ -276,10 +272,6 @@ public abstract class FrameDecoder extends ChannelInboundHandlerAdapter
|
|||
allocator.putUnusedPortion(buf);
|
||||
channelRead(ShareableBytes.wrap(buf));
|
||||
}
|
||||
else if (msg instanceof ShareableBytes) // legacy LZ4 decoder
|
||||
{
|
||||
channelRead((ShareableBytes) msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new IllegalArgumentException();
|
||||
|
|
|
|||
|
|
@ -1,184 +0,0 @@
|
|||
/*
|
||||
* 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.cassandra.net;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Collection;
|
||||
|
||||
import io.netty.channel.ChannelPipeline;
|
||||
|
||||
import static java.lang.Math.max;
|
||||
import static org.apache.cassandra.net.OutboundConnections.LARGE_MESSAGE_THRESHOLD;
|
||||
|
||||
/**
|
||||
* {@link InboundMessageHandler} operates on frames that adhere to a certain contract
|
||||
* (see {@link FrameDecoder.IntactFrame} and {@link FrameDecoder.CorruptFrame} javadoc).
|
||||
*
|
||||
* Legacy (pre-4.0) messaging protocol does not natively support framing, however. The job
|
||||
* of {@link FrameDecoderLegacy} is turn a raw stream of messages, serialized back to back,
|
||||
* into a sequence of frames that adhere to 4.0+ conventions.
|
||||
*/
|
||||
class FrameDecoderLegacy extends FrameDecoder
|
||||
{
|
||||
private final int messagingVersion;
|
||||
|
||||
private int remainingBytesInLargeMessage = 0;
|
||||
|
||||
FrameDecoderLegacy(BufferPoolAllocator allocator, int messagingVersion)
|
||||
{
|
||||
super(allocator);
|
||||
this.messagingVersion = messagingVersion;
|
||||
}
|
||||
|
||||
final void decode(Collection<Frame> into, ShareableBytes newBytes)
|
||||
{
|
||||
ByteBuffer in = newBytes.get();
|
||||
try
|
||||
{
|
||||
if (stash != null)
|
||||
{
|
||||
int length = Message.serializer.inferMessageSize(stash, 0, stash.position(), messagingVersion);
|
||||
while (length < 0)
|
||||
{
|
||||
if (!in.hasRemaining())
|
||||
return;
|
||||
|
||||
if (stash.position() == stash.capacity())
|
||||
stash = ensureCapacity(stash, stash.capacity() * 2);
|
||||
copyToSize(in, stash, stash.capacity());
|
||||
|
||||
length = Message.serializer.inferMessageSize(stash, 0, stash.position(), messagingVersion);
|
||||
if (length >= 0 && length < stash.position())
|
||||
{
|
||||
int excess = stash.position() - length;
|
||||
in.position(in.position() - excess);
|
||||
stash.position(length);
|
||||
}
|
||||
}
|
||||
|
||||
final boolean isSelfContained;
|
||||
if (length <= LARGE_MESSAGE_THRESHOLD)
|
||||
{
|
||||
isSelfContained = true;
|
||||
|
||||
if (length > stash.capacity())
|
||||
stash = ensureCapacity(stash, length);
|
||||
|
||||
stash.limit(length);
|
||||
allocator.putUnusedPortion(stash); // we may be over capacity from earlier doubling
|
||||
if (!copyToSize(in, stash, length))
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
isSelfContained = false;
|
||||
remainingBytesInLargeMessage = length - stash.position();
|
||||
|
||||
stash.limit(stash.position());
|
||||
allocator.putUnusedPortion(stash);
|
||||
}
|
||||
|
||||
stash.flip();
|
||||
assert !isSelfContained || stash.limit() == length;
|
||||
ShareableBytes stashed = ShareableBytes.wrap(stash);
|
||||
into.add(new IntactFrame(isSelfContained, stashed));
|
||||
stash = null;
|
||||
}
|
||||
|
||||
if (remainingBytesInLargeMessage > 0)
|
||||
{
|
||||
if (remainingBytesInLargeMessage >= newBytes.remaining())
|
||||
{
|
||||
remainingBytesInLargeMessage -= newBytes.remaining();
|
||||
into.add(new IntactFrame(false, newBytes.sliceAndConsume(newBytes.remaining())));
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
Frame frame = new IntactFrame(false, newBytes.sliceAndConsume(remainingBytesInLargeMessage));
|
||||
remainingBytesInLargeMessage = 0;
|
||||
into.add(frame);
|
||||
}
|
||||
}
|
||||
|
||||
// we loop incrementing our end pointer until we have no more complete messages,
|
||||
// at which point we slice the complete messages, and stash the remainder
|
||||
int begin = in.position();
|
||||
int end = begin;
|
||||
int limit = in.limit();
|
||||
|
||||
if (begin == limit)
|
||||
return;
|
||||
|
||||
while (true)
|
||||
{
|
||||
int length = Message.serializer.inferMessageSize(in, end, limit, messagingVersion);
|
||||
|
||||
if (length >= 0)
|
||||
{
|
||||
if (end + length <= limit)
|
||||
{
|
||||
// we have a complete message, so just bump our end pointer
|
||||
end += length;
|
||||
|
||||
// if we have more bytes, continue to look for another message
|
||||
if (end < limit)
|
||||
continue;
|
||||
|
||||
// otherwise reset length, as we have accounted for it in end
|
||||
length = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// we are done; if we have found any complete messages, slice them all into a single frame
|
||||
if (begin < end)
|
||||
into.add(new IntactFrame(true, newBytes.slice(begin, end)));
|
||||
|
||||
// now consider stashing anything leftover
|
||||
if (length < 0)
|
||||
{
|
||||
stash(newBytes, max(64, limit - end), end, limit - end);
|
||||
}
|
||||
else if (length > LARGE_MESSAGE_THRESHOLD)
|
||||
{
|
||||
remainingBytesInLargeMessage = length - (limit - end);
|
||||
Frame frame = new IntactFrame(false, newBytes.slice(end, limit));
|
||||
into.add(frame);
|
||||
}
|
||||
else if (length > 0)
|
||||
{
|
||||
stash(newBytes, length, end, limit - end);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Message.InvalidLegacyProtocolMagic e)
|
||||
{
|
||||
into.add(CorruptFrame.unrecoverable(e.read, Message.PROTOCOL_MAGIC));
|
||||
}
|
||||
finally
|
||||
{
|
||||
newBytes.release();
|
||||
}
|
||||
}
|
||||
|
||||
void addLastTo(ChannelPipeline pipeline)
|
||||
{
|
||||
pipeline.addLast("frameDecoderNone", this);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,381 +0,0 @@
|
|||
/*
|
||||
* 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.cassandra.net;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Collection;
|
||||
import java.util.Deque;
|
||||
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||
import io.netty.channel.ChannelPipeline;
|
||||
import io.netty.handler.codec.compression.Lz4FrameDecoder;
|
||||
import net.jpountz.lz4.LZ4Factory;
|
||||
import net.jpountz.lz4.LZ4SafeDecompressor;
|
||||
import net.jpountz.xxhash.XXHash32;
|
||||
import net.jpountz.xxhash.XXHashFactory;
|
||||
import org.apache.cassandra.utils.memory.BufferPool;
|
||||
import org.apache.cassandra.utils.memory.BufferPools;
|
||||
|
||||
import static java.lang.Integer.reverseBytes;
|
||||
import static java.lang.String.format;
|
||||
import static org.apache.cassandra.net.LegacyLZ4Constants.*;
|
||||
import static org.apache.cassandra.utils.ByteBufferUtil.copyBytes;
|
||||
|
||||
/**
|
||||
* A {@link FrameDecoder} consisting of two chained handlers:
|
||||
* 1. A legacy LZ4 block decoder, described below in the description of {@link LZ4Decoder}, followed by
|
||||
* 2. An instance of {@link FrameDecoderLegacy} - transforming the raw messages in the uncompressed stream
|
||||
* into properly formed frames expected by {@link InboundMessageHandler}
|
||||
*/
|
||||
class FrameDecoderLegacyLZ4 extends FrameDecoderLegacy
|
||||
{
|
||||
private static final BufferPool bufferPool = BufferPools.forNetworking();
|
||||
|
||||
FrameDecoderLegacyLZ4(BufferPoolAllocator allocator, int messagingVersion)
|
||||
{
|
||||
super(allocator, messagingVersion);
|
||||
}
|
||||
|
||||
@Override
|
||||
void addLastTo(ChannelPipeline pipeline)
|
||||
{
|
||||
pipeline.addLast("legacyLZ4Decoder", new LZ4Decoder(allocator));
|
||||
pipeline.addLast("frameDecoderNone", this);
|
||||
}
|
||||
|
||||
/**
|
||||
* An implementation of LZ4 decoder, used for legacy (3.0, 3.11) connections.
|
||||
*
|
||||
* Netty's provided implementation - {@link Lz4FrameDecoder} couldn't be reused for
|
||||
* two reasons:
|
||||
* 1. It has very poor performance when coupled with xxHash, which we use for legacy connections -
|
||||
* allocating a single-byte array and making a JNI call <em>for every byte of the payload</em>
|
||||
* 2. It was tricky to efficiently integrate with upstream {@link FrameDecoder}, and impossible
|
||||
* to make it play nicely with flow control - Netty's implementation, based on
|
||||
* {@link io.netty.handler.codec.ByteToMessageDecoder}, would potentially keep triggering
|
||||
* reads on its own volition for as long as its last read had no completed frames to supply
|
||||
* - defying our goal to only ever trigger channel reads when explicitly requested
|
||||
*
|
||||
* Since the original LZ4 block format does not contains size of compressed block and size of original data
|
||||
* this encoder uses format like <a href="https://github.com/idelpivnitskiy/lz4-java">LZ4 Java</a> library
|
||||
* written by Adrien Grand and approved by Yann Collet (author of original LZ4 library), as implemented by
|
||||
* Netty's {@link Lz4FrameDecoder}, but adapted for our interaction model.
|
||||
*
|
||||
* 0 1 2 3
|
||||
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
* | |
|
||||
* + Magic +
|
||||
* | |
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
* |T| Compressed Length
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
* | Uncompressed Length
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
* | xxHash32 of Uncompressed Payload
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
* | |
|
||||
* +-+ +
|
||||
* | |
|
||||
* + Payload +
|
||||
* | |
|
||||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
*/
|
||||
private static class LZ4Decoder extends ChannelInboundHandlerAdapter
|
||||
{
|
||||
private static final XXHash32 xxhash =
|
||||
XXHashFactory.fastestInstance().hash32();
|
||||
|
||||
private static final LZ4SafeDecompressor decompressor =
|
||||
LZ4Factory.fastestInstance().safeDecompressor();
|
||||
|
||||
private final BufferPoolAllocator allocator;
|
||||
|
||||
LZ4Decoder(BufferPoolAllocator allocator)
|
||||
{
|
||||
this.allocator = allocator;
|
||||
}
|
||||
|
||||
private final Deque<ShareableBytes> frames = new ArrayDeque<>(4);
|
||||
|
||||
// total # of frames decoded between two subsequent invocations of channelReadComplete()
|
||||
private int decodedFrameCount = 0;
|
||||
|
||||
@Override
|
||||
public void channelRead(ChannelHandlerContext ctx, Object msg) throws CorruptLZ4Frame
|
||||
{
|
||||
assert msg instanceof BufferPoolAllocator.Wrapped;
|
||||
ByteBuffer buf = ((BufferPoolAllocator.Wrapped) msg).adopt();
|
||||
// netty will probably have mis-predicted the space needed
|
||||
bufferPool.putUnusedPortion(buf);
|
||||
|
||||
CorruptLZ4Frame error = null;
|
||||
try
|
||||
{
|
||||
decode(frames, ShareableBytes.wrap(buf));
|
||||
}
|
||||
catch (CorruptLZ4Frame e)
|
||||
{
|
||||
error = e;
|
||||
}
|
||||
finally
|
||||
{
|
||||
decodedFrameCount += frames.size();
|
||||
while (!frames.isEmpty())
|
||||
ctx.fireChannelRead(frames.poll());
|
||||
}
|
||||
|
||||
if (null != error)
|
||||
throw error;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelReadComplete(ChannelHandlerContext ctx)
|
||||
{
|
||||
/*
|
||||
* If no frames have been decoded from the entire batch of channelRead() calls,
|
||||
* then we must trigger another channel read explicitly, or else risk stalling
|
||||
* forever without bytes to complete the current in-flight frame.
|
||||
*/
|
||||
if (null != stash && decodedFrameCount == 0 && !ctx.channel().config().isAutoRead())
|
||||
ctx.read();
|
||||
|
||||
decodedFrameCount = 0;
|
||||
ctx.fireChannelReadComplete();
|
||||
}
|
||||
|
||||
private void decode(Collection<ShareableBytes> into, ShareableBytes newBytes) throws CorruptLZ4Frame
|
||||
{
|
||||
try
|
||||
{
|
||||
doDecode(into, newBytes);
|
||||
}
|
||||
finally
|
||||
{
|
||||
newBytes.release();
|
||||
}
|
||||
}
|
||||
|
||||
private void doDecode(Collection<ShareableBytes> into, ShareableBytes newBytes) throws CorruptLZ4Frame
|
||||
{
|
||||
ByteBuffer in = newBytes.get();
|
||||
|
||||
if (null != stash)
|
||||
{
|
||||
if (!copyToSize(in, stash, HEADER_LENGTH))
|
||||
return;
|
||||
|
||||
header.read(stash, 0);
|
||||
header.validate();
|
||||
|
||||
int frameLength = header.frameLength();
|
||||
stash = ensureCapacity(stash, frameLength);
|
||||
|
||||
if (!copyToSize(in, stash, frameLength))
|
||||
return;
|
||||
|
||||
stash.flip();
|
||||
ShareableBytes stashed = ShareableBytes.wrap(stash);
|
||||
stash = null;
|
||||
|
||||
try
|
||||
{
|
||||
into.add(decompressFrame(stashed, 0, frameLength, header));
|
||||
}
|
||||
finally
|
||||
{
|
||||
stashed.release();
|
||||
}
|
||||
}
|
||||
|
||||
int begin = in.position();
|
||||
int limit = in.limit();
|
||||
while (begin < limit)
|
||||
{
|
||||
int remaining = limit - begin;
|
||||
if (remaining < HEADER_LENGTH)
|
||||
{
|
||||
stash(newBytes, HEADER_LENGTH, begin, remaining);
|
||||
return;
|
||||
}
|
||||
|
||||
header.read(in, begin);
|
||||
header.validate();
|
||||
|
||||
int frameLength = header.frameLength();
|
||||
if (remaining < frameLength)
|
||||
{
|
||||
stash(newBytes, frameLength, begin, remaining);
|
||||
return;
|
||||
}
|
||||
|
||||
into.add(decompressFrame(newBytes, begin, begin + frameLength, header));
|
||||
begin += frameLength;
|
||||
}
|
||||
}
|
||||
|
||||
private ShareableBytes decompressFrame(ShareableBytes bytes, int begin, int end, Header header) throws CorruptLZ4Frame
|
||||
{
|
||||
ByteBuffer buf = bytes.get();
|
||||
|
||||
if (header.uncompressedLength == 0)
|
||||
return bytes.slice(begin + HEADER_LENGTH, end);
|
||||
|
||||
if (!header.isCompressed())
|
||||
{
|
||||
validateChecksum(buf, begin + HEADER_LENGTH, header);
|
||||
return bytes.slice(begin + HEADER_LENGTH, end);
|
||||
}
|
||||
|
||||
ByteBuffer out = allocator.get(header.uncompressedLength);
|
||||
try
|
||||
{
|
||||
int sourceLength = end - (begin + HEADER_LENGTH);
|
||||
decompressor.decompress(buf, begin + HEADER_LENGTH, sourceLength, out, 0, header.uncompressedLength);
|
||||
validateChecksum(out, 0, header);
|
||||
return ShareableBytes.wrap(out);
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
bufferPool.put(out);
|
||||
throw t;
|
||||
}
|
||||
}
|
||||
|
||||
private void validateChecksum(ByteBuffer buf, int begin, Header header) throws CorruptLZ4Frame
|
||||
{
|
||||
int checksum = xxhash.hash(buf, begin, header.uncompressedLength, XXHASH_SEED) & XXHASH_MASK;
|
||||
if (checksum != header.checksum)
|
||||
except("Invalid checksum detected: %d (expected: %d)", checksum, header.checksum);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelInactive(ChannelHandlerContext ctx)
|
||||
{
|
||||
if (null != stash)
|
||||
{
|
||||
bufferPool.put(stash);
|
||||
stash = null;
|
||||
}
|
||||
|
||||
while (!frames.isEmpty())
|
||||
frames.poll().release();
|
||||
|
||||
ctx.fireChannelInactive();
|
||||
}
|
||||
|
||||
/* reusable container for deserialized header fields */
|
||||
private static final class Header
|
||||
{
|
||||
long magicNumber;
|
||||
byte token;
|
||||
int compressedLength;
|
||||
int uncompressedLength;
|
||||
int checksum;
|
||||
|
||||
int frameLength()
|
||||
{
|
||||
return HEADER_LENGTH + compressedLength;
|
||||
}
|
||||
|
||||
boolean isCompressed()
|
||||
{
|
||||
return (token & 0xF0) == 0x20;
|
||||
}
|
||||
|
||||
int maxUncompressedLength()
|
||||
{
|
||||
return 1 << ((token & 0x0F) + 10);
|
||||
}
|
||||
|
||||
void read(ByteBuffer in, int begin)
|
||||
{
|
||||
magicNumber = in.getLong(begin + MAGIC_NUMBER_OFFSET );
|
||||
token = in.get (begin + TOKEN_OFFSET );
|
||||
compressedLength = reverseBytes(in.getInt (begin + COMPRESSED_LENGTH_OFFSET ));
|
||||
uncompressedLength = reverseBytes(in.getInt (begin + UNCOMPRESSED_LENGTH_OFFSET));
|
||||
checksum = reverseBytes(in.getInt (begin + CHECKSUM_OFFSET ));
|
||||
}
|
||||
|
||||
void validate() throws CorruptLZ4Frame
|
||||
{
|
||||
if (magicNumber != MAGIC_NUMBER)
|
||||
except("Invalid magic number at the beginning of an LZ4 block: %d", magicNumber);
|
||||
|
||||
int blockType = token & 0xF0;
|
||||
if (!(blockType == BLOCK_TYPE_COMPRESSED || blockType == BLOCK_TYPE_NON_COMPRESSED))
|
||||
except("Invalid block type encountered: %d", blockType);
|
||||
|
||||
if (compressedLength < 0 || compressedLength > MAX_BLOCK_LENGTH)
|
||||
except("Invalid compressedLength: %d (expected: 0-%d)", compressedLength, MAX_BLOCK_LENGTH);
|
||||
|
||||
if (uncompressedLength < 0 || uncompressedLength > maxUncompressedLength())
|
||||
except("Invalid uncompressedLength: %d (expected: 0-%d)", uncompressedLength, maxUncompressedLength());
|
||||
|
||||
if ( uncompressedLength == 0 && compressedLength != 0
|
||||
|| uncompressedLength != 0 && compressedLength == 0
|
||||
|| !isCompressed() && uncompressedLength != compressedLength)
|
||||
{
|
||||
except("Stream corrupted: compressedLength(%d) and decompressedLength(%d) mismatch", compressedLength, uncompressedLength);
|
||||
}
|
||||
}
|
||||
}
|
||||
private final Header header = new Header();
|
||||
|
||||
/**
|
||||
* @return {@code in} if has sufficient capacity, otherwise a replacement from {@code BufferPool} that {@code in} is copied into
|
||||
*/
|
||||
private ByteBuffer ensureCapacity(ByteBuffer in, int capacity)
|
||||
{
|
||||
if (in.capacity() >= capacity)
|
||||
return in;
|
||||
|
||||
ByteBuffer out = allocator.getAtLeast(capacity);
|
||||
in.flip();
|
||||
out.put(in);
|
||||
bufferPool.put(in);
|
||||
return out;
|
||||
}
|
||||
|
||||
private ByteBuffer stash;
|
||||
|
||||
private void stash(ShareableBytes in, int stashLength, int begin, int length)
|
||||
{
|
||||
ByteBuffer out = allocator.getAtLeast(stashLength);
|
||||
copyBytes(in.get(), begin, out, 0, length);
|
||||
out.position(length);
|
||||
stash = out;
|
||||
}
|
||||
|
||||
static final class CorruptLZ4Frame extends IOException
|
||||
{
|
||||
CorruptLZ4Frame(String message)
|
||||
{
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
|
||||
private static void except(String format, Object... args) throws CorruptLZ4Frame
|
||||
{
|
||||
throw new CorruptLZ4Frame(format(format, args));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
/*
|
||||
* 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.cassandra.net;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
|
||||
/**
|
||||
* A no-op frame encoder: legacy format doesn't support framing. Instead, the byte stream
|
||||
* contains messages, serialized back to back.
|
||||
*/
|
||||
@ChannelHandler.Sharable
|
||||
class FrameEncoderLegacy extends FrameEncoder
|
||||
{
|
||||
static final FrameEncoderLegacy instance = new FrameEncoderLegacy();
|
||||
|
||||
ByteBuf encode(boolean isSelfContained, ByteBuffer buffer)
|
||||
{
|
||||
return GlobalBufferPoolAllocator.wrap(buffer);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,136 +0,0 @@
|
|||
/*
|
||||
* 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.cassandra.net;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import net.jpountz.lz4.LZ4Compressor;
|
||||
import net.jpountz.lz4.LZ4Factory;
|
||||
import net.jpountz.xxhash.XXHash32;
|
||||
import net.jpountz.xxhash.XXHashFactory;
|
||||
import org.apache.cassandra.io.compress.BufferType;
|
||||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
|
||||
import static java.lang.Integer.reverseBytes;
|
||||
import static java.lang.Math.min;
|
||||
import static org.apache.cassandra.net.LegacyLZ4Constants.*;
|
||||
|
||||
/**
|
||||
* LZ4 {@link FrameEncoder} implementation for compressed legacy (3.0, 3.11) connections.
|
||||
*
|
||||
* Netty's provided implementation - {@link io.netty.handler.codec.compression.Lz4FrameEncoder} couldn't be reused
|
||||
* for two reasons:
|
||||
* 1. It notifies flushes as successful when they may not be, by flushing an empty buffer ahead
|
||||
* of the compressed buffer
|
||||
* 2. It has very poor performance when coupled with xxHash, which we use for legacy connections -
|
||||
* allocating a single-byte array and making a JNI call <em>for every byte of the payload</em>
|
||||
*
|
||||
* Please see {@link FrameDecoderLegacyLZ4} for the description of the on-wire format of the LZ4 blocks
|
||||
* used by this encoder.
|
||||
*/
|
||||
@ChannelHandler.Sharable
|
||||
class FrameEncoderLegacyLZ4 extends FrameEncoder
|
||||
{
|
||||
static final FrameEncoderLegacyLZ4 instance =
|
||||
new FrameEncoderLegacyLZ4(XXHashFactory.fastestInstance().hash32(),
|
||||
LZ4Factory.fastestInstance().fastCompressor());
|
||||
|
||||
private final XXHash32 xxhash;
|
||||
private final LZ4Compressor compressor;
|
||||
|
||||
private FrameEncoderLegacyLZ4(XXHash32 xxhash, LZ4Compressor compressor)
|
||||
{
|
||||
this.xxhash = xxhash;
|
||||
this.compressor = compressor;
|
||||
}
|
||||
|
||||
@Override
|
||||
ByteBuf encode(boolean isSelfContained, ByteBuffer payload)
|
||||
{
|
||||
ByteBuffer frame = null;
|
||||
try
|
||||
{
|
||||
frame = bufferPool.getAtLeast(calculateMaxFrameLength(payload), BufferType.OFF_HEAP);
|
||||
|
||||
int frameOffset = 0;
|
||||
int payloadOffset = 0;
|
||||
|
||||
int payloadLength = payload.remaining();
|
||||
while (payloadOffset < payloadLength)
|
||||
{
|
||||
int blockLength = min(DEFAULT_BLOCK_LENGTH, payloadLength - payloadOffset);
|
||||
frameOffset += compressBlock(frame, frameOffset, payload, payloadOffset, blockLength);
|
||||
payloadOffset += blockLength;
|
||||
}
|
||||
|
||||
frame.limit(frameOffset);
|
||||
bufferPool.putUnusedPortion(frame);
|
||||
|
||||
return GlobalBufferPoolAllocator.wrap(frame);
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
if (null != frame)
|
||||
bufferPool.put(frame);
|
||||
throw t;
|
||||
}
|
||||
finally
|
||||
{
|
||||
bufferPool.put(payload);
|
||||
}
|
||||
}
|
||||
|
||||
private int compressBlock(ByteBuffer frame, int frameOffset, ByteBuffer payload, int payloadOffset, int blockLength)
|
||||
{
|
||||
int frameBytesRemaining = frame.limit() - (frameOffset + HEADER_LENGTH);
|
||||
int compressedLength = compressor.compress(payload, payloadOffset, blockLength, frame, frameOffset + HEADER_LENGTH, frameBytesRemaining);
|
||||
if (compressedLength >= blockLength)
|
||||
{
|
||||
ByteBufferUtil.copyBytes(payload, payloadOffset, frame, frameOffset + HEADER_LENGTH, blockLength);
|
||||
compressedLength = blockLength;
|
||||
}
|
||||
int checksum = xxhash.hash(payload, payloadOffset, blockLength, XXHASH_SEED) & XXHASH_MASK;
|
||||
writeHeader(frame, frameOffset, compressedLength, blockLength, checksum);
|
||||
return HEADER_LENGTH + compressedLength;
|
||||
}
|
||||
|
||||
private static final byte TOKEN_NON_COMPRESSED = 0x15;
|
||||
private static final byte TOKEN_COMPRESSED = 0x25;
|
||||
|
||||
private static void writeHeader(ByteBuffer frame, int frameOffset, int compressedLength, int uncompressedLength, int checksum)
|
||||
{
|
||||
byte token = compressedLength == uncompressedLength
|
||||
? TOKEN_NON_COMPRESSED
|
||||
: TOKEN_COMPRESSED;
|
||||
|
||||
frame.putLong(frameOffset + MAGIC_NUMBER_OFFSET, MAGIC_NUMBER );
|
||||
frame.put (frameOffset + TOKEN_OFFSET, token );
|
||||
frame.putInt (frameOffset + COMPRESSED_LENGTH_OFFSET, reverseBytes(compressedLength) );
|
||||
frame.putInt (frameOffset + UNCOMPRESSED_LENGTH_OFFSET, reverseBytes(uncompressedLength));
|
||||
frame.putInt (frameOffset + CHECKSUM_OFFSET, reverseBytes(checksum) );
|
||||
}
|
||||
|
||||
private int calculateMaxFrameLength(ByteBuffer payload)
|
||||
{
|
||||
int payloadLength = payload.remaining();
|
||||
int blockCount = payloadLength / DEFAULT_BLOCK_LENGTH + (payloadLength % DEFAULT_BLOCK_LENGTH != 0 ? 1 : 0);
|
||||
return compressor.maxCompressedLength(payloadLength) + HEADER_LENGTH * blockCount;
|
||||
}
|
||||
}
|
||||
|
|
@ -22,21 +22,17 @@ import java.io.IOException;
|
|||
import java.nio.ByteBuffer;
|
||||
import java.util.Objects;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufAllocator;
|
||||
import org.apache.cassandra.config.DatabaseDescriptor;
|
||||
import org.apache.cassandra.io.compress.BufferType;
|
||||
import org.apache.cassandra.io.util.DataInputBuffer;
|
||||
import org.apache.cassandra.io.util.DataInputPlus;
|
||||
import org.apache.cassandra.io.util.DataOutputBufferFixed;
|
||||
import org.apache.cassandra.locator.InetAddressAndPort;
|
||||
import org.apache.cassandra.utils.memory.BufferPools;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||
import static org.apache.cassandra.locator.InetAddressAndPort.Serializer.inetAddressAndPortSerializer;
|
||||
import static org.apache.cassandra.net.MessagingService.VERSION_30;
|
||||
import static org.apache.cassandra.net.MessagingService.VERSION_40;
|
||||
import static org.apache.cassandra.net.Message.validateLegacyProtocolMagic;
|
||||
import static org.apache.cassandra.net.Crc.*;
|
||||
|
|
@ -52,8 +48,7 @@ import static org.apache.cassandra.net.OutboundConnectionSettings.*;
|
|||
* it will simply disconnect and reconnect with a more appropriate version. But if the version is acceptable, the connection
|
||||
* initiator sends the third message of the protocol, after which it considers the connection ready.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
public class HandshakeProtocol
|
||||
class HandshakeProtocol
|
||||
{
|
||||
static final long TIMEOUT_MILLIS = 3 * DatabaseDescriptor.getRpcTimeout(MILLISECONDS);
|
||||
|
||||
|
|
@ -94,8 +89,6 @@ public class HandshakeProtocol
|
|||
private static final int MIN_LENGTH = 8;
|
||||
private static final int MAX_LENGTH = 12 + InetAddressAndPort.Serializer.MAXIMUM_SIZE;
|
||||
|
||||
@Deprecated // this is ignored by post40 nodes, i.e. if maxMessagingVersion is set
|
||||
final int requestMessagingVersion;
|
||||
// the messagingVersion bounds the sender will accept to initiate a connection;
|
||||
// if the remote peer supports any, the newest supported version will be selected; otherwise the nearest supported version
|
||||
final AcceptVersions acceptVersions;
|
||||
|
|
@ -103,17 +96,15 @@ public class HandshakeProtocol
|
|||
final Framing framing;
|
||||
final InetAddressAndPort from;
|
||||
|
||||
Initiate(int requestMessagingVersion, AcceptVersions acceptVersions, ConnectionType type, Framing framing, InetAddressAndPort from)
|
||||
Initiate(AcceptVersions acceptVersions, ConnectionType type, Framing framing, InetAddressAndPort from)
|
||||
{
|
||||
this.requestMessagingVersion = requestMessagingVersion;
|
||||
this.acceptVersions = acceptVersions;
|
||||
this.type = type;
|
||||
this.framing = framing;
|
||||
this.from = from;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
int encodeFlags()
|
||||
private int encodeFlags()
|
||||
{
|
||||
int flags = 0;
|
||||
if (type.isMessaging())
|
||||
|
|
@ -123,11 +114,7 @@ public class HandshakeProtocol
|
|||
|
||||
// framing id is split over 2nd and 4th bits, for backwards compatibility
|
||||
flags |= ((framing.id & 1) << 2) | ((framing.id & 2) << 3);
|
||||
flags |= (requestMessagingVersion << 8);
|
||||
|
||||
if (requestMessagingVersion < VERSION_40 || acceptVersions.max < VERSION_40)
|
||||
return flags; // for testing, permit serializing as though we are pre40
|
||||
|
||||
flags |= (acceptVersions.min << 8); // legacy (pre40)
|
||||
flags |= (acceptVersions.min << 16);
|
||||
flags |= (acceptVersions.max << 24);
|
||||
return flags;
|
||||
|
|
@ -140,12 +127,8 @@ public class HandshakeProtocol
|
|||
{
|
||||
out.writeInt(Message.PROTOCOL_MAGIC);
|
||||
out.writeInt(encodeFlags());
|
||||
|
||||
if (requestMessagingVersion >= VERSION_40 && acceptVersions.max >= VERSION_40)
|
||||
{
|
||||
inetAddressAndPortSerializer.serialize(from, out, requestMessagingVersion);
|
||||
out.writeInt(computeCrc32(buffer, 0, buffer.position()));
|
||||
}
|
||||
inetAddressAndPortSerializer.serialize(from, out, acceptVersions.min);
|
||||
out.writeInt(computeCrc32(buffer, 0, buffer.position()));
|
||||
buffer.flip();
|
||||
return GlobalBufferPoolAllocator.wrap(buffer);
|
||||
}
|
||||
|
|
@ -167,9 +150,17 @@ public class HandshakeProtocol
|
|||
validateLegacyProtocolMagic(in.readInt());
|
||||
int flags = in.readInt();
|
||||
|
||||
int requestedMessagingVersion = getBits(flags, 8, 8);
|
||||
// legacy pre40 messagingVersion flag
|
||||
if (getBits(flags, 8, 8) < VERSION_40)
|
||||
return null;
|
||||
|
||||
int minMessagingVersion = getBits(flags, 16, 8);
|
||||
int maxMessagingVersion = getBits(flags, 24, 8);
|
||||
|
||||
// 5.0+ does not support pre40
|
||||
if (maxMessagingVersion < MessagingService.VERSION_40)
|
||||
return null;
|
||||
|
||||
int framingBits = getBits(flags, 2, 1) | (getBits(flags, 4, 1) << 1);
|
||||
Framing framing = Framing.forId(framingBits);
|
||||
|
||||
|
|
@ -179,23 +170,15 @@ public class HandshakeProtocol
|
|||
? ConnectionType.STREAMING
|
||||
: ConnectionType.fromId(getBits(flags, 0, 2));
|
||||
|
||||
InetAddressAndPort from = null;
|
||||
InetAddressAndPort from = inetAddressAndPortSerializer.deserialize(in, minMessagingVersion);
|
||||
|
||||
if (requestedMessagingVersion >= VERSION_40 && maxMessagingVersion >= MessagingService.VERSION_40)
|
||||
{
|
||||
from = inetAddressAndPortSerializer.deserialize(in, requestedMessagingVersion);
|
||||
|
||||
int computed = computeCrc32(nio, start, nio.position());
|
||||
int read = in.readInt();
|
||||
if (read != computed)
|
||||
throw new InvalidCrc(read, computed);
|
||||
}
|
||||
int computed = computeCrc32(nio, start, nio.position());
|
||||
int read = in.readInt();
|
||||
if (read != computed)
|
||||
throw new InvalidCrc(read, computed);
|
||||
|
||||
buf.skipBytes(nio.position() - start);
|
||||
return new Initiate(requestedMessagingVersion,
|
||||
minMessagingVersion == 0 && maxMessagingVersion == 0
|
||||
? null : new AcceptVersions(minMessagingVersion, maxMessagingVersion),
|
||||
type, framing, from);
|
||||
return new Initiate(new AcceptVersions(minMessagingVersion, maxMessagingVersion), type, framing, from);
|
||||
|
||||
}
|
||||
catch (EOFException e)
|
||||
|
|
@ -204,7 +187,6 @@ public class HandshakeProtocol
|
|||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
@Override
|
||||
public boolean equals(Object other)
|
||||
{
|
||||
|
|
@ -214,17 +196,15 @@ public class HandshakeProtocol
|
|||
Initiate that = (Initiate)other;
|
||||
return this.type == that.type
|
||||
&& this.framing == that.framing
|
||||
&& this.requestMessagingVersion == that.requestMessagingVersion
|
||||
&& Objects.equals(this.acceptVersions, that.acceptVersions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return String.format("Initiate(request: %d, min: %d, max: %d, type: %s, framing: %b, from: %s)",
|
||||
requestMessagingVersion,
|
||||
acceptVersions == null ? requestMessagingVersion : acceptVersions.min,
|
||||
acceptVersions == null ? requestMessagingVersion : acceptVersions.max,
|
||||
return String.format("Initiate(min: %d, max: %d, type: %s, framing: %b, from: %s)",
|
||||
acceptVersions.min,
|
||||
acceptVersions.max,
|
||||
type, framing, from);
|
||||
}
|
||||
}
|
||||
|
|
@ -238,9 +218,8 @@ public class HandshakeProtocol
|
|||
* 1) the messaging version of the peer sending this message
|
||||
* 2) the negotiated messaging version if one could be accepted by both peers,
|
||||
* or if not the closest version that this peer could support to the ones requested
|
||||
* 3) a CRC protectingn the integrity of the message
|
||||
* 3) a CRC protecting the integrity of the message
|
||||
*
|
||||
* Note that the pre40 equivalent of this message contains ONLY the messaging version of the peer.
|
||||
*/
|
||||
static class Accept
|
||||
{
|
||||
|
|
@ -266,18 +245,7 @@ public class HandshakeProtocol
|
|||
return buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Respond to pre40 nodes only with our current messagingVersion
|
||||
*/
|
||||
static ByteBuf respondPre40(int messagingVersion, ByteBufAllocator allocator)
|
||||
{
|
||||
ByteBuf buffer = allocator.directBuffer(4);
|
||||
buffer.clear();
|
||||
buffer.writeInt(messagingVersion);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static Accept maybeDecode(ByteBuf in, int handshakeMessagingVersion) throws InvalidCrc
|
||||
static Accept maybeDecode(ByteBuf in) throws InvalidCrc
|
||||
{
|
||||
int readerIndex = in.readerIndex();
|
||||
if (in.readableBytes() < 4)
|
||||
|
|
@ -285,9 +253,9 @@ public class HandshakeProtocol
|
|||
int maxMessagingVersion = in.readInt();
|
||||
int useMessagingVersion = 0;
|
||||
|
||||
// if the other node is pre-4.0, it will respond only with its maxMessagingVersion
|
||||
if (maxMessagingVersion < VERSION_40 || handshakeMessagingVersion < VERSION_40)
|
||||
return new Accept(useMessagingVersion, maxMessagingVersion);
|
||||
// pre-4.0 not supported, close the connection
|
||||
if (maxMessagingVersion < VERSION_40)
|
||||
return null;
|
||||
|
||||
if (in.readableBytes() < 8)
|
||||
{
|
||||
|
|
@ -305,7 +273,6 @@ public class HandshakeProtocol
|
|||
return new Accept(useMessagingVersion, maxMessagingVersion);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
@Override
|
||||
public boolean equals(Object other)
|
||||
{
|
||||
|
|
@ -321,91 +288,6 @@ public class HandshakeProtocol
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The third message of the handshake, sent by pre40 nodes on reception of {@link Accept}.
|
||||
* This message contains:
|
||||
* 1) The connection initiator's {@link org.apache.cassandra.net.MessagingService#current_version} (4 bytes).
|
||||
* This indicates the max messaging version supported by this node.
|
||||
* 2) The connection initiator's broadcast address as encoded by {@link InetAddressAndPort.Serializer}.
|
||||
* This can be either 7 bytes for an IPv4 address, or 19 bytes for an IPv6 one, post40.
|
||||
* This can be either 5 bytes for an IPv4 address, or 17 bytes for an IPv6 one, pre40.
|
||||
* <p>
|
||||
* This message concludes the legacy handshake protocol.
|
||||
*/
|
||||
static class ConfirmOutboundPre40
|
||||
{
|
||||
private static final int MAX_LENGTH = 4 + InetAddressAndPort.Serializer.MAXIMUM_SIZE;
|
||||
|
||||
final int maxMessagingVersion;
|
||||
final InetAddressAndPort from;
|
||||
|
||||
ConfirmOutboundPre40(int maxMessagingVersion, InetAddressAndPort from)
|
||||
{
|
||||
this.maxMessagingVersion = maxMessagingVersion;
|
||||
this.from = from;
|
||||
}
|
||||
|
||||
ByteBuf encode()
|
||||
{
|
||||
ByteBuffer buffer = BufferPools.forNetworking().get(MAX_LENGTH, BufferType.OFF_HEAP);
|
||||
try (DataOutputBufferFixed out = new DataOutputBufferFixed(buffer))
|
||||
{
|
||||
out.writeInt(maxMessagingVersion);
|
||||
// pre-4.0 nodes should only receive the address, never port, and it's ok to hardcode VERSION_30
|
||||
inetAddressAndPortSerializer.serialize(from, out, VERSION_30);
|
||||
buffer.flip();
|
||||
return GlobalBufferPoolAllocator.wrap(buffer);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("resource")
|
||||
static ConfirmOutboundPre40 maybeDecode(ByteBuf in)
|
||||
{
|
||||
ByteBuffer nio = in.nioBuffer();
|
||||
int start = nio.position();
|
||||
DataInputPlus input = new DataInputBuffer(nio, false);
|
||||
try
|
||||
{
|
||||
int version = input.readInt();
|
||||
InetAddressAndPort address = inetAddressAndPortSerializer.deserialize(input, version);
|
||||
in.skipBytes(nio.position() - start);
|
||||
return new ConfirmOutboundPre40(version, address);
|
||||
}
|
||||
catch (EOFException e)
|
||||
{
|
||||
// makes the assumption we didn't have enough bytes to deserialize an IPv6 address,
|
||||
// as we only check the MIN_LENGTH of the buf.
|
||||
return null;
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
@Override
|
||||
public boolean equals(Object other)
|
||||
{
|
||||
if (!(other instanceof ConfirmOutboundPre40))
|
||||
return false;
|
||||
|
||||
ConfirmOutboundPre40 that = (ConfirmOutboundPre40) other;
|
||||
return this.maxMessagingVersion == that.maxMessagingVersion
|
||||
&& Objects.equals(this.from, that.from);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return String.format("ConfirmOutboundPre40(maxMessagingVersion: %d; address: %s)", maxMessagingVersion, from);
|
||||
}
|
||||
}
|
||||
|
||||
private static int getBits(int packed, int start, int count)
|
||||
{
|
||||
return (packed >>> start) & ~(-1 << count);
|
||||
|
|
|
|||
|
|
@ -273,7 +273,6 @@ public class InboundConnectionInitiator
|
|||
private final InboundConnectionSettings settings;
|
||||
|
||||
private HandshakeProtocol.Initiate initiate;
|
||||
private HandshakeProtocol.ConfirmOutboundPre40 confirmOutboundPre40;
|
||||
|
||||
/**
|
||||
* A future the essentially places a timeout on how long we'll wait for the peer
|
||||
|
|
@ -301,7 +300,6 @@ public class InboundConnectionInitiator
|
|||
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception
|
||||
{
|
||||
if (initiate == null) initiate(ctx, in);
|
||||
else if (initiate.acceptVersions == null && confirmOutboundPre40 == null) confirmPre40(ctx, in);
|
||||
else throw new IllegalStateException("Should no longer be on pipeline");
|
||||
}
|
||||
|
||||
|
|
@ -321,78 +319,40 @@ public class InboundConnectionInitiator
|
|||
return;
|
||||
}
|
||||
|
||||
if (initiate.acceptVersions != null)
|
||||
assert initiate.acceptVersions != null;
|
||||
logger.trace("Connection version {} (min {}) from {}", initiate.acceptVersions.max, initiate.acceptVersions.min, initiate.from);
|
||||
|
||||
final AcceptVersions accept;
|
||||
|
||||
if (initiate.type.isStreaming())
|
||||
accept = settings.acceptStreaming;
|
||||
else
|
||||
accept = settings.acceptMessaging;
|
||||
|
||||
int useMessagingVersion = max(accept.min, min(accept.max, initiate.acceptVersions.max));
|
||||
ByteBuf flush = new HandshakeProtocol.Accept(useMessagingVersion, accept.max).encode(ctx.alloc());
|
||||
|
||||
AsyncChannelPromise.writeAndFlush(ctx, flush, (ChannelFutureListener) future -> {
|
||||
if (!future.isSuccess())
|
||||
exceptionCaught(future.channel(), future.cause());
|
||||
});
|
||||
|
||||
if (initiate.acceptVersions.min > accept.max)
|
||||
{
|
||||
logger.trace("Connection version {} (min {}) from {}", initiate.acceptVersions.max, initiate.acceptVersions.min, initiate.from);
|
||||
|
||||
final AcceptVersions accept;
|
||||
|
||||
if (initiate.type.isStreaming())
|
||||
accept = settings.acceptStreaming;
|
||||
else
|
||||
accept = settings.acceptMessaging;
|
||||
|
||||
int useMessagingVersion = max(accept.min, min(accept.max, initiate.acceptVersions.max));
|
||||
ByteBuf flush = new HandshakeProtocol.Accept(useMessagingVersion, accept.max).encode(ctx.alloc());
|
||||
|
||||
AsyncChannelPromise.writeAndFlush(ctx, flush, (ChannelFutureListener) future -> {
|
||||
if (!future.isSuccess())
|
||||
exceptionCaught(future.channel(), future.cause());
|
||||
});
|
||||
|
||||
if (initiate.acceptVersions.min > accept.max)
|
||||
{
|
||||
logger.info("peer {} only supports messaging versions higher ({}) than this node supports ({})", ctx.channel().remoteAddress(), initiate.acceptVersions.min, current_version);
|
||||
failHandshake(ctx);
|
||||
return;
|
||||
}
|
||||
else if (initiate.acceptVersions.max < accept.min)
|
||||
{
|
||||
logger.info("peer {} only supports messaging versions lower ({}) than this node supports ({})", ctx.channel().remoteAddress(), initiate.acceptVersions.max, minimum_version);
|
||||
failHandshake(ctx);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (initiate.type.isStreaming())
|
||||
setupStreamingPipeline(initiate.from, ctx);
|
||||
else
|
||||
setupMessagingPipeline(initiate.from, useMessagingVersion, initiate.acceptVersions.max, ctx.pipeline());
|
||||
}
|
||||
logger.info("peer {} only supports messaging versions higher ({}) than this node supports ({})", ctx.channel().remoteAddress(), initiate.acceptVersions.min, current_version);
|
||||
failHandshake(ctx);
|
||||
}
|
||||
else if (initiate.acceptVersions.max < accept.min)
|
||||
{
|
||||
logger.info("peer {} only supports messaging versions lower ({}) than this node supports ({})", ctx.channel().remoteAddress(), initiate.acceptVersions.max, minimum_version);
|
||||
failHandshake(ctx);
|
||||
}
|
||||
else
|
||||
{
|
||||
int version = initiate.requestMessagingVersion;
|
||||
assert version < VERSION_40 && version >= settings.acceptMessaging.min;
|
||||
logger.trace("Connection version {} from {}", version, ctx.channel().remoteAddress());
|
||||
|
||||
if (initiate.type.isStreaming())
|
||||
{
|
||||
// streaming connections are per-session and have a fixed version. we can't do anything with a wrong-version stream connection, so drop it.
|
||||
if (version != settings.acceptStreaming.max)
|
||||
{
|
||||
logger.warn("Received stream using protocol version {} (my version {}). Terminating connection", version, settings.acceptStreaming.max);
|
||||
failHandshake(ctx);
|
||||
return;
|
||||
}
|
||||
setupStreamingPipeline(initiate.from, ctx);
|
||||
}
|
||||
else
|
||||
{
|
||||
// if this version is < the MS version the other node is trying
|
||||
// to connect with, the other node will disconnect
|
||||
ByteBuf response = HandshakeProtocol.Accept.respondPre40(settings.acceptMessaging.max, ctx.alloc());
|
||||
AsyncChannelPromise.writeAndFlush(ctx, response,
|
||||
(ChannelFutureListener) future -> {
|
||||
if (!future.isSuccess())
|
||||
exceptionCaught(future.channel(), future.cause());
|
||||
});
|
||||
|
||||
if (version < VERSION_30)
|
||||
throw new IOException(String.format("Unable to read obsolete message version %s from %s; The earliest version supported is 3.0.0", version, ctx.channel().remoteAddress()));
|
||||
|
||||
// we don't setup the messaging pipeline here, as the legacy messaging handshake requires one more message to finish
|
||||
}
|
||||
setupMessagingPipeline(initiate.from, useMessagingVersion, initiate.acceptVersions.max, ctx.pipeline());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -406,21 +366,6 @@ public class InboundConnectionInitiator
|
|||
return ctx.pipeline().get(SslHandler.class) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the third (and last) message in the internode messaging handshake protocol for pre40 nodes.
|
||||
* Grabs the protocol version and IP addr the peer wants to use.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
void confirmPre40(ChannelHandlerContext ctx, ByteBuf in)
|
||||
{
|
||||
confirmOutboundPre40 = HandshakeProtocol.ConfirmOutboundPre40.maybeDecode(in);
|
||||
if (confirmOutboundPre40 == null)
|
||||
return;
|
||||
|
||||
logger.trace("Received third handshake message from peer {}, message = {}", ctx.channel().remoteAddress(), confirmOutboundPre40);
|
||||
setupMessagingPipeline(confirmOutboundPre40.from, initiate.requestMessagingVersion, confirmOutboundPre40.maxMessagingVersion, ctx.pipeline());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
|
||||
{
|
||||
|
|
@ -494,8 +439,7 @@ public class InboundConnectionInitiator
|
|||
// we can't infer the type of streaming connection at this point,
|
||||
// so we use CONTROL unconditionally; it's ugly but does what we want
|
||||
// (establishes an AsyncStreamingInputPlus)
|
||||
NettyStreamingChannel streamingChannel =
|
||||
new NettyStreamingChannel(current_version, channel, StreamingChannel.Kind.CONTROL);
|
||||
NettyStreamingChannel streamingChannel = new NettyStreamingChannel(channel, StreamingChannel.Kind.CONTROL);
|
||||
pipeline.replace(this, "streamInbound", streamingChannel);
|
||||
executorFactory().startThread(String.format("Stream-Deserializer-%s-%s", from, channel.id()),
|
||||
new StreamDeserializingTask(null, streamingChannel, current_version));
|
||||
|
|
@ -533,26 +477,17 @@ public class InboundConnectionInitiator
|
|||
{
|
||||
case LZ4:
|
||||
{
|
||||
if (useMessagingVersion >= VERSION_40)
|
||||
frameDecoder = FrameDecoderLZ4.fast(allocator);
|
||||
else
|
||||
frameDecoder = new FrameDecoderLegacyLZ4(allocator, useMessagingVersion);
|
||||
frameDecoder = FrameDecoderLZ4.fast(allocator);
|
||||
break;
|
||||
}
|
||||
case CRC:
|
||||
{
|
||||
if (useMessagingVersion >= VERSION_40)
|
||||
{
|
||||
frameDecoder = FrameDecoderCrc.create(allocator);
|
||||
break;
|
||||
}
|
||||
frameDecoder = FrameDecoderCrc.create(allocator);
|
||||
break;
|
||||
}
|
||||
case UNPROTECTED:
|
||||
{
|
||||
if (useMessagingVersion >= VERSION_40)
|
||||
frameDecoder = new FrameDecoderUnprotected(allocator);
|
||||
else
|
||||
frameDecoder = new FrameDecoderLegacy(allocator, useMessagingVersion);
|
||||
frameDecoder = new FrameDecoderUnprotected(allocator);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -125,7 +125,7 @@ public class InboundMessageHandler extends AbstractMessageHandler
|
|||
long currentTimeNanos = approxTime.now();
|
||||
Header header = serializer.extractHeader(buf, peer, currentTimeNanos, version);
|
||||
long timeElapsed = currentTimeNanos - header.createdAtNanos;
|
||||
int size = serializer.inferMessageSize(buf, buf.position(), buf.limit(), version);
|
||||
int size = serializer.inferMessageSize(buf, buf.position(), buf.limit());
|
||||
|
||||
if (approxTime.isAfter(currentTimeNanos, header.expiresAtNanos))
|
||||
{
|
||||
|
|
@ -211,7 +211,7 @@ public class InboundMessageHandler extends AbstractMessageHandler
|
|||
|
||||
long currentTimeNanos = approxTime.now();
|
||||
Header header = serializer.extractHeader(buf, peer, currentTimeNanos, version);
|
||||
int size = serializer.inferMessageSize(buf, buf.position(), buf.limit(), version);
|
||||
int size = serializer.inferMessageSize(buf, buf.position(), buf.limit());
|
||||
|
||||
boolean expired = approxTime.isAfter(currentTimeNanos, header.expiresAtNanos);
|
||||
if (!expired && !acquireCapacity(endpointReserve, globalReserve, size, currentTimeNanos, header.expiresAtNanos))
|
||||
|
|
|
|||
|
|
@ -1,65 +0,0 @@
|
|||
/*
|
||||
* 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.cassandra.net;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
import org.apache.cassandra.io.IVersionedSerializer;
|
||||
import org.apache.cassandra.io.util.DataInputPlus;
|
||||
import org.apache.cassandra.io.util.DataOutputPlus;
|
||||
|
||||
/**
|
||||
* Before 4.0 introduced flags field to {@link Message}, we used to encode flags in params field,
|
||||
* using a dummy value (single byte set to 0). From now on, {@link MessageFlag} should be extended
|
||||
* instead.
|
||||
*
|
||||
* Once 3.0/3.11 compatibility is phased out, this class should be removed.
|
||||
*/
|
||||
@Deprecated
|
||||
final class LegacyFlag
|
||||
{
|
||||
static final LegacyFlag instance = new LegacyFlag();
|
||||
|
||||
private LegacyFlag()
|
||||
{
|
||||
}
|
||||
|
||||
static IVersionedSerializer<LegacyFlag> serializer = new IVersionedSerializer<LegacyFlag>()
|
||||
{
|
||||
public void serialize(LegacyFlag param, DataOutputPlus out, int version) throws IOException
|
||||
{
|
||||
Preconditions.checkArgument(param == instance);
|
||||
out.write(0);
|
||||
}
|
||||
|
||||
public LegacyFlag deserialize(DataInputPlus in, int version) throws IOException
|
||||
{
|
||||
byte b = in.readByte();
|
||||
assert b == 0;
|
||||
return instance;
|
||||
}
|
||||
|
||||
public long serializedSize(LegacyFlag param, int version)
|
||||
{
|
||||
Preconditions.checkArgument(param == instance);
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -1,54 +0,0 @@
|
|||
/*
|
||||
* 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.cassandra.net;
|
||||
|
||||
abstract class LegacyLZ4Constants
|
||||
{
|
||||
static final int XXHASH_SEED = 0x9747B28C;
|
||||
|
||||
static final int HEADER_LENGTH = 8 // magic number
|
||||
+ 1 // token
|
||||
+ 4 // compressed length
|
||||
+ 4 // uncompressed length
|
||||
+ 4; // checksum
|
||||
|
||||
static final long MAGIC_NUMBER = (long) 'L' << 56
|
||||
| (long) 'Z' << 48
|
||||
| (long) '4' << 40
|
||||
| (long) 'B' << 32
|
||||
| 'l' << 24
|
||||
| 'o' << 16
|
||||
| 'c' << 8
|
||||
| 'k';
|
||||
|
||||
// offsets of header fields
|
||||
static final int MAGIC_NUMBER_OFFSET = 0;
|
||||
static final int TOKEN_OFFSET = 8;
|
||||
static final int COMPRESSED_LENGTH_OFFSET = 9;
|
||||
static final int UNCOMPRESSED_LENGTH_OFFSET = 13;
|
||||
static final int CHECKSUM_OFFSET = 17;
|
||||
|
||||
static final int DEFAULT_BLOCK_LENGTH = 1 << 15; // 32 KiB
|
||||
static final int MAX_BLOCK_LENGTH = 1 << 25; // 32 MiB
|
||||
|
||||
static final int BLOCK_TYPE_NON_COMPRESSED = 0x10;
|
||||
static final int BLOCK_TYPE_COMPRESSED = 0x20;
|
||||
|
||||
// xxhash to Checksum adapter discards most significant nibble of value ¯\_(ツ)_/¯
|
||||
static final int XXHASH_MASK = 0xFFFFFFF;
|
||||
}
|
||||
|
|
@ -50,12 +50,8 @@ import static java.util.concurrent.TimeUnit.MINUTES;
|
|||
import static java.util.concurrent.TimeUnit.NANOSECONDS;
|
||||
import static org.apache.cassandra.db.TypeSizes.sizeof;
|
||||
import static org.apache.cassandra.db.TypeSizes.sizeofUnsignedVInt;
|
||||
import static org.apache.cassandra.locator.InetAddressAndPort.Serializer.inetAddressAndPortSerializer;
|
||||
import static org.apache.cassandra.net.MessagingService.VERSION_3014;
|
||||
import static org.apache.cassandra.net.MessagingService.VERSION_30;
|
||||
import static org.apache.cassandra.net.MessagingService.VERSION_40;
|
||||
import static org.apache.cassandra.net.MessagingService.VERSION_50;
|
||||
import static org.apache.cassandra.net.MessagingService.instance;
|
||||
import static org.apache.cassandra.utils.FBUtilities.getBroadcastAddressAndPort;
|
||||
import static org.apache.cassandra.utils.MonotonicClock.Global.approxTime;
|
||||
import static org.apache.cassandra.utils.vint.VIntCoding.*;
|
||||
|
|
@ -711,15 +707,17 @@ public class Message<T>
|
|||
|
||||
public <T> void serialize(Message<T> message, DataOutputPlus out, int version) throws IOException
|
||||
{
|
||||
if (version >= VERSION_40)
|
||||
serializePost40(message, out, version);
|
||||
else
|
||||
serializePre40(message, out, version);
|
||||
serializeHeader(message.header, out, version);
|
||||
out.writeUnsignedVInt32(message.payloadSize(version));
|
||||
message.verb().serializer().serialize(message.payload, out, version);
|
||||
}
|
||||
|
||||
public <T> Message<T> deserialize(DataInputPlus in, InetAddressAndPort peer, int version) throws IOException
|
||||
{
|
||||
return version >= VERSION_40 ? deserializePost40(in, peer, version) : deserializePre40(in, version);
|
||||
Header header = deserializeHeader(in, peer, version);
|
||||
skipUnsignedVInt(in); // payload size, not needed by payload deserializer
|
||||
T payload = (T) header.verb.serializer().deserialize(in, version);
|
||||
return new Message<>(header, payload);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -729,20 +727,64 @@ public class Message<T>
|
|||
*/
|
||||
public <T> Message<T> deserialize(DataInputPlus in, Header header, int version) throws IOException
|
||||
{
|
||||
return version >= VERSION_40 ? deserializePost40(in, header, version) : deserializePre40(in, header, version);
|
||||
skipHeader(in);
|
||||
skipUnsignedVInt(in); // payload size, not needed by payload deserializer
|
||||
T payload = (T) header.verb.serializer().deserialize(in, version);
|
||||
return new Message<>(header, payload);
|
||||
}
|
||||
|
||||
private <T> int serializedSize(Message<T> message, int version)
|
||||
{
|
||||
return version >= VERSION_40 ? serializedSizePost40(message, version) : serializedSizePre40(message, version);
|
||||
long size = 0;
|
||||
size += serializedHeader(message.header, version);
|
||||
int payloadSize = message.payloadSize(version);
|
||||
size += sizeofUnsignedVInt(payloadSize) + payloadSize;
|
||||
return Ints.checkedCast(size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Size of the next message in the stream. Returns -1 if there aren't sufficient bytes read yet to determine size.
|
||||
*/
|
||||
int inferMessageSize(ByteBuffer buf, int index, int limit, int version) throws InvalidLegacyProtocolMagic
|
||||
int inferMessageSize(ByteBuffer buf, int readerIndex, int readerLimit)
|
||||
{
|
||||
int size = version >= VERSION_40 ? inferMessageSizePost40(buf, index, limit) : inferMessageSizePre40(buf, index, limit);
|
||||
int index = readerIndex;
|
||||
|
||||
int idSize = computeUnsignedVIntSize(buf, index, readerLimit);
|
||||
if (idSize < 0)
|
||||
return -1; // not enough bytes to read id
|
||||
index += idSize;
|
||||
|
||||
index += CREATION_TIME_SIZE;
|
||||
if (index > readerLimit)
|
||||
return -1;
|
||||
|
||||
int expirationSize = computeUnsignedVIntSize(buf, index, readerLimit);
|
||||
if (expirationSize < 0)
|
||||
return -1;
|
||||
index += expirationSize;
|
||||
|
||||
int verbIdSize = computeUnsignedVIntSize(buf, index, readerLimit);
|
||||
if (verbIdSize < 0)
|
||||
return -1;
|
||||
index += verbIdSize;
|
||||
|
||||
int flagsSize = computeUnsignedVIntSize(buf, index, readerLimit);
|
||||
if (flagsSize < 0)
|
||||
return -1;
|
||||
index += flagsSize;
|
||||
|
||||
int paramsSize = extractParamsSize(buf, index, readerLimit);
|
||||
if (paramsSize < 0)
|
||||
return -1;
|
||||
index += paramsSize;
|
||||
|
||||
long payloadSize = getUnsignedVInt(buf, index, readerLimit);
|
||||
if (payloadSize < 0)
|
||||
return -1;
|
||||
index += computeUnsignedVIntSize(payloadSize) + payloadSize;
|
||||
|
||||
int size = index - readerIndex;
|
||||
|
||||
if (size > DatabaseDescriptor.getInternodeMaxMessageSizeInBytes())
|
||||
throw new OversizedMessageException(size);
|
||||
return size;
|
||||
|
|
@ -757,71 +799,6 @@ public class Message<T>
|
|||
* It's assumed that the provided buffer contains all the bytes necessary to deserialize the header fully.
|
||||
*/
|
||||
Header extractHeader(ByteBuffer buf, InetAddressAndPort from, long currentTimeNanos, int version) throws IOException
|
||||
{
|
||||
return version >= VERSION_40
|
||||
? extractHeaderPost40(buf, from, currentTimeNanos, version)
|
||||
: extractHeaderPre40(buf, currentTimeNanos, version);
|
||||
}
|
||||
|
||||
private static long getExpiresAtNanos(long createdAtNanos, long currentTimeNanos, long expirationPeriodNanos)
|
||||
{
|
||||
if (!DatabaseDescriptor.hasCrossNodeTimeout() || createdAtNanos > currentTimeNanos)
|
||||
createdAtNanos = currentTimeNanos;
|
||||
return createdAtNanos + expirationPeriodNanos;
|
||||
}
|
||||
|
||||
/*
|
||||
* 4.0 ser/deser
|
||||
*/
|
||||
|
||||
private void serializeHeaderPost40(Header header, DataOutputPlus out, int version) throws IOException
|
||||
{
|
||||
out.writeUnsignedVInt(header.id);
|
||||
// int cast cuts off the high-order half of the timestamp, which we can assume remains
|
||||
// the same between now and when the recipient reconstructs it.
|
||||
out.writeInt((int) approxTime.translate().toMillisSinceEpoch(header.createdAtNanos));
|
||||
out.writeUnsignedVInt(NANOSECONDS.toMillis(header.expiresAtNanos - header.createdAtNanos));
|
||||
out.writeUnsignedVInt32(header.verb.id);
|
||||
out.writeUnsignedVInt32(header.flags);
|
||||
serializeParams(header.params, out, version);
|
||||
}
|
||||
|
||||
private Header deserializeHeaderPost40(DataInputPlus in, InetAddressAndPort peer, int version) throws IOException
|
||||
{
|
||||
long id = in.readUnsignedVInt();
|
||||
long currentTimeNanos = approxTime.now();
|
||||
MonotonicClockTranslation timeSnapshot = approxTime.translate();
|
||||
long creationTimeNanos = calculateCreationTimeNanos(in.readInt(), timeSnapshot, currentTimeNanos);
|
||||
long expiresAtNanos = getExpiresAtNanos(creationTimeNanos, currentTimeNanos, TimeUnit.MILLISECONDS.toNanos(in.readUnsignedVInt()));
|
||||
Verb verb = Verb.fromId(in.readUnsignedVInt32());
|
||||
int flags = in.readUnsignedVInt32();
|
||||
Map<ParamType, Object> params = deserializeParams(in, version);
|
||||
return new Header(id, verb, peer, creationTimeNanos, expiresAtNanos, flags, params);
|
||||
}
|
||||
|
||||
private void skipHeaderPost40(DataInputPlus in) throws IOException
|
||||
{
|
||||
skipUnsignedVInt(in); // id
|
||||
in.skipBytesFully(4); // createdAt
|
||||
skipUnsignedVInt(in); // expiresIn
|
||||
skipUnsignedVInt(in); // verb
|
||||
skipUnsignedVInt(in); // flags
|
||||
skipParamsPost40(in); // params
|
||||
}
|
||||
|
||||
private int serializedHeaderSizePost40(Header header, int version)
|
||||
{
|
||||
long size = 0;
|
||||
size += sizeofUnsignedVInt(header.id);
|
||||
size += CREATION_TIME_SIZE;
|
||||
size += sizeofUnsignedVInt(NANOSECONDS.toMillis(header.expiresAtNanos - header.createdAtNanos));
|
||||
size += sizeofUnsignedVInt(header.verb.id);
|
||||
size += sizeofUnsignedVInt(header.flags);
|
||||
size += serializedParamsSize(header.params, version);
|
||||
return Ints.checkedCast(size);
|
||||
}
|
||||
|
||||
private Header extractHeaderPost40(ByteBuffer buf, InetAddressAndPort from, long currentTimeNanos, int version) throws IOException
|
||||
{
|
||||
MonotonicClockTranslation timeSnapshot = approxTime.translate();
|
||||
|
||||
|
|
@ -850,292 +827,60 @@ public class Message<T>
|
|||
return new Header(id, verb, from, createdAtNanos, expiresAtNanos, flags, params);
|
||||
}
|
||||
|
||||
private <T> void serializePost40(Message<T> message, DataOutputPlus out, int version) throws IOException
|
||||
private static long getExpiresAtNanos(long createdAtNanos, long currentTimeNanos, long expirationPeriodNanos)
|
||||
{
|
||||
serializeHeaderPost40(message.header, out, version);
|
||||
out.writeUnsignedVInt32(message.payloadSize(version));
|
||||
message.verb().serializer().serialize(message.payload, out, version);
|
||||
if (!DatabaseDescriptor.hasCrossNodeTimeout() || createdAtNanos > currentTimeNanos)
|
||||
createdAtNanos = currentTimeNanos;
|
||||
return createdAtNanos + expirationPeriodNanos;
|
||||
}
|
||||
|
||||
private <T> Message<T> deserializePost40(DataInputPlus in, InetAddressAndPort peer, int version) throws IOException
|
||||
private void serializeHeader(Header header, DataOutputPlus out, int version) throws IOException
|
||||
{
|
||||
Header header = deserializeHeaderPost40(in, peer, version);
|
||||
skipUnsignedVInt(in); // payload size, not needed by payload deserializer
|
||||
T payload = (T) header.verb.serializer().deserialize(in, version);
|
||||
return new Message<>(header, payload);
|
||||
}
|
||||
|
||||
private <T> Message<T> deserializePost40(DataInputPlus in, Header header, int version) throws IOException
|
||||
{
|
||||
skipHeaderPost40(in);
|
||||
skipUnsignedVInt(in); // payload size, not needed by payload deserializer
|
||||
T payload = (T) header.verb.serializer().deserialize(in, version);
|
||||
return new Message<>(header, payload);
|
||||
}
|
||||
|
||||
private <T> int serializedSizePost40(Message<T> message, int version)
|
||||
{
|
||||
long size = 0;
|
||||
size += serializedHeaderSizePost40(message.header, version);
|
||||
int payloadSize = message.payloadSize(version);
|
||||
size += sizeofUnsignedVInt(payloadSize) + payloadSize;
|
||||
return Ints.checkedCast(size);
|
||||
}
|
||||
|
||||
private int inferMessageSizePost40(ByteBuffer buf, int readerIndex, int readerLimit)
|
||||
{
|
||||
int index = readerIndex;
|
||||
|
||||
int idSize = computeUnsignedVIntSize(buf, index, readerLimit);
|
||||
if (idSize < 0)
|
||||
return -1; // not enough bytes to read id
|
||||
index += idSize;
|
||||
|
||||
index += CREATION_TIME_SIZE;
|
||||
if (index > readerLimit)
|
||||
return -1;
|
||||
|
||||
int expirationSize = computeUnsignedVIntSize(buf, index, readerLimit);
|
||||
if (expirationSize < 0)
|
||||
return -1;
|
||||
index += expirationSize;
|
||||
|
||||
int verbIdSize = computeUnsignedVIntSize(buf, index, readerLimit);
|
||||
if (verbIdSize < 0)
|
||||
return -1;
|
||||
index += verbIdSize;
|
||||
|
||||
int flagsSize = computeUnsignedVIntSize(buf, index, readerLimit);
|
||||
if (flagsSize < 0)
|
||||
return -1;
|
||||
index += flagsSize;
|
||||
|
||||
int paramsSize = extractParamsSizePost40(buf, index, readerLimit);
|
||||
if (paramsSize < 0)
|
||||
return -1;
|
||||
index += paramsSize;
|
||||
|
||||
long payloadSize = getUnsignedVInt(buf, index, readerLimit);
|
||||
if (payloadSize < 0)
|
||||
return -1;
|
||||
index += computeUnsignedVIntSize(payloadSize) + payloadSize;
|
||||
|
||||
return index - readerIndex;
|
||||
}
|
||||
|
||||
/*
|
||||
* legacy ser/deser
|
||||
*/
|
||||
|
||||
private void serializeHeaderPre40(Header header, DataOutputPlus out, int version) throws IOException
|
||||
{
|
||||
out.writeInt(PROTOCOL_MAGIC);
|
||||
out.writeInt(Ints.checkedCast(header.id));
|
||||
out.writeUnsignedVInt(header.id);
|
||||
// int cast cuts off the high-order half of the timestamp, which we can assume remains
|
||||
// the same between now and when the recipient reconstructs it.
|
||||
out.writeInt((int) approxTime.translate().toMillisSinceEpoch(header.createdAtNanos));
|
||||
inetAddressAndPortSerializer.serialize(header.from, out, version);
|
||||
out.writeInt(header.verb.toPre40Verb().id);
|
||||
serializeParams(addFlagsToLegacyParams(header.params, header.flags), out, version);
|
||||
out.writeUnsignedVInt(NANOSECONDS.toMillis(header.expiresAtNanos - header.createdAtNanos));
|
||||
out.writeUnsignedVInt32(header.verb.id);
|
||||
out.writeUnsignedVInt32(header.flags);
|
||||
serializeParams(header.params, out, version);
|
||||
}
|
||||
|
||||
private Header deserializeHeaderPre40(DataInputPlus in, int version) throws IOException
|
||||
private Header deserializeHeader(DataInputPlus in, InetAddressAndPort peer, int version) throws IOException
|
||||
{
|
||||
validateLegacyProtocolMagic(in.readInt());
|
||||
int id = in.readInt();
|
||||
long id = in.readUnsignedVInt();
|
||||
long currentTimeNanos = approxTime.now();
|
||||
MonotonicClockTranslation timeSnapshot = approxTime.translate();
|
||||
long creationTimeNanos = calculateCreationTimeNanos(in.readInt(), timeSnapshot, currentTimeNanos);
|
||||
InetAddressAndPort from = inetAddressAndPortSerializer.deserialize(in, version);
|
||||
Verb verb = Verb.fromId(in.readInt());
|
||||
long expiresAtNanos = getExpiresAtNanos(creationTimeNanos, currentTimeNanos, TimeUnit.MILLISECONDS.toNanos(in.readUnsignedVInt()));
|
||||
Verb verb = Verb.fromId(in.readUnsignedVInt32());
|
||||
int flags = in.readUnsignedVInt32();
|
||||
Map<ParamType, Object> params = deserializeParams(in, version);
|
||||
int flags = removeFlagsFromLegacyParams(params);
|
||||
return new Header(id, verb, from, creationTimeNanos, verb.expiresAtNanos(creationTimeNanos), flags, params);
|
||||
return new Header(id, verb, peer, creationTimeNanos, expiresAtNanos, flags, params);
|
||||
}
|
||||
|
||||
private static final int PRE_40_MESSAGE_PREFIX_SIZE = 12; // protocol magic + id + createdAt
|
||||
|
||||
private void skipHeaderPre40(DataInputPlus in) throws IOException
|
||||
private void skipHeader(DataInputPlus in) throws IOException
|
||||
{
|
||||
in.skipBytesFully(PRE_40_MESSAGE_PREFIX_SIZE); // magic, id, createdAt
|
||||
in.skipBytesFully(in.readByte()); // from
|
||||
in.skipBytesFully(4); // verb
|
||||
skipParamsPre40(in); // params
|
||||
skipUnsignedVInt(in); // id
|
||||
in.skipBytesFully(4); // createdAt
|
||||
skipUnsignedVInt(in); // expiresIn
|
||||
skipUnsignedVInt(in); // verb
|
||||
skipUnsignedVInt(in); // flags
|
||||
skipParams(in); // params
|
||||
}
|
||||
|
||||
private int serializedHeaderSizePre40(Header header, int version)
|
||||
private int serializedHeader(Header header, int version)
|
||||
{
|
||||
long size = 0;
|
||||
size += PRE_40_MESSAGE_PREFIX_SIZE;
|
||||
size += inetAddressAndPortSerializer.serializedSize(header.from, version);
|
||||
size += sizeof(header.verb.id);
|
||||
size += serializedParamsSize(addFlagsToLegacyParams(header.params, header.flags), version);
|
||||
size += sizeofUnsignedVInt(header.id);
|
||||
size += CREATION_TIME_SIZE;
|
||||
size += sizeofUnsignedVInt(NANOSECONDS.toMillis(header.expiresAtNanos - header.createdAtNanos));
|
||||
size += sizeofUnsignedVInt(header.verb.id);
|
||||
size += sizeofUnsignedVInt(header.flags);
|
||||
size += serializedParamsSize(header.params, version);
|
||||
return Ints.checkedCast(size);
|
||||
}
|
||||
|
||||
private Header extractHeaderPre40(ByteBuffer buf, long currentTimeNanos, int version) throws IOException
|
||||
{
|
||||
MonotonicClockTranslation timeSnapshot = approxTime.translate();
|
||||
|
||||
int index = buf.position();
|
||||
|
||||
index += 4; // protocol magic
|
||||
|
||||
long id = buf.getInt(index);
|
||||
index += 4;
|
||||
|
||||
int createdAtMillis = buf.getInt(index);
|
||||
index += 4;
|
||||
|
||||
InetAddressAndPort from = inetAddressAndPortSerializer.extract(buf, index);
|
||||
index += 1 + buf.get(index);
|
||||
|
||||
Verb verb = Verb.fromId(buf.getInt(index));
|
||||
index += 4;
|
||||
|
||||
Map<ParamType, Object> params = extractParams(buf, index, version);
|
||||
int flags = removeFlagsFromLegacyParams(params);
|
||||
|
||||
long createdAtNanos = calculateCreationTimeNanos(createdAtMillis, timeSnapshot, currentTimeNanos);
|
||||
long expiresAtNanos = verb.expiresAtNanos(createdAtNanos);
|
||||
|
||||
return new Header(id, verb, from, createdAtNanos, expiresAtNanos, flags, params);
|
||||
}
|
||||
|
||||
private <T> void serializePre40(Message<T> message, DataOutputPlus out, int version) throws IOException
|
||||
{
|
||||
if (message.isFailureResponse())
|
||||
message = toPre40FailureResponse(message);
|
||||
|
||||
serializeHeaderPre40(message.header, out, version);
|
||||
|
||||
if (message.payload != null && message.payload != NoPayload.noPayload)
|
||||
{
|
||||
int payloadSize = message.payloadSize(version);
|
||||
out.writeInt(payloadSize);
|
||||
message.getPayloadSerializer().serialize(message.payload, out, version);
|
||||
}
|
||||
else
|
||||
{
|
||||
out.writeInt(0);
|
||||
}
|
||||
}
|
||||
|
||||
private <T> Message<T> deserializePre40(DataInputPlus in, int version) throws IOException
|
||||
{
|
||||
Header header = deserializeHeaderPre40(in, version);
|
||||
return deserializePre40(in, header, false, version);
|
||||
}
|
||||
|
||||
private <T> Message<T> deserializePre40(DataInputPlus in, Header header, int version) throws IOException
|
||||
{
|
||||
return deserializePre40(in, header, true, version);
|
||||
}
|
||||
|
||||
private <T> Message<T> deserializePre40(DataInputPlus in, Header header, boolean skipHeader, int version) throws IOException
|
||||
{
|
||||
if (skipHeader)
|
||||
skipHeaderPre40(in);
|
||||
|
||||
int payloadSize = in.readInt();
|
||||
T payload = deserializePayloadPre40(in, version, getPayloadSerializer(header.verb, header.id, header.from), payloadSize);
|
||||
|
||||
Message<T> message = new Message<>(header, payload);
|
||||
|
||||
return header.params.containsKey(ParamType.FAILURE_RESPONSE)
|
||||
? (Message<T>) toPost40FailureResponse(message)
|
||||
: message;
|
||||
}
|
||||
|
||||
private <T> T deserializePayloadPre40(DataInputPlus in, int version, IVersionedAsymmetricSerializer<?, T> serializer, int payloadSize) throws IOException
|
||||
{
|
||||
if (payloadSize == 0 || serializer == null)
|
||||
{
|
||||
// if there's no deserializer for the verb, skip the payload bytes to leave
|
||||
// the stream in a clean state (for the next message)
|
||||
in.skipBytesFully(payloadSize);
|
||||
return null;
|
||||
}
|
||||
|
||||
return serializer.deserialize(in, version);
|
||||
}
|
||||
|
||||
private <T> int serializedSizePre40(Message<T> message, int version)
|
||||
{
|
||||
if (message.isFailureResponse())
|
||||
message = toPre40FailureResponse(message);
|
||||
|
||||
long size = 0;
|
||||
size += serializedHeaderSizePre40(message.header, version);
|
||||
int payloadSize = message.payloadSize(version);
|
||||
size += sizeof(payloadSize);
|
||||
size += payloadSize;
|
||||
return Ints.checkedCast(size);
|
||||
}
|
||||
|
||||
private int inferMessageSizePre40(ByteBuffer buf, int readerIndex, int readerLimit) throws InvalidLegacyProtocolMagic
|
||||
{
|
||||
int index = readerIndex;
|
||||
// protocol magic
|
||||
index += 4;
|
||||
if (index > readerLimit)
|
||||
return -1;
|
||||
validateLegacyProtocolMagic(buf.getInt(index - 4));
|
||||
|
||||
// rest of prefix
|
||||
index += PRE_40_MESSAGE_PREFIX_SIZE - 4;
|
||||
// ip address
|
||||
index += 1;
|
||||
if (index > readerLimit)
|
||||
return -1;
|
||||
index += buf.get(index - 1);
|
||||
// verb
|
||||
index += 4;
|
||||
if (index > readerLimit)
|
||||
return -1;
|
||||
|
||||
int paramsSize = extractParamsSizePre40(buf, index, readerLimit);
|
||||
if (paramsSize < 0)
|
||||
return -1;
|
||||
index += paramsSize;
|
||||
|
||||
// payload
|
||||
index += 4;
|
||||
|
||||
if (index > readerLimit)
|
||||
return -1;
|
||||
index += buf.getInt(index - 4);
|
||||
|
||||
return index - readerIndex;
|
||||
}
|
||||
|
||||
private Message toPre40FailureResponse(Message post40)
|
||||
{
|
||||
Map<ParamType, Object> params = new EnumMap<>(ParamType.class);
|
||||
params.putAll(post40.header.params);
|
||||
|
||||
params.put(ParamType.FAILURE_RESPONSE, LegacyFlag.instance);
|
||||
params.put(ParamType.FAILURE_REASON, post40.payload);
|
||||
|
||||
Header header = new Header(post40.id(), post40.verb().toPre40Verb(), post40.from(), post40.createdAtNanos(), post40.expiresAtNanos(), 0, params);
|
||||
return new Message<>(header, NoPayload.noPayload);
|
||||
}
|
||||
|
||||
private Message<RequestFailureReason> toPost40FailureResponse(Message<?> pre40)
|
||||
{
|
||||
Map<ParamType, Object> params = new EnumMap<>(ParamType.class);
|
||||
params.putAll(pre40.header.params);
|
||||
|
||||
params.remove(ParamType.FAILURE_RESPONSE);
|
||||
|
||||
RequestFailureReason reason = (RequestFailureReason) params.remove(ParamType.FAILURE_REASON);
|
||||
if (null == reason)
|
||||
reason = RequestFailureReason.UNKNOWN;
|
||||
|
||||
Header header = new Header(pre40.id(), Verb.FAILURE_RSP, pre40.from(), pre40.createdAtNanos(), pre40.expiresAtNanos(), pre40.header.flags, params);
|
||||
return new Message<>(header, reason);
|
||||
}
|
||||
|
||||
/*
|
||||
* created at + cross-node
|
||||
*/
|
||||
|
|
@ -1184,59 +929,20 @@ public class Message<T>
|
|||
* param ser/deser
|
||||
*/
|
||||
|
||||
private Map<ParamType, Object> addFlagsToLegacyParams(Map<ParamType, Object> params, int flags)
|
||||
{
|
||||
if (flags == 0)
|
||||
return params;
|
||||
|
||||
Map<ParamType, Object> extended = new EnumMap<>(ParamType.class);
|
||||
extended.putAll(params);
|
||||
|
||||
if (MessageFlag.CALL_BACK_ON_FAILURE.isIn(flags))
|
||||
extended.put(ParamType.FAILURE_CALLBACK, LegacyFlag.instance);
|
||||
|
||||
if (MessageFlag.TRACK_REPAIRED_DATA.isIn(flags))
|
||||
extended.put(ParamType.TRACK_REPAIRED_DATA, LegacyFlag.instance);
|
||||
|
||||
return extended;
|
||||
}
|
||||
|
||||
private int removeFlagsFromLegacyParams(Map<ParamType, Object> params)
|
||||
{
|
||||
int flags = 0;
|
||||
|
||||
if (null != params.remove(ParamType.FAILURE_CALLBACK))
|
||||
flags = MessageFlag.CALL_BACK_ON_FAILURE.addTo(flags);
|
||||
|
||||
if (null != params.remove(ParamType.TRACK_REPAIRED_DATA))
|
||||
flags = MessageFlag.TRACK_REPAIRED_DATA.addTo(flags);
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
private void serializeParams(Map<ParamType, Object> params, DataOutputPlus out, int version) throws IOException
|
||||
{
|
||||
if (version >= VERSION_40)
|
||||
out.writeUnsignedVInt32(params.size());
|
||||
else
|
||||
out.writeInt(params.size());
|
||||
out.writeUnsignedVInt32(params.size());
|
||||
|
||||
for (Map.Entry<ParamType, Object> kv : params.entrySet())
|
||||
{
|
||||
ParamType type = kv.getKey();
|
||||
if (version >= VERSION_40)
|
||||
out.writeUnsignedVInt32(type.id);
|
||||
else
|
||||
out.writeUTF(type.legacyAlias);
|
||||
out.writeUnsignedVInt32(type.id);
|
||||
|
||||
IVersionedSerializer serializer = type.serializer;
|
||||
Object value = kv.getValue();
|
||||
|
||||
int length = Ints.checkedCast(serializer.serializedSize(value, version));
|
||||
if (version >= VERSION_40)
|
||||
out.writeUnsignedVInt32(length);
|
||||
else
|
||||
out.writeInt(length);
|
||||
out.writeUnsignedVInt32(length);
|
||||
|
||||
serializer.serialize(value, out, version);
|
||||
}
|
||||
|
|
@ -1244,7 +950,7 @@ public class Message<T>
|
|||
|
||||
private Map<ParamType, Object> deserializeParams(DataInputPlus in, int version) throws IOException
|
||||
{
|
||||
int count = version >= VERSION_40 ? in.readUnsignedVInt32() : in.readInt();
|
||||
int count = in.readUnsignedVInt32();
|
||||
|
||||
if (count == 0)
|
||||
return NO_PARAMS;
|
||||
|
|
@ -1253,25 +959,13 @@ public class Message<T>
|
|||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
ParamType type = version >= VERSION_40
|
||||
? ParamType.lookUpById(in.readUnsignedVInt32())
|
||||
: ParamType.lookUpByAlias(in.readUTF());
|
||||
ParamType type = ParamType.lookUpById(in.readUnsignedVInt32());
|
||||
|
||||
int length = version >= VERSION_40
|
||||
? in.readUnsignedVInt32()
|
||||
: in.readInt();
|
||||
int length = in.readUnsignedVInt32();
|
||||
|
||||
if (null != type)
|
||||
{
|
||||
// Have to special case deserializer as pre-4.0 needs length to decode correctly
|
||||
if (version < VERSION_40 && type == ParamType.RESPOND_TO)
|
||||
{
|
||||
params.put(type, InetAddressAndPort.FwdFrmSerializer.fwdFrmSerializer.pre40DeserializeWithLength(in, version, length));
|
||||
}
|
||||
else
|
||||
{
|
||||
params.put(type, type.serializer.deserialize(in, version));
|
||||
}
|
||||
params.put(type, type.serializer.deserialize(in, version));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -1282,12 +976,9 @@ public class Message<T>
|
|||
return params;
|
||||
}
|
||||
|
||||
/*
|
||||
* Extract post-4.0 params map from a ByteBuffer without modifying it.
|
||||
*/
|
||||
private Map<ParamType, Object> extractParams(ByteBuffer buf, int readerIndex, int version) throws IOException
|
||||
{
|
||||
long count = version >= VERSION_40 ? getUnsignedVInt(buf, readerIndex) : buf.getInt(readerIndex);
|
||||
long count = getUnsignedVInt(buf, readerIndex);
|
||||
|
||||
if (count == 0)
|
||||
return NO_PARAMS;
|
||||
|
|
@ -1305,7 +996,7 @@ public class Message<T>
|
|||
}
|
||||
}
|
||||
|
||||
private void skipParamsPost40(DataInputPlus in) throws IOException
|
||||
private void skipParams(DataInputPlus in) throws IOException
|
||||
{
|
||||
int count = in.readUnsignedVInt32();
|
||||
|
||||
|
|
@ -1316,22 +1007,9 @@ public class Message<T>
|
|||
}
|
||||
}
|
||||
|
||||
private void skipParamsPre40(DataInputPlus in) throws IOException
|
||||
{
|
||||
int count = in.readInt();
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
in.skipBytesFully(in.readShort());
|
||||
in.skipBytesFully(in.readInt());
|
||||
}
|
||||
}
|
||||
|
||||
private long serializedParamsSize(Map<ParamType, Object> params, int version)
|
||||
{
|
||||
long size = version >= VERSION_40
|
||||
? computeUnsignedVIntSize(params.size())
|
||||
: sizeof(params.size());
|
||||
long size = computeUnsignedVIntSize(params.size());
|
||||
|
||||
for (Map.Entry<ParamType, Object> kv : params.entrySet())
|
||||
{
|
||||
|
|
@ -1340,10 +1018,7 @@ public class Message<T>
|
|||
|
||||
long valueLength = type.serializer.serializedSize(value, version);
|
||||
|
||||
if (version >= VERSION_40)
|
||||
size += sizeofUnsignedVInt(type.id) + sizeofUnsignedVInt(valueLength);
|
||||
else
|
||||
size += sizeof(type.legacyAlias) + 4;
|
||||
size += sizeofUnsignedVInt(type.id) + sizeofUnsignedVInt(valueLength);
|
||||
|
||||
size += valueLength;
|
||||
}
|
||||
|
|
@ -1351,7 +1026,7 @@ public class Message<T>
|
|||
return size;
|
||||
}
|
||||
|
||||
private int extractParamsSizePost40(ByteBuffer buf, int readerIndex, int readerLimit)
|
||||
private int extractParamsSize(ByteBuffer buf, int readerIndex, int readerLimit)
|
||||
{
|
||||
int index = readerIndex;
|
||||
|
||||
|
|
@ -1376,33 +1051,6 @@ public class Message<T>
|
|||
return index - readerIndex;
|
||||
}
|
||||
|
||||
private int extractParamsSizePre40(ByteBuffer buf, int readerIndex, int readerLimit)
|
||||
{
|
||||
int index = readerIndex;
|
||||
|
||||
index += 4;
|
||||
if (index > readerLimit)
|
||||
return -1;
|
||||
int paramsCount = buf.getInt(index - 4);
|
||||
|
||||
for (int i = 0; i < paramsCount; i++)
|
||||
{
|
||||
// try to read length and skip to the end of the param name
|
||||
index += 2;
|
||||
|
||||
if (index > readerLimit)
|
||||
return -1;
|
||||
index += buf.getShort(index - 2);
|
||||
// try to read length and skip to the end of the param value
|
||||
index += 4;
|
||||
if (index > readerLimit)
|
||||
return -1;
|
||||
index += buf.getInt(index - 4);
|
||||
}
|
||||
|
||||
return index - readerIndex;
|
||||
}
|
||||
|
||||
private <T> int payloadSize(Message<T> message, int version)
|
||||
{
|
||||
long payloadSize = message.payload != null && message.payload != NoPayload.noPayload
|
||||
|
|
@ -1414,20 +1062,9 @@ public class Message<T>
|
|||
|
||||
private IVersionedAsymmetricSerializer<T, ?> getPayloadSerializer()
|
||||
{
|
||||
return getPayloadSerializer(verb(), id(), from());
|
||||
return verb().serializer();
|
||||
}
|
||||
|
||||
// Verb#serializer() is null for legacy response messages. Once all Verbs with null handlers
|
||||
// are removed in a future major, this method can be replaced with a call to verb.serializer.
|
||||
private static <In,Out> IVersionedAsymmetricSerializer<In, Out> getPayloadSerializer(Verb verb, long id, InetAddressAndPort from)
|
||||
{
|
||||
return null != verb.serializer()
|
||||
? verb.serializer()
|
||||
: instance().callbacks.responseSerializer(id, from);
|
||||
}
|
||||
|
||||
private int serializedSize30;
|
||||
private int serializedSize3014;
|
||||
private int serializedSize40;
|
||||
private int serializedSize50;
|
||||
|
||||
|
|
@ -1438,14 +1075,6 @@ public class Message<T>
|
|||
{
|
||||
switch (version)
|
||||
{
|
||||
case VERSION_30:
|
||||
if (serializedSize30 == 0)
|
||||
serializedSize30 = serializer.serializedSize(this, VERSION_30);
|
||||
return serializedSize30;
|
||||
case VERSION_3014:
|
||||
if (serializedSize3014 == 0)
|
||||
serializedSize3014 = serializer.serializedSize(this, VERSION_3014);
|
||||
return serializedSize3014;
|
||||
case VERSION_40:
|
||||
if (serializedSize40 == 0)
|
||||
serializedSize40 = serializer.serializedSize(this, VERSION_40);
|
||||
|
|
@ -1459,8 +1088,6 @@ public class Message<T>
|
|||
}
|
||||
}
|
||||
|
||||
private int payloadSize30 = -1;
|
||||
private int payloadSize3014 = -1;
|
||||
private int payloadSize40 = -1;
|
||||
private int payloadSize50 = -1;
|
||||
|
||||
|
|
@ -1468,14 +1095,6 @@ public class Message<T>
|
|||
{
|
||||
switch (version)
|
||||
{
|
||||
case VERSION_30:
|
||||
if (payloadSize30 < 0)
|
||||
payloadSize30 = serializer.payloadSize(this, VERSION_30);
|
||||
return payloadSize30;
|
||||
case VERSION_3014:
|
||||
if (payloadSize3014 < 0)
|
||||
payloadSize3014 = serializer.payloadSize(this, VERSION_3014);
|
||||
return payloadSize3014;
|
||||
case VERSION_40:
|
||||
if (payloadSize40 < 0)
|
||||
payloadSize40 = serializer.payloadSize(this, VERSION_40);
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import java.io.IOException;
|
|||
import java.nio.channels.ClosedChannelException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
|
@ -29,13 +30,11 @@ import java.util.concurrent.TimeoutException;
|
|||
import java.util.stream.Collectors;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
|
||||
import org.apache.cassandra.utils.concurrent.AsyncPromise;
|
||||
import org.apache.cassandra.utils.concurrent.FutureCombiner;
|
||||
import com.google.common.collect.Lists;
|
||||
import io.netty.util.concurrent.Future; //checkstyle: permit this import
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import io.netty.util.concurrent.Future; //checkstyle: permit this import
|
||||
import org.apache.cassandra.concurrent.ScheduledExecutors;
|
||||
import org.apache.cassandra.concurrent.Stage;
|
||||
import org.apache.cassandra.config.DatabaseDescriptor;
|
||||
|
|
@ -47,9 +46,12 @@ import org.apache.cassandra.metrics.MessagingMetrics;
|
|||
import org.apache.cassandra.service.AbstractWriteResponseHandler;
|
||||
import org.apache.cassandra.utils.ExecutorUtils;
|
||||
import org.apache.cassandra.utils.FBUtilities;
|
||||
import org.apache.cassandra.utils.concurrent.AsyncPromise;
|
||||
import org.apache.cassandra.utils.concurrent.FutureCombiner;
|
||||
|
||||
import static java.util.Collections.synchronizedList;
|
||||
import static java.util.concurrent.TimeUnit.MINUTES;
|
||||
|
||||
import static org.apache.cassandra.concurrent.Stage.MUTATION;
|
||||
import static org.apache.cassandra.config.CassandraRelevantProperties.NON_GRACEFUL_SHUTDOWN;
|
||||
import static org.apache.cassandra.utils.Clock.Global.nanoTime;
|
||||
|
|
@ -208,11 +210,13 @@ public class MessagingService extends MessagingServiceMBeanImpl
|
|||
private static final Logger logger = LoggerFactory.getLogger(MessagingService.class);
|
||||
|
||||
// 8 bits version, so don't waste versions
|
||||
@Deprecated
|
||||
public static final int VERSION_30 = 10;
|
||||
@Deprecated
|
||||
public static final int VERSION_3014 = 11;
|
||||
public static final int VERSION_40 = 12;
|
||||
public static final int VERSION_50 = 13; // c14227 TTL overflow, 'uint' timestamps
|
||||
public static final int minimum_version = VERSION_30;
|
||||
public static final int minimum_version = VERSION_40;
|
||||
public static final int current_version = DatabaseDescriptor.getStorageCompatibilityMode().isBefore(5) ? VERSION_40 : VERSION_50;
|
||||
static AcceptVersions accept_messaging = new AcceptVersions(minimum_version, current_version);
|
||||
static AcceptVersions accept_streaming = new AcceptVersions(current_version, current_version);
|
||||
|
|
@ -236,7 +240,9 @@ public class MessagingService extends MessagingServiceMBeanImpl
|
|||
|
||||
public enum Version
|
||||
{
|
||||
@Deprecated
|
||||
VERSION_30(10),
|
||||
@Deprecated
|
||||
VERSION_3014(11),
|
||||
VERSION_40(12),
|
||||
VERSION_50(13);
|
||||
|
|
@ -247,6 +253,16 @@ public class MessagingService extends MessagingServiceMBeanImpl
|
|||
{
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public static List<Version> supportedVersions()
|
||||
{
|
||||
List<Version> versions = Lists.newArrayList();
|
||||
for (Version version : values())
|
||||
if (minimum_version <= version.value)
|
||||
versions.add(version);
|
||||
|
||||
return Collections.unmodifiableList(versions);
|
||||
}
|
||||
}
|
||||
|
||||
private static class MSHandle
|
||||
|
|
|
|||
|
|
@ -1215,9 +1215,6 @@ public class OutboundConnection
|
|||
if (messagingVersion > settings.acceptVersions.max)
|
||||
messagingVersion = settings.acceptVersions.max;
|
||||
|
||||
// ensure we connect to the correct SSL port
|
||||
settings = settings.withLegacyPortIfNecessary(messagingVersion);
|
||||
|
||||
// In mixed mode operation, some nodes might be configured to use SSL for internode connections and
|
||||
// others might be configured to not use SSL. When a node is configured in optional SSL mode, It should
|
||||
// be able to handle SSL and Non-SSL internode connections. We take care of this when accepting NON-SSL
|
||||
|
|
@ -1231,7 +1228,7 @@ public class OutboundConnection
|
|||
{
|
||||
logger.info("ConnectionId {} is falling back to {} reconnect strategy for retry", id(), fallBackSslFallbackConnectionTypes[index]);
|
||||
}
|
||||
initiateMessaging(eventLoop, type, fallBackSslFallbackConnectionTypes[index], settings, messagingVersion, result)
|
||||
initiateMessaging(eventLoop, type, fallBackSslFallbackConnectionTypes[index], settings, result)
|
||||
.addListener(future -> {
|
||||
if (future.isCancelled())
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -68,12 +68,10 @@ import static org.apache.cassandra.auth.IInternodeAuthenticator.InternodeConnect
|
|||
import static org.apache.cassandra.net.InternodeConnectionUtils.DISCARD_HANDLER_NAME;
|
||||
import static org.apache.cassandra.net.InternodeConnectionUtils.SSL_HANDLER_NAME;
|
||||
import static org.apache.cassandra.net.InternodeConnectionUtils.certificates;
|
||||
import static org.apache.cassandra.net.MessagingService.VERSION_40;
|
||||
import static org.apache.cassandra.net.HandshakeProtocol.*;
|
||||
import static org.apache.cassandra.net.ConnectionType.STREAMING;
|
||||
import static org.apache.cassandra.net.OutboundConnectionInitiator.Result.incompatible;
|
||||
import static org.apache.cassandra.net.OutboundConnectionInitiator.Result.messagingSuccess;
|
||||
import static org.apache.cassandra.net.OutboundConnectionInitiator.Result.retry;
|
||||
import static org.apache.cassandra.net.OutboundConnectionInitiator.Result.streamingSuccess;
|
||||
import static org.apache.cassandra.net.SocketFactory.*;
|
||||
|
||||
|
|
@ -96,16 +94,15 @@ public class OutboundConnectionInitiator<SuccessType extends OutboundConnectionI
|
|||
private final ConnectionType type;
|
||||
private final SslFallbackConnectionType sslConnectionType;
|
||||
private final OutboundConnectionSettings settings;
|
||||
private final int requestMessagingVersion; // for pre40 nodes
|
||||
private final Promise<Result<SuccessType>> resultPromise;
|
||||
private boolean isClosed;
|
||||
|
||||
private OutboundConnectionInitiator(ConnectionType type, SslFallbackConnectionType sslConnectionType, OutboundConnectionSettings settings,
|
||||
int requestMessagingVersion, Promise<Result<SuccessType>> resultPromise)
|
||||
Promise<Result<SuccessType>> resultPromise)
|
||||
{
|
||||
this.type = type;
|
||||
this.sslConnectionType = sslConnectionType;
|
||||
this.requestMessagingVersion = requestMessagingVersion;
|
||||
|
||||
this.settings = settings;
|
||||
this.resultPromise = resultPromise;
|
||||
}
|
||||
|
|
@ -118,9 +115,9 @@ public class OutboundConnectionInitiator<SuccessType extends OutboundConnectionI
|
|||
* The returned {@code Future} is guaranteed to be completed on the supplied eventLoop.
|
||||
*/
|
||||
public static Future<Result<StreamingSuccess>> initiateStreaming(EventLoop eventLoop, OutboundConnectionSettings settings,
|
||||
SslFallbackConnectionType sslConnectionType, int requestMessagingVersion)
|
||||
SslFallbackConnectionType sslConnectionType)
|
||||
{
|
||||
return new OutboundConnectionInitiator<StreamingSuccess>(STREAMING, sslConnectionType, settings, requestMessagingVersion, AsyncPromise.withExecutor(eventLoop))
|
||||
return new OutboundConnectionInitiator<StreamingSuccess>(STREAMING, sslConnectionType, settings, AsyncPromise.withExecutor(eventLoop))
|
||||
.initiate(eventLoop);
|
||||
}
|
||||
|
||||
|
|
@ -132,16 +129,16 @@ public class OutboundConnectionInitiator<SuccessType extends OutboundConnectionI
|
|||
* The returned {@code Future} is guaranteed to be completed on the supplied eventLoop.
|
||||
*/
|
||||
static Future<Result<MessagingSuccess>> initiateMessaging(EventLoop eventLoop, ConnectionType type, SslFallbackConnectionType sslConnectionType,
|
||||
OutboundConnectionSettings settings, int requestMessagingVersion, Promise<Result<MessagingSuccess>> result)
|
||||
OutboundConnectionSettings settings, Promise<Result<MessagingSuccess>> result)
|
||||
{
|
||||
return new OutboundConnectionInitiator<>(type, sslConnectionType, settings, requestMessagingVersion, result)
|
||||
return new OutboundConnectionInitiator<>(type, sslConnectionType, settings, result)
|
||||
.initiate(eventLoop);
|
||||
}
|
||||
|
||||
private Future<Result<SuccessType>> initiate(EventLoop eventLoop)
|
||||
{
|
||||
if (logger.isTraceEnabled())
|
||||
logger.trace("creating outbound bootstrap to {}, requestVersion: {}", settings, requestMessagingVersion);
|
||||
logger.trace("creating outbound bootstrap to {}", settings);
|
||||
|
||||
if (!settings.authenticator.authenticate(settings.to.getAddress(), settings.to.getPort(), null, OUTBOUND_PRECONNECT))
|
||||
{
|
||||
|
|
@ -306,15 +303,13 @@ public class OutboundConnectionInitiator<SuccessType extends OutboundConnectionI
|
|||
* containing the streaming protocol version, is all that is required.
|
||||
*/
|
||||
@Override
|
||||
public void channelActive(final ChannelHandlerContext ctx)
|
||||
public void channelActive(final ChannelHandlerContext ctx) throws Exception
|
||||
{
|
||||
Initiate msg = new Initiate(requestMessagingVersion, settings.acceptVersions, type, settings.framing, settings.from);
|
||||
Initiate msg = new Initiate(settings.acceptVersions, type, settings.framing, settings.from);
|
||||
logger.trace("starting handshake with peer {}, msg = {}", settings.connectToId(), msg);
|
||||
AsyncChannelPromise.writeAndFlush(ctx, msg.encode(),
|
||||
future -> { if (!future.isSuccess()) exceptionCaught(ctx, future.cause()); });
|
||||
|
||||
if (type.isStreaming() && requestMessagingVersion < VERSION_40)
|
||||
ctx.pipeline().remove(this);
|
||||
AsyncChannelPromise.writeAndFlush(ctx, msg.encode(),
|
||||
future -> { if (!future.isSuccess()) exceptionCaught(ctx, future.cause()); });
|
||||
|
||||
ctx.fireChannelActive();
|
||||
}
|
||||
|
|
@ -335,12 +330,13 @@ public class OutboundConnectionInitiator<SuccessType extends OutboundConnectionI
|
|||
* do *not* send out the third message of the internode messaging handshake.
|
||||
* We will reconnect on the appropriate protocol version.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out)
|
||||
{
|
||||
try
|
||||
{
|
||||
Accept msg = Accept.maybeDecode(in, requestMessagingVersion);
|
||||
Accept msg = Accept.maybeDecode(in);
|
||||
if (msg == null)
|
||||
return;
|
||||
|
||||
|
|
@ -350,68 +346,35 @@ public class OutboundConnectionInitiator<SuccessType extends OutboundConnectionI
|
|||
|
||||
FrameEncoder frameEncoder = null;
|
||||
Result<SuccessType> result;
|
||||
if (useMessagingVersion > 0)
|
||||
{
|
||||
if (useMessagingVersion < settings.acceptVersions.min || useMessagingVersion > settings.acceptVersions.max)
|
||||
{
|
||||
result = incompatible(useMessagingVersion, peerMessagingVersion);
|
||||
}
|
||||
else
|
||||
{
|
||||
// This is a bit ugly
|
||||
if (type.isMessaging())
|
||||
{
|
||||
switch (settings.framing)
|
||||
{
|
||||
case LZ4:
|
||||
frameEncoder = FrameEncoderLZ4.fastInstance;
|
||||
break;
|
||||
case CRC:
|
||||
frameEncoder = FrameEncoderCrc.instance;
|
||||
break;
|
||||
case UNPROTECTED:
|
||||
frameEncoder = FrameEncoderUnprotected.instance;
|
||||
break;
|
||||
}
|
||||
assert useMessagingVersion > 0;
|
||||
|
||||
result = (Result<SuccessType>) messagingSuccess(ctx.channel(), useMessagingVersion, frameEncoder.allocator());
|
||||
}
|
||||
else
|
||||
{
|
||||
result = (Result<SuccessType>) streamingSuccess(ctx.channel(), useMessagingVersion);
|
||||
}
|
||||
}
|
||||
if (useMessagingVersion < settings.acceptVersions.min || useMessagingVersion > settings.acceptVersions.max)
|
||||
{
|
||||
result = incompatible(useMessagingVersion, peerMessagingVersion);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert type.isMessaging();
|
||||
|
||||
// pre40 handshake responses only (can be a post40 node)
|
||||
if (peerMessagingVersion == requestMessagingVersion
|
||||
|| peerMessagingVersion > settings.acceptVersions.max) // this clause is for impersonating 3.0 node in testing only
|
||||
// This is a bit ugly
|
||||
if (type.isMessaging())
|
||||
{
|
||||
switch (settings.framing)
|
||||
{
|
||||
case CRC:
|
||||
case UNPROTECTED:
|
||||
frameEncoder = FrameEncoderLegacy.instance;
|
||||
break;
|
||||
case LZ4:
|
||||
frameEncoder = FrameEncoderLegacyLZ4.instance;
|
||||
frameEncoder = FrameEncoderLZ4.fastInstance;
|
||||
break;
|
||||
case CRC:
|
||||
frameEncoder = FrameEncoderCrc.instance;
|
||||
break;
|
||||
case UNPROTECTED:
|
||||
frameEncoder = FrameEncoderUnprotected.instance;
|
||||
break;
|
||||
}
|
||||
|
||||
result = (Result<SuccessType>) messagingSuccess(ctx.channel(), requestMessagingVersion, frameEncoder.allocator());
|
||||
result = (Result<SuccessType>) messagingSuccess(ctx.channel(), useMessagingVersion, frameEncoder.allocator());
|
||||
}
|
||||
else if (peerMessagingVersion < settings.acceptVersions.min)
|
||||
result = incompatible(-1, peerMessagingVersion);
|
||||
else
|
||||
result = retry(peerMessagingVersion);
|
||||
|
||||
if (result.isSuccess())
|
||||
{
|
||||
ConfirmOutboundPre40 message = new ConfirmOutboundPre40(settings.acceptVersions.max, settings.from);
|
||||
AsyncChannelPromise.writeAndFlush(ctx, message.encode());
|
||||
result = (Result<SuccessType>) streamingSuccess(ctx.channel(), useMessagingVersion);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -33,7 +33,6 @@ import org.apache.cassandra.locator.InetAddressAndPort;
|
|||
import org.apache.cassandra.utils.FBUtilities;
|
||||
|
||||
import static org.apache.cassandra.config.DatabaseDescriptor.getEndpointSnitch;
|
||||
import static org.apache.cassandra.net.MessagingService.VERSION_40;
|
||||
import static org.apache.cassandra.net.MessagingService.instance;
|
||||
import static org.apache.cassandra.utils.FBUtilities.getBroadcastAddressAndPort;
|
||||
|
||||
|
|
@ -50,14 +49,11 @@ public class OutboundConnectionSettings
|
|||
|
||||
public enum Framing
|
||||
{
|
||||
// for < VERSION_40, implies no framing
|
||||
// for >= VERSION_40, uses simple unprotected frames with header crc but no payload protection
|
||||
// uses simple unprotected frames with header crc but no payload protection
|
||||
UNPROTECTED(0),
|
||||
// for < VERSION_40, uses the jpountz framing format
|
||||
// for >= VERSION_40, uses our framing format with header crc24
|
||||
// uses our framing format with header crc24
|
||||
LZ4(1),
|
||||
// for < VERSION_40, implies UNPROTECTED
|
||||
// for >= VERSION_40, uses simple frames with separate header and payload crc
|
||||
// uses simple frames with separate header and payload crc
|
||||
CRC(2);
|
||||
|
||||
public static Framing forId(int id)
|
||||
|
|
@ -133,6 +129,7 @@ public class OutboundConnectionSettings
|
|||
Preconditions.checkArgument(applicationSendQueueCapacityInBytes == null || applicationSendQueueCapacityInBytes >= 1 << 10, "illegal application send queue capacity: " + applicationSendQueueCapacityInBytes);
|
||||
Preconditions.checkArgument(tcpUserTimeoutInMS == null || tcpUserTimeoutInMS >= 0, "tcp user timeout must be non negative: " + tcpUserTimeoutInMS);
|
||||
Preconditions.checkArgument(tcpConnectTimeoutInMS == null || tcpConnectTimeoutInMS > 0, "tcp connect timeout must be positive: " + tcpConnectTimeoutInMS);
|
||||
Preconditions.checkArgument(acceptVersions == null || acceptVersions.min >= MessagingService.minimum_version, "acceptVersions.min must be minimum_version or higher: " + (acceptVersions == null ? null : acceptVersions.min));
|
||||
|
||||
this.authenticator = authenticator;
|
||||
this.to = to;
|
||||
|
|
@ -437,11 +434,6 @@ public class OutboundConnectionSettings
|
|||
: MessagingService.accept_messaging;
|
||||
}
|
||||
|
||||
public OutboundConnectionSettings withLegacyPortIfNecessary(int messagingVersion)
|
||||
{
|
||||
return withConnectTo(maybeWithSecurePort(connectTo(), messagingVersion, withEncryption()));
|
||||
}
|
||||
|
||||
public InetAddressAndPort connectTo()
|
||||
{
|
||||
InetAddressAndPort connectTo = this.connectTo;
|
||||
|
|
@ -508,20 +500,4 @@ public class OutboundConnectionSettings
|
|||
|| ((DatabaseDescriptor.internodeCompression() == Config.InternodeCompression.dc) && !isInLocalDC(snitch, localHost, remoteHost));
|
||||
}
|
||||
|
||||
private static InetAddressAndPort maybeWithSecurePort(InetAddressAndPort address, int messagingVersion, boolean isEncrypted)
|
||||
{
|
||||
if (!isEncrypted || messagingVersion >= VERSION_40)
|
||||
return address;
|
||||
|
||||
// if we don't know the version of the peer, assume it is 4.0 (or higher) as the only time is would be lower
|
||||
// (as in a 3.x version) is during a cluster upgrade (from 3.x to 4.0). In that case the outbound connection will
|
||||
// unfortunately fail - however the peer should connect to this node (at some point), and once we learn it's version, it'll be
|
||||
// in versions map. thus, when we attempt to reconnect to that node, we'll have the version and we can get the correct port.
|
||||
// we will be able to remove this logic at 5.0.
|
||||
// Also as of 4.0 we will propagate the "regular" port (which will support both SSL and non-SSL) via gossip so
|
||||
// for SSL and version 4.0 always connect to the gossiped port because if SSL is enabled it should ALWAYS
|
||||
// listen for SSL on the "regular" port.
|
||||
return address.withPort(DatabaseDescriptor.getSSLStoragePort());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,7 +43,6 @@ import static java.lang.Math.max;
|
|||
import static org.apache.cassandra.config.CassandraRelevantProperties.OTCP_LARGE_MESSAGE_THRESHOLD;
|
||||
import static org.apache.cassandra.gms.Gossiper.instance;
|
||||
import static org.apache.cassandra.net.FrameEncoderCrc.HEADER_AND_TRAILER_LENGTH;
|
||||
import static org.apache.cassandra.net.LegacyLZ4Constants.HEADER_LENGTH;
|
||||
import static org.apache.cassandra.net.MessagingService.current_version;
|
||||
import static org.apache.cassandra.net.ConnectionType.URGENT_MESSAGES;
|
||||
import static org.apache.cassandra.net.ConnectionType.LARGE_MESSAGES;
|
||||
|
|
@ -60,6 +59,12 @@ public class OutboundConnections
|
|||
{
|
||||
private static final Logger logger = LoggerFactory.getLogger(OutboundConnections.class);
|
||||
|
||||
private static final int HEADER_LENGTH = 8 // magic number
|
||||
+ 1 // token
|
||||
+ 4 // compressed length
|
||||
+ 4 // uncompressed length
|
||||
+ 4; // checksum
|
||||
|
||||
@VisibleForTesting
|
||||
public static final int LARGE_MESSAGE_THRESHOLD = OTCP_LARGE_MESSAGE_THRESHOLD.getInt()
|
||||
- max(max(HEADER_LENGTH, HEADER_AND_TRAILER_LENGTH), FrameEncoderLZ4.HEADER_AND_TRAILER_LENGTH);
|
||||
|
|
|
|||
|
|
@ -17,11 +17,8 @@
|
|||
*/
|
||||
package org.apache.cassandra.net;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.apache.cassandra.exceptions.RequestFailureReason;
|
||||
import org.apache.cassandra.io.IVersionedSerializer;
|
||||
import org.apache.cassandra.tracing.Tracing;
|
||||
import org.apache.cassandra.utils.Int32Serializer;
|
||||
|
|
@ -40,50 +37,39 @@ import static org.apache.cassandra.locator.InetAddressAndPort.FwdFrmSerializer.f
|
|||
* will skip over any params it doesn't recognise.
|
||||
*
|
||||
* Please don't add boolean params here. Extend and use {@link MessageFlag} instead.
|
||||
*
|
||||
* Do not re-use old, nor fill gaps in the sequence of, ids. New IDs must be higher.
|
||||
*/
|
||||
public enum ParamType
|
||||
{
|
||||
FORWARD_TO (0, "FWD_TO", ForwardingInfo.serializer),
|
||||
RESPOND_TO (1, "FWD_FRM", fwdFrmSerializer),
|
||||
FORWARD_TO (0, ForwardingInfo.serializer),
|
||||
RESPOND_TO (1, fwdFrmSerializer),
|
||||
|
||||
@Deprecated
|
||||
FAILURE_RESPONSE (2, "FAIL", LegacyFlag.serializer),
|
||||
@Deprecated
|
||||
FAILURE_REASON (3, "FAIL_REASON", RequestFailureReason.serializer),
|
||||
@Deprecated
|
||||
FAILURE_CALLBACK (4, "CAL_BAC", LegacyFlag.serializer),
|
||||
TRACE_SESSION (5, TimeUUID.Serializer.instance),
|
||||
TRACE_TYPE (6, Tracing.traceTypeSerializer),
|
||||
|
||||
TRACE_SESSION (5, "TraceSession", TimeUUID.Serializer.instance),
|
||||
TRACE_TYPE (6, "TraceType", Tracing.traceTypeSerializer),
|
||||
|
||||
@Deprecated
|
||||
TRACK_REPAIRED_DATA (7, "TrackRepaired", LegacyFlag.serializer),
|
||||
|
||||
TOMBSTONE_FAIL (8, "TSF", Int32Serializer.serializer),
|
||||
TOMBSTONE_WARNING (9, "TSW", Int32Serializer.serializer),
|
||||
LOCAL_READ_SIZE_FAIL (10, "LRSF", Int64Serializer.serializer),
|
||||
LOCAL_READ_SIZE_WARN (11, "LRSW", Int64Serializer.serializer),
|
||||
ROW_INDEX_READ_SIZE_FAIL (12, "RIRSF", Int64Serializer.serializer),
|
||||
ROW_INDEX_READ_SIZE_WARN (13, "RIRSW", Int64Serializer.serializer),
|
||||
CUSTOM_MAP (14, "CUSTOM", CustomParamsSerializer.serializer),
|
||||
SNAPSHOT_RANGES (15, "SNAPSHOT_RANGES", RangesSerializer.serializer);
|
||||
TOMBSTONE_FAIL (8, Int32Serializer.serializer),
|
||||
TOMBSTONE_WARNING (9, Int32Serializer.serializer),
|
||||
LOCAL_READ_SIZE_FAIL (10, Int64Serializer.serializer),
|
||||
LOCAL_READ_SIZE_WARN (11, Int64Serializer.serializer),
|
||||
ROW_INDEX_READ_SIZE_FAIL (12, Int64Serializer.serializer),
|
||||
ROW_INDEX_READ_SIZE_WARN (13, Int64Serializer.serializer),
|
||||
CUSTOM_MAP (14, CustomParamsSerializer.serializer),
|
||||
SNAPSHOT_RANGES (15, RangesSerializer.serializer);
|
||||
|
||||
final int id;
|
||||
@Deprecated final String legacyAlias; // pre-4.0 we used to serialize entire param name string
|
||||
final IVersionedSerializer serializer;
|
||||
|
||||
ParamType(int id, String legacyAlias, IVersionedSerializer serializer)
|
||||
ParamType(int id, IVersionedSerializer serializer)
|
||||
{
|
||||
if (id < 0)
|
||||
throw new IllegalArgumentException("ParamType id must be non-negative");
|
||||
|
||||
this.id = id;
|
||||
this.legacyAlias = legacyAlias;
|
||||
this.serializer = serializer;
|
||||
}
|
||||
|
||||
private static final ParamType[] idToTypeMap;
|
||||
private static final Map<String, ParamType> aliasToTypeMap;
|
||||
|
||||
static
|
||||
{
|
||||
|
|
@ -94,7 +80,6 @@ public enum ParamType
|
|||
max = max(t.id, max);
|
||||
|
||||
ParamType[] idMap = new ParamType[max + 1];
|
||||
Map<String, ParamType> aliasMap = new HashMap<>();
|
||||
|
||||
for (ParamType type : types)
|
||||
{
|
||||
|
|
@ -102,12 +87,9 @@ public enum ParamType
|
|||
throw new RuntimeException("Two ParamType-s that map to the same id: " + type.id);
|
||||
idMap[type.id] = type;
|
||||
|
||||
if (aliasMap.put(type.legacyAlias, type) != null)
|
||||
throw new RuntimeException("Two ParamType-s that map to the same legacy alias: " + type.legacyAlias);
|
||||
}
|
||||
|
||||
idToTypeMap = idMap;
|
||||
aliasToTypeMap = aliasMap;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
|
@ -119,9 +101,4 @@ public enum ParamType
|
|||
return id < idToTypeMap.length ? idToTypeMap[id] : null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static ParamType lookUpByAlias(String alias)
|
||||
{
|
||||
return aliasToTypeMap.get(alias);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,7 +32,6 @@ import org.slf4j.LoggerFactory;
|
|||
|
||||
import org.apache.cassandra.config.DatabaseDescriptor;
|
||||
import org.apache.cassandra.exceptions.RequestFailureReason;
|
||||
import org.apache.cassandra.io.IVersionedAsymmetricSerializer;
|
||||
import org.apache.cassandra.locator.InetAddressAndPort;
|
||||
import org.apache.cassandra.locator.Replica;
|
||||
import org.apache.cassandra.metrics.InternodeOutboundMetrics;
|
||||
|
|
@ -109,12 +108,6 @@ public class RequestCallbacks implements OutboundMessageCallbacks
|
|||
assert previous == null : format("Callback already exists for id %d/%s! (%s)", message.id(), to.endpoint(), previous);
|
||||
}
|
||||
|
||||
<In,Out> IVersionedAsymmetricSerializer<In, Out> responseSerializer(long id, InetAddressAndPort peer)
|
||||
{
|
||||
CallbackInfo info = get(id, peer);
|
||||
return info == null ? null : info.responseVerb.serializer();
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public void removeAndRespond(long id, InetAddressAndPort peer, Message message)
|
||||
{
|
||||
|
|
@ -243,16 +236,12 @@ public class RequestCallbacks implements OutboundMessageCallbacks
|
|||
final InetAddressAndPort peer;
|
||||
public final RequestCallback callback;
|
||||
|
||||
@Deprecated // for 3.0 compatibility purposes only
|
||||
public final Verb responseVerb;
|
||||
|
||||
private CallbackInfo(Message message, InetAddressAndPort peer, RequestCallback callback)
|
||||
{
|
||||
this.createdAtNanos = message.createdAtNanos();
|
||||
this.expiresAtNanos = message.expiresAtNanos();
|
||||
this.peer = peer;
|
||||
this.callback = callback;
|
||||
this.responseVerb = message.verb().responseVerb;
|
||||
}
|
||||
|
||||
public long timeout()
|
||||
|
|
|
|||
|
|
@ -337,15 +337,6 @@ public enum Verb
|
|||
return handler.get() == ResponseVerbHandler.instance;
|
||||
}
|
||||
|
||||
Verb toPre40Verb()
|
||||
{
|
||||
if (!isResponse())
|
||||
return this;
|
||||
if (priority == P0)
|
||||
return INTERNAL_RSP;
|
||||
return REQUEST_RSP;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
Supplier<? extends IVerbHandler<?>> unsafeSetHandler(Supplier<? extends IVerbHandler<?>> handler) throws NoSuchFieldException, IllegalAccessException
|
||||
{
|
||||
|
|
|
|||
|
|
@ -46,7 +46,6 @@ import org.apache.cassandra.net.MessagingService;
|
|||
|
||||
import static java.lang.String.format;
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public final class CompressionParams
|
||||
{
|
||||
private static final Logger logger = LoggerFactory.getLogger(CompressionParams.class);
|
||||
|
|
@ -605,6 +604,7 @@ public final class CompressionParams
|
|||
{
|
||||
public void serialize(CompressionParams parameters, DataOutputPlus out, int version) throws IOException
|
||||
{
|
||||
assert version >= MessagingService.VERSION_40;
|
||||
out.writeUTF(parameters.sstableCompressor.getClass().getSimpleName());
|
||||
out.writeInt(parameters.otherOptions.size());
|
||||
for (Map.Entry<String, String> entry : parameters.otherOptions.entrySet())
|
||||
|
|
@ -613,15 +613,12 @@ public final class CompressionParams
|
|||
out.writeUTF(entry.getValue());
|
||||
}
|
||||
out.writeInt(parameters.chunkLength());
|
||||
if (version >= MessagingService.VERSION_40)
|
||||
out.writeInt(parameters.maxCompressedLength);
|
||||
else
|
||||
if (parameters.maxCompressedLength != Integer.MAX_VALUE)
|
||||
throw new UnsupportedOperationException("Cannot stream SSTables with uncompressed chunks to pre-4.0 nodes.");
|
||||
out.writeInt(parameters.maxCompressedLength);
|
||||
}
|
||||
|
||||
public CompressionParams deserialize(DataInputPlus in, int version) throws IOException
|
||||
{
|
||||
assert version >= MessagingService.VERSION_40;
|
||||
String compressorName = in.readUTF();
|
||||
int optionCount = in.readInt();
|
||||
Map<String, String> options = new HashMap<>();
|
||||
|
|
@ -632,9 +629,7 @@ public final class CompressionParams
|
|||
options.put(key, value);
|
||||
}
|
||||
int chunkLength = in.readInt();
|
||||
int minCompressRatio = Integer.MAX_VALUE; // Earlier Cassandra cannot use uncompressed chunks.
|
||||
if (version >= MessagingService.VERSION_40)
|
||||
minCompressRatio = in.readInt();
|
||||
int minCompressRatio = in.readInt();
|
||||
|
||||
CompressionParams parameters;
|
||||
try
|
||||
|
|
@ -650,6 +645,7 @@ public final class CompressionParams
|
|||
|
||||
public long serializedSize(CompressionParams parameters, int version)
|
||||
{
|
||||
assert version >= MessagingService.VERSION_40;
|
||||
long size = TypeSizes.sizeof(parameters.sstableCompressor.getClass().getSimpleName());
|
||||
size += TypeSizes.sizeof(parameters.otherOptions.size());
|
||||
for (Map.Entry<String, String> entry : parameters.otherOptions.entrySet())
|
||||
|
|
@ -658,8 +654,7 @@ public final class CompressionParams
|
|||
size += TypeSizes.sizeof(entry.getValue());
|
||||
}
|
||||
size += TypeSizes.sizeof(parameters.chunkLength());
|
||||
if (version >= MessagingService.VERSION_40)
|
||||
size += TypeSizes.sizeof(parameters.maxCompressedLength());
|
||||
size += TypeSizes.sizeof(parameters.maxCompressedLength());
|
||||
return size;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -400,9 +400,9 @@ public class PagingState
|
|||
}
|
||||
else
|
||||
{
|
||||
// We froze the serialization version to 3.0 as we need to make this this doesn't change (that is, it has to be
|
||||
// fix for a given version of the protocol).
|
||||
mark = Clustering.serializer.serialize(row.clustering(), MessagingService.VERSION_30, makeClusteringTypes(metadata));
|
||||
// We froze the serialization version to 3.0 as we need to make sure this this doesn't change
|
||||
// It got bumped to 4.0 when 3.0 got dropped, knowing it didn't change
|
||||
mark = Clustering.serializer.serialize(row.clustering(), MessagingService.VERSION_40, makeClusteringTypes(metadata));
|
||||
}
|
||||
return new RowMark(mark, protocolVersion);
|
||||
}
|
||||
|
|
@ -414,7 +414,7 @@ public class PagingState
|
|||
|
||||
return protocolVersion.isSmallerOrEqualTo(ProtocolVersion.V3)
|
||||
? decodeClustering(metadata, mark)
|
||||
: Clustering.serializer.deserialize(mark, MessagingService.VERSION_30, makeClusteringTypes(metadata));
|
||||
: Clustering.serializer.deserialize(mark, MessagingService.VERSION_40, makeClusteringTypes(metadata));
|
||||
}
|
||||
|
||||
// Old (pre-3.0) encoding of cells. We need that for the protocol v3 as that is how things where encoded
|
||||
|
|
|
|||
|
|
@ -40,7 +40,6 @@ import org.apache.cassandra.db.rows.Cell;
|
|||
import org.apache.cassandra.db.rows.DeserializationHelper;
|
||||
import org.apache.cassandra.db.rows.Row;
|
||||
import org.apache.cassandra.db.rows.UnfilteredRowIterator;
|
||||
import org.apache.cassandra.exceptions.UnknownTableException;
|
||||
import org.apache.cassandra.net.MessagingService;
|
||||
import org.apache.cassandra.schema.ColumnMetadata;
|
||||
import org.apache.cassandra.schema.SchemaConstants;
|
||||
|
|
@ -96,7 +95,7 @@ public class PaxosRows
|
|||
return null;
|
||||
|
||||
Ballot ballot = ballotCell.accessor().toBallot(ballotCell.value());
|
||||
int version = getInt(row, PROPOSAL_VERSION, MessagingService.VERSION_30);
|
||||
int version = getInt(row, PROPOSAL_VERSION, MessagingService.VERSION_40);
|
||||
PartitionUpdate update = getUpdate(row, PROPOSAL_UPDATE, version);
|
||||
return ballotCell.isExpiring()
|
||||
? new AcceptedWithTTL(ballot, update, ballotCell.localDeletionTime())
|
||||
|
|
@ -110,7 +109,7 @@ public class PaxosRows
|
|||
return Committed.none(partitionKey, metadata);
|
||||
|
||||
Ballot ballot = ballotCell.accessor().toBallot(ballotCell.value());
|
||||
int version = getInt(row, COMMIT_VERSION, MessagingService.VERSION_30);
|
||||
int version = getInt(row, COMMIT_VERSION, MessagingService.VERSION_40);
|
||||
PartitionUpdate update = getUpdate(row, COMMIT_UPDATE, version);
|
||||
return ballotCell.isExpiring()
|
||||
? new CommittedWithTTL(ballot, update, ballotCell.localDeletionTime())
|
||||
|
|
@ -140,22 +139,8 @@ public class PaxosRows
|
|||
Cell cell = row.getCell(cmeta);
|
||||
if (cell == null)
|
||||
throw new IllegalStateException();
|
||||
try
|
||||
{
|
||||
return PartitionUpdate.fromBytes(cell.buffer(), version);
|
||||
}
|
||||
catch (RuntimeException e)
|
||||
{
|
||||
// the legacy behaviors of not deleting proposal_version along with proposal and proposal_ballot on commit,
|
||||
// and accepting proposals younger than the most recent commit combined with the right sequence of tombstone
|
||||
// purging and retention over a few compactions can result in 3.x format proposals without a proposal version
|
||||
// value, causing deserialization to fail when looking up the table. So here we detect that and attempt to
|
||||
// deserialize with the current version
|
||||
if (e.getCause() instanceof UnknownTableException && version == MessagingService.VERSION_30)
|
||||
return PartitionUpdate.fromBytes(cell.buffer(), MessagingService.current_version);
|
||||
|
||||
throw e;
|
||||
}
|
||||
return PartitionUpdate.fromBytes(cell.buffer(), version);
|
||||
}
|
||||
|
||||
private static Ballot getBallot(Row row, ColumnMetadata cmeta)
|
||||
|
|
|
|||
|
|
@ -59,7 +59,6 @@ public class NettyStreamingChannel extends ChannelInboundHandlerAdapter implemen
|
|||
|
||||
@VisibleForTesting
|
||||
static final AttributeKey<Boolean> TRANSFERRING_FILE_ATTR = valueOf("transferringFile");
|
||||
final int messagingVersion;
|
||||
final Channel channel;
|
||||
|
||||
/**
|
||||
|
|
@ -75,9 +74,8 @@ public class NettyStreamingChannel extends ChannelInboundHandlerAdapter implemen
|
|||
|
||||
private volatile boolean closed;
|
||||
|
||||
public NettyStreamingChannel(int messagingVersion, Channel channel, Kind kind)
|
||||
public NettyStreamingChannel(Channel channel, Kind kind)
|
||||
{
|
||||
this.messagingVersion = messagingVersion;
|
||||
this.channel = channel;
|
||||
channel.attr(TRANSFERRING_FILE_ATTR).set(FALSE);
|
||||
if (kind == Kind.CONTROL)
|
||||
|
|
|
|||
|
|
@ -61,12 +61,12 @@ public class NettyStreamingConnectionFactory implements StreamingChannel.Factory
|
|||
{
|
||||
for (int i = 0; i < MAX_CONNECT_ATTEMPTS; i++)
|
||||
{
|
||||
Future<Result<StreamingSuccess>> result = initiateStreaming(eventLoop, settings, sslFallbackConnectionType, messagingVersion);
|
||||
Future<Result<StreamingSuccess>> result = initiateStreaming(eventLoop, settings, sslFallbackConnectionType);
|
||||
result.awaitUninterruptibly(); // initiate has its own timeout, so this is "guaranteed" to return relatively promptly
|
||||
if (result.isSuccess())
|
||||
{
|
||||
Channel channel = result.getNow().success().channel;
|
||||
NettyStreamingChannel streamingChannel = new NettyStreamingChannel(messagingVersion, channel, kind);
|
||||
NettyStreamingChannel streamingChannel = new NettyStreamingChannel(channel, kind);
|
||||
if (kind == StreamingChannel.Kind.CONTROL)
|
||||
{
|
||||
ChannelPipeline pipeline = channel.pipeline();
|
||||
|
|
|
|||
|
|
@ -53,12 +53,14 @@ import org.apache.cassandra.utils.concurrent.Semaphore;
|
|||
import org.apache.cassandra.utils.concurrent.UncheckedInterruptedException;
|
||||
|
||||
import static com.google.common.base.Throwables.getRootCause;
|
||||
|
||||
import static java.lang.String.format;
|
||||
import static java.lang.Thread.currentThread;
|
||||
import static java.util.concurrent.TimeUnit.*;
|
||||
|
||||
import static org.apache.cassandra.concurrent.ExecutorFactory.Global.executorFactory;
|
||||
import static org.apache.cassandra.config.CassandraRelevantProperties.STREAMING_SESSION_PARALLELTRANSFERS;
|
||||
import static org.apache.cassandra.net.MessagingService.VERSION_40;
|
||||
import static org.apache.cassandra.streaming.StreamSession.createLogTag;
|
||||
import static org.apache.cassandra.streaming.messages.StreamMessage.serialize;
|
||||
import static org.apache.cassandra.streaming.messages.StreamMessage.serializedSize;
|
||||
|
|
@ -122,6 +124,7 @@ public class StreamingMultiplexedChannel
|
|||
this.session = session;
|
||||
this.factory = factory;
|
||||
this.to = to;
|
||||
assert messagingVersion >= VERSION_40;
|
||||
this.messagingVersion = messagingVersion;
|
||||
this.controlChannel = controlChannel;
|
||||
|
||||
|
|
|
|||
|
|
@ -163,7 +163,7 @@ public class ConnectionBurnTest
|
|||
|
||||
public long serializedSize(byte[] payload, int version)
|
||||
{
|
||||
return MessageGenerator.serializedSize(payload, version);
|
||||
return MessageGenerator.serializedSize(payload);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -147,9 +147,8 @@ abstract class MessageGenerator
|
|||
|
||||
static Header readHeader(DataInputPlus in, int messagingVersion) throws IOException
|
||||
{
|
||||
int length = messagingVersion < VERSION_40
|
||||
? in.readInt()
|
||||
: in.readUnsignedVInt32();
|
||||
assert messagingVersion >= VERSION_40;
|
||||
int length = in.readUnsignedVInt32();
|
||||
long id = in.readLong();
|
||||
if (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN)
|
||||
id = Long.reverseBytes(id);
|
||||
|
|
@ -159,15 +158,13 @@ abstract class MessageGenerator
|
|||
|
||||
static void writeLength(byte[] payload, DataOutputPlus out, int messagingVersion) throws IOException
|
||||
{
|
||||
if (messagingVersion < VERSION_40)
|
||||
out.writeInt(payload.length);
|
||||
else
|
||||
out.writeUnsignedVInt32(payload.length);
|
||||
assert messagingVersion >= VERSION_40;
|
||||
out.writeUnsignedVInt32(payload.length);
|
||||
}
|
||||
|
||||
static long serializedSize(byte[] payload, int messagingVersion)
|
||||
static long serializedSize(byte[] payload)
|
||||
{
|
||||
return payload.length + (messagingVersion < VERSION_40 ? 4 : VIntCoding.computeUnsignedVIntSize(payload.length));
|
||||
return payload.length + VIntCoding.computeUnsignedVIntSize(payload.length);
|
||||
}
|
||||
|
||||
private static final Unsafe unsafe;
|
||||
|
|
|
|||
|
|
@ -765,11 +765,12 @@ public class Verifier
|
|||
assert m.is(ENQUEUE);
|
||||
m.serialize = e.at;
|
||||
m.messagingVersion = e.messagingVersion;
|
||||
assert m.messagingVersion >= VERSION_40;
|
||||
if (current_version != e.messagingVersion)
|
||||
controller.adjust(m.message.serializedSize(current_version), m.message.serializedSize(e.messagingVersion));
|
||||
|
||||
m.processOnEventLoop = willProcessOnEventLoop(outbound.type(), m.message, e.messagingVersion);
|
||||
m.expiresAtNanos = expiresAtNanos(m.message, e.messagingVersion);
|
||||
m.expiresAtNanos = expiresAtNanos(m.message);
|
||||
int mi = enqueueing.indexOf(m);
|
||||
for (int i = 0 ; i < mi ; ++i)
|
||||
{
|
||||
|
|
@ -1621,18 +1622,15 @@ public class Verifier
|
|||
private static boolean willProcessOnEventLoop(ConnectionType type, Message<?> message, int messagingVersion)
|
||||
{
|
||||
int size = message.serializedSize(messagingVersion);
|
||||
if (type == ConnectionType.SMALL_MESSAGES && messagingVersion >= VERSION_40)
|
||||
if (type == ConnectionType.SMALL_MESSAGES)
|
||||
return size <= LARGE_MESSAGE_THRESHOLD;
|
||||
else if (messagingVersion >= VERSION_40)
|
||||
return size <= DEFAULT_BUFFER_SIZE;
|
||||
else
|
||||
return size <= LARGE_MESSAGE_THRESHOLD;
|
||||
return size <= DEFAULT_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
private static long expiresAtNanos(Message<?> message, int messagingVersion)
|
||||
private static long expiresAtNanos(Message<?> message)
|
||||
{
|
||||
return messagingVersion < VERSION_40 ? message.verb().expiresAtNanos(message.createdAtNanos())
|
||||
: message.expiresAtNanos();
|
||||
return message.expiresAtNanos();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -104,10 +104,4 @@ public class MessageOutBench
|
|||
return msgOut.serializedSize(messagingVersion);
|
||||
}
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public int serializePre40() throws Exception
|
||||
{
|
||||
return serialize(MessagingService.VERSION_30);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -162,12 +162,9 @@ public class ReadResponseTest
|
|||
}
|
||||
|
||||
private void verifySerDe(ReadResponse response) {
|
||||
// check that roundtripping through ReadResponse.serializer behaves as expected.
|
||||
// ReadResponses from pre-4.0 nodes will never contain repaired data digest
|
||||
// or pending session info, but we run all messages through both pre/post 4.0
|
||||
// serde to check that the defaults are correctly applied
|
||||
roundTripSerialization(response, MessagingService.current_version);
|
||||
roundTripSerialization(response, MessagingService.VERSION_30);
|
||||
// check that roundtripping through ReadResponse.serializer behaves as expected
|
||||
for (MessagingService.Version version : MessagingService.Version.supportedVersions())
|
||||
roundTripSerialization(response, version.value);
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -180,19 +177,10 @@ public class ReadResponseTest
|
|||
|
||||
DataInputBuffer in = new DataInputBuffer(out.buffer(), false);
|
||||
ReadResponse deser = ReadResponse.serializer.deserialize(in, version);
|
||||
if (version < MessagingService.VERSION_40)
|
||||
{
|
||||
assertFalse(deser.mayIncludeRepairedDigest());
|
||||
// even though that means they should never be used, verify that the default values are present
|
||||
assertEquals(ByteBufferUtil.EMPTY_BYTE_BUFFER, deser.repairedDataDigest());
|
||||
assertTrue(deser.isRepairedDigestConclusive());
|
||||
}
|
||||
else
|
||||
{
|
||||
assertTrue(deser.mayIncludeRepairedDigest());
|
||||
assertEquals(response.repairedDataDigest(), deser.repairedDataDigest());
|
||||
assertEquals(response.isRepairedDigestConclusive(), deser.isRepairedDigestConclusive());
|
||||
}
|
||||
assertTrue(version >= MessagingService.VERSION_40);
|
||||
assertTrue(deser.mayIncludeRepairedDigest());
|
||||
assertEquals(response.repairedDataDigest(), deser.repairedDataDigest());
|
||||
assertEquals(response.isRepairedDigestConclusive(), deser.isRepairedDigestConclusive());
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -269,10 +269,10 @@ public class SinglePartitionSliceCommandTest
|
|||
response = ReadResponse.createDataResponse(pi, cmd, executionController.getRepairedDataInfo());
|
||||
}
|
||||
|
||||
out = new DataOutputBuffer((int) ReadResponse.serializer.serializedSize(response, MessagingService.VERSION_30));
|
||||
ReadResponse.serializer.serialize(response, out, MessagingService.VERSION_30);
|
||||
out = new DataOutputBuffer((int) ReadResponse.serializer.serializedSize(response, MessagingService.VERSION_40));
|
||||
ReadResponse.serializer.serialize(response, out, MessagingService.VERSION_40);
|
||||
in = new DataInputBuffer(out.buffer(), true);
|
||||
dst = ReadResponse.serializer.deserialize(in, MessagingService.VERSION_30);
|
||||
dst = ReadResponse.serializer.deserialize(in, MessagingService.VERSION_40);
|
||||
try (UnfilteredPartitionIterator pi = dst.makeIterator(cmd))
|
||||
{
|
||||
checkForS(pi);
|
||||
|
|
@ -284,10 +284,10 @@ public class SinglePartitionSliceCommandTest
|
|||
{
|
||||
response = ReadResponse.createDataResponse(pi, cmd, executionController.getRepairedDataInfo());
|
||||
}
|
||||
out = new DataOutputBuffer((int) ReadResponse.serializer.serializedSize(response, MessagingService.VERSION_30));
|
||||
ReadResponse.serializer.serialize(response, out, MessagingService.VERSION_30);
|
||||
out = new DataOutputBuffer((int) ReadResponse.serializer.serializedSize(response, MessagingService.VERSION_40));
|
||||
ReadResponse.serializer.serialize(response, out, MessagingService.VERSION_40);
|
||||
in = new DataInputBuffer(out.buffer(), true);
|
||||
dst = ReadResponse.serializer.deserialize(in, MessagingService.VERSION_30);
|
||||
dst = ReadResponse.serializer.deserialize(in, MessagingService.VERSION_40);
|
||||
try (UnfilteredPartitionIterator pi = dst.makeIterator(cmd))
|
||||
{
|
||||
checkForS(pi);
|
||||
|
|
|
|||
|
|
@ -20,15 +20,12 @@ package org.apache.cassandra.db.filter;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
|
||||
import org.apache.cassandra.Util;
|
||||
import org.apache.cassandra.config.DatabaseDescriptor;
|
||||
|
|
@ -52,14 +49,10 @@ import org.apache.cassandra.utils.Throwables;
|
|||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
@RunWith(Parameterized.class)
|
||||
public class ColumnFilterTest
|
||||
{
|
||||
private static final ColumnFilter.Serializer serializer = new ColumnFilter.Serializer();
|
||||
|
||||
@Parameterized.Parameter
|
||||
public String clusterMinVersion;
|
||||
|
||||
private final TableMetadata metadata = TableMetadata.builder("ks", "table")
|
||||
.partitioner(Murmur3Partitioner.instance)
|
||||
.addPartitionKeyColumn("pk", Int32Type.instance)
|
||||
|
|
@ -82,13 +75,6 @@ public class ColumnFilterTest
|
|||
private final CellPath path3 = CellPath.create(ByteBufferUtil.bytes(3));
|
||||
private final CellPath path4 = CellPath.create(ByteBufferUtil.bytes(4));
|
||||
|
||||
|
||||
@Parameterized.Parameters(name = "{index}: clusterMinVersion={0}")
|
||||
public static Collection<Object[]> data()
|
||||
{
|
||||
return Arrays.asList(new Object[]{ "3.0" }, new Object[]{ "3.11" }, new Object[]{ "4.0-rc1" }, new Object[]{ "4.0" });
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass()
|
||||
{
|
||||
|
|
@ -104,7 +90,7 @@ public class ColumnFilterTest
|
|||
@Before
|
||||
public void before()
|
||||
{
|
||||
Util.setUpgradeFromVersion(clusterMinVersion);
|
||||
Util.setUpgradeFromVersion("4.0");
|
||||
}
|
||||
|
||||
// Select all
|
||||
|
|
@ -341,15 +327,7 @@ public class ColumnFilterTest
|
|||
Consumer<ColumnFilter> check = filter -> {
|
||||
testRoundTrips(filter);
|
||||
assertFetchedQueried(true, true, filter, v1);
|
||||
if ("3.0".equals(clusterMinVersion))
|
||||
{
|
||||
assertEquals("*/*", filter.toString());
|
||||
assertEquals("*", filter.toCQLString());
|
||||
assertFetchedQueried(true, true, filter, s1, s2, v2);
|
||||
assertCellFetchedQueried(true, true, filter, v2, path0, path1, path2, path3, path4);
|
||||
assertCellFetchedQueried(true, true, filter, s2, path0, path1, path2, path3, path4);
|
||||
}
|
||||
else if ("3.11".equals(clusterMinVersion) || (returnStaticContentOnPartitionWithNoRows && "4.0".equals(clusterMinVersion)))
|
||||
if (returnStaticContentOnPartitionWithNoRows)
|
||||
{
|
||||
assertEquals("*/[v1]", filter.toString());
|
||||
assertEquals("v1", filter.toCQLString());
|
||||
|
|
@ -389,15 +367,7 @@ public class ColumnFilterTest
|
|||
Consumer<ColumnFilter> check = filter -> {
|
||||
testRoundTrips(filter);
|
||||
assertFetchedQueried(true, true, filter, s1);
|
||||
if ("3.0".equals(clusterMinVersion))
|
||||
{
|
||||
assertEquals("*/*", filter.toString());
|
||||
assertEquals("*", filter.toCQLString());
|
||||
assertFetchedQueried(true, true, filter, v1, v2, s2);
|
||||
assertCellFetchedQueried(true, true, filter, v2, path0, path1, path2, path3, path4);
|
||||
assertCellFetchedQueried(true, true, filter, s2, path0, path1, path2, path3, path4);
|
||||
}
|
||||
else if ("3.11".equals(clusterMinVersion) || (returnStaticContentOnPartitionWithNoRows && "4.0".equals(clusterMinVersion)))
|
||||
if (returnStaticContentOnPartitionWithNoRows)
|
||||
{
|
||||
assertEquals("*/[s1]", filter.toString());
|
||||
assertEquals("s1", filter.toCQLString());
|
||||
|
|
@ -439,15 +409,7 @@ public class ColumnFilterTest
|
|||
.build();
|
||||
testRoundTrips(filter);
|
||||
assertFetchedQueried(true, true, filter, v2);
|
||||
if ("3.0".equals(clusterMinVersion))
|
||||
{
|
||||
assertEquals("*/*", filter.toString());
|
||||
assertEquals("*", filter.toCQLString());
|
||||
assertFetchedQueried(true, true, filter, s1, s2, v1);
|
||||
assertCellFetchedQueried(true, true, filter, v2, path0, path1, path2, path3, path4);
|
||||
assertCellFetchedQueried(true, true, filter, s2, path0, path1, path2, path3, path4);
|
||||
}
|
||||
else if ("3.11".equals(clusterMinVersion) || (returnStaticContentOnPartitionWithNoRows && "4.0".equals(clusterMinVersion)))
|
||||
if (returnStaticContentOnPartitionWithNoRows)
|
||||
{
|
||||
assertEquals("*/[v2[1]]", filter.toString());
|
||||
assertEquals("v2[1]", filter.toCQLString());
|
||||
|
|
@ -487,15 +449,7 @@ public class ColumnFilterTest
|
|||
.build();
|
||||
testRoundTrips(filter);
|
||||
assertFetchedQueried(true, true, filter, s2);
|
||||
if ("3.0".equals(clusterMinVersion))
|
||||
{
|
||||
assertEquals("*/*", filter.toString());
|
||||
assertEquals("*", filter.toCQLString());
|
||||
assertFetchedQueried(true, true, filter, v1, v2, s1);
|
||||
assertCellFetchedQueried(true, true, filter, v2, path0, path1, path2, path3, path4);
|
||||
assertCellFetchedQueried(true, true, filter, s2, path1, path0, path2, path3, path4);
|
||||
}
|
||||
else if ("3.11".equals(clusterMinVersion) || (returnStaticContentOnPartitionWithNoRows && "4.0".equals(clusterMinVersion)))
|
||||
if (returnStaticContentOnPartitionWithNoRows)
|
||||
{
|
||||
assertEquals("*/[s2[1]]", filter.toString());
|
||||
assertEquals("s2[1]", filter.toCQLString());
|
||||
|
|
@ -518,8 +472,6 @@ public class ColumnFilterTest
|
|||
|
||||
private void testRoundTrips(ColumnFilter cf)
|
||||
{
|
||||
testRoundTrip(cf, MessagingService.VERSION_30);
|
||||
testRoundTrip(cf, MessagingService.VERSION_3014);
|
||||
testRoundTrip(cf, MessagingService.VERSION_40);
|
||||
}
|
||||
|
||||
|
|
@ -533,14 +485,7 @@ public class ColumnFilterTest
|
|||
DataInputPlus input = new DataInputBuffer(output.buffer(), false);
|
||||
ColumnFilter deserialized = serializer.deserialize(input, version, metadata);
|
||||
|
||||
if (version == MessagingService.VERSION_30 && columnFilter.fetchesAllColumns(false))
|
||||
{
|
||||
Assert.assertEquals(metadata.regularAndStaticColumns(), deserialized.fetchedColumns());
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.assertEquals(deserialized, columnFilter);
|
||||
}
|
||||
Assert.assertEquals(deserialized, columnFilter);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -37,10 +37,11 @@ public class InetAddressAndPortSerializerTest
|
|||
InetAddressAndPort ipv4 = InetAddressAndPort.getByName("127.0.0.1:42");
|
||||
InetAddressAndPort ipv6 = InetAddressAndPort.getByName("[2001:db8:0:0:0:ff00:42:8329]:42");
|
||||
|
||||
testAddress(ipv4, MessagingService.VERSION_30);
|
||||
testAddress(ipv6, MessagingService.VERSION_30);
|
||||
testAddress(ipv4, MessagingService.current_version);
|
||||
testAddress(ipv6, MessagingService.current_version);
|
||||
for (MessagingService.Version version : MessagingService.Version.supportedVersions())
|
||||
{
|
||||
testAddress(ipv4, version.value);
|
||||
testAddress(ipv6, version.value);
|
||||
}
|
||||
}
|
||||
|
||||
private void testAddress(InetAddressAndPort address, int version) throws Exception
|
||||
|
|
|
|||
|
|
@ -58,7 +58,6 @@ import io.netty.channel.ChannelPromise;
|
|||
import org.apache.cassandra.config.DatabaseDescriptor;
|
||||
import org.apache.cassandra.config.EncryptionOptions;
|
||||
import org.apache.cassandra.db.commitlog.CommitLog;
|
||||
import org.apache.cassandra.distributed.shared.WithProperties;
|
||||
import org.apache.cassandra.exceptions.RequestFailureReason;
|
||||
import org.apache.cassandra.exceptions.UnknownColumnException;
|
||||
import org.apache.cassandra.io.IVersionedAsymmetricSerializer;
|
||||
|
|
@ -71,15 +70,12 @@ import org.apache.cassandra.utils.FBUtilities;
|
|||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||
import static java.util.concurrent.TimeUnit.MINUTES;
|
||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
import static org.apache.cassandra.config.CassandraRelevantProperties.SSL_STORAGE_PORT;
|
||||
import static org.apache.cassandra.net.MessagingService.VERSION_30;
|
||||
import static org.apache.cassandra.net.MessagingService.VERSION_3014;
|
||||
import static org.apache.cassandra.net.MessagingService.VERSION_40;
|
||||
import static org.apache.cassandra.net.NoPayload.noPayload;
|
||||
import static org.apache.cassandra.net.MessagingService.current_version;
|
||||
import static org.apache.cassandra.net.ConnectionUtils.*;
|
||||
import static org.apache.cassandra.net.ConnectionType.LARGE_MESSAGES;
|
||||
import static org.apache.cassandra.net.ConnectionType.SMALL_MESSAGES;
|
||||
import static org.apache.cassandra.net.ConnectionUtils.*;
|
||||
import static org.apache.cassandra.net.OutboundConnectionSettings.Framing.LZ4;
|
||||
import static org.apache.cassandra.net.OutboundConnections.LARGE_MESSAGE_THRESHOLD;
|
||||
import static org.apache.cassandra.utils.Clock.Global.nanoTime;
|
||||
|
|
@ -104,11 +100,6 @@ public class ConnectionTest
|
|||
handlers.putIfAbsent(verb, verb.unsafeSetHandler(supplier));
|
||||
}
|
||||
|
||||
private void unsafeSetExpiration(Verb verb, ToLongFunction<TimeUnit> expiration) throws Throwable
|
||||
{
|
||||
timeouts.putIfAbsent(verb, verb.unsafeSetExpiration(expiration));
|
||||
}
|
||||
|
||||
@After
|
||||
public void resetVerbs() throws Throwable
|
||||
{
|
||||
|
|
@ -192,11 +183,7 @@ public class ConnectionTest
|
|||
.withRequireClientAuth(false)
|
||||
.withCipherSuites("TLS_RSA_WITH_AES_128_CBC_SHA");
|
||||
|
||||
static final AcceptVersions legacy = new AcceptVersions(VERSION_30, VERSION_30);
|
||||
|
||||
static final List<Function<Settings, Settings>> MODIFIERS = ImmutableList.of(
|
||||
settings -> settings.outbound(outbound -> outbound.withAcceptVersions(legacy))
|
||||
.inbound(inbound -> inbound.withAcceptMessaging(legacy)),
|
||||
settings -> settings.outbound(outbound -> outbound.withEncryption(encryptionOptions))
|
||||
.inbound(inbound -> inbound.withEncryption(encryptionOptions)),
|
||||
settings -> settings.outbound(outbound -> outbound.withFraming(LZ4))
|
||||
|
|
@ -545,115 +532,6 @@ public class ConnectionTest
|
|||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPre40() throws Throwable
|
||||
{
|
||||
MessagingService.instance().versions.set(FBUtilities.getBroadcastAddressAndPort(),
|
||||
MessagingService.VERSION_30);
|
||||
|
||||
try
|
||||
{
|
||||
test((inbound, outbound, endpoint) -> {
|
||||
CountDownLatch done = new CountDownLatch(1);
|
||||
unsafeSetHandler(Verb._TEST_1,
|
||||
() -> (msg) -> done.countDown());
|
||||
|
||||
Message<?> message = Message.out(Verb._TEST_1, noPayload);
|
||||
outbound.enqueue(message);
|
||||
Assert.assertTrue(done.await(1, MINUTES));
|
||||
Assert.assertTrue(outbound.isConnected());
|
||||
});
|
||||
}
|
||||
finally
|
||||
{
|
||||
MessagingService.instance().versions.set(FBUtilities.getBroadcastAddressAndPort(),
|
||||
current_version);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPendingOutboundConnectionUpdatesMessageVersionOnReconnectAttempt() throws Throwable
|
||||
{
|
||||
try (WithProperties properties = new WithProperties().set(SSL_STORAGE_PORT, 7011))
|
||||
{
|
||||
// Set up an inbound connection listening *only* on the SSL storage port to
|
||||
// replicate a 3.x node. Force the messaging version to be incorrectly set to 4.0
|
||||
// before the outbound connection attempt.
|
||||
final Settings settings = Settings.LARGE;
|
||||
final InetAddressAndPort endpoint = FBUtilities.getBroadcastAddressAndPort();
|
||||
|
||||
MessagingService.instance().versions.set(FBUtilities.getBroadcastAddressAndPort(),
|
||||
MessagingService.VERSION_40);
|
||||
|
||||
final InetAddressAndPort legacySSLAddrsAndPort = endpoint.withPort(DatabaseDescriptor.getSSLStoragePort());
|
||||
InboundConnectionSettings inboundSettings = settings.inbound.apply(new InboundConnectionSettings().withEncryption(encryptionOptions))
|
||||
.withBindAddress(legacySSLAddrsAndPort)
|
||||
.withAcceptMessaging(new AcceptVersions(VERSION_30, VERSION_3014))
|
||||
.withSocketFactory(factory);
|
||||
InboundSockets inbound = new InboundSockets(Collections.singletonList(inboundSettings));
|
||||
OutboundConnectionSettings outboundTemplate = settings.outbound.apply(new OutboundConnectionSettings(endpoint).withEncryption(encryptionOptions))
|
||||
.withDefaultReserveLimits()
|
||||
.withSocketFactory(factory)
|
||||
.withDefaults(ConnectionCategory.MESSAGING);
|
||||
ResourceLimits.EndpointAndGlobal reserveCapacityInBytes = new ResourceLimits.EndpointAndGlobal(new ResourceLimits.Concurrent(outboundTemplate.applicationSendQueueReserveEndpointCapacityInBytes), outboundTemplate.applicationSendQueueReserveGlobalCapacityInBytes);
|
||||
OutboundConnection outbound = new OutboundConnection(settings.type, outboundTemplate, reserveCapacityInBytes);
|
||||
try
|
||||
{
|
||||
logger.info("Running {} {} -> {}", outbound.messagingVersion(), outbound.settings(), inboundSettings);
|
||||
inbound.open().sync();
|
||||
|
||||
CountDownLatch done = new CountDownLatch(1);
|
||||
unsafeSetHandler(Verb._TEST_1,
|
||||
() -> (msg) -> done.countDown());
|
||||
|
||||
// Enqueuing outbound message will initiate an outbound
|
||||
// connection with pending data in the pipeline
|
||||
Message<?> message = Message.out(Verb._TEST_1, noPayload);
|
||||
outbound.enqueue(message);
|
||||
|
||||
// Wait until the first connection attempt has taken place
|
||||
// before updating the endpoint messaging version so that the
|
||||
// connection takes place to a 4.0 node.
|
||||
int attempts = 0;
|
||||
final long waitForAttemptMillis = TimeUnit.SECONDS.toMillis(15);
|
||||
while (outbound.connectionAttempts() == 0 && attempts < waitForAttemptMillis / 10)
|
||||
{
|
||||
Uninterruptibles.sleepUninterruptibly(10, TimeUnit.MILLISECONDS);
|
||||
attempts++;
|
||||
}
|
||||
|
||||
// Now that the connection is being attempted, set the endpoint version so
|
||||
// that on the reconnect attempt the messaging version is rechecked and the
|
||||
// legacy ssl logic picks the storage port instead. This should trigger a
|
||||
// TRACE level log message "Endpoint version changed from 12 to 10 since
|
||||
// connection initialized, updating."
|
||||
outbound.settings().endpointToVersion.set(endpoint, VERSION_30);
|
||||
|
||||
// The connection should have successfully connected and delivered the _TEST_1
|
||||
// message within the timout.
|
||||
Assert.assertTrue(done.await(15, SECONDS));
|
||||
Assert.assertTrue(outbound.isConnected());
|
||||
Assert.assertTrue(String.format("expect less successful connections (%d) than attempts (%d)",
|
||||
outbound.successfulConnections(), outbound.connectionAttempts()),
|
||||
outbound.successfulConnections() < outbound.connectionAttempts());
|
||||
|
||||
}
|
||||
finally
|
||||
{
|
||||
outbound.close(false);
|
||||
inbound.close().get(30L, SECONDS);
|
||||
outbound.close(false).get(30L, SECONDS);
|
||||
resetVerbs();
|
||||
MessagingService.instance().messageHandlers.clear();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
MessagingService.instance().versions.set(FBUtilities.getBroadcastAddressAndPort(),
|
||||
current_version);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCloseIfEndpointDown() throws Throwable
|
||||
{
|
||||
|
|
@ -750,7 +628,7 @@ public class ConnectionTest
|
|||
unsafeSetHandler(Verb._TEST_1, () -> msg -> done.countDown());
|
||||
outbound.enqueue(Message.out(Verb._TEST_1, noPayload));
|
||||
Assert.assertTrue(done.await(10, SECONDS));
|
||||
Assert.assertEquals(done.getCount(), 0);
|
||||
Assert.assertEquals(0, done.getCount());
|
||||
|
||||
// Simulate disconnect
|
||||
inbound.close().get(10, SECONDS);
|
||||
|
|
@ -763,7 +641,7 @@ public class ConnectionTest
|
|||
outbound.enqueue(Message.out(Verb._TEST_1, noPayload));
|
||||
|
||||
latch2.await(10, SECONDS);
|
||||
Assert.assertEquals(latch2.getCount(), 0);
|
||||
Assert.assertEquals(0, latch2.getCount());
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
|
|
|||
|
|
@ -35,16 +35,12 @@ import static org.junit.Assert.assertTrue;
|
|||
|
||||
public class ForwardingInfoTest
|
||||
{
|
||||
@Test
|
||||
public void testCurrent() throws Exception
|
||||
{
|
||||
testVersion(MessagingService.current_version);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test30() throws Exception
|
||||
public void testSupportedVersions() throws Exception
|
||||
{
|
||||
testVersion(MessagingService.VERSION_30);
|
||||
for (MessagingService.Version version : MessagingService.Version.supportedVersions())
|
||||
testVersion(version.value);
|
||||
}
|
||||
|
||||
private void testVersion(int version) throws Exception
|
||||
|
|
|
|||
|
|
@ -48,11 +48,6 @@ import org.apache.cassandra.utils.memory.BufferPools;
|
|||
import org.apache.cassandra.utils.vint.VIntCoding;
|
||||
|
||||
import static java.lang.Math.*;
|
||||
import static org.apache.cassandra.net.MessagingService.VERSION_30;
|
||||
import static org.apache.cassandra.net.MessagingService.VERSION_3014;
|
||||
import static org.apache.cassandra.net.MessagingService.current_version;
|
||||
import static org.apache.cassandra.net.MessagingService.minimum_version;
|
||||
import static org.apache.cassandra.net.OutboundConnections.LARGE_MESSAGE_THRESHOLD;
|
||||
import static org.apache.cassandra.net.ShareableBytes.wrap;
|
||||
|
||||
// TODO: test corruption
|
||||
|
|
@ -210,12 +205,6 @@ public class FramingTest
|
|||
return new SequenceOfFrames(uncompressed, cumulativeCompressedLength, frames);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void burnRandomLegacy()
|
||||
{
|
||||
burnRandomLegacy(1000);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSerializeSizeMatchesEdgeCases() // See CASSANDRA-16103
|
||||
{
|
||||
|
|
@ -247,212 +236,6 @@ public class FramingTest
|
|||
subTest.accept(1L << 14 - 1);
|
||||
}
|
||||
|
||||
private void burnRandomLegacy(int count)
|
||||
{
|
||||
SecureRandom seed = new SecureRandom();
|
||||
Random random = new Random();
|
||||
for (int i = 0 ; i < count ; ++i)
|
||||
{
|
||||
long innerSeed = seed.nextLong();
|
||||
float ratio = seed.nextFloat();
|
||||
int version = minimum_version + random.nextInt(1 + current_version - minimum_version);
|
||||
logger.debug("seed: {}, ratio: {}, version: {}", innerSeed, ratio, version);
|
||||
random.setSeed(innerSeed);
|
||||
testRandomSequenceOfMessages(random, ratio, version, new FrameDecoderLegacy(GlobalBufferPoolAllocator.instance, version));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRandomLegacy()
|
||||
{
|
||||
testRandomLegacy(250);
|
||||
}
|
||||
|
||||
private void testRandomLegacy(int count)
|
||||
{
|
||||
SecureRandom seeds = new SecureRandom();
|
||||
for (int messagingVersion : new int[] { VERSION_30, VERSION_3014, current_version})
|
||||
{
|
||||
FrameDecoder decoder = new FrameDecoderLegacy(GlobalBufferPoolAllocator.instance, messagingVersion);
|
||||
testSomeMessages(seeds.nextLong(), count, 0.0f, messagingVersion, decoder);
|
||||
testSomeMessages(seeds.nextLong(), count, 0.1f, messagingVersion, decoder);
|
||||
testSomeMessages(seeds.nextLong(), count, 0.95f, messagingVersion, decoder);
|
||||
testSomeMessages(seeds.nextLong(), count, 1.0f, messagingVersion, decoder);
|
||||
}
|
||||
}
|
||||
|
||||
private void testSomeMessages(long seed, int count, float largeRatio, int messagingVersion, FrameDecoder decoder)
|
||||
{
|
||||
logger.info("seed: {}, iterations: {}, largeRatio: {}, messagingVersion: {}, decoder: {}", seed, count, largeRatio, messagingVersion, decoder.getClass().getSimpleName());
|
||||
Random random = new Random(seed);
|
||||
for (int i = 0 ; i < count ; ++i)
|
||||
{
|
||||
long innerSeed = random.nextLong();
|
||||
logger.debug("inner seed: {}, iteration: {}", innerSeed, i);
|
||||
random.setSeed(innerSeed);
|
||||
testRandomSequenceOfMessages(random, largeRatio, messagingVersion, decoder);
|
||||
}
|
||||
}
|
||||
|
||||
private void testRandomSequenceOfMessages(Random random, float largeRatio, int messagingVersion, FrameDecoder decoder)
|
||||
{
|
||||
SequenceOfFrames sequenceOfMessages = sequenceOfMessages(random, largeRatio, messagingVersion);
|
||||
|
||||
List<byte[]> messages = sequenceOfMessages.original;
|
||||
ShareableBytes stream = sequenceOfMessages.frames;
|
||||
|
||||
int end = stream.get().limit();
|
||||
List<FrameDecoder.Frame> out = new ArrayList<>();
|
||||
|
||||
int messageStart = 0;
|
||||
int messageIndex = 0;
|
||||
for (int i = 0 ; i < end ; )
|
||||
{
|
||||
int limit = i + random.nextInt(1 + end - i);
|
||||
decoder.decode(out, stream.slice(i, limit));
|
||||
|
||||
int outIndex = 0;
|
||||
byte[] message = messages.get(messageIndex);
|
||||
if (i > messageStart)
|
||||
{
|
||||
int start;
|
||||
if (message.length <= LARGE_MESSAGE_THRESHOLD)
|
||||
{
|
||||
start = 0;
|
||||
}
|
||||
else if (!lengthIsReadable(message, i - messageStart, messagingVersion))
|
||||
{
|
||||
// we should have an initial frame containing only some prefix of the message (probably 64 bytes)
|
||||
// that was stashed only to decide how big the message was
|
||||
FrameDecoder.IntactFrame frame = (FrameDecoder.IntactFrame) out.get(outIndex++);
|
||||
Assert.assertFalse(frame.isSelfContained);
|
||||
start = frame.contents.remaining();
|
||||
verify(message, 0, frame.contents.remaining(), frame.contents);
|
||||
}
|
||||
else
|
||||
{
|
||||
start = i - messageStart;
|
||||
}
|
||||
|
||||
if (limit >= message.length + messageStart)
|
||||
{
|
||||
FrameDecoder.IntactFrame frame = (FrameDecoder.IntactFrame) out.get(outIndex++);
|
||||
Assert.assertEquals(start == 0, frame.isSelfContained);
|
||||
// verify remainder of a large message, or a single fully stashed small message
|
||||
verify(message, start, message.length, frame.contents);
|
||||
|
||||
messageStart += message.length;
|
||||
if (++messageIndex < messages.size())
|
||||
message = messages.get(messageIndex);
|
||||
}
|
||||
else if (message.length > LARGE_MESSAGE_THRESHOLD)
|
||||
{
|
||||
FrameDecoder.IntactFrame frame = (FrameDecoder.IntactFrame) out.get(outIndex++);
|
||||
Assert.assertFalse(frame.isSelfContained);
|
||||
// verify next portion of a large message
|
||||
verify(message, start, limit - messageStart, frame.contents);
|
||||
|
||||
Assert.assertEquals(outIndex, out.size());
|
||||
for (FrameDecoder.Frame f : out)
|
||||
f.release();
|
||||
out.clear();
|
||||
i = limit;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// message is fresh
|
||||
int beginFrameIndex = messageIndex;
|
||||
while (messageStart + message.length <= limit)
|
||||
{
|
||||
messageStart += message.length;
|
||||
if (++messageIndex < messages.size())
|
||||
message = messages.get(messageIndex);
|
||||
}
|
||||
|
||||
if (beginFrameIndex < messageIndex)
|
||||
{
|
||||
FrameDecoder.IntactFrame frame = (FrameDecoder.IntactFrame) out.get(outIndex++);
|
||||
Assert.assertTrue(frame.isSelfContained);
|
||||
while (beginFrameIndex < messageIndex)
|
||||
{
|
||||
byte[] m = messages.get(beginFrameIndex);
|
||||
ShareableBytes bytesToVerify = frame.contents.sliceAndConsume(m.length);
|
||||
verify(m, bytesToVerify);
|
||||
bytesToVerify.release();
|
||||
++beginFrameIndex;
|
||||
}
|
||||
Assert.assertFalse(frame.contents.hasRemaining());
|
||||
}
|
||||
|
||||
if (limit > messageStart
|
||||
&& message.length > LARGE_MESSAGE_THRESHOLD
|
||||
&& lengthIsReadable(message, limit - messageStart, messagingVersion))
|
||||
{
|
||||
FrameDecoder.IntactFrame frame = (FrameDecoder.IntactFrame) out.get(outIndex++);
|
||||
Assert.assertFalse(frame.isSelfContained);
|
||||
verify(message, 0, limit - messageStart, frame.contents);
|
||||
}
|
||||
|
||||
Assert.assertEquals(outIndex, out.size());
|
||||
for (FrameDecoder.Frame frame : out)
|
||||
frame.release();
|
||||
out.clear();
|
||||
|
||||
i = limit;
|
||||
}
|
||||
stream.release();
|
||||
Assert.assertTrue(stream.isReleased());
|
||||
Assert.assertNull(decoder.stash);
|
||||
Assert.assertTrue(decoder.frames.isEmpty());
|
||||
}
|
||||
|
||||
private static boolean lengthIsReadable(byte[] message, int limit, int messagingVersion)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Message.serializer.inferMessageSize(ByteBuffer.wrap(message), 0, limit, messagingVersion) >= 0;
|
||||
}
|
||||
catch (Message.InvalidLegacyProtocolMagic e)
|
||||
{
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static SequenceOfFrames sequenceOfMessages(Random random, float largeRatio, int messagingVersion)
|
||||
{
|
||||
int messageCount = 1 + random.nextInt(63);
|
||||
List<byte[]> messages = new ArrayList<>();
|
||||
int[] cumulativeLength = new int[messageCount];
|
||||
for (int i = 0 ; i < messageCount ; ++i)
|
||||
{
|
||||
byte[] payload;
|
||||
if (random.nextFloat() < largeRatio) payload = randomishBytes(random, 1 << 16, 1 << 17);
|
||||
else payload = randomishBytes(random, 1, 1 << 16);
|
||||
Message<byte[]> messageObj = Message.out(Verb._TEST_1, payload);
|
||||
|
||||
byte[] message;
|
||||
try (DataOutputBuffer out = new DataOutputBuffer(messageObj.serializedSize(messagingVersion)))
|
||||
{
|
||||
Message.serializer.serialize(messageObj, out, messagingVersion);
|
||||
message = out.toByteArray();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
messages.add(message);
|
||||
|
||||
cumulativeLength[i] = (i == 0 ? 0 : cumulativeLength[i - 1]) + message.length;
|
||||
}
|
||||
|
||||
ByteBuffer frames = BufferPools.forNetworking().getAtLeast(cumulativeLength[messageCount - 1], BufferType.OFF_HEAP);
|
||||
for (byte[] buffer : messages)
|
||||
frames.put(buffer);
|
||||
frames.flip();
|
||||
return new SequenceOfFrames(messages, cumulativeLength, frames);
|
||||
}
|
||||
|
||||
public static byte[] randomishBytes(Random random, int minLength, int maxLength)
|
||||
{
|
||||
byte[] bytes = new byte[minLength + random.nextInt(Math.max(1, maxLength - minLength))];
|
||||
|
|
|
|||
|
|
@ -22,36 +22,34 @@ import java.nio.channels.ClosedChannelException;
|
|||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import com.google.common.net.InetAddresses;
|
||||
|
||||
import org.apache.cassandra.config.DatabaseDescriptor;
|
||||
import org.apache.cassandra.config.EncryptionOptions.ServerEncryptionOptions;
|
||||
import org.apache.cassandra.config.ParameterizedClass;
|
||||
import org.apache.cassandra.db.commitlog.CommitLog;
|
||||
import org.apache.cassandra.gms.GossipDigestSyn;
|
||||
import org.apache.cassandra.locator.InetAddressAndPort;
|
||||
import org.apache.cassandra.net.OutboundConnectionInitiator.Result.MessagingSuccess;
|
||||
import org.apache.cassandra.security.DefaultSslContextFactory;
|
||||
import org.apache.cassandra.utils.concurrent.AsyncPromise;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Assert;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import io.netty.channel.EventLoop;
|
||||
import io.netty.util.concurrent.Future;
|
||||
import org.apache.cassandra.config.DatabaseDescriptor;
|
||||
import org.apache.cassandra.db.commitlog.CommitLog;
|
||||
import org.apache.cassandra.locator.InetAddressAndPort;
|
||||
import org.apache.cassandra.net.OutboundConnectionInitiator.Result.MessagingSuccess;
|
||||
|
||||
import static org.apache.cassandra.net.MessagingService.VERSION_30;
|
||||
import static org.apache.cassandra.net.MessagingService.VERSION_3014;
|
||||
import static org.apache.cassandra.net.MessagingService.current_version;
|
||||
import static org.apache.cassandra.net.MessagingService.minimum_version;
|
||||
import static org.apache.cassandra.net.ConnectionType.SMALL_MESSAGES;
|
||||
import static org.apache.cassandra.net.OutboundConnectionInitiator.*;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
|
|
@ -75,15 +73,15 @@ public class HandshakeTest
|
|||
factory.shutdownNow();
|
||||
}
|
||||
|
||||
private Result handshake(int req, int outMin, int outMax) throws ExecutionException, InterruptedException
|
||||
private Result handshake(int outMin, int outMax) throws ExecutionException, InterruptedException
|
||||
{
|
||||
return handshake(req, new AcceptVersions(outMin, outMax), null);
|
||||
return handshake(new AcceptVersions(outMin, outMax), null);
|
||||
}
|
||||
private Result handshake(int req, int outMin, int outMax, int inMin, int inMax) throws ExecutionException, InterruptedException
|
||||
private Result handshake(int outMin, int outMax, int inMin, int inMax) throws ExecutionException, InterruptedException
|
||||
{
|
||||
return handshake(req, new AcceptVersions(outMin, outMax), new AcceptVersions(inMin, inMax));
|
||||
return handshake(new AcceptVersions(outMin, outMax), new AcceptVersions(inMin, inMax));
|
||||
}
|
||||
private Result handshake(int req, AcceptVersions acceptOutbound, AcceptVersions acceptInbound) throws ExecutionException, InterruptedException
|
||||
private Result handshake(AcceptVersions acceptOutbound, AcceptVersions acceptInbound) throws ExecutionException, InterruptedException
|
||||
{
|
||||
InboundSockets inbound = new InboundSockets(new InboundConnectionSettings().withAcceptMessaging(acceptInbound));
|
||||
try
|
||||
|
|
@ -98,7 +96,7 @@ public class HandshakeTest
|
|||
new OutboundConnectionSettings(endpoint)
|
||||
.withAcceptVersions(acceptOutbound)
|
||||
.withDefaults(ConnectionCategory.MESSAGING),
|
||||
req, AsyncPromise.withExecutor(eventLoop));
|
||||
AsyncPromise.withExecutor(eventLoop));
|
||||
return future.get();
|
||||
}
|
||||
finally
|
||||
|
|
@ -111,7 +109,7 @@ public class HandshakeTest
|
|||
@Test
|
||||
public void testBothCurrentVersion() throws InterruptedException, ExecutionException
|
||||
{
|
||||
Result result = handshake(current_version, minimum_version, current_version);
|
||||
Result result = handshake(minimum_version, current_version);
|
||||
Assert.assertEquals(Result.Outcome.SUCCESS, result.outcome);
|
||||
result.success().channel.close();
|
||||
}
|
||||
|
|
@ -119,7 +117,7 @@ public class HandshakeTest
|
|||
@Test
|
||||
public void testSendCompatibleOldVersion() throws InterruptedException, ExecutionException
|
||||
{
|
||||
Result result = handshake(current_version, current_version, current_version + 1, current_version +1, current_version + 2);
|
||||
Result result = handshake(current_version, current_version + 1, current_version +1, current_version + 2);
|
||||
Assert.assertEquals(Result.Outcome.SUCCESS, result.outcome);
|
||||
Assert.assertEquals(current_version + 1, result.success().messagingVersion);
|
||||
result.success().channel.close();
|
||||
|
|
@ -128,7 +126,7 @@ public class HandshakeTest
|
|||
@Test
|
||||
public void testSendCompatibleFutureVersion() throws InterruptedException, ExecutionException
|
||||
{
|
||||
Result result = handshake(current_version + 1, current_version - 1, current_version + 1);
|
||||
Result result = handshake(MessagingService.minimum_version, current_version + 1);
|
||||
Assert.assertEquals(Result.Outcome.SUCCESS, result.outcome);
|
||||
Assert.assertEquals(current_version, result.success().messagingVersion);
|
||||
result.success().channel.close();
|
||||
|
|
@ -137,7 +135,7 @@ public class HandshakeTest
|
|||
@Test
|
||||
public void testSendIncompatibleFutureVersion() throws InterruptedException, ExecutionException
|
||||
{
|
||||
Result result = handshake(current_version + 1, current_version + 1, current_version + 1);
|
||||
Result result = handshake(current_version + 1, current_version + 1);
|
||||
Assert.assertEquals(Result.Outcome.INCOMPATIBLE, result.outcome);
|
||||
Assert.assertEquals(current_version, result.incompatible().closestSupportedVersion);
|
||||
Assert.assertEquals(current_version, result.incompatible().maxMessagingVersion);
|
||||
|
|
@ -146,94 +144,38 @@ public class HandshakeTest
|
|||
@Test
|
||||
public void testSendIncompatibleOldVersion() throws InterruptedException, ExecutionException
|
||||
{
|
||||
Result result = handshake(current_version + 1, current_version + 1, current_version + 1, current_version + 2, current_version + 3);
|
||||
Result result = handshake(current_version + 1, current_version + 1, current_version + 2, current_version + 3);
|
||||
Assert.assertEquals(Result.Outcome.INCOMPATIBLE, result.outcome);
|
||||
Assert.assertEquals(current_version + 2, result.incompatible().closestSupportedVersion);
|
||||
Assert.assertEquals(current_version + 3, result.incompatible().maxMessagingVersion);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSendCompatibleMaxVersionPre40() throws InterruptedException, ExecutionException
|
||||
public void testSendAllSupported() throws InterruptedException, ExecutionException
|
||||
{
|
||||
Result result = handshake(VERSION_3014, VERSION_30, VERSION_3014, VERSION_30, VERSION_3014);
|
||||
Assert.assertEquals(Result.Outcome.SUCCESS, result.outcome);
|
||||
Assert.assertEquals(VERSION_3014, result.success().messagingVersion);
|
||||
result.success().channel.close();
|
||||
}
|
||||
List<MessagingService.Version> supportedVersions = MessagingService.Version.supportedVersions();
|
||||
for (MessagingService.Version outMin : supportedVersions)
|
||||
for (MessagingService.Version outMax : supportedVersions)
|
||||
if (outMin.value <= outMax.value)
|
||||
for (MessagingService.Version inMin : supportedVersions)
|
||||
for (MessagingService.Version inMax : supportedVersions)
|
||||
if (inMin.value <= inMax.value)
|
||||
{
|
||||
Result result = handshake(outMin.value, outMax.value, inMin.value, inMax.value);
|
||||
// expect success if out and in have a version in common
|
||||
boolean expectSuccess = outMin.value <= inMax.value && inMin.value <= outMax.value;
|
||||
|
||||
@Test
|
||||
public void testSendCompatibleFutureVersionPre40() throws InterruptedException, ExecutionException
|
||||
{
|
||||
Result result = handshake(VERSION_3014, VERSION_30, VERSION_3014, VERSION_30, VERSION_30);
|
||||
Assert.assertEquals(Result.Outcome.RETRY, result.outcome);
|
||||
Assert.assertEquals(VERSION_30, result.retry().withMessagingVersion);
|
||||
}
|
||||
Assert.assertEquals(String.format("wrong result outcome for outMin %s outMax %s inMin %s inMax %s", outMin.value, outMax.value, inMin.value, inMax.value),
|
||||
expectSuccess ? Result.Outcome.SUCCESS : Result.Outcome.INCOMPATIBLE, result.outcome);
|
||||
|
||||
@Test
|
||||
public void testSendIncompatibleFutureVersionPre40() throws InterruptedException, ExecutionException
|
||||
{
|
||||
Result result = handshake(VERSION_3014, VERSION_3014, VERSION_3014, VERSION_30, VERSION_30);
|
||||
Assert.assertEquals(Result.Outcome.INCOMPATIBLE, result.outcome);
|
||||
Assert.assertEquals(-1, result.incompatible().closestSupportedVersion);
|
||||
Assert.assertEquals(VERSION_30, result.incompatible().maxMessagingVersion);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSendCompatibleOldVersionPre40() throws InterruptedException
|
||||
{
|
||||
try
|
||||
{
|
||||
handshake(VERSION_30, VERSION_30, VERSION_3014, VERSION_3014, VERSION_3014);
|
||||
Assert.fail("Should have thrown");
|
||||
if (expectSuccess)
|
||||
{
|
||||
Assert.assertEquals(String.format("wrong agreed messagingVersion for outMin %s outMax %s inMin %s inMax %s", outMin.value, outMax.value, inMin.value, inMax.value),
|
||||
Math.min(outMax.value, inMax.value), result.success().messagingVersion);
|
||||
result.success().channel.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (ExecutionException e)
|
||||
{
|
||||
assertTrue(e.getCause() instanceof ClosedChannelException);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSendIncompatibleOldVersionPre40() throws InterruptedException
|
||||
{
|
||||
try
|
||||
{
|
||||
handshake(VERSION_30, VERSION_30, VERSION_30, VERSION_3014, VERSION_3014);
|
||||
Assert.fail("Should have thrown");
|
||||
}
|
||||
catch (ExecutionException e)
|
||||
{
|
||||
assertTrue(e.getCause() instanceof ClosedChannelException);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSendCompatibleOldVersion40() throws InterruptedException, ExecutionException
|
||||
{
|
||||
Result result = handshake(VERSION_30, VERSION_30, VERSION_30, VERSION_30, current_version);
|
||||
Assert.assertEquals(Result.Outcome.SUCCESS, result.outcome);
|
||||
Assert.assertEquals(VERSION_30, result.success().messagingVersion);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSendIncompatibleOldVersion40() throws InterruptedException
|
||||
{
|
||||
try
|
||||
{
|
||||
Assert.fail(Objects.toString(handshake(VERSION_30, VERSION_30, VERSION_30, current_version, current_version)));
|
||||
}
|
||||
catch (ExecutionException e)
|
||||
{
|
||||
assertTrue(e.getCause() instanceof ClosedChannelException);
|
||||
}
|
||||
}
|
||||
|
||||
@Test // fairly contrived case, but since we introduced logic for testing we need to be careful it doesn't make us worse
|
||||
public void testSendToFuturePost40BelievedToBePre40() throws InterruptedException, ExecutionException
|
||||
{
|
||||
Result result = handshake(VERSION_30, VERSION_30, current_version, VERSION_30, current_version + 1);
|
||||
Assert.assertEquals(Result.Outcome.SUCCESS, result.outcome);
|
||||
Assert.assertEquals(VERSION_30, result.success().messagingVersion);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOutboundConnectionfFallbackDuringUpgrades() throws ClosedChannelException, InterruptedException
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ public class MessageSerializationPropertyTest implements Serializable
|
|||
try (DataOutputBuffer out = new DataOutputBuffer(1024))
|
||||
{
|
||||
qt().withShrinkCycles(0).forAll(MESSAGE_GEN).checkAssert(orFail(message -> {
|
||||
for (MessagingService.Version version : MessagingService.Version.values())
|
||||
for (MessagingService.Version version : MessagingService.Version.supportedVersions())
|
||||
{
|
||||
out.clear();
|
||||
serializer.serialize(message, out, version.value);
|
||||
|
|
@ -99,7 +99,7 @@ public class MessageSerializationPropertyTest implements Serializable
|
|||
{
|
||||
qt().withShrinkCycles(0).forAll(MESSAGE_GEN).checkAssert(orFail(message -> {
|
||||
withTable(schema, message, orFail(ignore -> {
|
||||
for (MessagingService.Version version : MessagingService.Version.values())
|
||||
for (MessagingService.Version version : MessagingService.Version.supportedVersions())
|
||||
{
|
||||
first.clear();
|
||||
second.clear();
|
||||
|
|
|
|||
|
|
@ -43,8 +43,6 @@ import org.apache.cassandra.utils.FreeRunningClock;
|
|||
import org.apache.cassandra.utils.TimeUUID;
|
||||
|
||||
import static org.apache.cassandra.net.Message.serializer;
|
||||
import static org.apache.cassandra.net.MessagingService.VERSION_3014;
|
||||
import static org.apache.cassandra.net.MessagingService.VERSION_30;
|
||||
import static org.apache.cassandra.net.MessagingService.VERSION_40;
|
||||
import static org.apache.cassandra.net.NoPayload.noPayload;
|
||||
import static org.apache.cassandra.net.ParamType.RESPOND_TO;
|
||||
|
|
@ -103,8 +101,6 @@ public class MessageTest
|
|||
.withParam(TRACE_SESSION, nextTimeUUID())
|
||||
.build();
|
||||
|
||||
testInferMessageSize(msg, VERSION_30);
|
||||
testInferMessageSize(msg, VERSION_3014);
|
||||
testInferMessageSize(msg, VERSION_40);
|
||||
}
|
||||
|
||||
|
|
@ -122,11 +118,11 @@ public class MessageTest
|
|||
|
||||
// should return -1 - fail to infer size - for all lengths of buffer until payload length can be read
|
||||
for (int limit = 0; limit < serializedSize - payloadSize; limit++)
|
||||
assertEquals(-1, serializer.inferMessageSize(buffer, 0, limit, version));
|
||||
assertEquals(-1, serializer.inferMessageSize(buffer, 0, limit));
|
||||
|
||||
// once payload size can be read, should correctly infer message size
|
||||
for (int limit = serializedSize - payloadSize; limit < serializedSize; limit++)
|
||||
assertEquals(serializedSize, serializer.inferMessageSize(buffer, 0, limit, version));
|
||||
assertEquals(serializedSize, serializer.inferMessageSize(buffer, 0, limit));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -264,8 +260,6 @@ public class MessageTest
|
|||
|
||||
private void testCycle(Message msg) throws IOException
|
||||
{
|
||||
testCycle(msg, VERSION_30);
|
||||
testCycle(msg, VERSION_3014);
|
||||
testCycle(msg, VERSION_40);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -199,18 +199,11 @@ public class ProxyHandlerConnectionsTest
|
|||
boolean expire = i % 2 == 0;
|
||||
Message.Builder builder = Message.builder(Verb._TEST_1, 1L);
|
||||
|
||||
if (settings.right.acceptVersions == ConnectionTest.legacy)
|
||||
{
|
||||
// backdate messages; leave 500 milliseconds to leave outbound path
|
||||
builder.withCreatedAt(nanoTime - (expire ? 0 : MILLISECONDS.toNanos(1500)));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Give messages 500 milliseconds to leave outbound path
|
||||
builder.withCreatedAt(nanoTime)
|
||||
.withExpiresAt(nanoTime + (expire ? MILLISECONDS.toNanos(500) : MILLISECONDS.toNanos(3000)));
|
||||
}
|
||||
outbound.enqueue(builder.build());
|
||||
// Give messages 500 milliseconds to leave outbound path
|
||||
builder.withCreatedAt(nanoTime)
|
||||
.withExpiresAt(nanoTime + (expire ? MILLISECONDS.toNanos(500) : MILLISECONDS.toNanos(3000)));
|
||||
|
||||
outbound.enqueue(builder.build());
|
||||
}
|
||||
enqueueDone.countDown();
|
||||
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ public class StreamTransferTaskTest
|
|||
@Override
|
||||
public NettyStreamingChannel create(InetSocketAddress to, int messagingVersion, StreamingChannel.Kind kind)
|
||||
{
|
||||
return new NettyStreamingChannel(messagingVersion, new TestChannel(), kind);
|
||||
return new NettyStreamingChannel(new TestChannel(), kind);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -56,7 +56,6 @@ import static org.apache.cassandra.net.TestChannel.REMOTE_ADDR;
|
|||
|
||||
public class StreamingInboundHandlerTest
|
||||
{
|
||||
private static final int VERSION = MessagingService.current_version;
|
||||
|
||||
private NettyStreamingChannel streamingChannel;
|
||||
private EmbeddedChannel channel;
|
||||
|
|
@ -72,7 +71,7 @@ public class StreamingInboundHandlerTest
|
|||
public void setup()
|
||||
{
|
||||
channel = new TestChannel();
|
||||
streamingChannel = new NettyStreamingChannel(VERSION, channel, StreamingChannel.Kind.CONTROL);
|
||||
streamingChannel = new NettyStreamingChannel(channel, StreamingChannel.Kind.CONTROL);
|
||||
channel.pipeline().addLast("stream", streamingChannel);
|
||||
}
|
||||
|
||||
|
|
@ -100,7 +99,7 @@ public class StreamingInboundHandlerTest
|
|||
public void StreamDeserializingTask_deriveSession_StreamInitMessage()
|
||||
{
|
||||
StreamInitMessage msg = new StreamInitMessage(REMOTE_ADDR, 0, nextTimeUUID(), StreamOperation.REPAIR, nextTimeUUID(), PreviewKind.ALL);
|
||||
StreamDeserializingTask task = new StreamDeserializingTask(null, streamingChannel, streamingChannel.messagingVersion);
|
||||
StreamDeserializingTask task = new StreamDeserializingTask(null, streamingChannel, MessagingService.current_version);
|
||||
StreamSession session = task.deriveSession(msg);
|
||||
Assert.assertNotNull(session);
|
||||
}
|
||||
|
|
@ -109,7 +108,7 @@ public class StreamingInboundHandlerTest
|
|||
public void StreamDeserializingTask_deriveSession_NoSession()
|
||||
{
|
||||
CompleteMessage msg = new CompleteMessage();
|
||||
StreamDeserializingTask task = new StreamDeserializingTask(null, streamingChannel, streamingChannel.messagingVersion);
|
||||
StreamDeserializingTask task = new StreamDeserializingTask(null, streamingChannel, MessagingService.current_version);
|
||||
task.deriveSession(msg);
|
||||
}
|
||||
|
||||
|
|
@ -133,7 +132,7 @@ public class StreamingInboundHandlerTest
|
|||
public void StreamDeserializingTask_deserialize_ISM_HasSession()
|
||||
{
|
||||
TimeUUID planId = nextTimeUUID();
|
||||
StreamResultFuture future = StreamResultFuture.createFollower(0, planId, StreamOperation.REPAIR, REMOTE_ADDR, streamingChannel, streamingChannel.messagingVersion, nextTimeUUID(), PreviewKind.ALL);
|
||||
StreamResultFuture future = StreamResultFuture.createFollower(0, planId, StreamOperation.REPAIR, REMOTE_ADDR, streamingChannel, MessagingService.current_version, nextTimeUUID(), PreviewKind.ALL);
|
||||
StreamManager.instance.registerFollower(future);
|
||||
StreamMessageHeader header = new StreamMessageHeader(TableId.generate(), REMOTE_ADDR, planId, false,
|
||||
0, 0, 0, nextTimeUUID());
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ public class StreamingMultiplexedChannelTest
|
|||
public void setUp()
|
||||
{
|
||||
channel = new TestChannel();
|
||||
streamingChannel = new NettyStreamingChannel(current_version, channel, StreamingChannel.Kind.CONTROL);
|
||||
streamingChannel = new NettyStreamingChannel(channel, StreamingChannel.Kind.CONTROL);
|
||||
TimeUUID pendingRepair = nextTimeUUID();
|
||||
session = new StreamSession(StreamOperation.BOOTSTRAP, REMOTE_ADDR, new NettyStreamingConnectionFactory(), streamingChannel, current_version, true, 0, pendingRepair, PreviewKind.ALL);
|
||||
StreamResultFuture future = StreamResultFuture.createFollower(0, nextTimeUUID(), StreamOperation.REPAIR, REMOTE_ADDR, streamingChannel, current_version, pendingRepair, session.getPreviewKind());
|
||||
|
|
|
|||
Loading…
Reference in New Issue