Author: jbellis
Date: Thu Sep 30 13:35:26 2010
New Revision: 1003060
URL: http://svn.apache.org/viewvc?rev=1003060&view=rev
Log:
log warning when using randomly generated token.
patch by jbellis; reviewed by gdusbabek for CASSANDRA-1552
Removed:
cassandra/trunk/test/unit/org/apache/cassandra/db/SystemTableTest.java
Modified:
cassandra/trunk/CHANGES.txt
cassandra/trunk/src/java/org/apache/cassandra/db/SystemTable.java
cassandra/trunk/src/java/org/apache/cassandra/service/StorageService.java
Modified: cassandra/trunk/CHANGES.txt
URL:
http://svn.apache.org/viewvc/cassandra/trunk/CHANGES.txt?rev=1003060&r1=1003059&r2=1003060&view=diff
==============================================================================
--- cassandra/trunk/CHANGES.txt (original)
+++ cassandra/trunk/CHANGES.txt Thu Sep 30 13:35:26 2010
@@ -1,5 +1,6 @@
dev
* add strategy options to describe_keyspace output (CASSANDRA-1560)
+ * log warning when using randomly generated token (CASSANDRA-1552)
0.7-beta2
Modified: cassandra/trunk/src/java/org/apache/cassandra/db/SystemTable.java
URL:
http://svn.apache.org/viewvc/cassandra/trunk/src/java/org/apache/cassandra/db/SystemTable.java?rev=1003060&r1=1003059&r2=1003060&view=diff
==============================================================================
--- cassandra/trunk/src/java/org/apache/cassandra/db/SystemTable.java (original)
+++ cassandra/trunk/src/java/org/apache/cassandra/db/SystemTable.java Thu Sep
30 13:35:26 2010
@@ -59,7 +59,6 @@ public class SystemTable
private static final byte[] GENERATION = "Generation".getBytes(UTF_8);
private static final byte[] CLUSTERNAME = "ClusterName".getBytes(UTF_8);
private static final byte[] PARTITIONER = "Partioner".getBytes(UTF_8);
- private static StorageMetadata metadata;
private static DecoratedKey decorate(byte[] key)
{
@@ -110,7 +109,6 @@ public class SystemTable
*/
public static synchronized void updateToken(Token token)
{
- assert metadata != null;
IPartitioner p = StorageService.getPartitioner();
ColumnFamily cf = ColumnFamily.create(Table.SYSTEM_TABLE, STATUS_CF);
cf.addColumn(new Column(SystemTable.TOKEN,
p.getTokenFactory().toByteArray(token), new
TimestampClock(System.currentTimeMillis())));
@@ -124,7 +122,6 @@ public class SystemTable
{
throw new IOError(e);
}
- metadata.setToken(token);
}
/**
@@ -134,7 +131,7 @@ public class SystemTable
* 3. files are present but you can't read them: bad (suspect that the
partitioner was changed).
* @throws ConfigurationException
*/
- public static void checkHealth() throws ConfigurationException
+ public static void checkHealth() throws ConfigurationException, IOException
{
Table table = null;
try
@@ -150,9 +147,8 @@ public class SystemTable
}
SortedSet<byte[]> cols = new TreeSet<byte[]>(BytesType.instance);
- cols.add(TOKEN);
- cols.add(GENERATION);
cols.add(PARTITIONER);
+ cols.add(CLUSTERNAME);
QueryFilter filter =
QueryFilter.getNamesFilter(decorate(LOCATION_KEY), new QueryPath(STATUS_CF),
cols);
ColumnFamily cf =
table.getColumnFamilyStore(STATUS_CF).getColumnFamily(filter);
@@ -170,129 +166,62 @@ public class SystemTable
});
if (dbContents.length > 0)
throw new ConfigurationException("Found system table
files, but they couldn't be loaded. Did you change the partitioner?");
- }
- // no system files. data is either in the commit log or this is a
new node.
+ }
+
+ // no system files. this is a new node.
+ RowMutation rm = new RowMutation(Table.SYSTEM_TABLE, LOCATION_KEY);
+ cf = ColumnFamily.create(Table.SYSTEM_TABLE,
SystemTable.STATUS_CF);
+ cf.addColumn(new Column(PARTITIONER,
DatabaseDescriptor.getPartitioner().getClass().getName().getBytes(UTF_8), new
TimestampClock(FBUtilities.timestampMicros())));
+ cf.addColumn(new Column(CLUSTERNAME,
DatabaseDescriptor.getClusterName().getBytes(), new
TimestampClock(FBUtilities.timestampMicros())));
+ rm.add(cf);
+ rm.apply();
+
return;
}
- // token and generation should *always* be there. If either are
missing, we can assume that the partitioner has
- // been switched.
- if (cf.getColumnCount() > 0 && (cf.getColumn(GENERATION) == null ||
cf.getColumn(TOKEN) == null))
- throw new ConfigurationException("Couldn't read system generation
or token. Did you change the partitioner?");
IColumn partitionerCol = cf.getColumn(PARTITIONER);
- if (partitionerCol != null &&
!DatabaseDescriptor.getPartitioner().getClass().getName().equals(new
String(partitionerCol.value(), UTF_8)))
+ IColumn clusterCol = cf.getColumn(CLUSTERNAME);
+ assert partitionerCol != null;
+ assert clusterCol != null;
+ if
(!DatabaseDescriptor.getPartitioner().getClass().getName().equals(new
String(partitionerCol.value(), UTF_8)))
throw new ConfigurationException("Detected partitioner mismatch!
Did you change the partitioner?");
- if (partitionerCol == null)
- logger.info("Did not see a partitioner in system storage.");
+ if (!DatabaseDescriptor.getClusterName().equals(new
String(clusterCol.value())));
+ throw new ConfigurationException("Saved cluster name " + new
String(clusterCol.value()) + " != configured name " +
DatabaseDescriptor.getClusterName());
}
-
- /*
- * This method reads the system table and retrieves the metadata
- * associated with this storage instance. Currently we store the
- * metadata in a Column Family called LocatioInfo which has two
- * columns namely "Token" and "Generation". This is the token that
- * gets gossiped around and the generation info is used for FD.
- * We also store whether we're in bootstrap mode in a third column
- */
- public static synchronized StorageMetadata initMetadata() throws
IOException
+
+ public static Token getSavedToken()
{
- if (metadata != null) // guard to protect against being called twice
- return metadata;
+ Table table = Table.open(Table.SYSTEM_TABLE);
+ QueryFilter filter =
QueryFilter.getNamesFilter(decorate(LOCATION_KEY), new QueryPath(STATUS_CF),
TOKEN);
+ ColumnFamily cf =
table.getColumnFamilyStore(STATUS_CF).getColumnFamily(filter);
+ return cf == null ? null :
StorageService.getPartitioner().getTokenFactory().fromByteArray(cf.getColumn(TOKEN).value());
+ }
- /* Read the system table to retrieve the storage ID and the generation
*/
- IPartitioner p = StorageService.getPartitioner();
+ public static int incrementAndGetGeneration() throws IOException
+ {
Table table = Table.open(Table.SYSTEM_TABLE);
- SortedSet<byte[]> columns = new TreeSet<byte[]>(BytesType.instance);
- columns.add(TOKEN);
- columns.add(GENERATION);
- columns.add(CLUSTERNAME);
- QueryFilter filter =
QueryFilter.getNamesFilter(decorate(LOCATION_KEY), new QueryPath(STATUS_CF),
columns);
+ QueryFilter filter =
QueryFilter.getNamesFilter(decorate(LOCATION_KEY), new QueryPath(STATUS_CF),
TOKEN);
ColumnFamily cf =
table.getColumnFamilyStore(STATUS_CF).getColumnFamily(filter);
- String partitioner =
DatabaseDescriptor.getPartitioner().getClass().getName();
+ int generation;
if (cf == null)
{
- Token token;
- String initialToken = DatabaseDescriptor.getInitialToken();
- if (initialToken == null)
- token = p.getRandomToken();
- else
- token = p.getTokenFactory().fromString(initialToken);
-
- logger.info("Saved Token not found. Using " + token);
// seconds-since-epoch isn't a foolproof new generation
// (where foolproof is "guaranteed to be larger than the last one
seen at this ip address"),
// but it's as close as sanely possible
- int generation = (int) (System.currentTimeMillis() / 1000);
-
- logger.info("Saved ClusterName not found. Using " +
DatabaseDescriptor.getClusterName());
-
- RowMutation rm = new RowMutation(Table.SYSTEM_TABLE, LOCATION_KEY);
- cf = ColumnFamily.create(Table.SYSTEM_TABLE,
SystemTable.STATUS_CF);
- cf.addColumn(new Column(TOKEN,
p.getTokenFactory().toByteArray(token), TimestampClock.ZERO_VALUE));
- cf.addColumn(new Column(GENERATION,
FBUtilities.toByteArray(generation), TimestampClock.ZERO_VALUE));
- cf.addColumn(new Column(CLUSTERNAME,
DatabaseDescriptor.getClusterName().getBytes(), TimestampClock.ZERO_VALUE));
- cf.addColumn(new Column(PARTITIONER, partitioner.getBytes(UTF_8),
TimestampClock.ZERO_VALUE));
- rm.add(cf);
- rm.apply();
- try
- {
-
table.getColumnFamilyStore(SystemTable.STATUS_CF).forceBlockingFlush();
- }
- catch (ExecutionException e)
- {
- throw new RuntimeException(e);
- }
- catch (InterruptedException e)
- {
- throw new RuntimeException(e);
- }
- metadata = new StorageMetadata(token, generation,
DatabaseDescriptor.getClusterName().getBytes());
- return metadata;
- }
-
- if (cf.getColumnCount() < 2)
- throw new RuntimeException("Expected both token and generation
columns; found " + cf);
- /* we crashed and came back up: make sure new generation is greater
than old */
- IColumn tokenColumn = cf.getColumn(TOKEN);
- assert tokenColumn != null : cf;
- Token token = p.getTokenFactory().fromByteArray(tokenColumn.value());
- logger.info("Saved Token found: " + token);
-
- IColumn generation = cf.getColumn(GENERATION);
- assert generation != null : cf;
- int gen = Math.max(FBUtilities.byteArrayToInt(generation.value()) + 1,
(int) (System.currentTimeMillis() / 1000));
-
- IColumn cluster = cf.getColumn(CLUSTERNAME);
- IColumn partitionerColumn = cf.getColumn(PARTITIONER);
-
- RowMutation rm = new RowMutation(Table.SYSTEM_TABLE, LOCATION_KEY);
- cf = ColumnFamily.create(Table.SYSTEM_TABLE, SystemTable.STATUS_CF);
- TimestampClock genClock = new
TimestampClock(((TimestampClock)generation.clock()).timestamp() + 1);
- Column generation2 = new Column(GENERATION,
FBUtilities.toByteArray(gen), genClock);
- cf.addColumn(generation2);
- byte[] cname;
- if (cluster != null)
- {
- logger.info("Saved ClusterName found: " + new
String(cluster.value()));
- cname = cluster.value();
+ generation = (int) (System.currentTimeMillis() / 1000);
}
else
{
- Column clustername = new Column(CLUSTERNAME,
DatabaseDescriptor.getClusterName().getBytes(), TimestampClock.ZERO_VALUE);
- cf.addColumn(clustername);
- cname = DatabaseDescriptor.getClusterName().getBytes();
- logger.info("Saved ClusterName not found. Using " +
DatabaseDescriptor.getClusterName());
- }
-
- if (partitionerColumn == null)
- {
- Column c = new Column(PARTITIONER, partitioner.getBytes(UTF_8),
TimestampClock.ZERO_VALUE);
- cf.addColumn(c);
- logger.info("Saved partitioner not found. Using " + partitioner);
+ generation =
Math.max(FBUtilities.byteArrayToInt(cf.getColumn(GENERATION).value()) + 1,
+ (int) (System.currentTimeMillis() / 1000));
}
-
+
+ RowMutation rm = new RowMutation(Table.SYSTEM_TABLE, LOCATION_KEY);
+ cf = ColumnFamily.create(Table.SYSTEM_TABLE, SystemTable.STATUS_CF);
+ TimestampClock genClock = new
TimestampClock(FBUtilities.timestampMicros());
+ cf.addColumn(new Column(GENERATION,
FBUtilities.toByteArray(generation), genClock));
rm.add(cf);
rm.apply();
try
@@ -305,13 +234,12 @@ public class SystemTable
}
catch (InterruptedException e)
{
- throw new RuntimeException(e);
+ throw new AssertionError(e);
}
- metadata = new StorageMetadata(token, gen, cname);
- return metadata;
+ return generation;
}
-
+
public static boolean isBootstrapped()
{
Table table = Table.open(Table.SYSTEM_TABLE);
@@ -362,38 +290,4 @@ public class SystemTable
throw new IOError(e);
}
}
-
- public static class StorageMetadata
- {
- private Token token;
- private int generation;
- private byte[] cluster;
-
- StorageMetadata(Token storageId, int generation, byte[] clustername)
- {
- token = storageId;
- this.generation = generation;
- cluster = clustername;
- }
-
- public Token getToken()
- {
- return token;
- }
-
- public void setToken(Token storageId)
- {
- token = storageId;
- }
-
- public int getGeneration()
- {
- return generation;
- }
-
- public byte[] getClusterName()
- {
- return cluster;
- }
- }
}
Modified:
cassandra/trunk/src/java/org/apache/cassandra/service/StorageService.java
URL:
http://svn.apache.org/viewvc/cassandra/trunk/src/java/org/apache/cassandra/service/StorageService.java?rev=1003060&r1=1003059&r2=1003060&view=diff
==============================================================================
--- cassandra/trunk/src/java/org/apache/cassandra/service/StorageService.java
(original)
+++ cassandra/trunk/src/java/org/apache/cassandra/service/StorageService.java
Thu Sep 30 13:35:26 2010
@@ -50,7 +50,6 @@ import org.apache.cassandra.dht.Range;
import org.apache.cassandra.dht.Token;
import org.apache.cassandra.gms.*;
import org.apache.cassandra.io.DeletionService;
-import org.apache.cassandra.io.sstable.SSTableReader;
import org.apache.cassandra.io.util.FileUtils;
import org.apache.cassandra.locator.AbstractReplicationStrategy;
import org.apache.cassandra.locator.IEndpointSnitch;
@@ -159,7 +158,6 @@ public class StorageService implements I
/* This abstraction maintains the token/endpoint metadata information */
private TokenMetadata tokenMetadata_ = new TokenMetadata();
- private SystemTable.StorageMetadata storageMetadata_;
/* This thread pool does consistency checks when the client doesn't care
about consistency */
private ExecutorService consistencyManager_ = new
JMXEnabledThreadPoolExecutor(DatabaseDescriptor.getConsistencyThreads(),
@@ -340,15 +338,6 @@ public class StorageService implements I
}
initialized = true;
isClientMode = false;
- storageMetadata_ = SystemTable.initMetadata();
-
- // be certain that the recorded clustername matches what the user
specified
- if
(!(Arrays.equals(storageMetadata_.getClusterName(),DatabaseDescriptor.getClusterName().getBytes())))
- {
- logger_.error("ClusterName mismatch: " + new
String(storageMetadata_.getClusterName()) + " != " +
- DatabaseDescriptor.getClusterName());
- System.exit(3);
- }
DatabaseDescriptor.createAllDirectories();
@@ -368,7 +357,7 @@ public class StorageService implements I
// (we won't be part of the storage ring though until we add a nodeId
to our state, below.)
Gossiper.instance.register(this);
Gossiper.instance.register(migrationManager);
- Gossiper.instance.start(FBUtilities.getLocalAddress(),
storageMetadata_.getGeneration()); // needed for node-ring gathering.
+ Gossiper.instance.start(FBUtilities.getLocalAddress(),
SystemTable.incrementAndGetGeneration()); // needed for node-ring gathering.
MessagingService.instance.listen(FBUtilities.getLocalAddress());
StorageLoadBalancer.instance.startBroadcasting();
@@ -419,8 +408,23 @@ public class StorageService implements I
}
else
{
+ Token token = SystemTable.getSavedToken();
+ if (token == null)
+ {
+ String initialToken = DatabaseDescriptor.getInitialToken();
+ if (initialToken == null)
+ {
+ token = partitioner_.getRandomToken();
+ logger_.warn("Generated random token " + token + ". Random
tokens will result in an unbalanced ring; see
http://wiki.apache.org/cassandra/Operations");
+ }
+ else
+ {
+ token =
partitioner_.getTokenFactory().fromString(initialToken);
+ logger_.info("Saved Token not found. Using " + token + "
from configuration");
+ }
+ SystemTable.updateToken(token);
+ }
SystemTable.setBootstrapped(true);
- Token token = storageMetadata_.getToken();
tokenMetadata_.updateNormalToken(token,
FBUtilities.getLocalAddress());
Gossiper.instance.addLocalApplicationState(ApplicationState.STATUS,
valueFactory.normal(token));
setMode("Normal", false);
@@ -1109,7 +1113,9 @@ public class StorageService implements I
public Token getLocalToken()
{
- return storageMetadata_.getToken();
+ Token token = SystemTable.getSavedToken();
+ assert token != null; // should not be called before initServer sets
this
+ return token;
}
/* These methods belong to the MBean interface */