Merge branch 'cassandra-2.0' into cassandra-2.1 Conflicts: CHANGES.txt src/java/org/apache/cassandra/db/ColumnFamily.java src/java/org/apache/cassandra/db/compaction/LazilyCompactedRow.java
Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/3ff7a776 Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/3ff7a776 Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/3ff7a776 Branch: refs/heads/trunk Commit: 3ff7a776a76d5ca9c3ee569067896f6098075885 Parents: baf524f 303ff22 Author: Marcus Eriksson <marc...@apache.org> Authored: Thu Jun 19 09:51:28 2014 +0200 Committer: Marcus Eriksson <marc...@apache.org> Committed: Thu Jun 19 09:51:28 2014 +0200 ---------------------------------------------------------------------- CHANGES.txt | 1 + .../org/apache/cassandra/db/ColumnFamily.java | 21 ++-- .../db/compaction/LazilyCompactedRow.java | 10 +- .../cassandra/io/sstable/SSTableWriter.java | 3 + .../apache/cassandra/db/ColumnFamilyTest.java | 12 +++ .../db/compaction/CompactionsTest.java | 100 ++++++++++++++++++- 6 files changed, 132 insertions(+), 15 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cassandra/blob/3ff7a776/CHANGES.txt ---------------------------------------------------------------------- diff --cc CHANGES.txt index af6e8c0,65e3161..ad5fb1c --- a/CHANGES.txt +++ b/CHANGES.txt @@@ -1,25 -1,23 +1,26 @@@ -2.0.9 - * Fix assertion error in CL.ANY timeout handling (CASSANDRA-7364) - * Handle empty CFs in Memtable#maybeUpdateLiveRatio() (CASSANDRA-7401) +2.1.0 + * Avoid incremental compaction on Windows (CASSANDRA-7365) + * Fix exception when querying a composite-keyed table with a collection index + (CASSANDRA-7372) + * Use node's host id in place of counter ids (CASSANDRA-7366) * Fix native protocol CAS batches (CASSANDRA-7337) + * Reduce likelihood of contention on local paxos locking (CASSANDRA-7359) + * Upgrade to Pig 0.12.1 (CASSANDRA-6556) + * Make sure we clear out repair sessions from netstats (CASSANDRA-7329) + * Don't fail streams on failure detector downs (CASSANDRA-3569) + * Add optional keyspace to DROP INDEX statement (CASSANDRA-7314) + * Reduce run time for CQL tests (CASSANDRA-7327) + * Fix heap size calculation on Windows (CASSANDRA-7352, 7353) + * RefCount native frames from netty (CASSANDRA-7245) + * Use tarball dir instead of /var for default paths (CASSANDRA-7136) + * Remove rows_per_partition_to_cache keyword (CASSANDRA-7193) +Merged from 2.0: + * Fix assertion error in CL.ANY timeout handling (CASSANDRA-7364) * Add per-CF range read request latency metrics (CASSANDRA-7338) * Fix NPE in StreamTransferTask.createMessageForRetry() (CASSANDRA-7323) - * Add conditional CREATE/DROP USER support (CASSANDRA-7264) - * Swap local and global default read repair chances (CASSANDRA-7320) - * Add missing iso8601 patterns for date strings (CASSANDRA-6973) - * Support selecting multiple rows in a partition using IN (CASSANDRA-6875) - * cqlsh: always emphasize the partition key in DESC output (CASSANDRA-7274) - * Copy compaction options to make sure they are reloaded (CASSANDRA-7290) - * Add option to do more aggressive tombstone compactions (CASSANDRA-6563) - * Don't try to compact already-compacting files in HHOM (CASSANDRA-7288) - * Add authentication support to shuffle (CASSANDRA-6484) - * Cqlsh counts non-empty lines for "Blank lines" warning (CASSANDRA-7325) * Make StreamSession#closeSession() idempotent (CASSANDRA-7262) * Fix infinite loop on exception while streaming (CASSANDRA-7330) - * Reference sstables before populating key cache (CASSANDRA-7234) + * Account for range tombstones in min/max column names (CASSANDRA-7235) Merged from 1.2: * cqlsh: ignore .cassandra permission errors (CASSANDRA-7266) * Errors in FlushRunnable may leave threads hung (CASSANDRA-7275) http://git-wip-us.apache.org/repos/asf/cassandra/blob/3ff7a776/src/java/org/apache/cassandra/db/ColumnFamily.java ---------------------------------------------------------------------- diff --cc src/java/org/apache/cassandra/db/ColumnFamily.java index 45b8eff,638eacc..38e1591 --- a/src/java/org/apache/cassandra/db/ColumnFamily.java +++ b/src/java/org/apache/cassandra/db/ColumnFamily.java @@@ -402,36 -418,31 +402,41 @@@ public abstract class ColumnFamily impl int maxLocalDeletionTime = Integer.MIN_VALUE; List<ByteBuffer> minColumnNamesSeen = Collections.emptyList(); List<ByteBuffer> maxColumnNamesSeen = Collections.emptyList(); + boolean hasLegacyCounterShards = false; + + if (deletionInfo().getTopLevelDeletion().localDeletionTime < Integer.MAX_VALUE) + tombstones.update(deletionInfo().getTopLevelDeletion().localDeletionTime); + Iterator<RangeTombstone> it = deletionInfo().rangeIterator(); + while (it.hasNext()) + { + RangeTombstone rangeTombstone = it.next(); + tombstones.update(rangeTombstone.getLocalDeletionTime()); + + minColumnNamesSeen = ColumnNameHelper.minComponents(minColumnNamesSeen, rangeTombstone.min, metadata.comparator); + maxColumnNamesSeen = ColumnNameHelper.maxComponents(maxColumnNamesSeen, rangeTombstone.max, metadata.comparator); + } + - for (Column column : this) + for (Cell cell : this) { - if (deletionInfo().getTopLevelDeletion().localDeletionTime < Integer.MAX_VALUE) - tombstones.update(deletionInfo().getTopLevelDeletion().localDeletionTime); - Iterator<RangeTombstone> it = deletionInfo().rangeIterator(); - while (it.hasNext()) - { - RangeTombstone rangeTombstone = it.next(); - tombstones.update(rangeTombstone.getLocalDeletionTime()); - } - minTimestampSeen = Math.min(minTimestampSeen, column.minTimestamp()); - maxTimestampSeen = Math.max(maxTimestampSeen, column.maxTimestamp()); - maxLocalDeletionTime = Math.max(maxLocalDeletionTime, column.getLocalDeletionTime()); - int deletionTime = column.getLocalDeletionTime(); + minTimestampSeen = Math.min(minTimestampSeen, cell.timestamp()); + maxTimestampSeen = Math.max(maxTimestampSeen, cell.timestamp()); + maxLocalDeletionTime = Math.max(maxLocalDeletionTime, cell.getLocalDeletionTime()); + int deletionTime = cell.getLocalDeletionTime(); if (deletionTime < Integer.MAX_VALUE) tombstones.update(deletionTime); - minColumnNamesSeen = ColumnNameHelper.minComponents(minColumnNamesSeen, column.name, metadata.comparator); - maxColumnNamesSeen = ColumnNameHelper.maxComponents(maxColumnNamesSeen, column.name, metadata.comparator); + minColumnNamesSeen = ColumnNameHelper.minComponents(minColumnNamesSeen, cell.name(), metadata.comparator); + maxColumnNamesSeen = ColumnNameHelper.maxComponents(maxColumnNamesSeen, cell.name(), metadata.comparator); + if (cell instanceof CounterCell) + hasLegacyCounterShards = hasLegacyCounterShards || ((CounterCell) cell).hasLegacyShards(); } - return new ColumnStats(getColumnCount(), minTimestampSeen, maxTimestampSeen, maxLocalDeletionTime, tombstones, minColumnNamesSeen, maxColumnNamesSeen); + return new ColumnStats(getColumnCount(), + minTimestampSeen, + maxTimestampSeen, + maxLocalDeletionTime, + tombstones, + minColumnNamesSeen, + maxColumnNamesSeen, + hasLegacyCounterShards); } public boolean isMarkedForDelete() http://git-wip-us.apache.org/repos/asf/cassandra/blob/3ff7a776/src/java/org/apache/cassandra/db/compaction/LazilyCompactedRow.java ---------------------------------------------------------------------- diff --cc src/java/org/apache/cassandra/db/compaction/LazilyCompactedRow.java index d0f3610,7cd0842..73a1927 --- a/src/java/org/apache/cassandra/db/compaction/LazilyCompactedRow.java +++ b/src/java/org/apache/cassandra/db/compaction/LazilyCompactedRow.java @@@ -244,6 -252,11 +244,10 @@@ public class LazilyCompactedRow extend } else { + tombstones.update(t.getLocalDeletionTime()); + + minColumnNameSeen = ColumnNameHelper.minComponents(minColumnNameSeen, t.min, controller.cfs.metadata.comparator); + maxColumnNameSeen = ColumnNameHelper.maxComponents(maxColumnNameSeen, t.max, controller.cfs.metadata.comparator); - return t; } } @@@ -259,22 -270,11 +263,16 @@@ container.clear(); return null; } - Column reduced = purged.iterator().next(); + + int localDeletionTime = container.deletionInfo().getTopLevelDeletion().localDeletionTime; + if (localDeletionTime < Integer.MAX_VALUE) + tombstones.update(localDeletionTime); - Iterator<RangeTombstone> rangeTombstoneIterator = container.deletionInfo().rangeIterator(); - while (rangeTombstoneIterator.hasNext()) - { - RangeTombstone rangeTombstone = rangeTombstoneIterator.next(); - tombstones.update(rangeTombstone.getLocalDeletionTime()); - } + + Cell reduced = iter.next(); container.clear(); - // PrecompactedRow.removeDeleted has only checked the top-level CF deletion times, - // not the range tombstones. For that we use the columnIndexer tombstone tracker. + // removeDeleted have only checked the top-level CF deletion times, + // not the range tombstone. For that we use the columnIndexer tombstone tracker. if (indexBuilder.tombstoneTracker().isDeleted(reduced)) { indexer.remove(reduced); http://git-wip-us.apache.org/repos/asf/cassandra/blob/3ff7a776/src/java/org/apache/cassandra/io/sstable/SSTableWriter.java ---------------------------------------------------------------------- diff --cc src/java/org/apache/cassandra/io/sstable/SSTableWriter.java index 9567f0e,3a2dca0..f2168c5 --- a/src/java/org/apache/cassandra/io/sstable/SSTableWriter.java +++ b/src/java/org/apache/cassandra/io/sstable/SSTableWriter.java @@@ -266,9 -243,12 +266,12 @@@ public class SSTableWriter extends SSTa { RangeTombstone rangeTombstone = rangeTombstoneIterator.next(); tombstones.update(rangeTombstone.getLocalDeletionTime()); + + minColumnNames = ColumnNameHelper.minComponents(minColumnNames, rangeTombstone.min, metadata.comparator); + maxColumnNames = ColumnNameHelper.maxComponents(maxColumnNames, rangeTombstone.max, metadata.comparator); } - Iterator<OnDiskAtom> iter = metadata.getOnDiskIterator(in, columnCount, ColumnSerializer.Flag.PRESERVE_SIZE, Integer.MIN_VALUE, version); + Iterator<OnDiskAtom> iter = metadata.getOnDiskIterator(in, ColumnSerializer.Flag.PRESERVE_SIZE, Integer.MIN_VALUE, version); try { while (iter.hasNext()) http://git-wip-us.apache.org/repos/asf/cassandra/blob/3ff7a776/test/unit/org/apache/cassandra/db/ColumnFamilyTest.java ---------------------------------------------------------------------- diff --cc test/unit/org/apache/cassandra/db/ColumnFamilyTest.java index 151cbdc,e13d0d7..2141020 --- a/test/unit/org/apache/cassandra/db/ColumnFamilyTest.java +++ b/test/unit/org/apache/cassandra/db/ColumnFamilyTest.java @@@ -206,5 -163,17 +206,17 @@@ public class ColumnFamilyTest extends S cf.delete(new DeletionInfo(timestamp, localDeletionTime)); ColumnStats stats = cf.getColumnStats(); assertEquals(timestamp, stats.maxTimestamp); + - cf.delete(new RangeTombstone(ByteBufferUtil.bytes("col2"), ByteBufferUtil.bytes("col21"), timestamp, localDeletionTime)); ++ cf.delete(new RangeTombstone(Util.cellname("col2"), Util.cellname("col21"), timestamp, localDeletionTime)); + + stats = cf.getColumnStats(); + assertEquals(ByteBufferUtil.bytes("col2"), stats.minColumnNames.get(0)); + assertEquals(ByteBufferUtil.bytes("col21"), stats.maxColumnNames.get(0)); + - cf.delete(new RangeTombstone(ByteBufferUtil.bytes("col6"), ByteBufferUtil.bytes("col61"), timestamp, localDeletionTime)); ++ cf.delete(new RangeTombstone(Util.cellname("col6"), Util.cellname("col61"), timestamp, localDeletionTime)); + stats = cf.getColumnStats(); + + assertEquals(ByteBufferUtil.bytes("col2"), stats.minColumnNames.get(0)); + assertEquals(ByteBufferUtil.bytes("col61"), stats.maxColumnNames.get(0)); } } http://git-wip-us.apache.org/repos/asf/cassandra/blob/3ff7a776/test/unit/org/apache/cassandra/db/compaction/CompactionsTest.java ---------------------------------------------------------------------- diff --cc test/unit/org/apache/cassandra/db/compaction/CompactionsTest.java index 8a24771,1879838..c60b650 --- a/test/unit/org/apache/cassandra/db/compaction/CompactionsTest.java +++ b/test/unit/org/apache/cassandra/db/compaction/CompactionsTest.java @@@ -40,8 -43,11 +42,12 @@@ import org.apache.cassandra.dht.BytesTo import org.apache.cassandra.dht.Range; import org.apache.cassandra.dht.Token; import org.apache.cassandra.io.sstable.Component; -import org.apache.cassandra.io.sstable.SSTableMetadata; import org.apache.cassandra.io.sstable.SSTableReader; import org.apache.cassandra.io.sstable.SSTableScanner; + import org.apache.cassandra.io.sstable.SSTableWriter; ++import org.apache.cassandra.io.sstable.metadata.MetadataCollector; ++import org.apache.cassandra.io.sstable.metadata.StatsMetadata; + import org.apache.cassandra.service.StorageService; import org.apache.cassandra.utils.ByteBufferUtil; import org.apache.cassandra.utils.FBUtilities; import org.apache.cassandra.utils.Pair; @@@ -344,6 -349,96 +350,98 @@@ public class CompactionsTest extends Sc } @Test + public void testRangeTombstones() throws IOException, ExecutionException, InterruptedException + { + boolean lazy = false; + + do + { + Keyspace keyspace = Keyspace.open(KEYSPACE1); + ColumnFamilyStore cfs = keyspace.getColumnFamilyStore("Standard2"); + cfs.clearUnsafe(); + + // disable compaction while flushing + cfs.disableAutoCompaction(); + + final CFMetaData cfmeta = cfs.metadata; - Directories dir = Directories.create(cfmeta.ksName, cfmeta.cfName); ++ Directories dir = cfs.directories; + + ArrayList<DecoratedKey> keys = new ArrayList<DecoratedKey>(); + + for (int i=0; i < 4; i++) + { + keys.add(Util.dk(""+i)); + } + + ArrayBackedSortedColumns cf = ArrayBackedSortedColumns.factory.create(cfmeta); + cf.addColumn(Util.column("01", "a", 1)); // this must not resurrect + cf.addColumn(Util.column("a", "a", 3)); - cf.deletionInfo().add(new RangeTombstone(ByteBufferUtil.bytes("0"), ByteBufferUtil.bytes("b"), 2, (int) (System.currentTimeMillis()/1000)),cfmeta.comparator); ++ cf.deletionInfo().add(new RangeTombstone(Util.cellname("0"), Util.cellname("b"), 2, (int) (System.currentTimeMillis()/1000)),cfmeta.comparator); + + SSTableWriter writer = new SSTableWriter(cfs.getTempSSTablePath(dir.getDirectoryForNewSSTables()), + 0, ++ 0, + cfs.metadata, + StorageService.getPartitioner(), - SSTableMetadata.createCollector(cfs.metadata.comparator)); ++ new MetadataCollector(cfs.metadata.comparator)); + + + writer.append(Util.dk("0"), cf); + writer.append(Util.dk("1"), cf); + writer.append(Util.dk("3"), cf); + + cfs.addSSTable(writer.closeAndOpenReader()); + writer = new SSTableWriter(cfs.getTempSSTablePath(dir.getDirectoryForNewSSTables()), + 0, ++ 0, + cfs.metadata, + StorageService.getPartitioner(), - SSTableMetadata.createCollector(cfs.metadata.comparator)); ++ new MetadataCollector(cfs.metadata.comparator)); + + writer.append(Util.dk("0"), cf); + writer.append(Util.dk("1"), cf); + writer.append(Util.dk("2"), cf); + writer.append(Util.dk("3"), cf); + cfs.addSSTable(writer.closeAndOpenReader()); + + Collection<SSTableReader> toCompact = cfs.getSSTables(); + assert toCompact.size() == 2; + + // forcing lazy comapction + if (lazy) + DatabaseDescriptor.setInMemoryCompactionLimit(0); + + // Force compaction on first sstables. Since each row is in only one sstable, we will be using EchoedRow. + Util.compact(cfs, toCompact); + assertEquals(1, cfs.getSSTables().size()); + + // Now assert we do have the 4 keys + assertEquals(4, Util.getRangeSlice(cfs).size()); + + ArrayList<DecoratedKey> k = new ArrayList<DecoratedKey>(); + for (Row r : Util.getRangeSlice(cfs)) + { + k.add(r.key); - assertEquals(ByteBufferUtil.bytes("a"),r.cf.getColumn(ByteBufferUtil.bytes("a")).value()); - assertNull(r.cf.getColumn(ByteBufferUtil.bytes("01"))); - assertEquals(3,r.cf.getColumn(ByteBufferUtil.bytes("a")).timestamp()); ++ assertEquals(ByteBufferUtil.bytes("a"),r.cf.getColumn(Util.cellname("a")).value()); ++ assertNull(r.cf.getColumn(Util.cellname("01"))); ++ assertEquals(3,r.cf.getColumn(Util.cellname("a")).timestamp()); + } + + for (SSTableReader sstable : cfs.getSSTables()) + { - SSTableMetadata stats = sstable.getSSTableMetadata(); ++ StatsMetadata stats = sstable.getSSTableMetadata(); + assertEquals(ByteBufferUtil.bytes("0"), stats.minColumnNames.get(0)); + assertEquals(ByteBufferUtil.bytes("b"), stats.maxColumnNames.get(0)); + } + + assertEquals(keys, k); + + lazy=!lazy; + } + while (lazy); + } + + @Test public void testCompactionLog() throws Exception { SystemKeyspace.discardCompactionsInProgress();