You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cassandra.apache.org by al...@apache.org on 2017/09/30 09:57:21 UTC

[1/4] cassandra git commit: Implement short read protection on partition boundaries

Repository: cassandra
Updated Branches:
  refs/heads/cassandra-3.11 be2117492 -> e819fec89


Implement short read protection on partition boundaries

patch by Aleksey Yeschenko; reviewed by Sam Tunnicliffe for
CASSANDRA-13595


Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/68a67469
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/68a67469
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/68a67469

Branch: refs/heads/cassandra-3.11
Commit: 68a67469f8b25534d086b29b8fe0fa4ec3f9d1ec
Parents: 1efdf33
Author: Aleksey Yeschenko <al...@yeschenko.com>
Authored: Thu Sep 21 14:29:05 2017 +0100
Committer: Aleksey Yeschenko <al...@yeschenko.com>
Committed: Sat Sep 30 10:33:30 2017 +0100

----------------------------------------------------------------------
 CHANGES.txt                                     |   1 +
 .../cassandra/db/PartitionRangeReadCommand.java |  14 ++
 .../org/apache/cassandra/db/ReadCommand.java    |   2 +
 .../db/SinglePartitionReadCommand.java          |   5 +
 .../apache/cassandra/db/filter/DataLimits.java  |   5 +-
 .../apache/cassandra/service/DataResolver.java  | 216 ++++++++++++++-----
 6 files changed, 180 insertions(+), 63 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cassandra/blob/68a67469/CHANGES.txt
----------------------------------------------------------------------
diff --git a/CHANGES.txt b/CHANGES.txt
index 1c53aa5..c5e54d4 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,5 @@
 3.0.15
+ * Implement short read protection on partition boundaries (CASSANDRA-13595)
  * Fix ISE thrown by UPI.Serializer.hasNext() for some SELECT queries (CASSANDRA-13911)
  * Filter header only commit logs before recovery (CASSANDRA-13918)
  * AssertionError prepending to a list (CASSANDRA-13149)

http://git-wip-us.apache.org/repos/asf/cassandra/blob/68a67469/src/java/org/apache/cassandra/db/PartitionRangeReadCommand.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/PartitionRangeReadCommand.java b/src/java/org/apache/cassandra/db/PartitionRangeReadCommand.java
index 9e557e0..84e3c7d 100644
--- a/src/java/org/apache/cassandra/db/PartitionRangeReadCommand.java
+++ b/src/java/org/apache/cassandra/db/PartitionRangeReadCommand.java
@@ -32,6 +32,7 @@ import org.apache.cassandra.db.partitions.*;
 import org.apache.cassandra.db.rows.BaseRowIterator;
 import org.apache.cassandra.db.transform.Transformation;
 import org.apache.cassandra.dht.AbstractBounds;
+import org.apache.cassandra.dht.Bounds;
 import org.apache.cassandra.exceptions.RequestExecutionException;
 import org.apache.cassandra.index.Index;
 import org.apache.cassandra.io.sstable.format.SSTableReader;
@@ -400,6 +401,19 @@ public class PartitionRangeReadCommand extends ReadCommand
         return DataRange.serializer.serializedSize(dataRange(), version, metadata());
     }
 
