You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cassandra.apache.org by pa...@apache.org on 2018/02/11 13:26:13 UTC
[28/29] cassandra git commit: Merge branch 'cassandra-3.0' into
cassandra-3.11
Merge branch 'cassandra-3.0' into cassandra-3.11
Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/0a6b6f50
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/0a6b6f50
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/0a6b6f50
Branch: refs/heads/trunk
Commit: 0a6b6f506b012d4d491757d6216c5fa1c53bedc9
Parents: 6eb65e5 c231ed5
Author: Paulo Motta <pa...@apache.org>
Authored: Sat Feb 10 14:58:13 2018 -0200
Committer: Paulo Motta <pa...@apache.org>
Committed: Sat Feb 10 14:59:28 2018 -0200
----------------------------------------------------------------------
CASSANDRA-14092.txt | 81 +++++
CHANGES.txt | 1 +
NEWS.txt | 21 ++
conf/jvm.options | 11 +
debian/rules | 2 +-
redhat/cassandra.spec | 2 +-
.../org/apache/cassandra/cql3/Attributes.java | 15 +-
.../cql3/statements/ModificationStatement.java | 2 +-
.../apache/cassandra/db/ColumnFamilyStore.java | 8 +-
.../db/ExpirationDateOverflowHandling.java | 121 +++++++
.../org/apache/cassandra/db/LegacyLayout.java | 6 +-
.../org/apache/cassandra/db/LivenessInfo.java | 13 +-
.../db/compaction/CompactionManager.java | 16 +-
.../cassandra/db/compaction/Scrubber.java | 225 +++++++++++--
.../apache/cassandra/db/rows/BufferCell.java | 8 +-
src/java/org/apache/cassandra/db/rows/Cell.java | 10 +
.../apache/cassandra/db/rows/NativeCell.java | 5 +
.../cassandra/service/StorageService.java | 7 +-
.../cassandra/service/StorageServiceMBean.java | 3 +
.../cassandra/thrift/ThriftValidation.java | 8 +-
.../org/apache/cassandra/tools/NodeProbe.java | 8 +-
.../cassandra/tools/StandaloneScrubber.java | 6 +-
.../apache/cassandra/tools/nodetool/Scrub.java | 7 +-
.../table1/mc-1-big-CompressionInfo.db | Bin 0 -> 43 bytes
.../table1/mc-1-big-Data.db | Bin 0 -> 58 bytes
.../table1/mc-1-big-Digest.crc32 | 1 +
.../table1/mc-1-big-Filter.db | Bin 0 -> 16 bytes
.../table1/mc-1-big-Index.db | Bin 0 -> 16 bytes
.../table1/mc-1-big-Statistics.db | Bin 0 -> 4676 bytes
.../table1/mc-1-big-Summary.db | Bin 0 -> 56 bytes
.../table1/mc-1-big-TOC.txt | 8 +
.../table2/mc-1-big-CompressionInfo.db | Bin 0 -> 43 bytes
.../table2/mc-1-big-Data.db | Bin 0 -> 60 bytes
.../table2/mc-1-big-Digest.crc32 | 1 +
.../table2/mc-1-big-Filter.db | Bin 0 -> 16 bytes
.../table2/mc-1-big-Index.db | Bin 0 -> 16 bytes
.../table2/mc-1-big-Statistics.db | Bin 0 -> 4686 bytes
.../table2/mc-1-big-Summary.db | Bin 0 -> 56 bytes
.../table2/mc-1-big-TOC.txt | 8 +
.../table3/mc-1-big-CompressionInfo.db | Bin 0 -> 43 bytes
.../table3/mc-1-big-Data.db | Bin 0 -> 111 bytes
.../table3/mc-1-big-Digest.crc32 | 1 +
.../table3/mc-1-big-Filter.db | Bin 0 -> 16 bytes
.../table3/mc-1-big-Index.db | Bin 0 -> 16 bytes
.../table3/mc-1-big-Statistics.db | Bin 0 -> 4732 bytes
.../table3/mc-1-big-Summary.db | Bin 0 -> 56 bytes
.../table3/mc-1-big-TOC.txt | 8 +
.../table4/mc-1-big-CompressionInfo.db | Bin 0 -> 43 bytes
.../table4/mc-1-big-Data.db | Bin 0 -> 108 bytes
.../table4/mc-1-big-Digest.crc32 | 1 +
.../table4/mc-1-big-Filter.db | Bin 0 -> 16 bytes
.../table4/mc-1-big-Index.db | Bin 0 -> 16 bytes
.../table4/mc-1-big-Statistics.db | Bin 0 -> 4742 bytes
.../table4/mc-1-big-Summary.db | Bin 0 -> 56 bytes
.../table4/mc-1-big-TOC.txt | 8 +
.../cql3/validation/operations/TTLTest.java | 327 ++++++++++++++++++-
test/unit/org/apache/cassandra/db/CellTest.java | 22 +-
.../unit/org/apache/cassandra/db/ScrubTest.java | 6 +-
58 files changed, 893 insertions(+), 84 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/0a6b6f50/CHANGES.txt
----------------------------------------------------------------------
diff --cc CHANGES.txt
index c38b69b,a492c42..5b49f48
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@@ -48,26 -28,12 +48,27 @@@ Merged from 2.2
* Fix the inspectJvmOptions startup check (CASSANDRA-14112)
* Fix race that prevents submitting compaction for a table when executor is full (CASSANDRA-13801)
* Rely on the JVM to handle OutOfMemoryErrors (CASSANDRA-13006)
+ * Grab refs during scrub/index redistribution/cleanup (CASSANDRA-13873)
Merged from 2.1:
- * More PEP8 compliance for cqlsh (CASSANDRA-14021)
++ * Protect against overflow of local expiration time (CASSANDRA-14092)
* RPM package spec: fix permissions for installed jars and config files (CASSANDRA-14181)
-
-
-3.0.15
+ * More PEP8 compiance for cqlsh (CASSANDRA-14021)
+
+
+3.11.1
+ * Fix the computation of cdc_total_space_in_mb for exabyte filesystems (CASSANDRA-13808)
+ * AbstractTokenTreeBuilder#serializedSize returns wrong value when there is a single leaf and overflow collisions (CASSANDRA-13869)
+ * Add a compaction option to TWCS to ignore sstables overlapping checks (CASSANDRA-13418)
+ * BTree.Builder memory leak (CASSANDRA-13754)
+ * Revert CASSANDRA-10368 of supporting non-pk column filtering due to correctness (CASSANDRA-13798)
+ * Add a skip read validation flag to cassandra-stress (CASSANDRA-13772)
+ * Fix cassandra-stress hang issues when an error during cluster connection happens (CASSANDRA-12938)
+ * Better bootstrap failure message when blocked by (potential) range movement (CASSANDRA-13744)
+ * "ignore" option is ignored in sstableloader (CASSANDRA-13721)
+ * Deadlock in AbstractCommitLogSegmentManager (CASSANDRA-13652)
+ * Duplicate the buffer before passing it to analyser in SASI operation (CASSANDRA-13512)
+ * Properly evict pstmts from prepared statements cache (CASSANDRA-13641)
+Merged from 3.0:
* Improve TRUNCATE performance (CASSANDRA-13909)
* Implement short read protection on partition boundaries (CASSANDRA-13595)
* Fix ISE thrown by UPI.Serializer.hasNext() for some SELECT queries (CASSANDRA-13911)
http://git-wip-us.apache.org/repos/asf/cassandra/blob/0a6b6f50/NEWS.txt
----------------------------------------------------------------------
diff --cc NEWS.txt
index f4b15e7,f574c33..fb1dafe
--- a/NEWS.txt
+++ b/NEWS.txt
@@@ -18,22 -38,14 +38,23 @@@ using the provided 'sstableupgrade' too
Upgrading
---------
+ - See MAXIMUM TTL EXPIRATION DATE NOTICE above.
- - Cassandra is now relying on the JVM options to properly shutdown on OutOfMemoryError. By default it will
- rely on the OnOutOfMemoryError option as the ExitOnOutOfMemoryError and CrashOnOutOfMemoryError options
- are not supported by the older 1.7 and 1.8 JVMs. A warning will be logged at startup if none of those JVM
- options are used. See CASSANDRA-13006 for more details.
- - Cassandra is not logging anymore by default an Heap histogram on OutOfMemoryError. To enable that behavior
- set the 'cassandra.printHeapHistogramOnOutOfMemoryError' System property to 'true'. See CASSANDRA-13006
- for more details.
+ - Cassandra is now relying on the JVM options to properly shutdown on OutOfMemoryError. By default it will
+ rely on the OnOutOfMemoryError option as the ExitOnOutOfMemoryError and CrashOnOutOfMemoryError options
+ are not supported by the older 1.7 and 1.8 JVMs. A warning will be logged at startup if none of those JVM
+ options are used. See CASSANDRA-13006 for more details
+ - Cassandra is not logging anymore by default an Heap histogram on OutOfMemoryError. To enable that behavior
+ set the 'cassandra.printHeapHistogramOnOutOfMemoryError' System property to 'true'. See CASSANDRA-13006
+ for more details.
+ - Upgrades from 3.0 might have produced unnecessary schema migrations while
+ there was at least one 3.0 node in the cluster. It is therefore highly
+ recommended to upgrade from 3.0 to at least 3.11.2. The root cause of
+ this schema mismatch was a difference in the way how schema digests were computed
+ in 3.0 and 3.11.2. To mitigate this issue, 3.11.2 and newer announce
+ 3.0 compatible digests as long as there is at least one 3.0 node in the
+ cluster. Once all nodes have been upgraded, the "real" schema version will be
+ announced. Note: this fix is only necessary in 3.11.2 and therefore only applies
+ to 3.11. (CASSANDRA-14109)
Materialized Views
-------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/0a6b6f50/conf/jvm.options
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/0a6b6f50/redhat/cassandra.spec
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/0a6b6f50/src/java/org/apache/cassandra/cql3/Attributes.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/Attributes.java
index d915560,832d0a7..d4e230f
--- a/src/java/org/apache/cassandra/cql3/Attributes.java
+++ b/src/java/org/apache/cassandra/cql3/Attributes.java
@@@ -20,8 -20,9 +20,10 @@@ package org.apache.cassandra.cql3
import java.nio.ByteBuffer;
import java.util.List;
+ import org.apache.cassandra.config.CFMetaData;
import org.apache.cassandra.cql3.functions.Function;
+ import org.apache.cassandra.db.ExpirationDateOverflowHandling;
+import org.apache.cassandra.db.LivenessInfo;
import org.apache.cassandra.db.marshal.Int32Type;
import org.apache.cassandra.db.marshal.LongType;
import org.apache.cassandra.exceptions.InvalidRequestException;
@@@ -105,11 -109,11 +110,11 @@@ public class Attribute
ByteBuffer tval = timeToLive.bindAndGet(options);
if (tval == null)
- throw new InvalidRequestException("Invalid null value of TTL");
-
- if (tval == ByteBufferUtil.UNSET_BYTE_BUFFER) // treat as unlimited
return 0;
+ if (tval == ByteBufferUtil.UNSET_BYTE_BUFFER)
- return defaultTimeToLive;
++ return metadata.params.defaultTimeToLive;
+
try
{
Int32Type.instance.validate(tval);
@@@ -126,9 -130,8 +131,11 @@@
if (ttl > MAX_TTL)
throw new InvalidRequestException(String.format("ttl is too large. requested (%d) maximum (%d)", ttl, MAX_TTL));
- if (defaultTimeToLive != LivenessInfo.NO_TTL && ttl == LivenessInfo.NO_TTL)
++ if (metadata.params.defaultTimeToLive != LivenessInfo.NO_TTL && ttl == LivenessInfo.NO_TTL)
+ return LivenessInfo.NO_TTL;
+
+ ExpirationDateOverflowHandling.maybeApplyExpirationDateOverflowPolicy(metadata, ttl, false);
+
return ttl;
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/0a6b6f50/src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/0a6b6f50/src/java/org/apache/cassandra/db/ColumnFamilyStore.java
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/0a6b6f50/src/java/org/apache/cassandra/db/LegacyLayout.java
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/0a6b6f50/src/java/org/apache/cassandra/db/LivenessInfo.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/db/LivenessInfo.java
index 5d17aea,f6c9b62..c2a2291
--- a/src/java/org/apache/cassandra/db/LivenessInfo.java
+++ b/src/java/org/apache/cassandra/db/LivenessInfo.java
@@@ -66,13 -72,13 +68,13 @@@ public class LivenessInf
public static LivenessInfo expiring(long timestamp, int ttl, int nowInSec)
{
assert ttl != EXPIRED_LIVENESS_TTL;
- return new ExpiringLivenessInfo(timestamp, ttl, nowInSec + ttl);
+ return new ExpiringLivenessInfo(timestamp, ttl, ExpirationDateOverflowHandling.computeLocalExpirationTime(nowInSec, ttl));
}
- public static LivenessInfo create(CFMetaData metadata, long timestamp, int ttl, int nowInSec)
+ public static LivenessInfo create(long timestamp, int ttl, int nowInSec)
{
return ttl == NO_TTL
- ? create(metadata, timestamp, nowInSec)
+ ? create(timestamp, nowInSec)
: expiring(timestamp, ttl, nowInSec);
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/0a6b6f50/src/java/org/apache/cassandra/db/compaction/CompactionManager.java
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/0a6b6f50/src/java/org/apache/cassandra/db/compaction/Scrubber.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/db/compaction/Scrubber.java
index ed107d7,bc11504..f8fa548
--- a/src/java/org/apache/cassandra/db/compaction/Scrubber.java
+++ b/src/java/org/apache/cassandra/db/compaction/Scrubber.java
@@@ -69,10 -73,10 +73,10 @@@ public class Scrubber implements Closea
private static final Comparator<Partition> partitionComparator = new Comparator<Partition>()
{
-- public int compare(Partition r1, Partition r2)
-- {
-- return r1.partitionKey().compareTo(r2.partitionKey());
-- }
++ public int compare(Partition r1, Partition r2)
++ {
++ return r1.partitionKey().compareTo(r2.partitionKey());
++ }
};
private final SortedSet<Partition> outOfOrder = new TreeSet<>(partitionComparator);
@@@ -112,8 -126,8 +124,8 @@@
}
this.checkData = checkData && !this.isIndex; //LocalByPartitionerType does not support validation
this.expectedBloomFilterSize = Math.max(
-- cfs.metadata.params.minIndexInterval,
-- hasIndexFile ? SSTableReader.getApproximateKeyCount(toScrub) : 0);
++ cfs.metadata.params.minIndexInterval,
++ hasIndexFile ? SSTableReader.getApproximateKeyCount(toScrub) : 0);
// loop through each row, deserializing to check for damage.
// we'll also loop through the index at the same time, using the position from the index to recover if the
@@@ -124,8 -138,8 +136,8 @@@
: sstable.openDataReader(CompactionManager.instance.getRateLimiter());
this.indexFile = hasIndexFile
-- ? RandomAccessReader.open(new File(sstable.descriptor.filenameFor(Component.PRIMARY_INDEX)))
-- : null;
++ ? RandomAccessReader.open(new File(sstable.descriptor.filenameFor(Component.PRIMARY_INDEX)))
++ : null;
this.scrubInfo = new ScrubInfo(dataFile, sstable);
@@@ -203,8 -220,8 +218,8 @@@
if (currentIndexKey != null && !key.getKey().equals(currentIndexKey))
{
throw new IOError(new IOException(String.format("Key from data file (%s) does not match key from index file (%s)",
-- //ByteBufferUtil.bytesToHex(key.getKey()), ByteBufferUtil.bytesToHex(currentIndexKey))));
-- "_too big_", ByteBufferUtil.bytesToHex(currentIndexKey))));
++ //ByteBufferUtil.bytesToHex(key.getKey()), ByteBufferUtil.bytesToHex(currentIndexKey))));
++ "_too big_", ByteBufferUtil.bytesToHex(currentIndexKey))));
}
if (indexFile != null && dataSizeFromIndex > dataFile.length())
@@@ -225,7 -242,7 +240,7 @@@
&& (key == null || !key.getKey().equals(currentIndexKey) || dataStart != dataStartFromIndex))
{
outputHandler.output(String.format("Retrying from row index; data is %s bytes starting at %s",
-- dataSizeFromIndex, dataStartFromIndex));
++ dataSizeFromIndex, dataStartFromIndex));
key = sstable.decorateKey(currentIndexKey);
try
{
@@@ -333,6 -352,18 +350,18 @@@
return true;
}
+ /**
+ * Only wrap with {@link FixNegativeLocalDeletionTimeIterator} if {@link #reinsertOverflowedTTLRows} option
+ * is specified
+ */
+ private UnfilteredRowIterator getIterator(DecoratedKey key)
+ {
- RowMergingSSTableIterator rowMergingIterator = new RowMergingSSTableIterator(sstable, dataFile, key);
++ RowMergingSSTableIterator rowMergingIterator = new RowMergingSSTableIterator(SSTableIdentityIterator.create(sstable, dataFile, key));
+ return reinsertOverflowedTTLRows ? new FixNegativeLocalDeletionTimeIterator(rowMergingIterator,
+ outputHandler,
+ negativeLocalDeletionInfoMetrics) : rowMergingIterator;
+ }
+
private void updateIndexKey()
{
currentIndexKey = nextIndexKey;
@@@ -342,8 -373,8 +371,8 @@@
nextIndexKey = !indexAvailable() ? null : ByteBufferUtil.readWithShortLength(indexFile);
nextRowPositionFromIndex = !indexAvailable()
-- ? dataFile.length()
- : rowIndexEntrySerializer.deserializePositionAndSkip(indexFile);
- : rowIndexEntrySerializer.deserialize(indexFile).position;
++ ? dataFile.length()
++ : rowIndexEntrySerializer.deserializePositionAndSkip(indexFile);
}
catch (Throwable th)
{
@@@ -620,6 -652,152 +654,153 @@@
previous = next;
return next;
}
+ }
+ /**
+ * This iterator converts negative {@link AbstractCell#localDeletionTime()} into {@link AbstractCell#MAX_DELETION_TIME}
+ *
+ * This is to recover entries with overflowed localExpirationTime due to CASSANDRA-14092
+ */
+ private static final class FixNegativeLocalDeletionTimeIterator extends AbstractIterator<Unfiltered> implements UnfilteredRowIterator
+ {
+ /**
+ * The decorated iterator.
+ */
+ private final UnfilteredRowIterator iterator;
+
+ private final OutputHandler outputHandler;
+ private final NegativeLocalDeletionInfoMetrics negativeLocalExpirationTimeMetrics;
+
+ public FixNegativeLocalDeletionTimeIterator(UnfilteredRowIterator iterator, OutputHandler outputHandler,
+ NegativeLocalDeletionInfoMetrics negativeLocalDeletionInfoMetrics)
+ {
+ this.iterator = iterator;
+ this.outputHandler = outputHandler;
+ this.negativeLocalExpirationTimeMetrics = negativeLocalDeletionInfoMetrics;
+ }
+
+ public CFMetaData metadata()
+ {
+ return iterator.metadata();
+ }
+
+ public boolean isReverseOrder()
+ {
+ return iterator.isReverseOrder();
+ }
+
+ public PartitionColumns columns()
+ {
+ return iterator.columns();
+ }
+
+ public DecoratedKey partitionKey()
+ {
+ return iterator.partitionKey();
+ }
+
+ public Row staticRow()
+ {
+ return iterator.staticRow();
+ }
+
+ @Override
+ public boolean isEmpty()
+ {
+ return iterator.isEmpty();
+ }
+
+ public void close()
+ {
+ iterator.close();
+ }
+
+ public DeletionTime partitionLevelDeletion()
+ {
+ return iterator.partitionLevelDeletion();
+ }
+
+ public EncodingStats stats()
+ {
+ return iterator.stats();
+ }
+
+ protected Unfiltered computeNext()
+ {
+ if (!iterator.hasNext())
+ return endOfData();
+
+ Unfiltered next = iterator.next();
+ if (!next.isRow())
+ return next;
+
+ if (hasNegativeLocalExpirationTime((Row) next))
+ {
+ outputHandler.debug(String.format("Found row with negative local expiration time: %s", next.toString(metadata(), false)));
+ negativeLocalExpirationTimeMetrics.fixedRows++;
+ return fixNegativeLocalExpirationTime((Row) next);
+ }
+
+ return next;
+ }
+
+ private boolean hasNegativeLocalExpirationTime(Row next)
+ {
+ Row row = next;
+ if (row.primaryKeyLivenessInfo().isExpiring() && row.primaryKeyLivenessInfo().localExpirationTime() < 0)
+ {
+ return true;
+ }
+
+ for (ColumnData cd : row)
+ {
+ if (cd.column().isSimple())
+ {
+ Cell cell = (Cell)cd;
+ if (cell.isExpiring() && cell.localDeletionTime() < 0)
+ return true;
+ }
+ else
+ {
+ ComplexColumnData complexData = (ComplexColumnData)cd;
+ for (Cell cell : complexData)
+ {
+ if (cell.isExpiring() && cell.localDeletionTime() < 0)
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ private Unfiltered fixNegativeLocalExpirationTime(Row row)
+ {
+ Row.Builder builder = HeapAllocator.instance.cloningBTreeRowBuilder();
+ builder.newRow(row.clustering());
+ builder.addPrimaryKeyLivenessInfo(row.primaryKeyLivenessInfo().isExpiring() && row.primaryKeyLivenessInfo().localExpirationTime() < 0 ?
+ row.primaryKeyLivenessInfo().withUpdatedTimestampAndLocalDeletionTime(row.primaryKeyLivenessInfo().timestamp() + 1, AbstractCell.MAX_DELETION_TIME)
+ :row.primaryKeyLivenessInfo());
+ builder.addRowDeletion(row.deletion());
+ for (ColumnData cd : row)
+ {
+ if (cd.column().isSimple())
+ {
+ Cell cell = (Cell)cd;
+ builder.addCell(cell.isExpiring() && cell.localDeletionTime() < 0 ? cell.withUpdatedTimestampAndLocalDeletionTime(cell.timestamp() + 1, AbstractCell.MAX_DELETION_TIME) : cell);
+ }
+ else
+ {
+ ComplexColumnData complexData = (ComplexColumnData)cd;
+ builder.addComplexDeletion(complexData.column(), complexData.complexDeletion());
+ for (Cell cell : complexData)
+ {
+ builder.addCell(cell.isExpiring() && cell.localDeletionTime() < 0 ? cell.withUpdatedTimestampAndLocalDeletionTime(cell.timestamp() + 1, AbstractCell.MAX_DELETION_TIME) : cell);
+ }
+ }
+ }
+ return builder.build();
+ }
}
++
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/0a6b6f50/src/java/org/apache/cassandra/db/rows/BufferCell.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/db/rows/BufferCell.java
index 9b31c16,df2619c..b62d95a
--- a/src/java/org/apache/cassandra/db/rows/BufferCell.java
+++ b/src/java/org/apache/cassandra/db/rows/BufferCell.java
@@@ -17,12 -17,18 +17,13 @@@
*/
package org.apache.cassandra.db.rows;
-import java.io.IOException;
import java.nio.ByteBuffer;
-import org.apache.cassandra.config.*;
-import org.apache.cassandra.db.*;
-import org.apache.cassandra.db.context.CounterContext;
+import org.apache.cassandra.config.ColumnDefinition;
++import org.apache.cassandra.db.ExpirationDateOverflowHandling;
import org.apache.cassandra.db.marshal.ByteType;
-import org.apache.cassandra.io.util.DataInputPlus;
-import org.apache.cassandra.io.util.DataOutputPlus;
import org.apache.cassandra.utils.ByteBufferUtil;
import org.apache.cassandra.utils.ObjectSizes;
-import org.apache.cassandra.utils.FBUtilities;
import org.apache.cassandra.utils.memory.AbstractAllocator;
public class BufferCell extends AbstractCell
http://git-wip-us.apache.org/repos/asf/cassandra/blob/0a6b6f50/src/java/org/apache/cassandra/db/rows/Cell.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/db/rows/Cell.java
index 19d1f30,c69e11f..1205b7d
--- a/src/java/org/apache/cassandra/db/rows/Cell.java
+++ b/src/java/org/apache/cassandra/db/rows/Cell.java
@@@ -21,7 -21,13 +21,14 @@@ import java.io.IOException
import java.nio.ByteBuffer;
import java.util.Comparator;
+ import com.google.common.annotations.VisibleForTesting;
+ import org.slf4j.Logger;
+ import org.slf4j.LoggerFactory;
+
+ import org.apache.cassandra.config.CFMetaData;
+ import org.apache.cassandra.config.ColumnDefinition;
+ import org.apache.cassandra.cql3.Attributes;
+import org.apache.cassandra.config.*;
import org.apache.cassandra.db.*;
import org.apache.cassandra.io.util.DataOutputPlus;
import org.apache.cassandra.io.util.DataInputPlus;
http://git-wip-us.apache.org/repos/asf/cassandra/blob/0a6b6f50/src/java/org/apache/cassandra/db/rows/NativeCell.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/db/rows/NativeCell.java
index 5930332,0000000..31ce0b7
mode 100644,000000..100644
--- a/src/java/org/apache/cassandra/db/rows/NativeCell.java
+++ b/src/java/org/apache/cassandra/db/rows/NativeCell.java
@@@ -1,156 -1,0 +1,161 @@@
+/*
+ * 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.db.rows;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import org.apache.cassandra.config.ColumnDefinition;
+import org.apache.cassandra.utils.ObjectSizes;
+import org.apache.cassandra.utils.concurrent.OpOrder;
+import org.apache.cassandra.utils.memory.MemoryUtil;
+import org.apache.cassandra.utils.memory.NativeAllocator;
+
+public class NativeCell extends AbstractCell
+{
+ private static final long EMPTY_SIZE = ObjectSizes.measure(new NativeCell());
+
+ private static final long HAS_CELLPATH = 0;
+ private static final long TIMESTAMP = 1;
+ private static final long TTL = 9;
+ private static final long DELETION = 13;
+ private static final long LENGTH = 17;
+ private static final long VALUE = 21;
+
+ private final long peer;
+
+ private NativeCell()
+ {
+ super(null);
+ this.peer = 0;
+ }
+
+ public NativeCell(NativeAllocator allocator,
+ OpOrder.Group writeOp,
+ Cell cell)
+ {
+ this(allocator,
+ writeOp,
+ cell.column(),
+ cell.timestamp(),
+ cell.ttl(),
+ cell.localDeletionTime(),
+ cell.value(),
+ cell.path());
+ }
+
+ public NativeCell(NativeAllocator allocator,
+ OpOrder.Group writeOp,
+ ColumnDefinition column,
+ long timestamp,
+ int ttl,
+ int localDeletionTime,
+ ByteBuffer value,
+ CellPath path)
+ {
+ super(column);
+ long size = simpleSize(value.remaining());
+
+ assert value.order() == ByteOrder.BIG_ENDIAN;
+ assert column.isComplex() == (path != null);
+ if (path != null)
+ {
+ assert path.size() == 1;
+ size += 4 + path.get(0).remaining();
+ }
+
+ if (size > Integer.MAX_VALUE)
+ throw new IllegalStateException();
+
+ // cellpath? : timestamp : ttl : localDeletionTime : length : <data> : [cell path length] : [<cell path data>]
+ peer = allocator.allocate((int) size, writeOp);
+ MemoryUtil.setByte(peer + HAS_CELLPATH, (byte)(path == null ? 0 : 1));
+ MemoryUtil.setLong(peer + TIMESTAMP, timestamp);
+ MemoryUtil.setInt(peer + TTL, ttl);
+ MemoryUtil.setInt(peer + DELETION, localDeletionTime);
+ MemoryUtil.setInt(peer + LENGTH, value.remaining());
+ MemoryUtil.setBytes(peer + VALUE, value);
+
+ if (path != null)
+ {
+ ByteBuffer pathbuffer = path.get(0);
+ assert pathbuffer.order() == ByteOrder.BIG_ENDIAN;
+
+ long offset = peer + VALUE + value.remaining();
+ MemoryUtil.setInt(offset, pathbuffer.remaining());
+ MemoryUtil.setBytes(offset + 4, pathbuffer);
+ }
+ }
+
+ private static long simpleSize(int length)
+ {
+ return VALUE + length;
+ }
+
+ public long timestamp()
+ {
+ return MemoryUtil.getLong(peer + TIMESTAMP);
+ }
+
+ public int ttl()
+ {
+ return MemoryUtil.getInt(peer + TTL);
+ }
+
+ public int localDeletionTime()
+ {
+ return MemoryUtil.getInt(peer + DELETION);
+ }
+
+ public ByteBuffer value()
+ {
+ int length = MemoryUtil.getInt(peer + LENGTH);
+ return MemoryUtil.getByteBuffer(peer + VALUE, length, ByteOrder.BIG_ENDIAN);
+ }
+
+ public CellPath path()
+ {
+ if (MemoryUtil.getByte(peer+ HAS_CELLPATH) == 0)
+ return null;
+
+ long offset = peer + VALUE + MemoryUtil.getInt(peer + LENGTH);
+ int size = MemoryUtil.getInt(offset);
+ return CellPath.create(MemoryUtil.getByteBuffer(offset + 4, size, ByteOrder.BIG_ENDIAN));
+ }
+
+ public Cell withUpdatedValue(ByteBuffer newValue)
+ {
+ throw new UnsupportedOperationException();
+ }
+
++ public Cell withUpdatedTimestampAndLocalDeletionTime(long newTimestamp, int newLocalDeletionTime)
++ {
++ return new BufferCell(column, newTimestamp, ttl(), newLocalDeletionTime, value(), path());
++ }
++
+ public Cell withUpdatedColumn(ColumnDefinition column)
+ {
+ return new BufferCell(column, timestamp(), ttl(), localDeletionTime(), value(), path());
+ }
+
+ public long unsharedHeapSizeExcludingData()
+ {
+ return EMPTY_SIZE;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/0a6b6f50/src/java/org/apache/cassandra/service/StorageService.java
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/0a6b6f50/src/java/org/apache/cassandra/service/StorageServiceMBean.java
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/0a6b6f50/src/java/org/apache/cassandra/thrift/ThriftValidation.java
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/0a6b6f50/src/java/org/apache/cassandra/tools/NodeProbe.java
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/0a6b6f50/src/java/org/apache/cassandra/tools/StandaloneScrubber.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/tools/StandaloneScrubber.java
index 54b340e,4778d72..ead8fc5
--- a/src/java/org/apache/cassandra/tools/StandaloneScrubber.java
+++ b/src/java/org/apache/cassandra/tools/StandaloneScrubber.java
@@@ -266,6 -274,7 +269,7 @@@ public class StandaloneScrubbe
options.addOption("m", MANIFEST_CHECK_OPTION, "only check and repair the leveled manifest, without actually scrubbing the sstables");
options.addOption("s", SKIP_CORRUPTED_OPTION, "skip corrupt rows in counter tables");
options.addOption("n", NO_VALIDATE_OPTION, "do not validate columns using column validator");
- options.addOption("r", REINSERT_OVERFLOWED_TTL_OPTION, REINSERT_OVERFLOWED_TTL_OPTION_DESCRIPTION);
++ options.addOption("r", REINSERT_OVERFLOWED_TTL_OPTION, "Reinsert found rows with overflowed TTL affected by CASSANDRA-14092");
return options;
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/0a6b6f50/src/java/org/apache/cassandra/tools/nodetool/Scrub.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/tools/nodetool/Scrub.java
index 2345a85,ead2fd4..812202d
--- a/src/java/org/apache/cassandra/tools/nodetool/Scrub.java
+++ b/src/java/org/apache/cassandra/tools/nodetool/Scrub.java
@@@ -48,6 -49,11 +48,11 @@@ public class Scrub extends NodeToolCm
description = "Do not validate columns using column validator")
private boolean noValidation = false;
+ @Option(title = "reinsert_overflowed_ttl",
+ name = {"r", "--reinsert-overflowed-ttl"},
- description = StandaloneScrubber.REINSERT_OVERFLOWED_TTL_OPTION_DESCRIPTION)
++ description = "Reinsert found rows with overflowed TTL affected by CASSANDRA-14092")
+ private boolean reinsertOverflowedTTL = false;
+
@Option(title = "jobs",
name = {"-j", "--jobs"},
description = "Number of sstables to scrub simultanously, set to 0 to use all available compaction threads")
http://git-wip-us.apache.org/repos/asf/cassandra/blob/0a6b6f50/test/data/negative-local-expiration-test/table1/mc-1-big-Data.db
----------------------------------------------------------------------
diff --cc test/data/negative-local-expiration-test/table1/mc-1-big-Data.db
index 0000000,e7a72da..cb96af3
mode 000000,100644..100644
Binary files differ
http://git-wip-us.apache.org/repos/asf/cassandra/blob/0a6b6f50/test/data/negative-local-expiration-test/table1/mc-1-big-Digest.crc32
----------------------------------------------------------------------
diff --cc test/data/negative-local-expiration-test/table1/mc-1-big-Digest.crc32
index 0000000,a3c633a..44c47fb
mode 000000,100644..100644
--- a/test/data/negative-local-expiration-test/table1/mc-1-big-Digest.crc32
+++ b/test/data/negative-local-expiration-test/table1/mc-1-big-Digest.crc32
@@@ -1,0 -1,1 +1,1 @@@
-203700622
++4223695539
http://git-wip-us.apache.org/repos/asf/cassandra/blob/0a6b6f50/test/data/negative-local-expiration-test/table1/mc-1-big-Statistics.db
----------------------------------------------------------------------
diff --cc test/data/negative-local-expiration-test/table1/mc-1-big-Statistics.db
index 0000000,faf367b..ebcf4c8
mode 000000,100644..100644
Binary files differ
http://git-wip-us.apache.org/repos/asf/cassandra/blob/0a6b6f50/test/data/negative-local-expiration-test/table1/mc-1-big-TOC.txt
----------------------------------------------------------------------
diff --cc test/data/negative-local-expiration-test/table1/mc-1-big-TOC.txt
index 0000000,45113dc..831e376
mode 000000,100644..100644
--- a/test/data/negative-local-expiration-test/table1/mc-1-big-TOC.txt
+++ b/test/data/negative-local-expiration-test/table1/mc-1-big-TOC.txt
@@@ -1,0 -1,8 +1,8 @@@
++Digest.crc32
+ CompressionInfo.db
++Index.db
++TOC.txt
+ Data.db
-Summary.db
-Filter.db
+ Statistics.db
-TOC.txt
-Digest.crc32
-Index.db
++Filter.db
++Summary.db
http://git-wip-us.apache.org/repos/asf/cassandra/blob/0a6b6f50/test/data/negative-local-expiration-test/table2/mc-1-big-Data.db
----------------------------------------------------------------------
diff --cc test/data/negative-local-expiration-test/table2/mc-1-big-Data.db
index 0000000,c1de572..8f41a21
mode 000000,100644..100644
Binary files differ
http://git-wip-us.apache.org/repos/asf/cassandra/blob/0a6b6f50/test/data/negative-local-expiration-test/table2/mc-1-big-Digest.crc32
----------------------------------------------------------------------
diff --cc test/data/negative-local-expiration-test/table2/mc-1-big-Digest.crc32
index 0000000,0403b5b..da919fe
mode 000000,100644..100644
--- a/test/data/negative-local-expiration-test/table2/mc-1-big-Digest.crc32
+++ b/test/data/negative-local-expiration-test/table2/mc-1-big-Digest.crc32
@@@ -1,0 -1,1 +1,1 @@@
-82785930
++2886964045
http://git-wip-us.apache.org/repos/asf/cassandra/blob/0a6b6f50/test/data/negative-local-expiration-test/table2/mc-1-big-Statistics.db
----------------------------------------------------------------------
diff --cc test/data/negative-local-expiration-test/table2/mc-1-big-Statistics.db
index 0000000,e9d6577..549dabe
mode 000000,100644..100644
Binary files differ
http://git-wip-us.apache.org/repos/asf/cassandra/blob/0a6b6f50/test/data/negative-local-expiration-test/table2/mc-1-big-TOC.txt
----------------------------------------------------------------------
diff --cc test/data/negative-local-expiration-test/table2/mc-1-big-TOC.txt
index 0000000,45113dc..831e376
mode 000000,100644..100644
--- a/test/data/negative-local-expiration-test/table2/mc-1-big-TOC.txt
+++ b/test/data/negative-local-expiration-test/table2/mc-1-big-TOC.txt
@@@ -1,0 -1,8 +1,8 @@@
++Digest.crc32
+ CompressionInfo.db
++Index.db
++TOC.txt
+ Data.db
-Summary.db
-Filter.db
+ Statistics.db
-TOC.txt
-Digest.crc32
-Index.db
++Filter.db
++Summary.db
http://git-wip-us.apache.org/repos/asf/cassandra/blob/0a6b6f50/test/data/negative-local-expiration-test/table3/mc-1-big-Data.db
----------------------------------------------------------------------
diff --cc test/data/negative-local-expiration-test/table3/mc-1-big-Data.db
index 0000000,e96f772..008d3e8
mode 000000,100644..100644
Binary files differ
http://git-wip-us.apache.org/repos/asf/cassandra/blob/0a6b6f50/test/data/negative-local-expiration-test/table3/mc-1-big-Digest.crc32
----------------------------------------------------------------------
diff --cc test/data/negative-local-expiration-test/table3/mc-1-big-Digest.crc32
index 0000000,459804b..0bdc0bf
mode 000000,100644..100644
--- a/test/data/negative-local-expiration-test/table3/mc-1-big-Digest.crc32
+++ b/test/data/negative-local-expiration-test/table3/mc-1-big-Digest.crc32
@@@ -1,0 -1,1 +1,1 @@@
-3064924389
++3254141434
http://git-wip-us.apache.org/repos/asf/cassandra/blob/0a6b6f50/test/data/negative-local-expiration-test/table3/mc-1-big-Statistics.db
----------------------------------------------------------------------
diff --cc test/data/negative-local-expiration-test/table3/mc-1-big-Statistics.db
index 0000000,1ee01e6..62bf84e
mode 000000,100644..100644
Binary files differ
http://git-wip-us.apache.org/repos/asf/cassandra/blob/0a6b6f50/test/data/negative-local-expiration-test/table3/mc-1-big-TOC.txt
----------------------------------------------------------------------
diff --cc test/data/negative-local-expiration-test/table3/mc-1-big-TOC.txt
index 0000000,f445537..831e376
mode 000000,100644..100644
--- a/test/data/negative-local-expiration-test/table3/mc-1-big-TOC.txt
+++ b/test/data/negative-local-expiration-test/table3/mc-1-big-TOC.txt
@@@ -1,0 -1,8 +1,8 @@@
-Summary.db
-TOC.txt
-Filter.db
-Index.db
+ Digest.crc32
+ CompressionInfo.db
++Index.db
++TOC.txt
+ Data.db
+ Statistics.db
++Filter.db
++Summary.db
http://git-wip-us.apache.org/repos/asf/cassandra/blob/0a6b6f50/test/data/negative-local-expiration-test/table4/mc-1-big-Data.db
----------------------------------------------------------------------
diff --cc test/data/negative-local-expiration-test/table4/mc-1-big-Data.db
index 0000000,a22a7a3..128ea47
mode 000000,100644..100644
Binary files differ
http://git-wip-us.apache.org/repos/asf/cassandra/blob/0a6b6f50/test/data/negative-local-expiration-test/table4/mc-1-big-Digest.crc32
----------------------------------------------------------------------
diff --cc test/data/negative-local-expiration-test/table4/mc-1-big-Digest.crc32
index 0000000,db7a6c7..9d52209
mode 000000,100644..100644
--- a/test/data/negative-local-expiration-test/table4/mc-1-big-Digest.crc32
+++ b/test/data/negative-local-expiration-test/table4/mc-1-big-Digest.crc32
@@@ -1,0 -1,1 +1,1 @@@
-1803989939
++3231150985
http://git-wip-us.apache.org/repos/asf/cassandra/blob/0a6b6f50/test/data/negative-local-expiration-test/table4/mc-1-big-Statistics.db
----------------------------------------------------------------------
diff --cc test/data/negative-local-expiration-test/table4/mc-1-big-Statistics.db
index 0000000,4ee9294..4eee729
mode 000000,100644..100644
Binary files differ
http://git-wip-us.apache.org/repos/asf/cassandra/blob/0a6b6f50/test/data/negative-local-expiration-test/table4/mc-1-big-TOC.txt
----------------------------------------------------------------------
diff --cc test/data/negative-local-expiration-test/table4/mc-1-big-TOC.txt
index 0000000,f445537..831e376
mode 000000,100644..100644
--- a/test/data/negative-local-expiration-test/table4/mc-1-big-TOC.txt
+++ b/test/data/negative-local-expiration-test/table4/mc-1-big-TOC.txt
@@@ -1,0 -1,8 +1,8 @@@
-Summary.db
-TOC.txt
-Filter.db
-Index.db
+ Digest.crc32
+ CompressionInfo.db
++Index.db
++TOC.txt
+ Data.db
+ Statistics.db
++Filter.db
++Summary.db
http://git-wip-us.apache.org/repos/asf/cassandra/blob/0a6b6f50/test/unit/org/apache/cassandra/db/CellTest.java
----------------------------------------------------------------------
diff --cc test/unit/org/apache/cassandra/db/CellTest.java
index ea009f6,22f1b78..c68b4ec
--- a/test/unit/org/apache/cassandra/db/CellTest.java
+++ b/test/unit/org/apache/cassandra/db/CellTest.java
@@@ -6,9 -6,9 +6,9 @@@
* 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
@@@ -148,88 -141,19 +148,88 @@@ public class CellTes
// But this should be valid even though the underlying value is an empty BB (catches bug #11618)
assertValid(BufferCell.tombstone(c, 0, 4));
// And of course, this should be valid with a proper value
- assertValid(BufferCell.live(fakeMetadata, c, 0, ByteBufferUtil.bytes((short)4)));
+ assertValid(BufferCell.live(c, 0, bbs(4)));
// Invalid ttl
- assertInvalid(BufferCell.expiring(c, 0, -4, 4, ByteBufferUtil.bytes(4)));
- // Invalid local deletion times
- assertInvalid(BufferCell.expiring(c, 0, 4, -4, ByteBufferUtil.bytes(4)));
- assertInvalid(BufferCell.expiring(c, 0, 4, Cell.NO_DELETION_TIME, ByteBufferUtil.bytes(4)));
+ assertInvalid(BufferCell.expiring(c, 0, -4, 4, bbs(4)));
- // Invalid local deletion times
- assertInvalid(BufferCell.expiring(c, 0, 4, -5, bbs(4)));
- assertInvalid(BufferCell.expiring(c, 0, 4, Cell.NO_DELETION_TIME, bbs(4)));
++ // Cells with overflowed localExpirationTime are valid after CASSANDRA-14092
++ assertValid(BufferCell.expiring(c, 0, 4, -5, bbs(4)));
++ assertValid(BufferCell.expiring(c, 0, 4, Cell.NO_DELETION_TIME, bbs(4)));
c = fakeColumn("c", MapType.getInstance(Int32Type.instance, Int32Type.instance, true));
// Valid cell path
- assertValid(BufferCell.live(fakeMetadata, c, 0, ByteBufferUtil.bytes(4), CellPath.create(ByteBufferUtil.bytes(4))));
+ assertValid(BufferCell.live(c, 0, ByteBufferUtil.bytes(4), CellPath.create(ByteBufferUtil.bytes(4))));
// Invalid cell path (int values should be 0 or 4 bytes)
- assertInvalid(BufferCell.live(fakeMetadata, c, 0, ByteBufferUtil.bytes(4), CellPath.create(ByteBufferUtil.bytes((long)4))));
+ assertInvalid(BufferCell.live(c, 0, ByteBufferUtil.bytes(4), CellPath.create(ByteBufferUtil.bytes((long)4))));
+ }
+
+ @Test
+ public void testValidateNonFrozenUDT()
+ {
+ FieldIdentifier f1 = field("f1"); // has field position 0
+ FieldIdentifier f2 = field("f2"); // has field position 1
+ UserType udt = new UserType("ks",
+ bb("myType"),
+ asList(f1, f2),
+ asList(Int32Type.instance, UTF8Type.instance),
+ true);
+ ColumnDefinition c;
+
+ // Valid cells
+ c = fakeColumn("c", udt);
+ assertValid(BufferCell.live(c, 0, bb(1), CellPath.create(bbs(0))));
+ assertValid(BufferCell.live(c, 0, bb("foo"), CellPath.create(bbs(1))));
+ assertValid(BufferCell.expiring(c, 0, 4, 4, bb(1), CellPath.create(bbs(0))));
+ assertValid(BufferCell.expiring(c, 0, 4, 4, bb("foo"), CellPath.create(bbs(1))));
+ assertValid(BufferCell.tombstone(c, 0, 4, CellPath.create(bbs(0))));
+
+ // Invalid value (text in an int field)
+ assertInvalid(BufferCell.live(c, 0, bb("foo"), CellPath.create(bbs(0))));
+
+ // Invalid ttl
+ assertInvalid(BufferCell.expiring(c, 0, -4, 4, bb(1), CellPath.create(bbs(0))));
- // Invalid local deletion times
- assertInvalid(BufferCell.expiring(c, 0, 4, -5, bb(1), CellPath.create(bbs(0))));
- assertInvalid(BufferCell.expiring(c, 0, 4, Cell.NO_DELETION_TIME, bb(1), CellPath.create(bbs(0))));
++ // Cells with overflowed localExpirationTime are valid after CASSANDRA-14092
++ assertValid(BufferCell.expiring(c, 0, 4, -5, bb(1), CellPath.create(bbs(0))));
++ assertValid((BufferCell.expiring(c, 0, 4, Cell.NO_DELETION_TIME, bb(1), CellPath.create(bbs(0)))));
+
+ // Invalid cell path (int values should be 0 or 2 bytes)
+ assertInvalid(BufferCell.live(c, 0, bb(1), CellPath.create(ByteBufferUtil.bytes((long)4))));
+ }
+
+ @Test
+ public void testValidateFrozenUDT()
+ {
+ FieldIdentifier f1 = field("f1"); // has field position 0
+ FieldIdentifier f2 = field("f2"); // has field position 1
+ UserType udt = new UserType("ks",
+ bb("myType"),
+ asList(f1, f2),
+ asList(Int32Type.instance, UTF8Type.instance),
+ false);
+
+ ColumnDefinition c = fakeColumn("c", udt);
+ ByteBuffer val = udt(bb(1), bb("foo"));
+
+ // Valid cells
+ assertValid(BufferCell.live(c, 0, val));
+ assertValid(BufferCell.live(c, 0, val));
+ assertValid(BufferCell.expiring(c, 0, 4, 4, val));
+ assertValid(BufferCell.expiring(c, 0, 4, 4, val));
+ assertValid(BufferCell.tombstone(c, 0, 4));
+ // fewer values than types is accepted
+ assertValid(BufferCell.live(c, 0, udt(bb(1))));
+
+ // Invalid values
+ // invalid types
+ assertInvalid(BufferCell.live(c, 0, udt(bb("foo"), bb(1))));
+ // too many types
+ assertInvalid(BufferCell.live(c, 0, udt(bb(1), bb("foo"), bb("bar"))));
+
+ // Invalid ttl
+ assertInvalid(BufferCell.expiring(c, 0, -4, 4, val));
- // Invalid local deletion times
- assertInvalid(BufferCell.expiring(c, 0, 4, -5, val));
- assertInvalid(BufferCell.expiring(c, 0, 4, Cell.NO_DELETION_TIME, val));
++ // Cells with overflowed localExpirationTime are valid after CASSANDRA-14092
++ assertValid(BufferCell.expiring(c, 0, 4, -5, val));
++ assertValid(BufferCell.expiring(c, 0, 4, Cell.NO_DELETION_TIME, val));
}
@Test
http://git-wip-us.apache.org/repos/asf/cassandra/blob/0a6b6f50/test/unit/org/apache/cassandra/db/ScrubTest.java
----------------------------------------------------------------------
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cassandra.apache.org
For additional commands, e-mail: commits-help@cassandra.apache.org