migration support for virtual nodes Patch by Sam Overton; reviewed by Brandon Williams for CASSANDRA-4127
Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/201fe944 Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/201fe944 Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/201fe944 Branch: refs/heads/cassandra-1.1 Commit: 201fe94413db0125d73e01afff45fa6bd7b295a0 Parents: 4f9fd76 Author: Eric Evans <[email protected]> Authored: Wed Jul 18 13:47:39 2012 -0500 Committer: Eric Evans <[email protected]> Committed: Wed Jul 18 13:47:39 2012 -0500 ---------------------------------------------------------------------- .../apache/cassandra/service/StorageService.java | 53 ++++++++++++++- 1 files changed, 52 insertions(+), 1 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cassandra/blob/201fe944/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 b5d6d20..621b06b 100644 --- a/src/java/org/apache/cassandra/service/StorageService.java +++ b/src/java/org/apache/cassandra/service/StorageService.java @@ -621,7 +621,58 @@ public class StorageService implements IEndpointStateChangeSubscriber, StorageSe } else { - logger.info("Using saved token " + tokens); + // if we were already bootstrapped with 1 token but num_tokens is set higher in the config, + // then we need to migrate to multi-token + if (tokens.size() == 1 && DatabaseDescriptor.getNumTokens() > 1) + { + // wait for ring info + logger.info("Sleeping for ring delay (" + delay + "ms)"); + try + { + Thread.sleep(delay); + } + catch (InterruptedException e) + { + throw new AssertionError(e); + } + logger.info("Calculating new tokens"); + // calculate num_tokens tokens evenly spaced in the range (left, right] + Token right = tokens.iterator().next(); + TokenMetadata clone = tokenMetadata.cloneOnlyTokenMap(); + clone.updateNormalToken(right, FBUtilities.getBroadcastAddress()); + Token left = clone.getPredecessor(right); + + // get (num_tokens - 1) tokens spaced evenly, and the last token will be our current token (right) + for (int tok = 1; tok < DatabaseDescriptor.getNumTokens(); ++tok) + { + Token l = left; + Token r = right; + // iteratively calculate the location of the token using midpoint + // num iterations is number of bits in IEE754 mantissa (including implicit leading 1) + // we stop early for terminating fractions + // TODO: alternatively we could add an interpolate() method to IPartitioner + double frac = (double)tok / (double)DatabaseDescriptor.getNumTokens(); + Token midpoint = getPartitioner().midpoint(l, r); + for (int i = 0; i < 53; ++i) + { + frac *= 2; + if (frac == 1.0) /* not a bug */ + break; + else if (frac > 1.0) + { + l = midpoint; + frac -= 1.0; + } + else + r = midpoint; + midpoint = getPartitioner().midpoint(l, r); + } + tokens.add(midpoint); + } + logger.info("Split previous range (" + left + ", " + right + "] into " + tokens); + } + else + logger.info("Using saved token " + tokens); } }