+    /*
+     * We are currently using PartitionRangeReadCommand for most index queries, even if they are explicitly restricted
+     * to a single partition key. Return true if that is the case.
+     *
+     * See CASSANDRA-11617 and CASSANDRA-11872 for details.
+     */
+    public boolean isLimitedToOnePartition()
+    {
+        return dataRange.keyRange instanceof Bounds
+            && dataRange.startKey().kind() == PartitionPosition.Kind.ROW_KEY
+            && dataRange.startKey().equals(dataRange.stopKey());
+    }
+
     private static class Deserializer extends SelectionDeserializer
     {
         public ReadCommand deserialize(DataInputPlus in,

http://git-wip-us.apache.org/repos/asf/cassandra/blob/68a67469/src/java/org/apache/cassandra/db/ReadCommand.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/ReadCommand.java b/src/java/org/apache/cassandra/db/ReadCommand.java
index 160b104..2d399d8 100644
--- a/src/java/org/apache/cassandra/db/ReadCommand.java
+++ b/src/java/org/apache/cassandra/db/ReadCommand.java
@@ -170,6 +170,8 @@ public abstract class ReadCommand implements ReadQuery
     protected abstract void serializeSelection(DataOutputPlus out, int version) throws IOException;
     protected abstract long selectionSerializedSize(int version);
 
+    public abstract boolean isLimitedToOnePartition();
+
     /**
      * The metadata for the table queried.
      *

http://git-wip-us.apache.org/repos/asf/cassandra/blob/68a67469/src/java/org/apache/cassandra/db/SinglePartitionReadCommand.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/SinglePartitionReadCommand.java b/src/java/org/apache/cassandra/db/SinglePartitionReadCommand.java
index 7a66eca..4b10530 100644
--- a/src/java/org/apache/cassandra/db/SinglePartitionReadCommand.java
+++ b/src/java/org/apache/cassandra/db/SinglePartitionReadCommand.java
@@ -1096,6 +1096,11 @@ public class SinglePartitionReadCommand extends ReadCommand
              + ClusteringIndexFilter.serializer.serializedSize(clusteringIndexFilter(), version);
     }
 
+    public boolean isLimitedToOnePartition()
+    {
+        return true;
+    }
+
     /**
      * Groups multiple single partition read commands.
      */

http://git-wip-us.apache.org/repos/asf/cassandra/blob/68a67469/src/java/org/apache/cassandra/db/filter/DataLimits.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/filter/DataLimits.java b/src/java/org/apache/cassandra/db/filter/DataLimits.java
index 6b74293..4c57a76 100644
--- a/src/java/org/apache/cassandra/db/filter/DataLimits.java
+++ b/src/java/org/apache/cassandra/db/filter/DataLimits.java
@@ -312,10 +312,7 @@ public abstract class DataLimits
 
         public DataLimits forShortReadRetry(int toFetch)
         {
-            // When we do a short read retry, we're only ever querying the single partition on which we have a short read. So
-            // we use toFetch as the row limit and use no perPartitionLimit (it would be equivalent in practice to use toFetch
-            // for both argument or just for perPartitionLimit with no limit on rowLimit).
-            return new CQLLimits(toFetch, NO_LIMIT, isDistinct);
+            return new CQLLimits(toFetch, perPartitionLimit, isDistinct);
         }
 
         public boolean hasEnoughLiveData(CachedPartition cached, int nowInSec, boolean countPartitionsWithOnlyStaticData, boolean enforceStrictLiveness)

http://git-wip-us.apache.org/repos/asf/cassandra/blob/68a67469/src/java/org/apache/cassandra/service/DataResolver.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/service/DataResolver.java b/src/java/org/apache/cassandra/service/DataResolver.java
index 7d8ffc5..5fb34c6 100644
--- a/src/java/org/apache/cassandra/service/DataResolver.java
+++ b/src/java/org/apache/cassandra/service/DataResolver.java
@@ -34,6 +34,9 @@ import org.apache.cassandra.db.filter.DataLimits;
 import org.apache.cassandra.db.partitions.*;
 import org.apache.cassandra.db.rows.*;
 import org.apache.cassandra.db.transform.*;
+import org.apache.cassandra.dht.AbstractBounds;
+import org.apache.cassandra.dht.ExcludingBounds;
+import org.apache.cassandra.dht.Range;
 import org.apache.cassandra.exceptions.ReadTimeoutException;
 import org.apache.cassandra.net.*;
 import org.apache.cassandra.tracing.Tracing;
@@ -91,7 +94,7 @@ public class DataResolver extends ResponseResolver
          * have more rows than the client requested. To make sure that we still conform to the original limit,
          * we apply a top-level post-reconciliation counter to the merged partition iterator.
          *
-         * Short read protection logic (ShortReadRowProtection.moreContents()) relies on this counter to be applied
+         * Short read protection logic (ShortReadRowsProtection.moreContents()) relies on this counter to be applied
          * to the current partition to work. For this reason we have to apply the counter transformation before
          * empty partition discard logic kicks in - for it will eagerly consume the iterator.
          *
@@ -121,26 +124,13 @@ public class DataResolver extends ResponseResolver
         if (results.size() == 1)
             return results.get(0);
 
-        // So-called "short reads" stems from nodes returning only a subset of the results they have for a partition due to the limit,
-        // but that subset not being enough post-reconciliation. So if we don't have limit, don't bother.
+        /*
+         * So-called short reads stems from nodes returning only a subset of the results they have due to the limit,
+         * but that subset not being enough post-reconciliation. So if we don't have a limit, don't bother.
+         */
         if (!command.limits().isUnlimited())
-        {
             for (int i = 0; i < results.size(); i++)
-            {
-                DataLimits.Counter singleResultCounter =
-                    command.limits().newCounter(command.nowInSec(), false, command.selectsFullPartition(), enforceStrictLiveness).onlyCount();
-
-                ShortReadResponseProtection protection =
-                    new ShortReadResponseProtection(sources[i], singleResultCounter, mergedResultCounter);
-
-                /*
-                 * The order of transformations is important here. See ShortReadResponseProtection.applyToPartition()
-                 * comments for details. We want singleResultCounter.applyToPartition() to be called after SRRP applies
-                 * its transformations, so that this order is preserved when calling applyToRows() too.
-                 */
-                results.set(i, Transformation.apply(Transformation.apply(results.get(i), protection), singleResultCounter));
-            }
-        }
+                results.set(i, extendWithShortReadProtection(results.get(i), sources[i], mergedResultCounter));
 
         return UnfilteredPartitionIterators.merge(results, command.nowInSec(), new RepairMergeListener(sources));
     }
@@ -476,14 +466,60 @@ public class DataResolver extends ResponseResolver
         }
     }
 
-    private class ShortReadResponseProtection extends Transformation<UnfilteredRowIterator>
+    private UnfilteredPartitionIterator extendWithShortReadProtection(UnfilteredPartitionIterator partitions,
+                                                                      InetAddress source,
+                                                                      DataLimits.Counter mergedResultCounter)
+    {
+        DataLimits.Counter singleResultCounter =
+            command.limits().newCounter(command.nowInSec(), false, command.selectsFullPartition(), enforceStrictLiveness).onlyCount();
+
+        ShortReadPartitionsProtection protection =
+            new ShortReadPartitionsProtection(source, singleResultCounter, mergedResultCounter);
+
+        /*
+         * The order of extention and transformations is important here. Extending with more partitions has to happen
+         * first due to the way BaseIterator.hasMoreContents() works: only transformations applied after extension will
+         * be called on the first partition of the extended iterator.
+         *
+         * Additionally, we want singleResultCounter to be applied after SRPP, so that its applyToPartition() method will
+         * be called last, after the extension done by SRRP.applyToPartition() call. That way we preserve the same order
+         * when it comes to calling SRRP.moreContents() and applyToRow() callbacks.
+         *
+         * See ShortReadPartitionsProtection.applyToPartition() for more details.
+         */
+
+        // extend with moreContents() only if it's a range read command with no partition key specified
+        if (!command.isLimitedToOnePartition())
+            partitions = MorePartitions.extend(partitions, protection);     // register SRPP.moreContents()
+
+        partitions = Transformation.apply(partitions, protection);          // register SRPP.applyToPartition()
+        partitions = Transformation.apply(partitions, singleResultCounter); // register the per-source counter
+
+        return partitions;
+    }
+
+    /*
+     * We have a potential short read if the result from a given node contains the requested number of rows
+     * (i.e. it has stopped returning results due to the limit), but some of them haven't
+     * made it into the final post-reconciliation result due to other nodes' row, range, and/or partition tombstones.
+     *
+     * If that is the case, then that node may have more rows that we should fetch, as otherwise we could
+     * ultimately return fewer rows than required. Also, those additional rows may contain tombstones which
+     * which we also need to fetch as they may shadow rows or partitions from other replicas' results, which we would
+     * otherwise return incorrectly.
+     */
+    private class ShortReadPartitionsProtection extends Transformation<UnfilteredRowIterator> implements MorePartitions<UnfilteredPartitionIterator>
     {
         private final InetAddress source;
 
         private final DataLimits.Counter singleResultCounter; // unmerged per-source counter
         private final DataLimits.Counter mergedResultCounter; // merged end-result counter
 
-        private ShortReadResponseProtection(InetAddress source, DataLimits.Counter singleResultCounter, DataLimits.Counter mergedResultCounter)
+        private DecoratedKey lastPartitionKey; // key of the last observed partition
+
+        private boolean partitionsFetched; // whether we've seen any new partitions since iteration start or last moreContents() call
+
+        private ShortReadPartitionsProtection(InetAddress source, DataLimits.Counter singleResultCounter, DataLimits.Counter mergedResultCounter)
         {
             this.source = source;
             this.singleResultCounter = singleResultCounter;
@@ -493,29 +529,100 @@ public class DataResolver extends ResponseResolver
         @Override
         public UnfilteredRowIterator applyToPartition(UnfilteredRowIterator partition)
         {
-            ShortReadRowProtection protection = new ShortReadRowProtection(partition.metadata(), partition.partitionKey());
+            partitionsFetched = true;
+
+            lastPartitionKey = partition.partitionKey();
 
             /*
-             * Extend for moreContents() then apply protection to track lastClustering.
+             * Extend for moreContents() then apply protection to track lastClustering by applyToRow().
              *
              * If we don't apply the transformation *after* extending the partition with MoreRows,
              * applyToRow() method of protection will not be called on the first row of the new extension iterator.
              */
+            ShortReadRowsProtection protection = new ShortReadRowsProtection(partition.metadata(), partition.partitionKey());
             return Transformation.apply(MoreRows.extend(partition, protection), protection);
         }
 
-        private class ShortReadRowProtection extends Transformation implements MoreRows<UnfilteredRowIterator>
+        /*
+         * We only get here once all the rows and partitions in this iterator have been iterated over, and so
+         * if the node had returned the requested number of rows but we still get here, then some results were
+         * skipped during reconciliation.
+         */
+        public UnfilteredPartitionIterator moreContents()
+        {
+            // never try to request additional partitions from replicas if our reconciled partitions are already filled to the limit
+            assert !mergedResultCounter.isDone();
+
+            // we do not apply short read protection when we have no limits at all
+            assert !command.limits().isUnlimited();
+
+            /*
+             * If this is a single partition read command or an (indexed) partition range read command with
+             * a partition key specified, then we can't and shouldn't try fetch more partitions.
+             */
+            assert !command.isLimitedToOnePartition();
+
+            /*
+             * If the returned result doesn't have enough rows/partitions to satisfy even the original limit, don't ask for more.
+             *
+             * Can only take the short cut if there is no per partition limit set. Otherwise it's possible to hit false
+             * positives due to some rows being uncounted for in certain scenarios (see CASSANDRA-13911).
+             */
+            if (!singleResultCounter.isDone() && command.limits().perPartitionCount() == DataLimits.NO_LIMIT)
+                return null;
+
+            /*
+             * Either we had an empty iterator as the initial response, or our moreContents() call got us an empty iterator.
+             * There is no point to ask the replica for more rows - it has no more in the requested range.
+             */
+            if (!partitionsFetched)
+                return null;
+            partitionsFetched = false;
+
+            /*
+             * We are going to fetch one partition at a time for thrift and potentially more for CQL.
+             * The row limit will either be set to the per partition limit - if the command has no total row limit set, or
+             * the total # of rows remaining - if it has some. If we don't grab enough rows in some of the partitions,
+             * then future ShortReadRowsProtection.moreContents() calls will fetch the missing ones.
+             */
+            int toQuery = command.limits().count() != DataLimits.NO_LIMIT
+                        ? command.limits().count() - mergedResultCounter.counted()
+                        : command.limits().perPartitionCount();
+
+            ColumnFamilyStore.metricsFor(command.metadata().cfId).shortReadProtectionRequests.mark();
+            Tracing.trace("Requesting {} extra rows from {} for short read protection", toQuery, source);
+
+            PartitionRangeReadCommand cmd = makeFetchAdditionalPartitionReadCommand(toQuery);
+            return executeReadCommand(cmd);
+        }
+
+        private PartitionRangeReadCommand makeFetchAdditionalPartitionReadCommand(int toQuery)
+        {
+            PartitionRangeReadCommand cmd = (PartitionRangeReadCommand) command;
+
+            DataLimits newLimits = cmd.limits().forShortReadRetry(toQuery);
+
+            AbstractBounds<PartitionPosition> bounds = cmd.dataRange().keyRange();
+            AbstractBounds<PartitionPosition> newBounds = bounds.inclusiveRight()
+                                                        ? new Range<>(lastPartitionKey, bounds.right)
+                                                        : new ExcludingBounds<>(lastPartitionKey, bounds.right);
+            DataRange newDataRange = cmd.dataRange().forSubRange(newBounds);
+
+            return cmd.withUpdatedLimitsAndDataRange(newLimits, newDataRange);
+        }
+
+        private class ShortReadRowsProtection extends Transformation implements MoreRows<UnfilteredRowIterator>
         {
             private final CFMetaData metadata;
             private final DecoratedKey partitionKey;
 
-            private Clustering lastClustering;
+            private Clustering lastClustering; // clustering of the last observed row
 
             private int lastCounted = 0; // last seen recorded # before attempting to fetch more rows
             private int lastFetched = 0; // # rows returned by last attempt to get more (or by the original read command)
             private int lastQueried = 0; // # extra rows requested from the replica last time
 
-            private ShortReadRowProtection(CFMetaData metadata, DecoratedKey partitionKey)
+            private ShortReadRowsProtection(CFMetaData metadata, DecoratedKey partitionKey)
             {
                 this.metadata = metadata;
                 this.partitionKey = partitionKey;
@@ -529,18 +636,9 @@ public class DataResolver extends ResponseResolver
             }
 
             /*
-             * We have a potential short read if the result from a given node contains the requested number of rows
-             * for that partition (i.e. it has stopped returning results due to the limit), but some of them haven't
-             * made it into the final post-reconciliation result due to other nodes' tombstones.
-             *
-             * If that is the case, then that node may have more rows that we should fetch, as otherwise we could
-             * ultimately return fewer rows than required. Also, those additional rows may contain tombstones which
-             * which we also need to fetch as they may shadow rows from other replicas' results, which we would
-             * otherwise return incorrectly.
-             *
-             * Also note that we only get here once all the rows for this partition have been iterated over, and so
-             * if the node had returned the requested number of rows but we still get here, then some results were
-             * skipped during reconciliation.
+             * We only get here once all the rows in this iterator have been iterated over, and so if the node
+             * had returned the requested number of rows but we still get here, then some results were skipped
+             * during reconciliation.
              */
             public UnfilteredRowIterator moreContents()
             {
@@ -622,18 +720,17 @@ public class DataResolver extends ResponseResolver
                  * Note: it's ok to retrieve more rows that necessary since singleResultCounter is not stopping and only
                  * counts.
                  *
-                 * With that in mind, we'll just request the minimum of (count(), perPartitionCount()) limits,
-                 * but no fewer than 8 rows (an arbitrary round lower bound), to ensure that we won't fetch row by row
-                 * for SELECT DISTINCT queries (that set per partition limit to 1).
+                 * With that in mind, we'll just request the minimum of (count(), perPartitionCount()) limits.
                  *
                  * See CASSANDRA-13794 for more details.
                  */
-                lastQueried = Math.max(Math.min(command.limits().count(), command.limits().perPartitionCount()), 8);
+                lastQueried = Math.min(command.limits().count(), command.limits().perPartitionCount());
 
                 ColumnFamilyStore.metricsFor(metadata.cfId).shortReadProtectionRequests.mark();
                 Tracing.trace("Requesting {} extra rows from {} for short read protection", lastQueried, source);
 
-                return executeReadCommand(makeFetchAdditionalRowsReadCommand(lastQueried));
+                SinglePartitionReadCommand cmd = makeFetchAdditionalRowsReadCommand(lastQueried);
+                return UnfilteredPartitionIterators.getOnlyElement(executeReadCommand(cmd), cmd);
             }
 
             private SinglePartitionReadCommand makeFetchAdditionalRowsReadCommand(int toQuery)
@@ -649,24 +746,25 @@ public class DataResolver extends ResponseResolver
                                                          command.rowFilter(),
                                                          command.limits().forShortReadRetry(toQuery),
                                                          partitionKey,
-                                                         filter);
+                                                         filter,
+                                                         command.indexMetadata());
             }
+        }
 
-            private UnfilteredRowIterator executeReadCommand(SinglePartitionReadCommand cmd)
-            {
-                DataResolver resolver = new DataResolver(keyspace, cmd, ConsistencyLevel.ONE, 1);
-                ReadCallback handler = new ReadCallback(resolver, ConsistencyLevel.ONE, cmd, Collections.singletonList(source));
-
-                if (StorageProxy.canDoLocalRequest(source))
-                    StageManager.getStage(Stage.READ).maybeExecuteImmediately(new StorageProxy.LocalReadRunnable(cmd, handler));
-                else
-                    MessagingService.instance().sendRRWithFailure(cmd.createMessage(MessagingService.current_version), source, handler);
-
-                // We don't call handler.get() because we want to preserve tombstones since we're still in the middle of merging node results.
-                handler.awaitResults();
-                assert resolver.responses.size() == 1;
-                return UnfilteredPartitionIterators.getOnlyElement(resolver.responses.get(0).payload.makeIterator(command), cmd);
-            }
+        private UnfilteredPartitionIterator executeReadCommand(ReadCommand cmd)
+        {
+            DataResolver resolver = new DataResolver(keyspace, cmd, ConsistencyLevel.ONE, 1);
+            ReadCallback handler = new ReadCallback(resolver, ConsistencyLevel.ONE, cmd, Collections.singletonList(source));
+
+            if (StorageProxy.canDoLocalRequest(source))
+                StageManager.getStage(Stage.READ).maybeExecuteImmediately(new StorageProxy.LocalReadRunnable(cmd, handler));
+            else
+                MessagingService.instance().sendRRWithFailure(cmd.createMessage(MessagingService.current_version), source, handler);
+
+            // We don't call handler.get() because we want to preserve tombstones since we're still in the middle of merging node results.
+            handler.awaitResults();
+            assert resolver.responses.size() == 1;
+            return resolver.responses.get(0).payload.makeIterator(command);
         }
     }
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cassandra.apache.org
For additional commands, e-mail: commits-help@cassandra.apache.org


[4/4] cassandra git commit: Merge branch 'cassandra-3.0' into cassandra-3.11

Posted by al...@apache.org.
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/e819fec8
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/e819fec8
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/e819fec8

Branch: refs/heads/cassandra-3.11
Commit: e819fec89c38d4b6347ea9a683798e050c65dd86
Parents: be21174 15cee48
Author: Aleksey Yeschenko <al...@yeschenko.com>
Authored: Sat Sep 30 10:53:06 2017 +0100
Committer: Aleksey Yeschenko <al...@yeschenko.com>
Committed: Sat Sep 30 10:56:07 2017 +0100

----------------------------------------------------------------------
 CHANGES.txt                                     |   8 +-
 .../cassandra/db/PartitionRangeReadCommand.java |  14 ++
 .../org/apache/cassandra/db/ReadCommand.java    |   2 +
 .../db/SinglePartitionReadCommand.java          |   5 +
 .../apache/cassandra/db/filter/DataLimits.java  |   5 +-
 .../UnfilteredPartitionIterators.java           |  19 +-
 .../apache/cassandra/service/DataResolver.java  | 239 ++++++++++++++-----
 7 files changed, 219 insertions(+), 73 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cassandra/blob/e819fec8/CHANGES.txt
----------------------------------------------------------------------
diff --cc CHANGES.txt
index a782333,4a45469..61f3405
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@@ -1,20 -1,11 +1,22 @@@
 -3.0.15
 +3.11.1
 + * Fix the computation of cdc_total_space_in_mb for exabyte filesystems (CASSANDRA-13808)
