You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cassandra.apache.org by "maxwellguo (Jira)" <ji...@apache.org> on 2020/06/02 03:40:00 UTC

[jira] [Created] (CASSANDRA-15844) Create table Asynchronously or contact the same node from many client threads at same time may causing data lose

maxwellguo created CASSANDRA-15844:
--------------------------------------

             Summary: Create table Asynchronously or contact the same node from many client threads at same time may causing data lose
                 Key: CASSANDRA-15844
                 URL: https://issues.apache.org/jira/browse/CASSANDRA-15844
             Project: Cassandra
          Issue Type: Bug
          Components: Cluster/Schema
            Reporter: maxwellguo
            Assignee: maxwellguo
         Attachments: createkeyspace.jpg, keyspace inner.jpg, schemaversion.jpg

When creating a table from on one coordinator node from some client threads at the same time, Or creating a table using session.executeAsync() method, may cause the schema'information incorrect. Seriously will causing data lose.
For my test. I use executeAsync() to create table one by one using the same table name (Though I do konw create table should be synchronously, but some of our customers may create table using executAsync() ). My expectations is that the last cql 
{code:java}
CREATE TABLE ks.tb (name text PRIMARY KEY , age int, adds text, height text)
{code}
should take effect . 

 !createkeyspace.jpg! 

But after runing the code, I foud that the result is not what I am expected.  the schema struct is is :

{code:java}
CREATE TABLE ks.tb (name text PRIMARY KEY , age int, adds text, sex int, height int)
{code}
 !keyspace inner.jpg! 
And the schema version in the memory and on the disk is not the same. 
 !schemaversion.jpg! 

When add a new columnfamily (creat a new table), the request of creating same table with different schema definition arrived at the same time from different clients or using 
executeAsync method. 
{code:java}
 private static void announceNewColumnFamily(CFMetaData cfm, boolean announceLocally, boolean throwOnDuplicate, long timestamp) throws ConfigurationException
    {
        cfm.validate();

        KeyspaceMetadata ksm = Schema.instance.getKSMetaData(cfm.ksName);
        if (ksm == null)
            throw new ConfigurationException(String.format("Cannot add table '%s' to non existing keyspace '%s'.", cfm.cfName, cfm.ksName));
        // If we have a table or a view which has the same name, we can't add a new one
        else if (throwOnDuplicate && ksm.getTableOrViewNullable(cfm.cfName) != null)
            throw new AlreadyExistsException(cfm.ksName, cfm.cfName);

        logger.info("Create new table: {}", cfm);
        announce(SchemaKeyspace.makeCreateTableMutation(ksm, cfm, timestamp), announceLocally);
    }
{code}
The code of checking table existance may failed. And same table's request may all going to do announce() method;

{code:java}
public static synchronized void mergeSchema(Collection<Mutation> mutations, boolean forDynamoTTL)
    {
        // only compare the keyspaces affected by this set of schema mutations
        Set<String> affectedKeyspaces =
        mutations.stream()
                 .map(m -> UTF8Type.instance.compose(m.key().getKey()))
                 .collect(Collectors.toSet());

        // fetch the current state of schema for the affected keyspaces only
        Keyspaces before = Schema.instance.getKeyspaces(affectedKeyspaces);

        // apply the schema mutations and flush
        mutations.forEach(Mutation::apply);
        if (FLUSH_SCHEMA_TABLES)
            flush();


        // fetch the new state of schema from schema tables (not applied to Schema.instance yet)
        Keyspaces after = fetchKeyspacesOnly(affectedKeyspaces);

        mergeSchema(before, after);
        scheduleDynamoTTLClean(forDynamoTTL, mutations);
    }
{code}
For we may write the new table definition into disk, so at last we saw 
{code:java}
CREATE TABLE ks.tb (name text PRIMARY KEY , age int, adds text, sex int, height int)
{code}
in our case.
And we also saw the different version in memory and disk. 
when writing data we using the schema in memory, but when we doing node restart the schema definition on disk will be used. Then may causing data lose. 




--
This message was sent by Atlassian Jira
(v8.3.4#803005)

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