blob: 9c459363913dc0c512fdf103dcbf5d0fcd0039a6 [file] [log] [blame]
/*
* 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.cql3;
import java.util.List;
import java.util.concurrent.TimeUnit;
import org.junit.Assert;
import org.junit.Test;
import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.Row;
import org.apache.cassandra.Util;
import org.apache.cassandra.db.Keyspace;
import org.apache.cassandra.exceptions.InvalidRequestException;
import org.assertj.core.api.Assertions;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
/*
* This test class was too large and used to timeout CASSANDRA-16777. We're splitting it into:
* - ViewTest
* - ViewPKTest
* - ViewRangesTest
* - ViewTimesTest
*/
public class ViewTimesTest extends ViewAbstractTest
{
@Test
public void testRegularColumnTimestampUpdates() throws Throwable
{
// Regression test for CASSANDRA-10910
createTable("CREATE TABLE %s (" +
"k int PRIMARY KEY, " +
"c int, " +
"val int)");
createView("CREATE MATERIALIZED VIEW %s AS SELECT * FROM %s " +
"WHERE k IS NOT NULL AND c IS NOT NULL " +
"PRIMARY KEY (k,c)");
updateView("UPDATE %s SET c = ?, val = ? WHERE k = ?", 0, 0, 0);
updateView("UPDATE %s SET val = ? WHERE k = ?", 1, 0);
updateView("UPDATE %s SET c = ? WHERE k = ?", 1, 0);
assertRows(executeView("SELECT c, k, val FROM %s"), row(1, 0, 1));
updateView("TRUNCATE %s");
updateView("UPDATE %s USING TIMESTAMP 1 SET c = ?, val = ? WHERE k = ?", 0, 0, 0);
updateView("UPDATE %s USING TIMESTAMP 3 SET c = ? WHERE k = ?", 1, 0);
updateView("UPDATE %s USING TIMESTAMP 2 SET val = ? WHERE k = ?", 1, 0);
updateView("UPDATE %s USING TIMESTAMP 4 SET c = ? WHERE k = ?", 2, 0);
updateView("UPDATE %s USING TIMESTAMP 3 SET val = ? WHERE k = ?", 2, 0);
assertRows(executeView("SELECT c, k, val FROM %s"), row(2, 0, 2));
assertRows(executeView("SELECT c, k, val FROM %s limit 1"), row(2, 0, 2));
}
@Test
public void complexTimestampUpdateTestWithFlush() throws Throwable
{
complexTimestampUpdateTest(true);
}
@Test
public void complexTimestampUpdateTestWithoutFlush() throws Throwable
{
complexTimestampUpdateTest(false);
}
public void complexTimestampUpdateTest(boolean flush) throws Throwable
{
createTable("CREATE TABLE %s (a int, b int, c int, d int, e int, PRIMARY KEY (a, b))");
Keyspace ks = Keyspace.open(keyspace());
createView("CREATE MATERIALIZED VIEW %s AS SELECT * FROM %s " +
"WHERE a IS NOT NULL AND b IS NOT NULL AND c IS NOT NULL " +
"PRIMARY KEY (c, a, b)");
ks.getColumnFamilyStore(currentView()).disableAutoCompaction();
//Set initial values TS=0, leaving e null and verify view
executeNet("INSERT INTO %s (a, b, c, d) VALUES (0, 0, 1, 0) USING TIMESTAMP 0");
assertRows(executeView("SELECT d from %s WHERE c = ? and a = ? and b = ?", 1, 0, 0), row(0));
//update c's timestamp TS=2
executeNet("UPDATE %s USING TIMESTAMP 2 SET c = ? WHERE a = ? and b = ? ", 1, 0, 0);
assertRows(executeView("SELECT d from %s WHERE c = ? and a = ? and b = ?", 1, 0, 0), row(0));
if (flush)
Util.flush(ks);
// change c's value and TS=3, tombstones c=1 and adds c=0 record
executeNet("UPDATE %s USING TIMESTAMP 3 SET c = ? WHERE a = ? and b = ? ", 0, 0, 0);
if (flush)
Util.flush(ks);
assertRows(executeView("SELECT d from %s WHERE c = ? and a = ? and b = ?", 1, 0, 0));
if(flush)
{
ks.getColumnFamilyStore(currentView()).forceMajorCompaction();
Util.flush(ks);
}
//change c's value back to 1 with TS=4, check we can see d
executeNet("UPDATE %s USING TIMESTAMP 4 SET c = ? WHERE a = ? and b = ? ", 1, 0, 0);
if (flush)
{
ks.getColumnFamilyStore(currentView()).forceMajorCompaction();
Util.flush(ks);
}
assertRows(executeView("SELECT d,e from %s WHERE c = ? and a = ? and b = ?", 1, 0, 0), row(0, null));
//Add e value @ TS=1
executeNet("UPDATE %s USING TIMESTAMP 1 SET e = ? WHERE a = ? and b = ? ", 1, 0, 0);
assertRows(executeView("SELECT d,e from %s WHERE c = ? and a = ? and b = ?", 1, 0, 0), row(0, 1));
if (flush)
Util.flush(ks);
//Change d value @ TS=2
executeNet("UPDATE %s USING TIMESTAMP 2 SET d = ? WHERE a = ? and b = ? ", 2, 0, 0);
assertRows(executeView("SELECT d from %s WHERE c = ? and a = ? and b = ?", 1, 0, 0), row(2));
if (flush)
Util.flush(ks);
//Change d value @ TS=3
executeNet("UPDATE %s USING TIMESTAMP 3 SET d = ? WHERE a = ? and b = ? ", 1, 0, 0);
assertRows(executeView("SELECT d from %s WHERE c = ? and a = ? and b = ?", 1, 0, 0), row(1));
//Tombstone c
executeNet("DELETE FROM %s WHERE a = ? and b = ?", 0, 0);
assertRows(executeView("SELECT d from %s"));
//Add back without D
executeNet("INSERT INTO %s (a, b, c) VALUES (0, 0, 1)");
//Make sure D doesn't pop back in.
assertRows(executeView("SELECT d from %s WHERE c = ? and a = ? and b = ?", 1, 0, 0), row((Object) null));
//New partition
// insert a row with timestamp 0
executeNet("INSERT INTO %s (a, b, c, d, e) VALUES (?, ?, ?, ?, ?) USING TIMESTAMP 0", 1, 0, 0, 0, 0);
// overwrite pk and e with timestamp 1, but don't overwrite d
executeNet("INSERT INTO %s (a, b, c, e) VALUES (?, ?, ?, ?) USING TIMESTAMP 1", 1, 0, 0, 0);
// delete with timestamp 0 (which should only delete d)
executeNet("DELETE FROM %s USING TIMESTAMP 0 WHERE a = ? AND b = ?", 1, 0);
assertRows(executeView("SELECT a, b, c, d, e from %s WHERE c = ? and a = ? and b = ?", 0, 1, 0),
row(1, 0, 0, null, 0));
executeNet("UPDATE %s USING TIMESTAMP 2 SET c = ? WHERE a = ? AND b = ?", 1, 1, 0);
executeNet("UPDATE %s USING TIMESTAMP 3 SET c = ? WHERE a = ? AND b = ?", 0, 1, 0);
assertRows(executeView("SELECT a, b, c, d, e from %s WHERE c = ? and a = ? and b = ?", 0, 1, 0),
row(1, 0, 0, null, 0));
executeNet("UPDATE %s USING TIMESTAMP 3 SET d = ? WHERE a = ? AND b = ?", 0, 1, 0);
assertRows(executeView("SELECT a, b, c, d, e from %s WHERE c = ? and a = ? and b = ?", 0, 1, 0),
row(1, 0, 0, 0, 0));
}
@Test
public void ttlTest() throws Throwable
{
createTable("CREATE TABLE %s (" +
"a int," +
"b int," +
"c int," +
"d int," +
"PRIMARY KEY (a, b))");
executeNet("USE " + keyspace());
createView("CREATE MATERIALIZED VIEW %s AS SELECT * FROM %s WHERE c IS NOT NULL AND a IS NOT NULL AND b IS NOT NULL PRIMARY KEY (c, a, b)");
updateView("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?) USING TTL 3", 1, 1, 1, 1);
Thread.sleep(TimeUnit.SECONDS.toMillis(1));
updateView("INSERT INTO %s (a, b, c) VALUES (?, ?, ?)", 1, 1, 2);
Thread.sleep(TimeUnit.SECONDS.toMillis(5));
List<Row> results = executeViewNet("SELECT d FROM %s WHERE c = 2 AND a = 1 AND b = 1").all();
Assert.assertEquals(1, results.size());
Assert.assertTrue("There should be a null result given back due to ttl expiry", results.get(0).isNull(0));
}
@Test
public void ttlExpirationTest() throws Throwable
{
createTable("CREATE TABLE %s (" +
"a int," +
"b int," +
"c int," +
"d int," +
"PRIMARY KEY (a, b))");
executeNet("USE " + keyspace());
createView("CREATE MATERIALIZED VIEW %s AS SELECT * FROM %s WHERE c IS NOT NULL AND a IS NOT NULL AND b IS NOT NULL PRIMARY KEY (c, a, b)");
updateView("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?) USING TTL 3", 1, 1, 1, 1);
Thread.sleep(TimeUnit.SECONDS.toMillis(4));
Assert.assertEquals(0, executeViewNet("SELECT * FROM %s WHERE c = 1 AND a = 1 AND b = 1").all().size());
}
@Test
public void conflictingTimestampTest() throws Throwable
{
createTable("CREATE TABLE %s (" +
"a int," +
"b int," +
"c int," +
"PRIMARY KEY (a, b))");
executeNet("USE " + keyspace());
createView("CREATE MATERIALIZED VIEW %s AS SELECT * FROM %s WHERE c IS NOT NULL AND a IS NOT NULL AND b IS NOT NULL PRIMARY KEY (c, a, b)");
for (int i = 0; i < 50; i++)
{
updateView("INSERT INTO %s (a, b, c) VALUES (?, ?, ?) USING TIMESTAMP 1", 1, 1, i);
}
ResultSet mvRows = executeViewNet("SELECT c FROM %s");
List<Row> rows = executeNet("SELECT c FROM %s").all();
assertEquals("There should be exactly one row in base", 1, rows.size());
int expected = rows.get(0).getInt("c");
assertRowsNet(mvRows, row(expected));
}
@Test
public void testCreateMvWithTTL()
{
createTable("CREATE TABLE %s (" +
"k int PRIMARY KEY, " +
"c int, " +
"val int) WITH default_time_to_live = 60");
// Must NOT include "default_time_to_live" for Materialized View creation
try
{
createView("CREATE MATERIALIZED VIEW %s AS SELECT * FROM %s " +
"WHERE k IS NOT NULL AND c IS NOT NULL PRIMARY KEY (k,c) WITH default_time_to_live = 30");
fail("Should fail if TTL is provided for materialized view");
}
catch (RuntimeException e)
{
Throwable cause = e.getCause();
Assertions.assertThat(cause).isInstanceOf(InvalidRequestException.class);
Assertions.assertThat(cause.getMessage()).contains("Cannot set default_time_to_live for a materialized view");
}
}
@Test
public void testAlterMvWithNoZeroTTL() throws Throwable
{
createTable("CREATE TABLE %s (" +
"k int PRIMARY KEY, " +
"c int, " +
"val int) WITH default_time_to_live = 60");
createView("CREATE MATERIALIZED VIEW %s AS SELECT * FROM %s WHERE k IS NOT NULL AND c IS NOT NULL PRIMARY KEY (k,c)");
// Must NOT include "default_time_to_live" on alter Materialized View
try
{
executeNet("ALTER MATERIALIZED VIEW " + currentView() + " WITH default_time_to_live = 30");
fail("Should fail if TTL is provided while altering materialized view");
}
catch (Exception e)
{
// Make sure the message is clear. See CASSANDRA-16960
assertEquals("Forbidden default_time_to_live detected for a materialized view. Data in a materialized view always expire at the same time than the corresponding "
+ "data in the parent table. default_time_to_live must be set to zero, see CASSANDRA-12868 for more information",
e.getMessage());
}
}
@Test
public void testMvWithZeroTTL()
{
createTable("CREATE TABLE %s (" +
"k int PRIMARY KEY, " +
"c int, " +
"val int) WITH default_time_to_live = 60");
try
{
createView("CREATE MATERIALIZED VIEW %s AS SELECT * FROM %s WHERE k IS NOT NULL AND c IS NOT NULL PRIMARY KEY (k,c) WITH default_time_to_live = 0");
}
catch (Exception e)
{
fail("Should not fail if TTL equal to 0 is provided while altering materialized view");
}
}
@Test
public void testAlterMvWithZeroTTL() throws Throwable
{
createTable("CREATE TABLE %s (" +
"k int PRIMARY KEY, " +
"c int, " +
"val int) WITH default_time_to_live = 60");
createView("CREATE MATERIALIZED VIEW %s AS SELECT * FROM %s WHERE k IS NOT NULL AND c IS NOT NULL PRIMARY KEY (k,c)");
try
{
executeNet("ALTER MATERIALIZED VIEW " + currentView() + " WITH default_time_to_live = 0");
}
catch (Exception e)
{
fail("Should not fail if TTL equal to 0 is provided while altering materialized view");
}
}
}