-  * Handle limit correctly on tables with strict liveness (CASSANDRA-13883)
 + * 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)
 + * 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:
+  * Implement short read protection on partition boundaries (CASSANDRA-13595)
+  * Fix ISE thrown by UPI.Serializer.hasNext() for some SELECT queries (CASSANDRA-13911)
   * Filter header only commit logs before recovery (CASSANDRA-13918)
   * AssertionError prepending to a list (CASSANDRA-13149)
   * Fix support for SuperColumn tables (CASSANDRA-12373)
+  * Handle limit correctly on tables with strict liveness (CASSANDRA-13883)
 - * Fix missing original update in TriggerExecutor (CASSANDRA-13894)
   * Remove non-rpc-ready nodes from counter leader candidates (CASSANDRA-13043)
   * Improve short read protection performance (CASSANDRA-13794)
   * Fix sstable reader to support range-tombstone-marker for multi-slices (CASSANDRA-13787)
@@@ -155,35 -115,12 +157,39 @@@ Merged from 3.0
   * Propagate row deletions in 2i tables on upgrade (CASSANDRA-13320)
   * Slice.isEmpty() returns false for some empty slices (CASSANDRA-13305)
   * Add formatted row output to assertEmpty in CQL Tester (CASSANDRA-13238)
 - * Legacy caching options can prevent 3.0 upgrade (CASSANDRA-13384)
 + * Prevent data loss on upgrade 2.1 - 3.0 by adding component separator to LogRecord absolute path (CASSANDRA-13294)
 + * Improve testing on macOS by eliminating sigar logging (CASSANDRA-13233)
 + * Cqlsh copy-from should error out when csv contains invalid data for collections (CASSANDRA-13071)
 + * Fix "multiple versions of ant detected..." when running ant test (CASSANDRA-13232)
 + * Coalescing strategy sleeps too much (CASSANDRA-13090)
 + * Faster StreamingHistogram (CASSANDRA-13038)
 + * Legacy deserializer can create unexpected boundary range tombstones (CASSANDRA-13237)
 + * Remove unnecessary assertion from AntiCompactionTest (CASSANDRA-13070)
 + * Fix cqlsh COPY for dates before 1900 (CASSANDRA-13185)
 + * Use keyspace replication settings on system.size_estimates table (CASSANDRA-9639)
 + * Add vm.max_map_count StartupCheck (CASSANDRA-13008)
 + * Hint related logging should include the IP address of the destination in addition to
 +   host ID (CASSANDRA-13205)
 + * Reloading logback.xml does not work (CASSANDRA-13173)
 + * Lightweight transactions temporarily fail after upgrade from 2.1 to 3.0 (CASSANDRA-13109)
 + * Duplicate rows after upgrading from 2.1.16 to 3.0.10/3.9 (CASSANDRA-13125)
 + * Fix UPDATE queries with empty IN restrictions (CASSANDRA-13152)
 + * Fix handling of partition with partition-level deletion plus
 +   live rows in sstabledump (CASSANDRA-13177)
 + * Provide user workaround when system_schema.columns does not contain entries
 +   for a table that's in system_schema.tables (CASSANDRA-13180)
   * Nodetool upgradesstables/scrub/compact ignores system tables (CASSANDRA-13410)
++<<<<<<< HEAD
 + * Fix schema version calculation for rolling upgrades (CASSANDRA-13441)
++=======
+  * Fix NPE issue in StorageService (CASSANDRA-13060)
++>>>>>>> cassandra-3.0
  Merged from 2.2:
 + * Nodes started with join_ring=False should be able to serve requests when authentication is enabled (CASSANDRA-11381)
 + * cqlsh COPY FROM: increment error count only for failures, not for attempts (CASSANDRA-13209)
   * Avoid starting gossiper in RemoveTest (CASSANDRA-13407)
   * Fix weightedSize() for row-cache reported by JMX and NodeTool (CASSANDRA-13393)
 + * Fix JVM metric names (CASSANDRA-13103)
   * Honor truststore-password parameter in cassandra-stress (CASSANDRA-12773)
   * Discard in-flight shadow round responses (CASSANDRA-12653)
   * Don't anti-compact repaired data to avoid inconsistencies (CASSANDRA-13153)

http://git-wip-us.apache.org/repos/asf/cassandra/blob/e819fec8/src/java/org/apache/cassandra/db/PartitionRangeReadCommand.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/cassandra/blob/e819fec8/src/java/org/apache/cassandra/db/ReadCommand.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/db/ReadCommand.java
index 4f3c66f,2d399d8..c733b21
--- a/src/java/org/apache/cassandra/db/ReadCommand.java
+++ b/src/java/org/apache/cassandra/db/ReadCommand.java
@@@ -174,15 -170,9 +174,17 @@@ public abstract class ReadCommand exten
      protected abstract void serializeSelection(DataOutputPlus out, int version) throws IOException;
      protected abstract long selectionSerializedSize(int version);
  
+     public abstract boolean isLimitedToOnePartition();
+ 
      /**
 +     * Creates a new <code>ReadCommand</code> instance with new limits.
 +     *
 +     * @param newLimits the new limits
 +     * @return a new <code>ReadCommand</code> with the updated limits
 +     */
 +    public abstract ReadCommand withUpdatedLimit(DataLimits newLimits);
 +
 +    /**
       * The metadata for the table queried.
       *
       * @return the metadata for the table queried.

http://git-wip-us.apache.org/repos/asf/cassandra/blob/e819fec8/src/java/org/apache/cassandra/db/SinglePartitionReadCommand.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/cassandra/blob/e819fec8/src/java/org/apache/cassandra/db/filter/DataLimits.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/cassandra/blob/e819fec8/src/java/org/apache/cassandra/db/partitions/UnfilteredPartitionIterators.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/cassandra/blob/e819fec8/src/java/org/apache/cassandra/service/DataResolver.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/service/DataResolver.java
index 84e8685,5fb34c6..111d561
--- a/src/java/org/apache/cassandra/service/DataResolver.java
+++ b/src/java/org/apache/cassandra/service/DataResolver.java
@@@ -489,19 -466,60 +479,65 @@@ public class DataResolver extends Respo
          }
      }
  
-     private class ShortReadResponseProtection extends Transformation<UnfilteredRowIterator>
+     private UnfilteredPartitionIterator extendWithShortReadProtection(UnfilteredPartitionIterator partitions,
+                                                                       InetAddress source,
+                                                                       DataLimits.Counter mergedResultCounter)
+     {
+         DataLimits.Counter singleResultCounter =
+             command.limits().newCounter(command.nowInSec(), false, command.selectsFullPartition(), enforceStrictLiveness).onlyCount();
+ 
+         ShortReadPartitionsProtection protection =
 -            new ShortReadPartitionsProtection(source, singleResultCounter, mergedResultCounter);
++            new ShortReadPartitionsProtection(source, singleResultCounter, mergedResultCounter, queryStartNanoTime);
+ 
+         /*
+          * The order of extention and transformations is important here. Extending with more partitions has to happen
+          * first due to the way BaseIterator.hasMoreContents() works: only transformations applied after extension will
+          * be called on the first partition of the extended iterator.
+          *
+          * Additionally, we want singleResultCounter to be applied after SRPP, so that its applyToPartition() method will
+          * be called last, after the extension done by SRRP.applyToPartition() call. That way we preserve the same order
+          * when it comes to calling SRRP.moreContents() and applyToRow() callbacks.
+          *
+          * See ShortReadPartitionsProtection.applyToPartition() for more details.
+          */
+ 
+         // extend with moreContents() only if it's a range read command with no partition key specified
+         if (!command.isLimitedToOnePartition())
+             partitions = MorePartitions.extend(partitions, protection);     // register SRPP.moreContents()
+ 
+         partitions = Transformation.apply(partitions, protection);          // register SRPP.applyToPartition()
+         partitions = Transformation.apply(partitions, singleResultCounter); // register the per-source counter
+ 
+         return partitions;
+     }
+ 
+     /*
+      * We have a potential short read if the result from a given node contains the requested number of rows
+      * (i.e. it has stopped returning results due to the limit), but some of them haven't
+      * made it into the final post-reconciliation result due to other nodes' row, range, and/or partition tombstones.
+      *
+      * If that is the case, then that node may have more rows that we should fetch, as otherwise we could
+      * ultimately return fewer rows than required. Also, those additional rows may contain tombstones which
+      * which we also need to fetch as they may shadow rows or partitions from other replicas' results, which we would
+      * otherwise return incorrectly.
+      */
+     private class ShortReadPartitionsProtection extends Transformation<UnfilteredRowIterator> implements MorePartitions<UnfilteredPartitionIterator>
      {
          private final InetAddress source;
  
          private final DataLimits.Counter singleResultCounter; // unmerged per-source counter
          private final DataLimits.Counter mergedResultCounter; // merged end-result counter
  
+         private DecoratedKey lastPartitionKey; // key of the last observed partition
+ 
+         private boolean partitionsFetched; // whether we've seen any new partitions since iteration start or last moreContents() call
+ 
 -        private ShortReadPartitionsProtection(InetAddress source, DataLimits.Counter singleResultCounter, DataLimits.Counter mergedResultCounter)
 +        private final long queryStartNanoTime;
 +
-         private ShortReadResponseProtection(InetAddress source,
-                                             DataLimits.Counter singleResultCounter,
-                                             DataLimits.Counter mergedResultCounter,
-                                             long queryStartNanoTime)
++        private ShortReadPartitionsProtection(InetAddress source,
++                                              DataLimits.Counter singleResultCounter,
++                                              DataLimits.Counter mergedResultCounter,
++                                              long queryStartNanoTime)
          {
              this.source = source;
              this.singleResultCounter = singleResultCounter;
@@@ -523,7 -543,75 +562,83 @@@
              return Transformation.apply(MoreRows.extend(partition, protection), protection);
          }
  
-         private class ShortReadRowProtection extends Transformation implements MoreRows<UnfilteredRowIterator>
+         /*
+          * We only get here once all the rows and partitions in this iterator have been iterated over, and so
+          * if the node had returned the requested number of rows but we still get here, then some results were
+          * skipped during reconciliation.
+          */
+         public UnfilteredPartitionIterator moreContents()
+         {
+             // never try to request additional partitions from replicas if our reconciled partitions are already filled to the limit
+             assert !mergedResultCounter.isDone();
+ 
+             // we do not apply short read protection when we have no limits at all
+             assert !command.limits().isUnlimited();
+ 
+             /*
+              * If this is a single partition read command or an (indexed) partition range read command with
+              * a partition key specified, then we can't and shouldn't try fetch more partitions.
+              */
+             assert !command.isLimitedToOnePartition();
+ 
+             /*
+              * If the returned result doesn't have enough rows/partitions to satisfy even the original limit, don't ask for more.
+              *
+              * Can only take the short cut if there is no per partition limit set. Otherwise it's possible to hit false
+              * positives due to some rows being uncounted for in certain scenarios (see CASSANDRA-13911).
+              */
+             if (!singleResultCounter.isDone() && command.limits().perPartitionCount() == DataLimits.NO_LIMIT)
+                 return null;
+ 
+             /*
+              * Either we had an empty iterator as the initial response, or our moreContents() call got us an empty iterator.
+              * There is no point to ask the replica for more rows - it has no more in the requested range.
+              */
+             if (!partitionsFetched)
+                 return null;
+             partitionsFetched = false;
+ 
+             /*
+              * We are going to fetch one partition at a time for thrift and potentially more for CQL.
+              * The row limit will either be set to the per partition limit - if the command has no total row limit set, or
+              * the total # of rows remaining - if it has some. If we don't grab enough rows in some of the partitions,
+              * then future ShortReadRowsProtection.moreContents() calls will fetch the missing ones.
+              */
+             int toQuery = command.limits().count() != DataLimits.NO_LIMIT
 -                        ? command.limits().count() - mergedResultCounter.counted()
++                        ? command.limits().count() - counted(mergedResultCounter)
+                         : command.limits().perPartitionCount();
+ 
+             ColumnFamilyStore.metricsFor(command.metadata().cfId).shortReadProtectionRequests.mark();
+             Tracing.trace("Requesting {} extra rows from {} for short read protection", toQuery, source);
+ 
+             PartitionRangeReadCommand cmd = makeFetchAdditionalPartitionReadCommand(toQuery);
+             return executeReadCommand(cmd);
+         }
+ 
++        // Counts the number of rows for regular queries and the number of groups for GROUP BY queries
++        private int counted(Counter counter)
++        {
++            return command.limits().isGroupByLimit()
++                 ? counter.rowCounted()
++                 : counter.counted();
++        }
++
+         private PartitionRangeReadCommand makeFetchAdditionalPartitionReadCommand(int toQuery)
+         {
+             PartitionRangeReadCommand cmd = (PartitionRangeReadCommand) command;
+ 
+             DataLimits newLimits = cmd.limits().forShortReadRetry(toQuery);
+ 
+             AbstractBounds<PartitionPosition> bounds = cmd.dataRange().keyRange();
+             AbstractBounds<PartitionPosition> newBounds = bounds.inclusiveRight()
+                                                         ? new Range<>(lastPartitionKey, bounds.right)
+                                                         : new ExcludingBounds<>(lastPartitionKey, bounds.right);
+             DataRange newDataRange = cmd.dataRange().forSubRange(newBounds);
+ 
+             return cmd.withUpdatedLimitsAndDataRange(newLimits, newDataRange);
+         }
+ 
+         private class ShortReadRowsProtection extends Transformation implements MoreRows<UnfilteredRowIterator>
          {
              private final CFMetaData metadata;
              private final DecoratedKey partitionKey;
@@@ -647,17 -729,10 +756,18 @@@
                  ColumnFamilyStore.metricsFor(metadata.cfId).shortReadProtectionRequests.mark();
                  Tracing.trace("Requesting {} extra rows from {} for short read protection", lastQueried, source);
  
-                 return executeReadCommand(makeFetchAdditionalRowsReadCommand(lastQueried));
+                 SinglePartitionReadCommand cmd = makeFetchAdditionalRowsReadCommand(lastQueried);
+                 return UnfilteredPartitionIterators.getOnlyElement(executeReadCommand(cmd), cmd);
              }
  
 +            // Counts the number of rows for regular queries and the number of groups for GROUP BY queries
 +            private int countedInCurrentPartition(Counter counter)
 +            {
 +                return command.limits().isGroupByLimit()
 +                     ? counter.rowCountedInCurrentPartition()
 +                     : counter.countedInCurrentPartition();
 +            }
 +
              private SinglePartitionReadCommand makeFetchAdditionalRowsReadCommand(int toQuery)
              {
                  ClusteringIndexFilter filter = command.clusteringIndexFilter(partitionKey);
@@@ -671,24 -746,25 +781,25 @@@
                                                           command.rowFilter(),
                                                           command.limits().forShortReadRetry(toQuery),
                                                           partitionKey,
-                                                          filter);
+                                                          filter,
+                                                          command.indexMetadata());
              }
+         }
  
-             private UnfilteredRowIterator executeReadCommand(SinglePartitionReadCommand cmd)
-             {
-                 DataResolver resolver = new DataResolver(keyspace, cmd, ConsistencyLevel.ONE, 1, queryStartNanoTime);
-                 ReadCallback handler = new ReadCallback(resolver, ConsistencyLevel.ONE, cmd, Collections.singletonList(source), queryStartNanoTime);
- 
-                 if (StorageProxy.canDoLocalRequest(source))
-                     StageManager.getStage(Stage.READ).maybeExecuteImmediately(new StorageProxy.LocalReadRunnable(cmd, handler));
-                 else
-                     MessagingService.instance().sendRRWithFailure(cmd.createMessage(MessagingService.current_version), source, handler);
- 
-                 // We don't call handler.get() because we want to preserve tombstones since we're still in the middle of merging node results.
-                 handler.awaitResults();
-                 assert resolver.responses.size() == 1;
-                 return UnfilteredPartitionIterators.getOnlyElement(resolver.responses.get(0).payload.makeIterator(command), cmd);
-             }
+         private UnfilteredPartitionIterator executeReadCommand(ReadCommand cmd)
+         {
 -            DataResolver resolver = new DataResolver(keyspace, cmd, ConsistencyLevel.ONE, 1);
 -            ReadCallback handler = new ReadCallback(resolver, ConsistencyLevel.ONE, cmd, Collections.singletonList(source));
++            DataResolver resolver = new DataResolver(keyspace, cmd, ConsistencyLevel.ONE, 1, queryStartNanoTime);
++            ReadCallback handler = new ReadCallback(resolver, ConsistencyLevel.ONE, cmd, Collections.singletonList(source), queryStartNanoTime);
+ 
+             if (StorageProxy.canDoLocalRequest(source))
+                 StageManager.getStage(Stage.READ).maybeExecuteImmediately(new StorageProxy.LocalReadRunnable(cmd, handler));
+             else
+                 MessagingService.instance().sendRRWithFailure(cmd.createMessage(MessagingService.current_version), source, handler);
+ 
+             // We don't call handler.get() because we want to preserve tombstones since we're still in the middle of merging node results.
+             handler.awaitResults();
+             assert resolver.responses.size() == 1;
+             return resolver.responses.get(0).payload.makeIterator(command);
          }
      }
  }


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cassandra.apache.org
For additional commands, e-mail: commits-help@cassandra.apache.org


[2/4] cassandra git commit: Fix ISE thrown by UPI.Serializer.hasNext() for some SELECT queries

Posted by al...@apache.org.
Fix ISE thrown by UPI.Serializer.hasNext() for some SELECT queries

patch by Aleksey Yeschenko; reviewed by Sam Tunnicliffe for
CASSANDRA-13911


Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/1efdf330
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/1efdf330
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/1efdf330

Branch: refs/heads/cassandra-3.11
Commit: 1efdf330e291a41cd8051e0c1195f75b5d352370
Parents: 95839aa
Author: Aleksey Yeschenko <al...@yeschenko.com>
Authored: Thu Sep 28 17:41:00 2017 +0100
Committer: Aleksey Yeschenko <al...@yeschenko.com>
Committed: Sat Sep 30 10:33:30 2017 +0100

----------------------------------------------------------------------
 CHANGES.txt                                      |  1 +
 .../partitions/UnfilteredPartitionIterators.java | 19 +++++++++++++++----
 .../apache/cassandra/service/DataResolver.java   |  9 +++++++--
 3 files changed, 23 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cassandra/blob/1efdf330/CHANGES.txt
----------------------------------------------------------------------
diff --git a/CHANGES.txt b/CHANGES.txt
index 7ff61d3..1c53aa5 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,5 @@
 3.0.15
+ * Fix ISE thrown by UPI.Serializer.hasNext() for some SELECT queries (CASSANDRA-13911)
  * Filter header only commit logs before recovery (CASSANDRA-13918)
  * AssertionError prepending to a list (CASSANDRA-13149)
  * Fix support for SuperColumn tables (CASSANDRA-12373)

http://git-wip-us.apache.org/repos/asf/cassandra/blob/1efdf330/src/java/org/apache/cassandra/db/partitions/UnfilteredPartitionIterators.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/partitions/UnfilteredPartitionIterators.java b/src/java/org/apache/cassandra/db/partitions/UnfilteredPartitionIterators.java
index 4e0ac1b..efe3ff8 100644
--- a/src/java/org/apache/cassandra/db/partitions/UnfilteredPartitionIterators.java
+++ b/src/java/org/apache/cassandra/db/partitions/UnfilteredPartitionIterators.java
@@ -324,10 +324,21 @@ public abstract class UnfilteredPartitionIterators
                     if (!nextReturned)
                         return hasNext;
 
-                    // We can't answer this until the previously returned iterator has been fully consumed,
-                    // so complain if that's not the case.
-                    if (next != null && next.hasNext())
-                        throw new IllegalStateException("Cannot call hasNext() until the previous iterator has been fully consumed");
+                    /*
+                     * We must consume the previous iterator before we start deserializing the next partition, so
+                     * that we start from the right position in the byte stream.
+                     *
+                     * It's possible however that it hasn't been fully consumed by upstream consumers - for example,
+                     * if a per partition limit caused merge iterator to stop early (see CASSANDRA-13911).
+                     *
+                     * In that case we must drain the unconsumed iterator fully ourselves, here.
+                     *
+                     * NOTE: transformations of the upstream BaseRows won't be applied for these consumed elements,
+                     * so, for exmaple, they won't be counted.
+                     */
+                    if (null != next)
+                        while (next.hasNext())
+                            next.next();
 
                     try
                     {

http://git-wip-us.apache.org/repos/asf/cassandra/blob/1efdf330/src/java/org/apache/cassandra/service/DataResolver.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/service/DataResolver.java b/src/java/org/apache/cassandra/service/DataResolver.java
index 61bffe5..7d8ffc5 100644
--- a/src/java/org/apache/cassandra/service/DataResolver.java
+++ b/src/java/org/apache/cassandra/service/DataResolver.java
@@ -550,8 +550,13 @@ public class DataResolver extends ResponseResolver
                 // we do not apply short read protection when we have no limits at all
                 assert !command.limits().isUnlimited();
 
-                // if the returned partition doesn't have enough rows to satisfy even the original limit, don't ask for more
-                if (!singleResultCounter.isDoneForPartition())
+                /*
+                 * If the returned partition doesn't have enough rows to satisfy even the original limit, don't ask for more.
+                 *
+                 * Can only take the short cut if there is no per partition limit set. Otherwise it's possible to hit false
+                 * positives due to some rows being uncounted for in certain scenarios (see CASSANDRA-13911).
+                 */
+                if (!singleResultCounter.isDoneForPartition() && command.limits().perPartitionCount() == DataLimits.NO_LIMIT)
                     return null;
 
                 /*


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cassandra.apache.org
For additional commands, e-mail: commits-help@cassandra.apache.org


[3/4] cassandra git commit: Fix up CHANGES.txt

Posted by al...@apache.org.
Fix up CHANGES.txt


Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/15cee48b
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/15cee48b
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/15cee48b

Branch: refs/heads/cassandra-3.11
Commit: 15cee48bbabdd75a58df32940d1143c9056e6792
Parents: 68a6746
Author: Aleksey Yeschenko <al...@yeschenko.com>
Authored: Sat Sep 30 10:44:47 2017 +0100
Committer: Aleksey Yeschenko <al...@yeschenko.com>
Committed: Sat Sep 30 10:44:47 2017 +0100

----------------------------------------------------------------------
 CHANGES.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cassandra/blob/15cee48b/CHANGES.txt
----------------------------------------------------------------------
diff --git a/CHANGES.txt b/CHANGES.txt
index c5e54d4..4a45469 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -19,6 +19,7 @@
  * Fix pending view mutations handling and cleanup batchlog when there are local and remote paired mutations (CASSANDRA-13069)
  * Improve config validation and documentation on overflow and NPE (CASSANDRA-13622)
  * Range deletes in a CAS batch are ignored (CASSANDRA-13655)
+ * Avoid assertion error when IndexSummary > 2G (CASSANDRA-12014)
  * Change repair midpoint logging for tiny ranges (CASSANDRA-13603)
  * Better handle corrupt final commitlog segment (CASSANDRA-11995)
  * StreamingHistogram is not thread safe (CASSANDRA-13756)
@@ -117,7 +118,6 @@ Merged from 2.2:
  * Legacy caching options can prevent 3.0 upgrade (CASSANDRA-13384)
  * Nodetool upgradesstables/scrub/compact ignores system tables (CASSANDRA-13410)
  * Fix NPE issue in StorageService (CASSANDRA-13060)
- * Avoid assertion error when IndexSummary > 2G (CASSANDRA-12014)
 Merged from 2.2:
  * Avoid starting gossiper in RemoveTest (CASSANDRA-13407)
  * Fix weightedSize() for row-cache reported by JMX and NodeTool (CASSANDRA-13393)


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cassandra.apache.org
For additional commands, e-mail: commits-help@cassandra.apache.org