[ 
https://issues.apache.org/jira/browse/CASSANDRA-13776?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Benjamin Lerer updated CASSANDRA-13776:
---------------------------------------
    Description: 
Adding a field to an UDT which is used as a {{Set}} element or as a {{Map}} 
element can corrupt the table.
The problem can be reproduced using the following test case:
{code}
    @Test
    public void testReadAfterAlteringUserTypeNestedWithinSet() throws Throwable
    {
        String ut1 = createType("CREATE TYPE %s (a int)");
        String columnType = KEYSPACE + "." + ut1;

        try
        {
            createTable("CREATE TABLE %s (x int PRIMARY KEY, y set<frozen<" + 
columnType + ">>)");
            disableCompaction();

            execute("INSERT INTO %s (x, y) VALUES(1, ?)", set(userType(1), 
userType(2)));
            assertRows(execute("SELECT * FROM %s"), row(1, set(userType(1), 
userType(2))));
            flush();

            assertRows(execute("SELECT * FROM %s WHERE x = 1"),
                       row(1, set(userType(1), userType(2))));

            execute("ALTER TYPE " + KEYSPACE + "." + ut1 + " ADD b int");
            execute("UPDATE %s SET y = y + ? WHERE x = 1",
                    set(userType(1, 1), userType(1, 2), userType(2, 1)));

            flush();
            assertRows(execute("SELECT * FROM %s WHERE x = 1"),
                           row(1, set(userType(1),
                                      userType(1, 1),
                                      userType(1, 2),
                                      userType(2),
                                      userType(2, 1))));

            compact();

            assertRows(execute("SELECT * FROM %s WHERE x = 1"),
                       row(1, set(userType(1),
                                  userType(1, 1),
                                  userType(1, 2),
                                  userType(2),
                                  userType(2, 1))));
        }
        finally
        {
            enableCompaction();
        }
    }
{code} 

There are in fact 2 problems:
# When the {{sets}} from the 2 versions are merged the {{ColumnDefinition}} 
being picked up can be the older one. In which case when the tuples are sorted 
it my lead to an {{IndexOutOfBoundsException}}.
# During compaction, the old column definition can be the one being kept for 
the SSTable metadata. If it is the case the SSTable will not be readable any 
more and will be marked as {{corrupted}}.

If one of the tables using the type has a Materialized View attached to it, the 
MV updates can also fail with {{IndexOutOfBoundsException}}.

This problem can be reproduced using the following test:
{code}
    @Test
    public void testAlteringUserTypeNestedWithinSetWithView() throws Throwable
    {
        String columnType = typeWithKs(createType("CREATE TYPE %s (a int)"));

        createTable("CREATE TABLE %s (pk int, c int, v int, s set<frozen<" + 
columnType + ">>, PRIMARY KEY (pk, c))");
        execute("CREATE MATERIALIZED VIEW " + keyspace() + ".view1 AS SELECT c, 
pk, v FROM %s WHERE pk IS NOT NULL AND c IS NOT NULL AND v IS NOT NULL PRIMARY 
KEY (c, pk)");

        execute("INSERT INTO %s (pk, c, v, s) VALUES(?, ?, ?, ?)", 1, 1, 1, 
set(userType(1), userType(2)));
        flush();

        execute("ALTER TYPE " + columnType + " ADD b int");
        execute("UPDATE %s SET s = s + ?, v = ? WHERE pk = ? AND c = ?",
                set(userType(1, 1), userType(1, 2), userType(2, 1)), 2, 1, 1);


        assertRows(execute("SELECT * FROM %s WHERE pk = ? AND c = ?", 1, 1),
                       row(1, 1, 2, set(userType(1),
                                        userType(1, 1),
                                        userType(1, 2),
                                        userType(2),
                                        userType(2, 1))));
    }
{code}      

  was:
Adding a field to an UDT which is used as a {{Set}} element or as a {{Map}} 
element can corrupt the table.
The problem can be reproduced using the following test case:
{code}
    @Test
    public void testReadAfterAlteringUserTypeNestedWithinSet() throws Throwable
    {
        String ut1 = createType("CREATE TYPE %s (a int)");
        String columnType = KEYSPACE + "." + ut1;

        try
        {
            createTable("CREATE TABLE %s (x int PRIMARY KEY, y set<frozen<" + 
columnType + ">>)");
            disableCompaction();

            execute("INSERT INTO %s (x, y) VALUES(1, ?)", set(userType(1), 
userType(2)));
            assertRows(execute("SELECT * FROM %s"), row(1, set(userType(1), 
userType(2))));
            flush();

            assertRows(execute("SELECT * FROM %s WHERE x = 1"),
                       row(1, set(userType(1), userType(2))));

            execute("ALTER TYPE " + KEYSPACE + "." + ut1 + " ADD b int");
            execute("UPDATE %s SET y = y + ? WHERE x = 1",
                    set(userType(1, 1), userType(1, 2), userType(2, 1)));

            flush();
            assertRows(execute("SELECT * FROM %s WHERE x = 1"),
                           row(1, set(userType(1),
                                      userType(1, 1),
                                      userType(1, 2),
                                      userType(2),
                                      userType(2, 1))));

            compact();

            assertRows(execute("SELECT * FROM %s WHERE x = 1"),
                       row(1, set(userType(1),
                                  userType(1, 1),
                                  userType(1, 2),
                                  userType(2),
                                  userType(2, 1))));
        }
        finally
        {
            enableCompaction();
        }
    }
{code} 

There is in fact 2 problems:
# When the {{sets}} from the 2 versions are merged the {{ColumnDefinition}} 
being picked up can be the older one. In which case when the tuples are sorted 
it my lead to an {{IndexOutOfBoundException}}.
# During compaction, the old column definition can be the one being kept for 
the SSTable metadata. If it is the case the SSTable will not be readable any 
more and will be marked as {{corrupted}}.     


> Adding a field to an UDT can corrupte the tables using it
> ---------------------------------------------------------
>
>                 Key: CASSANDRA-13776
>                 URL: https://issues.apache.org/jira/browse/CASSANDRA-13776
>             Project: Cassandra
>          Issue Type: Bug
>            Reporter: Benjamin Lerer
>            Assignee: Benjamin Lerer
>            Priority: Critical
>
> Adding a field to an UDT which is used as a {{Set}} element or as a {{Map}} 
> element can corrupt the table.
> The problem can be reproduced using the following test case:
> {code}
>     @Test
>     public void testReadAfterAlteringUserTypeNestedWithinSet() throws 
> Throwable
>     {
>         String ut1 = createType("CREATE TYPE %s (a int)");
>         String columnType = KEYSPACE + "." + ut1;
>         try
>         {
>             createTable("CREATE TABLE %s (x int PRIMARY KEY, y set<frozen<" + 
> columnType + ">>)");
>             disableCompaction();
>             execute("INSERT INTO %s (x, y) VALUES(1, ?)", set(userType(1), 
> userType(2)));
>             assertRows(execute("SELECT * FROM %s"), row(1, set(userType(1), 
> userType(2))));
>             flush();
>             assertRows(execute("SELECT * FROM %s WHERE x = 1"),
>                        row(1, set(userType(1), userType(2))));
>             execute("ALTER TYPE " + KEYSPACE + "." + ut1 + " ADD b int");
>             execute("UPDATE %s SET y = y + ? WHERE x = 1",
>                     set(userType(1, 1), userType(1, 2), userType(2, 1)));
>             flush();
>             assertRows(execute("SELECT * FROM %s WHERE x = 1"),
>                            row(1, set(userType(1),
>                                       userType(1, 1),
>                                       userType(1, 2),
>                                       userType(2),
>                                       userType(2, 1))));
>             compact();
>             assertRows(execute("SELECT * FROM %s WHERE x = 1"),
>                        row(1, set(userType(1),
>                                   userType(1, 1),
>                                   userType(1, 2),
>                                   userType(2),
>                                   userType(2, 1))));
>         }
>         finally
>         {
>             enableCompaction();
>         }
>     }
> {code} 
> There are in fact 2 problems:
> # When the {{sets}} from the 2 versions are merged the {{ColumnDefinition}} 
> being picked up can be the older one. In which case when the tuples are 
> sorted it my lead to an {{IndexOutOfBoundsException}}.
> # During compaction, the old column definition can be the one being kept for 
> the SSTable metadata. If it is the case the SSTable will not be readable any 
> more and will be marked as {{corrupted}}.
> If one of the tables using the type has a Materialized View attached to it, 
> the MV updates can also fail with {{IndexOutOfBoundsException}}.
> This problem can be reproduced using the following test:
> {code}
>     @Test
>     public void testAlteringUserTypeNestedWithinSetWithView() throws Throwable
>     {
>         String columnType = typeWithKs(createType("CREATE TYPE %s (a int)"));
>         createTable("CREATE TABLE %s (pk int, c int, v int, s set<frozen<" + 
> columnType + ">>, PRIMARY KEY (pk, c))");
>         execute("CREATE MATERIALIZED VIEW " + keyspace() + ".view1 AS SELECT 
> c, pk, v FROM %s WHERE pk IS NOT NULL AND c IS NOT NULL AND v IS NOT NULL 
> PRIMARY KEY (c, pk)");
>         execute("INSERT INTO %s (pk, c, v, s) VALUES(?, ?, ?, ?)", 1, 1, 1, 
> set(userType(1), userType(2)));
>         flush();
>         execute("ALTER TYPE " + columnType + " ADD b int");
>         execute("UPDATE %s SET s = s + ?, v = ? WHERE pk = ? AND c = ?",
>                 set(userType(1, 1), userType(1, 2), userType(2, 1)), 2, 1, 1);
>         assertRows(execute("SELECT * FROM %s WHERE pk = ? AND c = ?", 1, 1),
>                        row(1, 1, 2, set(userType(1),
>                                         userType(1, 1),
>                                         userType(1, 2),
>                                         userType(2),
>                                         userType(2, 1))));
>     }
> {code}      



--
This message was sent by Atlassian JIRA
(v6.4.14#64029)

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

Reply via email to