mirror of https://github.com/apache/cassandra
Use node's host id in place of counter ids
patch by Aleksey Yeschenko; reviewed by Sylvain Lebresne for CASSANDRA-7366
This commit is contained in:
parent
5fe7557627
commit
99594cd687
|
|
@ -1,4 +1,5 @@
|
|||
2.1.0
|
||||
* Use node's host id in place of counter ids (CASSANDRA-7366)
|
||||
* Explicitly use Long.MAX_VALUE timestamp for counter deletions
|
||||
(CASSANDRA-7346)
|
||||
* Fix native protocol CAS batches (CASSANDRA-7337)
|
||||
|
|
|
|||
|
|
@ -144,12 +144,6 @@ public final class CFMetaData
|
|||
+ "PRIMARY KEY (table_name, index_name)"
|
||||
+ ") WITH COMPACT STORAGE AND COMMENT='indexes that have been completed'");
|
||||
|
||||
public static final CFMetaData CounterIdCf = compile("CREATE TABLE \"" + SystemKeyspace.COUNTER_ID_CF + "\" ("
|
||||
+ "key text,"
|
||||
+ "id timeuuid,"
|
||||
+ "PRIMARY KEY (key, id)"
|
||||
+ ") WITH COMPACT STORAGE AND COMMENT='counter node IDs'");
|
||||
|
||||
public static final CFMetaData SchemaKeyspacesCf = compile("CREATE TABLE " + SystemKeyspace.SCHEMA_KEYSPACES_CF + " ("
|
||||
+ "keyspace_name text PRIMARY KEY,"
|
||||
+ "durable_writes boolean,"
|
||||
|
|
|
|||
|
|
@ -96,7 +96,6 @@ public final class KSMetaData
|
|||
CFMetaData.PeerEventsCf,
|
||||
CFMetaData.HintsCf,
|
||||
CFMetaData.IndexCf,
|
||||
CFMetaData.CounterIdCf,
|
||||
CFMetaData.SchemaKeyspacesCf,
|
||||
CFMetaData.SchemaColumnFamiliesCf,
|
||||
CFMetaData.SchemaColumnsCf,
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@ import com.google.common.collect.HashMultimap;
|
|||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.SetMultimap;
|
||||
import com.google.common.collect.Sets;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
|
@ -44,7 +43,6 @@ import org.apache.cassandra.db.columniterator.IdentityQueryFilter;
|
|||
import org.apache.cassandra.db.compaction.CompactionHistoryTabularData;
|
||||
import org.apache.cassandra.db.commitlog.ReplayPosition;
|
||||
import org.apache.cassandra.db.composites.Composite;
|
||||
import org.apache.cassandra.db.composites.Composites;
|
||||
import org.apache.cassandra.db.filter.QueryFilter;
|
||||
import org.apache.cassandra.db.marshal.*;
|
||||
import org.apache.cassandra.dht.Range;
|
||||
|
|
@ -73,7 +71,6 @@ public class SystemKeyspace
|
|||
public static final String PEER_EVENTS_CF = "peer_events";
|
||||
public static final String LOCAL_CF = "local";
|
||||
public static final String INDEX_CF = "IndexInfo";
|
||||
public static final String COUNTER_ID_CF = "NodeIdInfo";
|
||||
public static final String HINTS_CF = "hints";
|
||||
public static final String RANGE_XFERS_CF = "range_xfers";
|
||||
public static final String BATCHLOG_CF = "batchlog";
|
||||
|
|
@ -89,7 +86,6 @@ public class SystemKeyspace
|
|||
public static final String COMPACTION_HISTORY_CF = "compaction_history";
|
||||
|
||||
private static final String LOCAL_KEY = "local";
|
||||
private static final ByteBuffer ALL_LOCAL_NODE_ID_KEY = ByteBufferUtil.bytes("Local");
|
||||
|
||||
public static final List<String> allSchemaCfs = Arrays.asList(SCHEMA_KEYSPACES_CF,
|
||||
SCHEMA_COLUMNFAMILIES_CF,
|
||||
|
|
@ -688,19 +684,15 @@ public class SystemKeyspace
|
|||
*/
|
||||
public static UUID getLocalHostId()
|
||||
{
|
||||
UUID hostId = null;
|
||||
|
||||
String req = "SELECT host_id FROM system.%s WHERE key='%s'";
|
||||
UntypedResultSet result = executeInternal(String.format(req, LOCAL_CF, LOCAL_KEY));
|
||||
|
||||
// Look up the Host UUID (return it if found)
|
||||
if (!result.isEmpty() && result.one().has("host_id"))
|
||||
{
|
||||
return result.one().getUUID("host_id");
|
||||
}
|
||||
|
||||
// ID not found, generate a new one, persist, and then return it.
|
||||
hostId = UUID.randomUUID();
|
||||
UUID hostId = UUID.randomUUID();
|
||||
logger.warn("No host ID found, created {} (Note: This should happen exactly once per node).", hostId);
|
||||
return setLocalHostId(hostId);
|
||||
}
|
||||
|
|
@ -715,45 +707,6 @@ public class SystemKeyspace
|
|||
return hostId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the current local node id from the system keyspace or null if no
|
||||
* such node id is recorded.
|
||||
*/
|
||||
public static CounterId getCurrentLocalCounterId()
|
||||
{
|
||||
Keyspace keyspace = Keyspace.open(Keyspace.SYSTEM_KS);
|
||||
|
||||
// Get the last CounterId (since CounterId are timeuuid is thus ordered from the older to the newer one)
|
||||
QueryFilter filter = QueryFilter.getSliceFilter(decorate(ALL_LOCAL_NODE_ID_KEY),
|
||||
COUNTER_ID_CF,
|
||||
Composites.EMPTY,
|
||||
Composites.EMPTY,
|
||||
true,
|
||||
1,
|
||||
System.currentTimeMillis());
|
||||
ColumnFamily cf = keyspace.getColumnFamilyStore(COUNTER_ID_CF).getColumnFamily(filter);
|
||||
if (cf != null && cf.hasColumns())
|
||||
return CounterId.wrap(cf.iterator().next().name().toByteBuffer());
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a new current local node id to the system keyspace.
|
||||
*
|
||||
* @param newCounterId the new current local node id to record
|
||||
* @param now microsecond time stamp.
|
||||
*/
|
||||
public static void writeCurrentLocalCounterId(CounterId newCounterId, long now)
|
||||
{
|
||||
ByteBuffer ip = ByteBuffer.wrap(FBUtilities.getBroadcastAddress().getAddress());
|
||||
|
||||
ColumnFamily cf = ArrayBackedSortedColumns.factory.create(Keyspace.SYSTEM_KS, COUNTER_ID_CF);
|
||||
cf.addColumn(new BufferCell(cf.getComparator().makeCellName(newCounterId.bytes()), ip, now));
|
||||
new Mutation(Keyspace.SYSTEM_KS, ALL_LOCAL_NODE_ID_KEY, cf).apply();
|
||||
forceBlockingFlush(COUNTER_ID_CF);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param cfName The name of the ColumnFamily responsible for part of the schema (keyspace, ColumnFamily, columns)
|
||||
* @return CFS responsible to hold low-level serialized schema
|
||||
|
|
|
|||
|
|
@ -560,17 +560,6 @@ public class StorageService extends NotificationBroadcasterSupport implements IE
|
|||
}
|
||||
}
|
||||
|
||||
if (Boolean.parseBoolean(System.getProperty("cassandra.renew_counter_id", "false")))
|
||||
{
|
||||
logger.info("Renewing local node id (as requested)");
|
||||
CounterId.renewLocalId();
|
||||
}
|
||||
|
||||
// Can't do this in CassandraDaemon before the SS start b/c local counter id can be renewed afterwards.
|
||||
for (ColumnFamilyStore cfs : ColumnFamilyStore.all())
|
||||
if (cfs.metadata.isCounter())
|
||||
cfs.initCounterCache();
|
||||
|
||||
// daemon threads, like our executors', continue to run while shutdown hooks are invoked
|
||||
Thread drainOnShutdown = new Thread(new WrappedRunnable()
|
||||
{
|
||||
|
|
@ -626,6 +615,12 @@ public class StorageService extends NotificationBroadcasterSupport implements IE
|
|||
Runtime.getRuntime().addShutdownHook(drainOnShutdown);
|
||||
|
||||
prepareToJoin();
|
||||
|
||||
// Has to be called after the host id has potentially changed in prepareToJoin().
|
||||
for (ColumnFamilyStore cfs : ColumnFamilyStore.all())
|
||||
if (cfs.metadata.isCounter())
|
||||
cfs.initCounterCache();
|
||||
|
||||
if (Boolean.parseBoolean(System.getProperty("cassandra.join_ring", "true")))
|
||||
{
|
||||
joinTokenRing(delay);
|
||||
|
|
|
|||
|
|
@ -20,15 +20,10 @@ package org.apache.cassandra.utils;
|
|||
import java.nio.ByteBuffer;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.apache.cassandra.db.SystemKeyspace;
|
||||
|
||||
public class CounterId implements Comparable<CounterId>
|
||||
{
|
||||
private static final Logger logger = LoggerFactory.getLogger(CounterId.class);
|
||||
|
||||
public static final int LENGTH = 16; // we assume a fixed length size for all CounterIds
|
||||
|
||||
// Lazy holder because this opens the system keyspace and we want to avoid
|
||||
|
|
@ -50,16 +45,6 @@ public class CounterId implements Comparable<CounterId>
|
|||
return localId().get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Renew the local counter id.
|
||||
* To use only when this strictly necessary, as using this will make all
|
||||
* counter context grow with time.
|
||||
*/
|
||||
public static synchronized void renewLocalId()
|
||||
{
|
||||
localId().renew(FBUtilities.timestampMicros());
|
||||
}
|
||||
|
||||
/**
|
||||
* Function for test purposes, do not use otherwise.
|
||||
* Pack an int in a valid CounterId so that the resulting ids respects the
|
||||
|
|
@ -150,28 +135,7 @@ public class CounterId implements Comparable<CounterId>
|
|||
|
||||
LocalCounterIdHolder()
|
||||
{
|
||||
CounterId id = SystemKeyspace.getCurrentLocalCounterId();
|
||||
|
||||
if (id == null)
|
||||
{
|
||||
// no recorded local counter id, generating a new one and saving it
|
||||
id = generate();
|
||||
logger.info("No saved local counter id, using newly generated: {}", id);
|
||||
SystemKeyspace.writeCurrentLocalCounterId(id, FBUtilities.timestampMicros());
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.info("Using saved local counter id: {}", id);
|
||||
}
|
||||
|
||||
current = new AtomicReference<>(id);
|
||||
}
|
||||
|
||||
synchronized void renew(long now)
|
||||
{
|
||||
CounterId newCounterId = generate();
|
||||
SystemKeyspace.writeCurrentLocalCounterId(newCounterId, now);
|
||||
current.set(newCounterId);
|
||||
current = new AtomicReference<>(wrap(ByteBufferUtil.bytes(SystemKeyspace.getLocalHostId())));
|
||||
}
|
||||
|
||||
CounterId get()
|
||||
|
|
|
|||
|
|
@ -1,49 +0,0 @@
|
|||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.cassandra.utils;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.cassandra.SchemaLoader;
|
||||
import org.apache.cassandra.db.SystemKeyspace;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class CounterIdTest extends SchemaLoader
|
||||
{
|
||||
@Test
|
||||
public void testGetCurrentIdFromSystemKeyspace()
|
||||
{
|
||||
// Renewing a bunch of times and checking we get the same thing from
|
||||
// the system keyspace that what is in memory
|
||||
CounterId id0 = CounterId.getLocalId();
|
||||
assertEquals(id0, SystemKeyspace.getCurrentLocalCounterId());
|
||||
|
||||
CounterId.renewLocalId();
|
||||
CounterId id1 = CounterId.getLocalId();
|
||||
assertEquals(id1, SystemKeyspace.getCurrentLocalCounterId());
|
||||
assertTrue(id1.compareTo(id0) == 1);
|
||||
|
||||
CounterId.renewLocalId();
|
||||
CounterId id2 = CounterId.getLocalId();
|
||||
assertEquals(id2, SystemKeyspace.getCurrentLocalCounterId());
|
||||
assertTrue(id2.compareTo(id1) == 1);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue