This is an automated email from the ASF dual-hosted git repository. benedict pushed a commit to branch burn-test-stability in repository https://gitbox.apache.org/repos/asf/cassandra.git
commit 64451dde91fcb17784bec7507192aee4a862b015 Author: Benedict Elliott Smith <[email protected]> AuthorDate: Fri Aug 2 15:46:53 2024 +0100 burn test stability: wip --- .gitmodules | 2 +- modules/accord | 2 +- .../service/accord/AccordConfigurationService.java | 1 + .../service/accord/AccordFetchCoordinator.java | 6 +++- .../service/accord/AccordObjectSizes.java | 16 +++++----- .../service/accord/api/AccordTopologySorter.java | 3 +- .../accord/serializers/CommandSerializers.java | 6 +--- .../service/accord/serializers/DepsSerializer.java | 8 ++--- .../service/accord/serializers/KeySerializers.java | 36 ++++++---------------- .../accord/serializers/TopologySerializers.java | 4 ++- .../cassandra/service/accord/txn/TxnRead.java | 16 ++++++++-- .../cassandra/service/accord/txn/TxnUpdate.java | 9 ++++++ .../accord/txn/UnrecoverableRepairUpdate.java | 7 +++++ .../cassandra/utils/CollectionSerializers.java | 11 +++++++ 14 files changed, 75 insertions(+), 52 deletions(-) diff --git a/.gitmodules b/.gitmodules index fc9b7c0807..c35fa2db30 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,4 @@ [submodule "modules/accord"] path = modules/accord url = https://github.com/belliottsmith/cassandra-accord.git - branch = exclusive-sync-point-fix + branch = burn-test-stability diff --git a/modules/accord b/modules/accord index 1c8b89da1f..ce6e7a514d 160000 --- a/modules/accord +++ b/modules/accord @@ -1 +1 @@ -Subproject commit 1c8b89da1fe6afd4f8691b8fe8328091055dedc2 +Subproject commit ce6e7a514de1d4b6ad1c290df423b831664fd535 diff --git a/src/java/org/apache/cassandra/service/accord/AccordConfigurationService.java b/src/java/org/apache/cassandra/service/accord/AccordConfigurationService.java index 1e6cb1d769..a990f1b591 100644 --- a/src/java/org/apache/cassandra/service/accord/AccordConfigurationService.java +++ b/src/java/org/apache/cassandra/service/accord/AccordConfigurationService.java @@ -25,6 +25,7 @@ import java.util.stream.Collectors; import javax.annotation.Nullable; import com.google.common.annotations.VisibleForTesting; +import com.google.common.collect.ImmutableSortedSet; import com.google.common.collect.Sets; import accord.impl.AbstractConfigurationService; diff --git a/src/java/org/apache/cassandra/service/accord/AccordFetchCoordinator.java b/src/java/org/apache/cassandra/service/accord/AccordFetchCoordinator.java index 088c6c1331..e4ad2aa559 100644 --- a/src/java/org/apache/cassandra/service/accord/AccordFetchCoordinator.java +++ b/src/java/org/apache/cassandra/service/accord/AccordFetchCoordinator.java @@ -35,6 +35,7 @@ import accord.local.CommandStore; import accord.local.Node; import accord.local.SafeCommandStore; import accord.primitives.PartialTxn; +import accord.primitives.Participants; import accord.primitives.Range; import accord.primitives.Ranges; import accord.primitives.Routable; @@ -290,6 +291,9 @@ public class AccordFetchCoordinator extends AbstractFetchCoordinator implements @Override public Read slice(Ranges ranges) { return new StreamingRead(to, this.ranges.slice(ranges)); } + @Override + public Read intersecting(Participants<?> participants) { return new StreamingRead(to, this.ranges.intersecting(ranges)); } + @Override public Read merge(Read other) { throw new UnsupportedOperationException(); } } @@ -383,7 +387,7 @@ public class AccordFetchCoordinator extends AbstractFetchCoordinator implements protected PartialTxn rangeReadTxn(Ranges ranges) { StreamingRead read = new StreamingRead(FBUtilities.getBroadcastAddressAndPort(), ranges); - return new PartialTxn.InMemory(ranges, Txn.Kind.Read, ranges, read, noopQuery, null); + return new PartialTxn.InMemory(Txn.Kind.Read, ranges, read, noopQuery, null); } @Override diff --git a/src/java/org/apache/cassandra/service/accord/AccordObjectSizes.java b/src/java/org/apache/cassandra/service/accord/AccordObjectSizes.java index d3cd7a34fd..46e0d8c158 100644 --- a/src/java/org/apache/cassandra/service/accord/AccordObjectSizes.java +++ b/src/java/org/apache/cassandra/service/accord/AccordObjectSizes.java @@ -137,7 +137,7 @@ public class AccordObjectSizes return EMPTY_ROUTING_KEYS_SIZE + routingKeysOnly(keys); } - private static final long EMPTY_FULL_KEY_ROUTE_SIZE = measure(new FullKeyRoute(new TokenKey(null, null), true, new RoutingKey[0])); + private static final long EMPTY_FULL_KEY_ROUTE_SIZE = measure(new FullKeyRoute(new TokenKey(null, null), new RoutingKey[0])); public static long fullKeyRoute(FullKeyRoute route) { return EMPTY_FULL_KEY_ROUTE_SIZE @@ -145,12 +145,11 @@ public class AccordObjectSizes + key(route.homeKey()); // TODO: we will probably dedup homeKey, serializer dependent, but perhaps this is an acceptable error } - private static final long EMPTY_PARTIAL_KEY_ROUTE_KEYS_SIZE = measure(new PartialKeyRoute(Ranges.EMPTY, new TokenKey(null, null), true, new RoutingKey[0])); + private static final long EMPTY_PARTIAL_KEY_ROUTE_KEYS_SIZE = measure(new PartialKeyRoute(new TokenKey(null, null), new RoutingKey[0])); public static long partialKeyRoute(PartialKeyRoute route) { return EMPTY_PARTIAL_KEY_ROUTE_KEYS_SIZE + routingKeysOnly(route) - + ranges(route.covering()) + key(route.homeKey()); } @@ -162,7 +161,7 @@ public class AccordObjectSizes return size; } - private static final long EMPTY_FULL_RANGE_ROUTE_SIZE = measure(new FullRangeRoute(new TokenKey(null, null), true, new Range[0])); + private static final long EMPTY_FULL_RANGE_ROUTE_SIZE = measure(new FullRangeRoute(new TokenKey(null, null), new Range[0])); public static long fullRangeRoute(FullRangeRoute route) { return EMPTY_FULL_RANGE_ROUTE_SIZE @@ -170,12 +169,11 @@ public class AccordObjectSizes + key(route.homeKey()); // TODO: we will probably dedup homeKey, serializer dependent, but perhaps this is an acceptable error } - private static final long EMPTY_PARTIAL_RANGE_ROUTE_KEYS_SIZE = measure(new PartialRangeRoute(Ranges.EMPTY, new TokenKey(null, null), true, new Range[0])); + private static final long EMPTY_PARTIAL_RANGE_ROUTE_KEYS_SIZE = measure(new PartialRangeRoute(new TokenKey(null, null), new Range[0])); public static long partialRangeRoute(PartialRangeRoute route) { return EMPTY_PARTIAL_RANGE_ROUTE_KEYS_SIZE + rangesOnly(route) - + ranges(route.covering()) + key(route.homeKey()); } @@ -193,7 +191,7 @@ public class AccordObjectSizes } } - private static final long EMPTY_TXN = measure(new PartialTxn.InMemory(null, null, null, null, null, null)); + private static final long EMPTY_TXN = measure(new PartialTxn.InMemory(null, null, null, null, null)); public static long txn(PartialTxn txn) { long size = EMPTY_TXN; @@ -283,13 +281,13 @@ public class AccordObjectSizes private static CommonAttributes attrs(boolean hasDeps, boolean hasTxn) { - CommonAttributes.Mutable attrs = new CommonAttributes.Mutable(EMPTY_TXNID).route(new FullKeyRoute(EMPTY_KEY, true, new RoutingKey[]{ EMPTY_KEY })); + CommonAttributes.Mutable attrs = new CommonAttributes.Mutable(EMPTY_TXNID).route(new FullKeyRoute(EMPTY_KEY, new RoutingKey[]{ EMPTY_KEY })); attrs.durability(Status.Durability.NotDurable); if (hasDeps) attrs.partialDeps(PartialDeps.NONE); if (hasTxn) - attrs.partialTxn(new PartialTxn.InMemory(null, null, null, null, null, null)); + attrs.partialTxn(new PartialTxn.InMemory(null, null, null, null, null)); return attrs; } diff --git a/src/java/org/apache/cassandra/service/accord/api/AccordTopologySorter.java b/src/java/org/apache/cassandra/service/accord/api/AccordTopologySorter.java index cbc46ef9a0..7d1ab21224 100644 --- a/src/java/org/apache/cassandra/service/accord/api/AccordTopologySorter.java +++ b/src/java/org/apache/cassandra/service/accord/api/AccordTopologySorter.java @@ -27,6 +27,7 @@ import accord.local.Node; import accord.topology.ShardSelection; import accord.topology.Topologies; import accord.topology.Topology; +import accord.utils.SortedList; import org.apache.cassandra.locator.DynamicEndpointSnitch; import org.apache.cassandra.locator.Endpoint; import org.apache.cassandra.locator.IEndpointSnitch; @@ -61,7 +62,7 @@ public class AccordTopologySorter implements TopologySorter return create(topologies.nodes()); } - private AccordTopologySorter create(Set<Node.Id> nodes) + private AccordTopologySorter create(SortedList<Node.Id> nodes) { SortableEndpoints endpoints = SortableEndpoints.from(nodes, mapper); Comparator<Endpoint> comparator = snitch.endpointComparator(FBUtilities.getBroadcastAddressAndPort(), endpoints); diff --git a/src/java/org/apache/cassandra/service/accord/serializers/CommandSerializers.java b/src/java/org/apache/cassandra/service/accord/serializers/CommandSerializers.java index fe16d3033e..cd76550262 100644 --- a/src/java/org/apache/cassandra/service/accord/serializers/CommandSerializers.java +++ b/src/java/org/apache/cassandra/service/accord/serializers/CommandSerializers.java @@ -36,7 +36,6 @@ import accord.local.Status.Known; import accord.primitives.Ballot; import accord.primitives.PartialTxn; import accord.primitives.ProgressToken; -import accord.primitives.Ranges; import accord.primitives.Seekables; import accord.primitives.Timestamp; import accord.primitives.Txn; @@ -234,7 +233,6 @@ public class CommandSerializers private void serializeWithoutKeys(PartialTxn txn, DataOutputPlus out, int version) throws IOException { CommandSerializers.kind.serialize(txn.kind(), out, version); - KeySerializers.ranges.serialize(txn.covering(), out, version); readSerializer.serialize(txn.read(), out, version); querySerializer.serialize(txn.query(), out, version); out.writeBoolean(txn.update() != null); @@ -245,18 +243,16 @@ public class CommandSerializers private PartialTxn deserializeWithoutKeys(Seekables<?, ?> keys, DataInputPlus in, int version) throws IOException { Txn.Kind kind = CommandSerializers.kind.deserialize(in, version); - Ranges covering = KeySerializers.ranges.deserialize(in, version); Read read = readSerializer.deserialize(in, version); Query query = querySerializer.deserialize(in, version); Update update = in.readBoolean() ? updateSerializer.deserialize(in, version) : null; - return new PartialTxn.InMemory(covering, kind, keys, read, query, update); + return new PartialTxn.InMemory(kind, keys, read, query, update); } private long serializedSizeWithoutKeys(PartialTxn txn, int version) { long size = CommandSerializers.kind.serializedSize(txn.kind(), version); - size += KeySerializers.ranges.serializedSize(txn.covering(), version); size += readSerializer.serializedSize(txn.read(), version); size += querySerializer.serializedSize(txn.query(), version); size += TypeSizes.sizeof(txn.update() != null); diff --git a/src/java/org/apache/cassandra/service/accord/serializers/DepsSerializer.java b/src/java/org/apache/cassandra/service/accord/serializers/DepsSerializer.java index dd78761cda..e39d0ac0f7 100644 --- a/src/java/org/apache/cassandra/service/accord/serializers/DepsSerializer.java +++ b/src/java/org/apache/cassandra/service/accord/serializers/DepsSerializer.java @@ -68,28 +68,28 @@ public abstract class DepsSerializer<D extends Deps> extends IVersionedWithKeysS public void serialize(PartialDeps partialDeps, DataOutputPlus out, int version) throws IOException { super.serialize(partialDeps, out, version); - KeySerializers.ranges.serialize(partialDeps.covering, out, version); + KeySerializers.participants.serialize(partialDeps.covering, out, version); } @Override public void serialize(Seekables<?, ?> superset, PartialDeps partialDeps, DataOutputPlus out, int version) throws IOException { super.serialize(superset, partialDeps, out, version); - KeySerializers.ranges.serialize(partialDeps.covering, out, version); + KeySerializers.participants.serialize(partialDeps.covering, out, version); } @Override public long serializedSize(PartialDeps partialDeps, int version) { return super.serializedSize(partialDeps, version) - + KeySerializers.ranges.serializedSize(partialDeps.covering, version); + + KeySerializers.participants.serializedSize(partialDeps.covering, version); } @Override public long serializedSize(Seekables<?, ?> keys, PartialDeps partialDeps, int version) { return super.serializedSize(keys, partialDeps, version) - + KeySerializers.ranges.serializedSize(partialDeps.covering, version); + + KeySerializers.participants.serializedSize(partialDeps.covering, version); } }; diff --git a/src/java/org/apache/cassandra/service/accord/serializers/KeySerializers.java b/src/java/org/apache/cassandra/service/accord/serializers/KeySerializers.java index 6d2e86e8bb..1e105d8192 100644 --- a/src/java/org/apache/cassandra/service/accord/serializers/KeySerializers.java +++ b/src/java/org/apache/cassandra/service/accord/serializers/KeySerializers.java @@ -91,38 +91,31 @@ public class KeySerializers { @Override PartialKeyRoute deserialize(DataInputPlus in, int version, RoutingKey[] keys) throws IOException { - Ranges covering = ranges.deserialize(in, version); RoutingKey homeKey = routingKey.deserialize(in, version); - boolean isParticipatingHomeKey = (in.readByte() & 0x1) != 0; - return PartialKeyRoute.SerializationSupport.create(covering, homeKey, isParticipatingHomeKey, keys); + return PartialKeyRoute.SerializationSupport.create(homeKey, keys); } @Override public void serialize(PartialKeyRoute route, DataOutputPlus out, int version) throws IOException { super.serialize(route, out, version); - ranges.serialize(route.covering, out, version); routingKey.serialize(route.homeKey, out, version); - out.writeByte(route.isParticipatingHomeKey ? 0x1 : 0); } @Override public long serializedSize(PartialKeyRoute keys, int version) { return super.serializedSize(keys, version) - + ranges.serializedSize(keys.covering, version) - + routingKey.serializedSize(keys.homeKey, version) - + 1; + + routingKey.serializedSize(keys.homeKey, version); } }; - public static final IVersionedSerializer<FullKeyRoute> fullKeyRoute = new AbstractKeysSerializer<RoutingKey, FullKeyRoute>(routingKey, RoutingKey[]::new) + public static final IVersionedSerializer<FullKeyRoute> fullKeyRoute = new AbstractKeysSerializer<>(routingKey, RoutingKey[]::new) { @Override FullKeyRoute deserialize(DataInputPlus in, int version, RoutingKey[] keys) throws IOException { RoutingKey homeKey = routingKey.deserialize(in, version); - boolean isParticipatingHomeKey = (in.readByte() & 0x1) != 0; - return FullKeyRoute.SerializationSupport.create(homeKey, isParticipatingHomeKey, keys); + return FullKeyRoute.SerializationSupport.create(homeKey, keys); } @Override @@ -130,15 +123,13 @@ public class KeySerializers { super.serialize(route, out, version); routingKey.serialize(route.homeKey, out, version); - out.writeByte(route.isParticipatingHomeKey ? 0x1 : 0); } @Override public long serializedSize(FullKeyRoute route, int version) { return super.serializedSize(route, version) - + routingKey.serializedSize(route.homeKey, version) - + 1; + + routingKey.serializedSize(route.homeKey, version); } }; @@ -146,28 +137,22 @@ public class KeySerializers { @Override PartialRangeRoute deserialize(DataInputPlus in, int version, Range[] rs) throws IOException { - Ranges covering = ranges.deserialize(in, version); RoutingKey homeKey = routingKey.deserialize(in, version); - boolean isParticipatingHomeKey = (in.readByte() & 0x1) != 0; - return PartialRangeRoute.SerializationSupport.create(covering, homeKey, isParticipatingHomeKey, rs); + return PartialRangeRoute.SerializationSupport.create(homeKey, rs); } @Override public void serialize(PartialRangeRoute route, DataOutputPlus out, int version) throws IOException { super.serialize(route, out, version); - ranges.serialize(route.covering, out, version); routingKey.serialize(route.homeKey, out, version); - out.writeByte(route.isParticipatingHomeKey ? 0x1 : 0); } @Override public long serializedSize(PartialRangeRoute rs, int version) { return super.serializedSize(rs, version) - + ranges.serializedSize(rs.covering, version) - + routingKey.serializedSize(rs.homeKey, version) - + 1; + + routingKey.serializedSize(rs.homeKey, version); } }; @@ -177,8 +162,7 @@ public class KeySerializers @Override FullRangeRoute deserialize(DataInputPlus in, int version, Range[] Ranges) throws IOException { RoutingKey homeKey = routingKey.deserialize(in, version); - boolean isParticipatingHomeKey = (in.readByte() & 0x1) != 0; - return FullRangeRoute.SerializationSupport.create(homeKey, isParticipatingHomeKey, Ranges); + return FullRangeRoute.SerializationSupport.create(homeKey, Ranges); } @Override @@ -186,15 +170,13 @@ public class KeySerializers { super.serialize(route, out, version); routingKey.serialize(route.homeKey, out, version); - out.writeByte(route.isParticipatingHomeKey ? 0x1 : 0); } @Override public long serializedSize(FullRangeRoute ranges, int version) { return super.serializedSize(ranges, version) - + routingKey.serializedSize(ranges.homeKey(), version) - + 1; + + routingKey.serializedSize(ranges.homeKey(), version); } }; diff --git a/src/java/org/apache/cassandra/service/accord/serializers/TopologySerializers.java b/src/java/org/apache/cassandra/service/accord/serializers/TopologySerializers.java index 4693c03c5c..aaae3e0f88 100644 --- a/src/java/org/apache/cassandra/service/accord/serializers/TopologySerializers.java +++ b/src/java/org/apache/cassandra/service/accord/serializers/TopologySerializers.java @@ -27,6 +27,8 @@ import accord.local.Node; import accord.primitives.Range; import accord.topology.Shard; import accord.topology.Topology; +import accord.utils.SortedArrays; +import accord.utils.SortedArrays.SortedArrayList; import org.apache.cassandra.db.TypeSizes; import org.apache.cassandra.db.marshal.ValueAccessor; import org.apache.cassandra.io.IVersionedSerializer; @@ -135,7 +137,7 @@ public class TopologySerializers public Shard deserialize(DataInputPlus in, int version) throws IOException { Range range = TokenRange.serializer.deserialize(in, version); - List<Node.Id> nodes = CollectionSerializers.deserializeList(in, version, nodeId); + SortedArrayList<Node.Id> nodes = CollectionSerializers.deserializeSortedArrayList(in, version, nodeId, Node.Id[]::new); Set<Node.Id> fastPathElectorate = CollectionSerializers.deserializeSet(in, version, nodeId); Set<Node.Id> joining = CollectionSerializers.deserializeSet(in, version, nodeId); return new Shard(range, nodes, fastPathElectorate, joining); diff --git a/src/java/org/apache/cassandra/service/accord/txn/TxnRead.java b/src/java/org/apache/cassandra/service/accord/txn/TxnRead.java index 62dfe68e2c..694c3f225a 100644 --- a/src/java/org/apache/cassandra/service/accord/txn/TxnRead.java +++ b/src/java/org/apache/cassandra/service/accord/txn/TxnRead.java @@ -32,6 +32,7 @@ import accord.api.DataStore; import accord.api.Read; import accord.local.SafeCommandStore; import accord.primitives.Keys; +import accord.primitives.Participants; import accord.primitives.Ranges; import accord.primitives.Seekable; import accord.primitives.Timestamp; @@ -158,14 +159,25 @@ public class TxnRead extends AbstractKeySorted<TxnNamedRead> implements Read @Override public Read slice(Ranges ranges) { - Keys keys = itemKeys.slice(ranges); + return intersecting(itemKeys.slice(ranges)); + } + + @Override + public Read intersecting(Participants<?> participants) + { + return intersecting(itemKeys.intersecting(participants)); + } + + private Read intersecting(Keys select) + { + Keys keys = itemKeys.intersecting(select); List<TxnNamedRead> reads = new ArrayList<>(keys.size()); for (TxnNamedRead read : items) if (keys.contains(read.key())) reads.add(read); - return createTxnRead(reads, txnKeys.slice(ranges), cassandraConsistencyLevel); + return createTxnRead(reads, txnKeys.intersecting(select), cassandraConsistencyLevel); } @Override diff --git a/src/java/org/apache/cassandra/service/accord/txn/TxnUpdate.java b/src/java/org/apache/cassandra/service/accord/txn/TxnUpdate.java index 5a32065e97..563af81675 100644 --- a/src/java/org/apache/cassandra/service/accord/txn/TxnUpdate.java +++ b/src/java/org/apache/cassandra/service/accord/txn/TxnUpdate.java @@ -32,6 +32,7 @@ import accord.api.Data; import accord.api.Key; import accord.api.Update; import accord.primitives.Keys; +import accord.primitives.Participants; import accord.primitives.Ranges; import accord.primitives.RoutableKey; import accord.primitives.Timestamp; @@ -148,6 +149,14 @@ public class TxnUpdate extends AccordUpdate return new TxnUpdate(keys, select(this.keys, keys, fragments), condition, cassandraCommitCL); } + @Override + public Update intersecting(Participants<?> participants) + { + Keys keys = this.keys.intersecting(participants); + // TODO: Slice the condition. + return new TxnUpdate(keys, select(this.keys, keys, fragments), condition, cassandraCommitCL); + } + private static ByteBuffer[] select(Keys in, Keys out, ByteBuffer[] from) { ByteBuffer[] result = new ByteBuffer[out.size()]; diff --git a/src/java/org/apache/cassandra/service/accord/txn/UnrecoverableRepairUpdate.java b/src/java/org/apache/cassandra/service/accord/txn/UnrecoverableRepairUpdate.java index 310a3e6a58..0efcbf1ffd 100644 --- a/src/java/org/apache/cassandra/service/accord/txn/UnrecoverableRepairUpdate.java +++ b/src/java/org/apache/cassandra/service/accord/txn/UnrecoverableRepairUpdate.java @@ -29,6 +29,7 @@ import accord.api.Data; import accord.api.Update; import accord.api.Write; import accord.local.Node; +import accord.primitives.Participants; import accord.primitives.Ranges; import accord.primitives.Seekables; import accord.primitives.Timestamp; @@ -147,6 +148,12 @@ public class UnrecoverableRepairUpdate<E extends Endpoints<E>, P extends Replica return this; } + @Override + public Update intersecting(Participants<?> participants) + { + return this; + } + @Override public Update merge(Update other) { diff --git a/src/java/org/apache/cassandra/utils/CollectionSerializers.java b/src/java/org/apache/cassandra/utils/CollectionSerializers.java index 1fcb7cc2f3..b20e157664 100644 --- a/src/java/org/apache/cassandra/utils/CollectionSerializers.java +++ b/src/java/org/apache/cassandra/utils/CollectionSerializers.java @@ -31,6 +31,8 @@ import javax.annotation.Nonnull; import com.google.common.collect.Maps; import com.google.common.collect.Sets; +import accord.utils.SortedArrays; +import accord.utils.SortedArrays.SortedArrayList; import org.apache.cassandra.dht.IPartitioner; import org.apache.cassandra.dht.IPartitionerDependentSerializer; import org.apache.cassandra.io.IVersionedSerializer; @@ -102,6 +104,15 @@ public class CollectionSerializers } } + public static <V extends Comparable<? super V>> SortedArrayList<V> deserializeSortedArrayList(DataInputPlus in, int version, IVersionedSerializer<V> serializer, IntFunction<V[]> allocator) throws IOException + { + int size = in.readUnsignedVInt32(); + V[] array = allocator.apply(size); + for (int i = 0 ; i < array.length ; ++i) + array[i] = serializer.deserialize(in, version); + return new SortedArrayList<>(array); + } + public static <V> List<V> deserializeList(DataInputPlus in, int version, IVersionedSerializer<V> serializer) throws IOException { return deserializeCollection(in, version, serializer, newArrayList()); --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
