Serialize batchlog mutations with the version of the target node

patch by Aleksey Yeschenko; reviewed by Sylvain Lebresne for
CASSANDRA-6931
This commit is contained in:
Aleksey Yeschenko 2014-03-31 13:09:36 +03:00
parent f6daf4e307
commit b7ac8f96c1
5 changed files with 50 additions and 44 deletions

View File

@ -33,7 +33,7 @@ New features
Upgrading Upgrading
--------- ---------
- Rolling upgrades from anything pre-2.0.6 is not supported. - Rolling upgrade from anything pre-2.0.7 is not supported.
- For leveled compaction users, 2.0 must be atleast started before - For leveled compaction users, 2.0 must be atleast started before
upgrading to 2.1 due to the fact that the old JSON leveled upgrading to 2.1 due to the fact that the old JSON leveled
manifest is migrated into the sstable metadata files on startup manifest is migrated into the sstable metadata files on startup

View File

@ -44,9 +44,7 @@ import org.apache.cassandra.config.CFMetaData;
import org.apache.cassandra.config.DatabaseDescriptor; import org.apache.cassandra.config.DatabaseDescriptor;
import org.apache.cassandra.cql3.QueryProcessor; import org.apache.cassandra.cql3.QueryProcessor;
import org.apache.cassandra.cql3.UntypedResultSet; import org.apache.cassandra.cql3.UntypedResultSet;
import org.apache.cassandra.db.composites.CellName;
import org.apache.cassandra.db.compaction.CompactionManager; import org.apache.cassandra.db.compaction.CompactionManager;
import org.apache.cassandra.db.marshal.LongType;
import org.apache.cassandra.db.marshal.UUIDType; import org.apache.cassandra.db.marshal.UUIDType;
import org.apache.cassandra.dht.Token; import org.apache.cassandra.dht.Token;
import org.apache.cassandra.exceptions.WriteTimeoutException; import org.apache.cassandra.exceptions.WriteTimeoutException;
@ -121,26 +119,23 @@ public class BatchlogManager implements BatchlogManagerMBean
batchlogTasks.execute(runnable); batchlogTasks.execute(runnable);
} }
public static Mutation getBatchlogMutationFor(Collection<Mutation> mutations, UUID uuid) public static Mutation getBatchlogMutationFor(Collection<Mutation> mutations, UUID uuid, int version)
{ {
return getBatchlogMutationFor(mutations, uuid, FBUtilities.timestampMicros()); return getBatchlogMutationFor(mutations, uuid, version, FBUtilities.timestampMicros());
} }
@VisibleForTesting @VisibleForTesting
static Mutation getBatchlogMutationFor(Collection<Mutation> mutations, UUID uuid, long now) static Mutation getBatchlogMutationFor(Collection<Mutation> mutations, UUID uuid, int version, long now)
{ {
ByteBuffer writtenAt = LongType.instance.decompose(now / 1000);
ByteBuffer data = serializeMutations(mutations);
ColumnFamily cf = ArrayBackedSortedColumns.factory.create(CFMetaData.BatchlogCf); ColumnFamily cf = ArrayBackedSortedColumns.factory.create(CFMetaData.BatchlogCf);
cf.addColumn(new Cell(cellName(""), ByteBufferUtil.EMPTY_BYTE_BUFFER, now)); CFRowAdder adder = new CFRowAdder(cf, CFMetaData.BatchlogCf.comparator.builder().build(), now);
cf.addColumn(new Cell(cellName("data"), data, now)); adder.add("data", serializeMutations(mutations, version))
cf.addColumn(new Cell(cellName("written_at"), writtenAt, now)); .add("written_at", new Date(now / 1000))
.add("version", version);
return new Mutation(Keyspace.SYSTEM_KS, UUIDType.instance.decompose(uuid), cf); return new Mutation(Keyspace.SYSTEM_KS, UUIDType.instance.decompose(uuid), cf);
} }
private static ByteBuffer serializeMutations(Collection<Mutation> mutations) private static ByteBuffer serializeMutations(Collection<Mutation> mutations, int version)
{ {
DataOutputBuffer buf = new DataOutputBuffer(); DataOutputBuffer buf = new DataOutputBuffer();
@ -148,7 +143,7 @@ public class BatchlogManager implements BatchlogManagerMBean
{ {
buf.writeInt(mutations.size()); buf.writeInt(mutations.size());
for (Mutation mutation : mutations) for (Mutation mutation : mutations)
Mutation.serializer.serialize(mutation, buf, MessagingService.VERSION_12); Mutation.serializer.serialize(mutation, buf, version);
} }
catch (IOException e) catch (IOException e)
{ {
@ -331,11 +326,6 @@ public class BatchlogManager implements BatchlogManagerMBean
return (int) ((HintedHandOffManager.calculateHintTTL(mutation) * 1000 - (System.currentTimeMillis() - writtenAt)) / 1000); return (int) ((HintedHandOffManager.calculateHintTTL(mutation) * 1000 - (System.currentTimeMillis() - writtenAt)) / 1000);
} }
private static CellName cellName(String name)
{
return CFMetaData.BatchlogCf.comparator.makeCellName(name);
}
// force flush + compaction to reclaim space from the replayed batches // force flush + compaction to reclaim space from the replayed batches
private void cleanup() throws ExecutionException, InterruptedException private void cleanup() throws ExecutionException, InterruptedException
{ {

View File

@ -70,9 +70,9 @@ public final class MessagingService implements MessagingServiceMBean
public static final String MBEAN_NAME = "org.apache.cassandra.net:type=MessagingService"; public static final String MBEAN_NAME = "org.apache.cassandra.net:type=MessagingService";
// 8 bits version, so don't waste versions // 8 bits version, so don't waste versions
public static final int VERSION_12 = 6; public static final int VERSION_12 = 6;
public static final int VERSION_20 = 7; public static final int VERSION_20 = 7;
public static final int VERSION_21 = 8; public static final int VERSION_21 = 8;
public static final int current_version = VERSION_21; public static final int current_version = VERSION_21;
/** /**

View File

@ -607,40 +607,53 @@ public class StorageProxy implements StorageProxyMBean
Keyspace.open(Keyspace.SYSTEM_KS), Keyspace.open(Keyspace.SYSTEM_KS),
null, null,
WriteType.BATCH_LOG); WriteType.BATCH_LOG);
updateBatchlog(BatchlogManager.getBatchlogMutationFor(mutations, uuid), endpoints, handler);
MessageOut<Mutation> message = BatchlogManager.getBatchlogMutationFor(mutations, uuid, MessagingService.current_version)
.createMessage();
for (InetAddress target : endpoints)
{
int targetVersion = MessagingService.instance().getVersion(target);
if (target.equals(FBUtilities.getBroadcastAddress()) && OPTIMIZE_LOCAL_REQUESTS)
{
insertLocal(message.payload, handler);
}
else if (targetVersion == MessagingService.current_version)
{
MessagingService.instance().sendRR(message, target, handler);
}
else
{
MessagingService.instance().sendRR(BatchlogManager.getBatchlogMutationFor(mutations, uuid, targetVersion)
.createMessage(),
target,
handler);
}
}
handler.get(); handler.get();
} }
private static void asyncRemoveFromBatchlog(Collection<InetAddress> endpoints, UUID uuid) private static void asyncRemoveFromBatchlog(Collection<InetAddress> endpoints, UUID uuid)
{ {
ColumnFamily cf = ArrayBackedSortedColumns.factory.create(Schema.instance.getCFMetaData(Keyspace.SYSTEM_KS, SystemKeyspace.BATCHLOG_CF));
cf.delete(new DeletionInfo(FBUtilities.timestampMicros(), (int) (System.currentTimeMillis() / 1000)));
AbstractWriteResponseHandler handler = new WriteResponseHandler(endpoints, AbstractWriteResponseHandler handler = new WriteResponseHandler(endpoints,
Collections.<InetAddress>emptyList(), Collections.<InetAddress>emptyList(),
ConsistencyLevel.ANY, ConsistencyLevel.ANY,
Keyspace.open(Keyspace.SYSTEM_KS), Keyspace.open(Keyspace.SYSTEM_KS),
null, null,
WriteType.SIMPLE); WriteType.SIMPLE);
updateBatchlog(new Mutation(Keyspace.SYSTEM_KS, UUIDType.instance.decompose(uuid), cf), endpoints, handler); Mutation mutation = new Mutation(Keyspace.SYSTEM_KS, UUIDType.instance.decompose(uuid));
} mutation.delete(SystemKeyspace.BATCHLOG_CF, FBUtilities.timestampMicros());
MessageOut<Mutation> message = mutation.createMessage();
private static void updateBatchlog(Mutation mutation, Collection<InetAddress> endpoints, AbstractWriteResponseHandler handler) for (InetAddress target : endpoints)
{
if (endpoints.contains(FBUtilities.getBroadcastAddress()))
{ {
assert endpoints.size() == 1; if (target.equals(FBUtilities.getBroadcastAddress()) && OPTIMIZE_LOCAL_REQUESTS)
insertLocal(mutation, handler); insertLocal(message.payload, handler);
} else
else
{
MessageOut<Mutation> message = mutation.createMessage();
for (InetAddress target : endpoints)
MessagingService.instance().sendRR(message, target, handler); MessagingService.instance().sendRR(message, target, handler);
} }
} }
private static void syncWriteBatchedMutations(List<WriteResponseHandlerWrapper> wrappers, private static void syncWriteBatchedMutations(List<WriteResponseHandlerWrapper> wrappers, String localDataCenter)
String localDataCenter)
throws WriteTimeoutException, OverloadedException throws WriteTimeoutException, OverloadedException
{ {
for (WriteResponseHandlerWrapper wrapper : wrappers) for (WriteResponseHandlerWrapper wrapper : wrappers)
@ -650,9 +663,7 @@ public class StorageProxy implements StorageProxyMBean
} }
for (WriteResponseHandlerWrapper wrapper : wrappers) for (WriteResponseHandlerWrapper wrapper : wrappers)
{
wrapper.handler.get(); wrapper.handler.get();
}
} }
/** /**

View File

@ -30,6 +30,7 @@ import org.apache.cassandra.cql3.QueryProcessor;
import org.apache.cassandra.cql3.UntypedResultSet; import org.apache.cassandra.cql3.UntypedResultSet;
import org.apache.cassandra.db.composites.CellNameType; import org.apache.cassandra.db.composites.CellNameType;
import org.apache.cassandra.locator.TokenMetadata; import org.apache.cassandra.locator.TokenMetadata;
import org.apache.cassandra.net.MessagingService;
import org.apache.cassandra.service.StorageService; import org.apache.cassandra.service.StorageService;
import org.apache.cassandra.utils.UUIDGen; import org.apache.cassandra.utils.UUIDGen;
@ -66,7 +67,11 @@ public class BatchlogManagerTest extends SchemaLoader
long timestamp = System.currentTimeMillis(); long timestamp = System.currentTimeMillis();
if (i < 500) if (i < 500)
timestamp -= DatabaseDescriptor.getWriteRpcTimeout() * 2; timestamp -= DatabaseDescriptor.getWriteRpcTimeout() * 2;
BatchlogManager.getBatchlogMutationFor(Collections.singleton(mutation), UUIDGen.getTimeUUID(), timestamp * 1000).apply(); BatchlogManager.getBatchlogMutationFor(Collections.singleton(mutation),
UUIDGen.getTimeUUID(),
MessagingService.current_version,
timestamp * 1000)
.apply();
} }
assertEquals(1000, BatchlogManager.instance.countAllBatches()); assertEquals(1000, BatchlogManager.instance.countAllBatches());