You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cassandra.apache.org by be...@apache.org on 2021/09/20 07:50:05 UTC

[cassandra] branch cassandra-4.0 updated (14af149 -> e98be8e)

This is an automated email from the ASF dual-hosted git repository.

bereng pushed a change to branch cassandra-4.0
in repository https://gitbox.apache.org/repos/asf/cassandra.git.


    from 14af149  Merge branch 'cassandra-3.11' into cassandra-4.0
     new 8f4ae7d  Improve MV TTL error message
     new e98be8e  Merge branch 'cassandra-3.11' into cassandra-4.0

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../cassandra/cql3/statements/schema/AlterViewStatement.java  |  5 +++--
 test/unit/org/apache/cassandra/cql3/ViewTimesTest.java        | 11 ++++++++++-
 2 files changed, 13 insertions(+), 3 deletions(-)

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


[cassandra] 01/01: Merge branch 'cassandra-3.11' into cassandra-4.0

Posted by be...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

bereng pushed a commit to branch cassandra-4.0
in repository https://gitbox.apache.org/repos/asf/cassandra.git

commit e98be8e3ec7ba68e17ce4b50a9a71b01ebefca1a
Merge: 14af149 8f4ae7d
Author: Bereng <be...@gmail.com>
AuthorDate: Mon Sep 20 09:44:02 2021 +0200

    Merge branch 'cassandra-3.11' into cassandra-4.0

 .../cassandra/cql3/statements/schema/AlterViewStatement.java  |  5 +++--
 test/unit/org/apache/cassandra/cql3/ViewTimesTest.java        | 11 ++++++++++-
 2 files changed, 13 insertions(+), 3 deletions(-)

diff --cc src/java/org/apache/cassandra/cql3/statements/schema/AlterViewStatement.java
index 1931bb4,0000000..3493eb0
mode 100644,000000..100644
--- a/src/java/org/apache/cassandra/cql3/statements/schema/AlterViewStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/schema/AlterViewStatement.java
@@@ -1,117 -1,0 +1,118 @@@
 +/*
 + * 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.statements.schema;
 +
 +import org.apache.cassandra.audit.AuditLogContext;
 +import org.apache.cassandra.audit.AuditLogEntryType;
 +import org.apache.cassandra.auth.Permission;
 +import org.apache.cassandra.cql3.CQLStatement;
 +import org.apache.cassandra.cql3.QualifiedName;
 +import org.apache.cassandra.schema.*;
 +import org.apache.cassandra.schema.Keyspaces.KeyspacesDiff;
 +import org.apache.cassandra.service.ClientState;
 +import org.apache.cassandra.transport.Event.SchemaChange;
 +import org.apache.cassandra.transport.Event.SchemaChange.Change;
 +import org.apache.cassandra.transport.Event.SchemaChange.Target;
 +
 +public final class AlterViewStatement extends AlterSchemaStatement
 +{
 +    private final String viewName;
 +    private final TableAttributes attrs;
 +
 +    public AlterViewStatement(String keyspaceName, String viewName, TableAttributes attrs)
 +    {
 +        super(keyspaceName);
 +        this.viewName = viewName;
 +        this.attrs = attrs;
 +    }
 +
 +    public Keyspaces apply(Keyspaces schema)
 +    {
 +        KeyspaceMetadata keyspace = schema.getNullable(keyspaceName);
 +
 +        ViewMetadata view = null == keyspace
 +                          ? null
 +                          : keyspace.views.getNullable(viewName);
 +
 +        if (null == view)
 +            throw ire("Materialized view '%s.%s' doesn't exist", keyspaceName, viewName);
 +
 +        attrs.validate();
 +
 +        TableParams params = attrs.asAlteredTableParams(view.metadata.params);
 +
 +        if (params.gcGraceSeconds == 0)
 +        {
 +            throw ire("Cannot alter gc_grace_seconds of a materialized view to 0, since this " +
 +                      "value is used to TTL undelivered updates. Setting gc_grace_seconds too " +
 +                      "low might cause undelivered updates to expire before being replayed.");
 +        }
 +
 +        if (params.defaultTimeToLive > 0)
 +        {
-             throw ire("Cannot set or alter default_time_to_live for a materialized view. " +
++            throw ire("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.");
++                      "the corresponding data in the parent table. default_time_to_live " +
++                      "must be set to zero, see CASSANDRA-12868 for more information");
 +        }
 +
 +        ViewMetadata newView = view.copy(view.metadata.withSwapped(params));
 +        return schema.withAddedOrUpdated(keyspace.withSwapped(keyspace.views.withSwapped(newView)));
 +    }
 +
 +    SchemaChange schemaChangeEvent(KeyspacesDiff diff)
 +    {
 +        return new SchemaChange(Change.UPDATED, Target.TABLE, keyspaceName, viewName);
 +    }
 +
 +    public void authorize(ClientState client)
 +    {
 +        ViewMetadata view = Schema.instance.getView(keyspaceName, viewName);
 +        if (null != view)
 +            client.ensureTablePermission(keyspaceName, view.baseTableName, Permission.ALTER);
 +    }
 +
 +    @Override
 +    public AuditLogContext getAuditLogContext()
 +    {
 +        return new AuditLogContext(AuditLogEntryType.ALTER_VIEW, keyspaceName, viewName);
 +    }
 +
 +    public String toString()
 +    {
 +        return String.format("%s (%s, %s)", getClass().getSimpleName(), keyspaceName, viewName);
 +    }
 +
 +    public static final class Raw extends CQLStatement.Raw
 +    {
 +        private final QualifiedName name;
 +        private final TableAttributes attrs;
 +
 +        public Raw(QualifiedName name, TableAttributes attrs)
 +        {
 +            this.name = name;
 +            this.attrs = attrs;
 +        }
 +
 +        public AlterViewStatement prepare(ClientState state)
 +        {
 +            String keyspaceName = name.hasKeyspace() ? name.getKeyspace() : state.getKeyspace();
 +            return new AlterViewStatement(keyspaceName, name.getName(), attrs);
 +        }
 +    }
 +}
diff --cc test/unit/org/apache/cassandra/cql3/ViewTimesTest.java
index 4fee422,0000000..14d7566
mode 100644,000000..100644
--- a/test/unit/org/apache/cassandra/cql3/ViewTimesTest.java
+++ b/test/unit/org/apache/cassandra/cql3/ViewTimesTest.java
@@@ -1,300 -1,0 +1,309 @@@
 +/*
 + * 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.db.Keyspace;
 +import org.apache.cassandra.utils.FBUtilities;
 +
++import static org.junit.Assert.assertEquals;
++
 +/*
 + * 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)");
 +
 +        execute("USE " + keyspace());
 +        executeNet("USE " + keyspace());
 +
 +        createView("mv_rctstest", "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(execute("SELECT c, k, val FROM mv_rctstest"), 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(execute("SELECT c, k, val FROM mv_rctstest"), row(2, 0, 2));
 +        assertRows(execute("SELECT c, k, val FROM mv_rctstest 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))");
 +
 +        execute("USE " + keyspace());
 +        executeNet("USE " + keyspace());
 +        Keyspace ks = Keyspace.open(keyspace());
 +
 +        createView("mv", "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("mv").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(execute("SELECT d from mv 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(execute("SELECT d from mv WHERE c = ? and a = ? and b = ?", 1, 0, 0), row(0));
 +
 +        if (flush)
 +            FBUtilities.waitOnFutures(ks.flush());
 +
 +        // 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)
 +            FBUtilities.waitOnFutures(ks.flush());
 +        assertRows(execute("SELECT d from mv WHERE c = ? and a = ? and b = ?", 1, 0, 0));
 +
 +        if(flush)
 +        {
 +            ks.getColumnFamilyStore("mv").forceMajorCompaction();
 +            FBUtilities.waitOnFutures(ks.flush());
 +        }
 +
 +
 +        //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("mv").forceMajorCompaction();
 +            FBUtilities.waitOnFutures(ks.flush());
 +        }
 +
 +        assertRows(execute("SELECT d,e from mv 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(execute("SELECT d,e from mv WHERE c = ? and a = ? and b = ?", 1, 0, 0), row(0, 1));
 +
 +        if (flush)
 +            FBUtilities.waitOnFutures(ks.flush());
 +
 +
 +        //Change d value @ TS=2
 +        executeNet("UPDATE %s USING TIMESTAMP 2 SET d = ? WHERE a = ? and b = ? ", 2, 0, 0);
 +        assertRows(execute("SELECT d from mv WHERE c = ? and a = ? and b = ?", 1, 0, 0), row(2));
 +
 +        if (flush)
 +            FBUtilities.waitOnFutures(ks.flush());
 +
 +
 +        //Change d value @ TS=3
 +        executeNet("UPDATE %s USING TIMESTAMP 3 SET d = ? WHERE a = ? and b = ? ", 1, 0, 0);
 +        assertRows(execute("SELECT d from mv WHERE c = ? and a = ? and b = ?", 1, 0, 0), row(1));
 +
 +
 +        //Tombstone c
 +        executeNet("DELETE FROM %s WHERE a = ? and b = ?", 0, 0);
 +        assertRows(execute("SELECT d from mv"));
 +
 +        //Add back without D
 +        executeNet("INSERT INTO %s (a, b, c) VALUES (0, 0, 1)");
 +
 +        //Make sure D doesn't pop back in.
 +        assertRows(execute("SELECT d from mv 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(execute("SELECT a, b, c, d, e from mv 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(execute("SELECT a, b, c, d, e from mv 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(execute("SELECT a, b, c, d, e from mv 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("mv", "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 = executeNet("SELECT d FROM mv 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("mv", "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, executeNet("SELECT * FROM mv 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("mv", "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 = executeNet("SELECT c FROM mv");
 +        List<Row> rows = executeNet("SELECT c FROM %s").all();
 +        Assert.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() throws Throwable
 +    {
 +        createTable("CREATE TABLE %s (" +
 +                    "k int PRIMARY KEY, " +
 +                    "c int, " +
 +                    "val int) WITH default_time_to_live = 60");
 +
 +        execute("USE " + keyspace());
 +        executeNet("USE " + keyspace());
 +
 +        // Must NOT include "default_time_to_live" for Materialized View creation
 +        try
 +        {
 +            createView("mv_ttl1", "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");
 +            Assert.fail("Should fail if TTL is provided for materialized view");
 +        }
 +        catch (Exception e)
 +        {
 +        }
 +    }
 +
 +    @Test
 +    public void testAlterMvWithTTL() throws Throwable
 +    {
 +        createTable("CREATE TABLE %s (" +
 +                    "k int PRIMARY KEY, " +
 +                    "c int, " +
 +                    "val int) WITH default_time_to_live = 60");
 +
++        execute("USE " + keyspace());
++        executeNet("USE " + keyspace());
++
 +        createView("mv_ttl2", "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 %s WITH default_time_to_live = 30");
++            executeNet("ALTER MATERIALIZED VIEW " + keyspace()+ ".mv_ttl2 WITH default_time_to_live = 30");
 +            Assert.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());
 +        }
 +    }
 +}

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