mirror of https://github.com/apache/cassandra
Merge f2633cebbc into 10557d7ffe
This commit is contained in:
commit
dd5ca068b3
|
|
@ -111,14 +111,32 @@ public class SerializationHeader
|
||||||
// but rather on their stats stored in StatsMetadata that are fully accurate.
|
// but rather on their stats stored in StatsMetadata that are fully accurate.
|
||||||
EncodingStats.Collector stats = new EncodingStats.Collector();
|
EncodingStats.Collector stats = new EncodingStats.Collector();
|
||||||
RegularAndStaticColumns.Builder columns = RegularAndStaticColumns.builder();
|
RegularAndStaticColumns.Builder columns = RegularAndStaticColumns.builder();
|
||||||
|
RegularAndStaticColumns currentSchemaColumns = metadata.regularAndStaticColumns();
|
||||||
// We need to order the SSTables by descending generation to be sure that we use latest column metadata.
|
// We need to order the SSTables by descending generation to be sure that we use latest column metadata.
|
||||||
for (SSTableReader sstable : orderByDescendingGeneration(sstables))
|
for (SSTableReader sstable : orderByDescendingGeneration(sstables))
|
||||||
{
|
{
|
||||||
stats.updateTimestamp(sstable.getMinTimestamp());
|
stats.updateTimestamp(sstable.getMinTimestamp());
|
||||||
stats.updateLocalDeletionTime(sstable.getMinLocalDeletionTime());
|
stats.updateLocalDeletionTime(sstable.getMinLocalDeletionTime());
|
||||||
stats.updateTTL(sstable.getMinTTL());
|
stats.updateTTL(sstable.getMinTTL());
|
||||||
columns.addAll(sstable.header.columns());
|
for (ColumnMetadata column : sstable.header.columns())
|
||||||
|
{
|
||||||
|
// Include column in a header only if it is in the current schema.
|
||||||
|
// It is not enough to check if a column is not among dropped ones,
|
||||||
|
// because that would not cover the scenario when a column is dropped
|
||||||
|
// and re-added back before flush. Consider:
|
||||||
|
//
|
||||||
|
// insert into ks.tb (id, val) values (1, 2);
|
||||||
|
// alter table ks.tb drop val;
|
||||||
|
// alter table ks.tb add val int;
|
||||||
|
//
|
||||||
|
// If we backed our logic only by a check against a dropped column,
|
||||||
|
// then we would see that it was dropped (in metadata.droppedColumn)
|
||||||
|
// but we would omit the fact that it was actually re-added.
|
||||||
|
if (currentSchemaColumns.contains(column))
|
||||||
|
columns.add(column);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return new SerializationHeader(true, metadata, columns.build(), stats.get());
|
return new SerializationHeader(true, metadata, columns.build(), stats.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -639,6 +639,16 @@ public class CursorCompactor extends CompactionInfo.Holder
|
||||||
ReusableLivenessInfo cellLiveness = cellCursor.cellLiveness;
|
ReusableLivenessInfo cellLiveness = cellCursor.cellLiveness;
|
||||||
DataOutputBuffer tempCellBuffer = null;
|
DataOutputBuffer tempCellBuffer = null;
|
||||||
|
|
||||||
|
if (!metadata().regularAndStaticColumns().contains(cellCursor.cellColumn))
|
||||||
|
{
|
||||||
|
for (int i = 0; i < cellMergeLimit; i++)
|
||||||
|
{
|
||||||
|
if (sstableCursors[i].state() == CELL_VALUE_START)
|
||||||
|
sstableCursors[i].skipCellValue();
|
||||||
|
}
|
||||||
|
return isRowDropped;
|
||||||
|
}
|
||||||
|
|
||||||
if (cellCursor.cellColumn.isComplex())
|
if (cellCursor.cellColumn.isComplex())
|
||||||
throw new UnsupportedOperationException("TODO: Not ready for complex cells.");
|
throw new UnsupportedOperationException("TODO: Not ready for complex cells.");
|
||||||
if (cellCursor.cellColumn.isCounterColumn())
|
if (cellCursor.cellColumn.isCounterColumn())
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,151 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
import org.junit.Ignore;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import org.apache.cassandra.cql3.CQLTester;
|
||||||
|
import org.apache.cassandra.io.sstable.format.SSTableReader;
|
||||||
|
import org.apache.cassandra.schema.ColumnMetadata;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
@Ignore
|
||||||
|
public abstract class AbstractSerializationHeaderCQLTest extends CQLTester
|
||||||
|
{
|
||||||
|
@Test
|
||||||
|
public void testDroppedColumnPresenceInSerialisationHeader()
|
||||||
|
{
|
||||||
|
createTable("CREATE TABLE %s (id int PRIMARY KEY, a text, b text, c text)");
|
||||||
|
execute("INSERT INTO %s (id, a, b, c) VALUES (1, 'a1', 'b1', 'c1')");
|
||||||
|
flush(keyspace());
|
||||||
|
alterTable("ALTER TABLE %s DROP b");
|
||||||
|
|
||||||
|
ColumnFamilyStore cfs = getCurrentColumnFamilyStore();
|
||||||
|
assertEquals(1, cfs.getLiveSSTables().size());
|
||||||
|
|
||||||
|
SSTableReader sstable = cfs.getLiveSSTables().iterator().next();
|
||||||
|
assertTrue("Column 'b' should be in the flushed SSTable header",
|
||||||
|
sstableHeaderContainsColumn(sstable, "b"));
|
||||||
|
|
||||||
|
// same but alter before flush
|
||||||
|
|
||||||
|
createTable("CREATE TABLE %s (id int PRIMARY KEY, a text, b text, c text)");
|
||||||
|
execute("INSERT INTO %s (id, a, b, c) VALUES (1, 'a1', 'b1', 'c1')");
|
||||||
|
alterTable("ALTER TABLE %s DROP b");
|
||||||
|
flush(keyspace());
|
||||||
|
|
||||||
|
ColumnFamilyStore cfs2 = getCurrentColumnFamilyStore();
|
||||||
|
assertEquals(1, cfs2.getLiveSSTables().size());
|
||||||
|
|
||||||
|
SSTableReader sstable2 = cfs2.getLiveSSTables().iterator().next();
|
||||||
|
assertTrue("Column 'b' should be in the flushed SSTable header",
|
||||||
|
sstableHeaderContainsColumn(sstable2, "b"));
|
||||||
|
|
||||||
|
// flush but without dropped column
|
||||||
|
|
||||||
|
createTable("CREATE TABLE %s (id int PRIMARY KEY, a text, b text, c text)");
|
||||||
|
// we are not populating column we go to drop on purpose
|
||||||
|
execute("INSERT INTO %s (id, a, c) VALUES (1, 'a1', 'c1')");
|
||||||
|
alterTable("ALTER TABLE %s DROP b");
|
||||||
|
flush(keyspace());
|
||||||
|
|
||||||
|
ColumnFamilyStore cfs3 = getCurrentColumnFamilyStore();
|
||||||
|
assertEquals(1, cfs3.getLiveSSTables().size());
|
||||||
|
|
||||||
|
SSTableReader sstable3 = cfs3.getLiveSSTables().iterator().next();
|
||||||
|
assertFalse("Column 'b' should not be in the flushed SSTable header",
|
||||||
|
sstableHeaderContainsColumn(sstable3, "b"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDroppedColumnNotInCompactedSerialisationHeader()
|
||||||
|
{
|
||||||
|
createTable("CREATE TABLE %s (id int PRIMARY KEY, a text, b text, c text)");
|
||||||
|
execute("INSERT INTO %s (id, a, b, c) VALUES (1, 'a1', 'b1', 'c1')");
|
||||||
|
alterTable("ALTER TABLE %s DROP b");
|
||||||
|
flush(keyspace());
|
||||||
|
|
||||||
|
ColumnFamilyStore cfs = getCurrentColumnFamilyStore();
|
||||||
|
assertEquals(1, cfs.getLiveSSTables().size());
|
||||||
|
assertTrue("Column 'b' should be in the flushed SSTable header",
|
||||||
|
sstableHeaderContainsColumn(cfs.getLiveSSTables().iterator().next(), "b"));
|
||||||
|
|
||||||
|
compact(keyspace(), currentTable());
|
||||||
|
|
||||||
|
assertEquals(1, cfs.getLiveSSTables().size());
|
||||||
|
|
||||||
|
// column dropped for a header after compaction
|
||||||
|
assertFalse("Dropped column 'b' should not be in the compacted SSTable header",
|
||||||
|
sstableHeaderContainsColumn(cfs.getLiveSSTables().iterator().next(), "b"));
|
||||||
|
|
||||||
|
assertTrue("Column 'a' should be in the compacted SSTable header",
|
||||||
|
sstableHeaderContainsColumn(cfs.getLiveSSTables().iterator().next(), "a"));
|
||||||
|
assertTrue("Column 'c' should be in the compacted SSTable header",
|
||||||
|
sstableHeaderContainsColumn(cfs.getLiveSSTables().iterator().next(), "c"));
|
||||||
|
|
||||||
|
assertRows(execute("SELECT id, a, c FROM %s"), row(1, "a1", "c1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testReAddedColumnInCompactedSerializationHeader()
|
||||||
|
{
|
||||||
|
createTable("CREATE TABLE %s (id int PRIMARY KEY, a text, b text, c text)");
|
||||||
|
execute("INSERT INTO %s (id, a, b, c) VALUES (1, 'a1', 'b1', 'c1')");
|
||||||
|
alterTable("ALTER TABLE %s DROP b");
|
||||||
|
alterTable("ALTER TABLE %s ADD b text");
|
||||||
|
flush(keyspace());
|
||||||
|
|
||||||
|
ColumnFamilyStore cfs = getCurrentColumnFamilyStore();
|
||||||
|
assertEquals(1, cfs.getLiveSSTables().size());
|
||||||
|
assertTrue("Column 'b' should be in the flushed SSTable header",
|
||||||
|
sstableHeaderContainsColumn(cfs.getLiveSSTables().iterator().next(), "b"));
|
||||||
|
|
||||||
|
compact(keyspace(), currentTable());
|
||||||
|
|
||||||
|
assertEquals(1, cfs.getLiveSSTables().size());
|
||||||
|
|
||||||
|
// re-added column b
|
||||||
|
assertTrue("Dropped column 'b' should be in the compacted SSTable header",
|
||||||
|
sstableHeaderContainsColumn(cfs.getLiveSSTables().iterator().next(), "b"));
|
||||||
|
|
||||||
|
assertTrue("Column 'a' should be in the compacted SSTable header",
|
||||||
|
sstableHeaderContainsColumn(cfs.getLiveSSTables().iterator().next(), "a"));
|
||||||
|
assertTrue("Column 'c' should be in the compacted SSTable header",
|
||||||
|
sstableHeaderContainsColumn(cfs.getLiveSSTables().iterator().next(), "c"));
|
||||||
|
|
||||||
|
assertRows(execute("SELECT id, a, b, c FROM %s"), row(1, "a1", null, "c1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a column with the given name exists in the SSTable header.
|
||||||
|
*/
|
||||||
|
private boolean sstableHeaderContainsColumn(SSTableReader sstable, String columnName)
|
||||||
|
{
|
||||||
|
for (ColumnMetadata column : sstable.header.columns())
|
||||||
|
{
|
||||||
|
if (column.name.toString().equals(columnName))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
|
||||||
|
import org.apache.cassandra.cql3.CQLTester;
|
||||||
|
|
||||||
|
public class SerializationHeaderCursorCompactionCQLTest extends AbstractSerializationHeaderCQLTest
|
||||||
|
{
|
||||||
|
@BeforeClass
|
||||||
|
public static void setUpClass()
|
||||||
|
{
|
||||||
|
System.setProperty("cassandra.cursor_compaction_enabled", "true");
|
||||||
|
CQLTester.setUpClass();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
|
||||||
|
import org.apache.cassandra.cql3.CQLTester;
|
||||||
|
|
||||||
|
public class SerializationHeaderLegacyCompactionCQLTest extends AbstractSerializationHeaderCQLTest
|
||||||
|
{
|
||||||
|
@BeforeClass
|
||||||
|
public static void setUpClass()
|
||||||
|
{
|
||||||
|
System.setProperty("cassandra.cursor_compaction_enabled", "false");
|
||||||
|
CQLTester.setUpClass();
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue