seed status no longer affects bootstrap setting patch by jbellis; reviewed by slebresne for CASSANDRA-4427
Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/0819ad14 Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/0819ad14 Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/0819ad14 Branch: refs/heads/trunk Commit: 0819ad144c8e3e4c035f8254743ec9cd1f82b919 Parents: 96075b3 Author: Jonathan Ellis <jbel...@apache.org> Authored: Sat Jul 28 09:37:15 2012 -0500 Committer: Jonathan Ellis <jbel...@apache.org> Committed: Sat Jul 28 09:37:52 2012 -0500 ---------------------------------------------------------------------- CHANGES.txt | 1 + src/java/org/apache/cassandra/config/Schema.java | 32 ++++----- .../org/apache/cassandra/gms/VersionedValue.java | 2 +- .../apache/cassandra/service/MigrationManager.java | 4 +- .../apache/cassandra/service/StorageService.java | 52 ++++++++++----- 5 files changed, 53 insertions(+), 38 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cassandra/blob/0819ad14/CHANGES.txt ---------------------------------------------------------------------- diff --git a/CHANGES.txt b/CHANGES.txt index fd6991c..78d7267 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -28,6 +28,7 @@ Merged from 1.0: * Fix LCS splitting sstable base on uncompressed size (CASSANDRA-4419) * Bootstraps that fail are detected upon restart and will retry safely without needing to delete existing data first (CASSANDRA-4427) + * seed status no longer disables bootstrap (CASSANDRA-4427) * (cqlsh) add a COPY TO command to copy a CF to a CSV file (CASSANDRA-4434) * Don't purge columns during upgradesstables (CASSANDRA-4462) * Push the validation of secondary index values to the SecondaryIndexManager (CASSANDRA-4240) http://git-wip-us.apache.org/repos/asf/cassandra/blob/0819ad14/src/java/org/apache/cassandra/config/Schema.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/config/Schema.java b/src/java/org/apache/cassandra/config/Schema.java index 9501778..95d092f 100644 --- a/src/java/org/apache/cassandra/config/Schema.java +++ b/src/java/org/apache/cassandra/config/Schema.java @@ -21,6 +21,7 @@ package org.apache.cassandra.config; import java.io.IOError; import java.nio.ByteBuffer; import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import java.util.*; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.ReadWriteLock; @@ -69,8 +70,20 @@ public class Schema private final BiMap<Pair<String, String>, Integer> cfIdMap = HashBiMap.create(); private volatile UUID version; - private final ReadWriteLock versionLock = new ReentrantReadWriteLock(); + public static final UUID emptyVersion; + + static + { + try + { + emptyVersion = UUID.nameUUIDFromBytes(MessageDigest.getInstance("MD5").digest()); + } + catch (NoSuchAlgorithmException e) + { + throw new AssertionError(); + } + } /** * Initialize empty schema object @@ -428,16 +441,7 @@ public class Schema */ public UUID getVersion() { - versionLock.readLock().lock(); - - try - { - return version; - } - finally - { - versionLock.readLock().unlock(); - } + return version; } /** @@ -446,8 +450,6 @@ public class Schema */ public void updateVersion() { - versionLock.writeLock().lock(); - try { MessageDigest versionDigest = MessageDigest.getInstance("MD5"); @@ -466,10 +468,6 @@ public class Schema { throw new RuntimeException(e); } - finally - { - versionLock.writeLock().unlock(); - } } /* http://git-wip-us.apache.org/repos/asf/cassandra/blob/0819ad14/src/java/org/apache/cassandra/gms/VersionedValue.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/gms/VersionedValue.java b/src/java/org/apache/cassandra/gms/VersionedValue.java index 85c9b38..0b89c5a 100644 --- a/src/java/org/apache/cassandra/gms/VersionedValue.java +++ b/src/java/org/apache/cassandra/gms/VersionedValue.java @@ -113,7 +113,7 @@ public class VersionedValue implements Comparable<VersionedValue> return new VersionedValue(String.valueOf(load)); } - public VersionedValue migration(UUID newVersion) + public VersionedValue schema(UUID newVersion) { return new VersionedValue(newVersion.toString()); } http://git-wip-us.apache.org/repos/asf/cassandra/blob/0819ad14/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 a067de3..eedb20d 100644 --- a/src/java/org/apache/cassandra/service/MigrationManager.java +++ b/src/java/org/apache/cassandra/service/MigrationManager.java @@ -236,7 +236,7 @@ public class MigrationManager implements IEndpointStateChangeSubscriber public static void passiveAnnounce(UUID version) { assert Gossiper.instance.isEnabled(); - Gossiper.instance.addLocalApplicationState(ApplicationState.SCHEMA, StorageService.instance.valueFactory.migration(version)); + Gossiper.instance.addLocalApplicationState(ApplicationState.SCHEMA, StorageService.instance.valueFactory.schema(version)); logger.debug("Gossiping my schema version " + version); } @@ -403,7 +403,6 @@ public class MigrationManager implements IEndpointStateChangeSubscriber IAsyncCallback cb = new IAsyncCallback() { - @Override public void response(Message message) { try @@ -420,7 +419,6 @@ public class MigrationManager implements IEndpointStateChangeSubscriber } } - @Override public boolean isLatencyForSnitch() { return false; http://git-wip-us.apache.org/repos/asf/cassandra/blob/0819ad14/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 bfc8c81..5591488 100644 --- a/src/java/org/apache/cassandra/service/StorageService.java +++ b/src/java/org/apache/cassandra/service/StorageService.java @@ -557,30 +557,47 @@ public class StorageService implements IEndpointStateChangeSubscriber, StorageSe HintedHandOffManager.instance.start(); - if (DatabaseDescriptor.isAutoBootstrap() - && DatabaseDescriptor.getSeeds().contains(FBUtilities.getBroadcastAddress()) - && !SystemTable.bootstrapComplete()) - logger_.info("This node will not auto bootstrap because it is configured to be a seed node."); + boolean schemaPresent = false; + if (DatabaseDescriptor.isAutoBootstrap() && !SystemTable.bootstrapComplete() && delay > 0) + { + // wait a couple gossip rounds so our schema check has something to go by + FBUtilities.sleep(2 * Gossiper.intervalInMillis); + } + for (Entry<InetAddress, EndpointState> entry : Gossiper.instance.getEndpointStates()) + { + if (entry.getKey().equals(FBUtilities.getBroadcastAddress())) + { + // skip ourselves to avoid confusing the tests, which always load a schema first thing + continue; + } - InetAddress current = null; - // we can bootstrap at startup, or if we detect a previous attempt that failed, which is to say: - // DD.isAutoBootstrap must be true AND: - // bootstrap is not recorded as complete, OR - // DD.getSeeds does not contain our BCA, OR - // we do not have non-system tables already - // OR: - // we detect that we were previously trying to bootstrap (ST.bootstrapInProgress is true) + if (!entry.getValue().getApplicationState(ApplicationState.SCHEMA).value.equals(Schema.emptyVersion.toString())) + { + schemaPresent = true; + break; + } + } + + // We can bootstrap at startup, or if we detect a previous attempt that failed. Either way, if the user + // manually sets auto_bootstrap to false, we'll skip streaming data from other nodes and jump directly + // into the ring. + // + // The one exception is if after the above sleep we still have no schema information, we'll assume + // we're part of a fresh cluster start, and also skip bootstrap. This is less confusing for new users, + // as well as avoiding the nonsensical state of trying to stream from cluster with no active peers. Token<?> token; + InetAddress current = null; + logger_.debug("Bootstrap variables: %s %s %s %s", + new Object[] {DatabaseDescriptor.isAutoBootstrap(), SystemTable.bootstrapInProgress(), SystemTable.bootstrapComplete(), schemaPresent}); if (DatabaseDescriptor.isAutoBootstrap() - && !(SystemTable.bootstrapComplete() || DatabaseDescriptor.getSeeds().contains(FBUtilities.getBroadcastAddress()) || !Schema.instance.getNonSystemTables().isEmpty()) - || SystemTable.bootstrapInProgress()) + && (SystemTable.bootstrapInProgress() || (!SystemTable.bootstrapComplete() && schemaPresent))) { if (SystemTable.bootstrapInProgress()) logger_.warn("Detected previous bootstrap failure; retrying"); else SystemTable.setBootstrapState(SystemTable.BootstrapState.IN_PROGRESS); - setMode(Mode.JOINING, "waiting for ring and schema information", true); - // first sleep the delay to make sure we see the schema + setMode(Mode.JOINING, "waiting for ring information", true); + // first sleep the delay to make sure we see all our peers try { Thread.sleep(delay); @@ -589,7 +606,8 @@ public class StorageService implements IEndpointStateChangeSubscriber, StorageSe { throw new AssertionError(e); } - // now if our schema hasn't matched, keep sleeping until it does + // if our schema hasn't matched yet, keep sleeping until it does + // (post CASSANDRA-1391 we don't expect this to be necessary very often, but it doesn't hurt to be careful) while (!MigrationManager.isReadyForBootstrap()) { setMode(Mode.JOINING, "waiting for schema information to complete", true);