Repository: cassandra Updated Branches: refs/heads/trunk 5c97de91b -> a177502b8
Always update system keyspace to the most up-to-date version patch by slebresne; reviewed by carlyeks for CASSANDRA-10652 Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/6367987f Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/6367987f Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/6367987f Branch: refs/heads/trunk Commit: 6367987f49a25512dbf715df9b6d564d53f27235 Parents: 801c50e Author: Sylvain Lebresne <[email protected]> Authored: Thu Nov 5 15:30:54 2015 +0100 Committer: Sylvain Lebresne <[email protected]> Committed: Fri Nov 6 14:42:31 2015 +0100 ---------------------------------------------------------------------- CHANGES.txt | 1 + .../cassandra/service/MigrationManager.java | 22 +++++++- .../cassandra/service/StorageService.java | 56 ++++++++++++-------- 3 files changed, 55 insertions(+), 24 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cassandra/blob/6367987f/CHANGES.txt ---------------------------------------------------------------------- diff --git a/CHANGES.txt b/CHANGES.txt index 538d5e4..7e969a5 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,4 +1,5 @@ 2.2.4 + * Use most up-to-date version of schema for system tables (CASSANDRA-10652) * Deprecate memory_allocator in cassandra.yaml (CASSANDRA-10581,10628) * Expose phi values from failure detector via JMX and tweak debug and trace logging (CASSANDRA-9526) http://git-wip-us.apache.org/repos/asf/cassandra/blob/6367987f/src/java/org/apache/cassandra/service/MigrationManager.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/service/MigrationManager.java b/src/java/org/apache/cassandra/service/MigrationManager.java index 9087672..ec7448a 100644 --- a/src/java/org/apache/cassandra/service/MigrationManager.java +++ b/src/java/org/apache/cassandra/service/MigrationManager.java @@ -277,12 +277,32 @@ public class MigrationManager public static void announceNewColumnFamily(CFMetaData cfm, boolean announceLocally) throws ConfigurationException { + announceNewColumnFamily(cfm, announceLocally, true); + } + + /** + * Announces the table even if the definition is already know locally. + * This should generally be avoided but is used internally when we want to force the most up to date version of + * a system table schema (Note that we don't know if the schema we force _is_ the most recent version or not, we + * just rely on idempotency to basically ignore that announce if it's not. That's why we can't use announceUpdateColumnFamily, + * it would for instance delete new columns if this is not called with the most up-to-date version) + * + * Note that this is only safe for system tables where we know the cfId is fixed and will be the same whatever version + * of the definition is used. + */ + public static void forceAnnounceNewColumnFamily(CFMetaData cfm) throws ConfigurationException + { + announceNewColumnFamily(cfm, false, false); + } + + private static void announceNewColumnFamily(CFMetaData cfm, boolean announceLocally, boolean throwOnDuplicate) throws ConfigurationException + { cfm.validate(); KSMetaData 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)); - else if (ksm.cfMetaData().containsKey(cfm.cfName)) + else if (throwOnDuplicate && ksm.cfMetaData().containsKey(cfm.cfName)) throw new AlreadyExistsException(cfm.ksName, cfm.cfName); logger.info(String.format("Create new table: %s", cfm)); http://git-wip-us.apache.org/repos/asf/cassandra/blob/6367987f/src/java/org/apache/cassandra/service/StorageService.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/service/StorageService.java b/src/java/org/apache/cassandra/service/StorageService.java index 77483f2..ad209fc 100644 --- a/src/java/org/apache/cassandra/service/StorageService.java +++ b/src/java/org/apache/cassandra/service/StorageService.java @@ -950,11 +950,8 @@ public class StorageService extends NotificationBroadcasterSupport implements IE } // if we don't have system_traces keyspace at this point, then create it manually - if (Schema.instance.getKSMetaData(TraceKeyspace.NAME) == null) - maybeAddKeyspace(TraceKeyspace.definition()); - - if (Schema.instance.getKSMetaData(SystemDistributedKeyspace.NAME) == null) - MigrationManager.announceNewKeyspace(SystemDistributedKeyspace.definition(), 0, false); + maybeAddOrUpdateKeyspace(TraceKeyspace.definition()); + maybeAddOrUpdateKeyspace(SystemDistributedKeyspace.definition()); if (!isSurveyMode) { @@ -1020,24 +1017,7 @@ public class StorageService extends NotificationBroadcasterSupport implements IE private void doAuthSetup() { - try - { - // if we don't have system_auth keyspace at this point, then create it - if (Schema.instance.getKSMetaData(AuthKeyspace.NAME) == null) - maybeAddKeyspace(AuthKeyspace.definition()); - } - catch (Exception e) - { - throw new AssertionError(e); // shouldn't ever happen. - } - - // create any necessary tables as we may be upgrading in which case - // the ks exists with the only the legacy tables defined. - // Also, the addKeyspace above can be racy if multiple nodes are started - // concurrently - see CASSANDRA-9201 - for (Map.Entry<String, CFMetaData> table : AuthKeyspace.definition().cfMetaData().entrySet()) - if (Schema.instance.getCFMetaData(AuthKeyspace.NAME, table.getKey()) == null) - maybeAddTable(table.getValue()); + maybeAddOrUpdateKeyspace(AuthKeyspace.definition()); DatabaseDescriptor.getRoleManager().setup(); DatabaseDescriptor.getAuthenticator().setup(); @@ -1069,6 +1049,36 @@ public class StorageService extends NotificationBroadcasterSupport implements IE } } + /** + * Ensure the schema of a pseudo-system keyspace (a distributed system keyspace: traces, auth and the so-called distributedKeyspace), + * is up to date with what we expected (creating it if it doesn't exist and updating tables that may have been upgraded). + */ + private void maybeAddOrUpdateKeyspace(KSMetaData expected) + { + // Note that want to deal with the keyspace and its table a bit differently: for the keyspace definition + // itself, we want to create it if it doesn't exist yet, but if it does exist, we don't want to modify it, + // because user can modify the definition to change the replication factor (#6016) and we don't want to + // override it. For the tables however, we have to deal with the fact that new version can add new columns + // (#8162 being an example), so even if the table definition exists, we still need to force the "current" + // version of the schema, the one the node will be expecting. + + KSMetaData defined = Schema.instance.getKSMetaData(expected.name); + if (defined == null) + { + // The keyspace doesn't exist, create it + maybeAddKeyspace(expected); + return; + } + + // While the keyspace exists, it might miss table or have outdated one + for (CFMetaData expectedTable : expected.cfMetaData().values()) + { + CFMetaData definedTable = defined.cfMetaData().get(expectedTable.cfName); + if (definedTable == null || !definedTable.equals(expectedTable)) + MigrationManager.forceAnnounceNewColumnFamily(expectedTable); + } + } + public boolean isJoined() { return joined && !isSurveyMode;
