| /* |
| * |
| * 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.db.context; |
| |
| import java.nio.ByteBuffer; |
| |
| import org.junit.BeforeClass; |
| import org.junit.Test; |
| |
| import org.apache.cassandra.Util; |
| import org.apache.cassandra.config.DatabaseDescriptor; |
| import org.apache.cassandra.db.ClockAndCount; |
| import org.apache.cassandra.db.LegacyLayout.LegacyCell; |
| import org.apache.cassandra.db.context.CounterContext.Relationship; |
| import org.apache.cassandra.utils.ByteBufferUtil; |
| import org.apache.cassandra.utils.CounterId; |
| |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertFalse; |
| import static org.junit.Assert.assertNotSame; |
| import static org.junit.Assert.assertSame; |
| import static org.junit.Assert.assertTrue; |
| |
| import static org.apache.cassandra.db.context.CounterContext.ContextState; |
| |
| public class CounterContextTest |
| { |
| private static final CounterContext cc = new CounterContext(); |
| |
| private static final int headerSizeLength = 2; |
| private static final int headerEltLength = 2; |
| private static final int idLength = 16; |
| private static final int clockLength = 8; |
| private static final int countLength = 8; |
| private static final int stepLength = idLength + clockLength + countLength; |
| |
| @BeforeClass |
| public static void setupDD() |
| { |
| DatabaseDescriptor.daemonInitialization(); |
| } |
| |
| @Test |
| public void testAllocate() |
| { |
| ContextState allGlobal = ContextState.allocate(3, 0, 0); |
| assertEquals(headerSizeLength + 3 * headerEltLength + 3 * stepLength, allGlobal.context.remaining()); |
| |
| ContextState allLocal = ContextState.allocate(0, 3, 0); |
| assertEquals(headerSizeLength + 3 * headerEltLength + 3 * stepLength, allLocal.context.remaining()); |
| |
| ContextState allRemote = ContextState.allocate(0, 0, 3); |
| assertEquals(headerSizeLength + 3 * stepLength, allRemote.context.remaining()); |
| |
| ContextState mixed = ContextState.allocate(1, 1, 1); |
| assertEquals(headerSizeLength + 2 * headerEltLength + 3 * stepLength, mixed.context.remaining()); |
| } |
| |
| @Test |
| public void testDiff() |
| { |
| ContextState left; |
| ContextState right; |
| |
| // equality: equal nodes, all counts same |
| left = ContextState.allocate(0, 0, 3); |
| left.writeRemote(CounterId.fromInt(3), 3L, 0L); |
| left.writeRemote(CounterId.fromInt(6), 2L, 0L); |
| left.writeRemote(CounterId.fromInt(9), 1L, 0L); |
| right = ContextState.wrap(ByteBufferUtil.clone(left.context)); |
| |
| assertEquals(Relationship.EQUAL, cc.diff(left.context, right.context)); |
| |
| // greater than: left has superset of nodes (counts equal) |
| left = ContextState.allocate(0, 0, 4); |
| left.writeRemote(CounterId.fromInt(3), 3L, 0L); |
| left.writeRemote(CounterId.fromInt(6), 2L, 0L); |
| left.writeRemote(CounterId.fromInt(9), 1L, 0L); |
| left.writeRemote(CounterId.fromInt(12), 0L, 0L); |
| |
| right = ContextState.allocate(0, 0, 3); |
| right.writeRemote(CounterId.fromInt(3), 3L, 0L); |
| right.writeRemote(CounterId.fromInt(6), 2L, 0L); |
| right.writeRemote(CounterId.fromInt(9), 1L, 0L); |
| |
| assertEquals(Relationship.GREATER_THAN, cc.diff(left.context, right.context)); |
| |
| // less than: left has subset of nodes (counts equal) |
| left = ContextState.allocate(0, 0, 3); |
| left.writeRemote(CounterId.fromInt(3), 3L, 0L); |
| left.writeRemote(CounterId.fromInt(6), 2L, 0L); |
| left.writeRemote(CounterId.fromInt(9), 1L, 0L); |
| |
| right = ContextState.allocate(0, 0, 4); |
| right.writeRemote(CounterId.fromInt(3), 3L, 0L); |
| right.writeRemote(CounterId.fromInt(6), 2L, 0L); |
| right.writeRemote(CounterId.fromInt(9), 1L, 0L); |
| right.writeRemote(CounterId.fromInt(12), 0L, 0L); |
| |
| assertEquals(Relationship.LESS_THAN, cc.diff(left.context, right.context)); |
| |
| // greater than: equal nodes, but left has higher counts |
| left = ContextState.allocate(0, 0, 3); |
| left.writeRemote(CounterId.fromInt(3), 3L, 0L); |
| left.writeRemote(CounterId.fromInt(6), 2L, 0L); |
| left.writeRemote(CounterId.fromInt(9), 3L, 0L); |
| |
| right = ContextState.allocate(0, 0, 3); |
| right.writeRemote(CounterId.fromInt(3), 3L, 0L); |
| right.writeRemote(CounterId.fromInt(6), 2L, 0L); |
| right.writeRemote(CounterId.fromInt(9), 1L, 0L); |
| |
| assertEquals(Relationship.GREATER_THAN, cc.diff(left.context, right.context)); |
| |
| // less than: equal nodes, but right has higher counts |
| left = ContextState.allocate(0, 0, 3); |
| left.writeRemote(CounterId.fromInt(3), 3L, 0L); |
| left.writeRemote(CounterId.fromInt(6), 2L, 0L); |
| left.writeRemote(CounterId.fromInt(9), 3L, 0L); |
| |
| right = ContextState.allocate(0, 0, 3); |
| right.writeRemote(CounterId.fromInt(3), 3L, 0L); |
| right.writeRemote(CounterId.fromInt(6), 9L, 0L); |
| right.writeRemote(CounterId.fromInt(9), 3L, 0L); |
| |
| assertEquals(Relationship.LESS_THAN, cc.diff(left.context, right.context)); |
| |
| // disjoint: right and left have disjoint node sets |
| left = ContextState.allocate(0, 0, 3); |
| left.writeRemote(CounterId.fromInt(3), 1L, 0L); |
| left.writeRemote(CounterId.fromInt(4), 1L, 0L); |
| left.writeRemote(CounterId.fromInt(9), 1L, 0L); |
| |
| right = ContextState.allocate(0, 0, 3); |
| right.writeRemote(CounterId.fromInt(3), 1L, 0L); |
| right.writeRemote(CounterId.fromInt(6), 1L, 0L); |
| right.writeRemote(CounterId.fromInt(9), 1L, 0L); |
| |
| assertEquals(Relationship.DISJOINT, cc.diff(left.context, right.context)); |
| |
| left = ContextState.allocate(0, 0, 3); |
| left.writeRemote(CounterId.fromInt(3), 1L, 0L); |
| left.writeRemote(CounterId.fromInt(4), 1L, 0L); |
| left.writeRemote(CounterId.fromInt(9), 1L, 0L); |
| |
| right = ContextState.allocate(0, 0, 3); |
| right.writeRemote(CounterId.fromInt(2), 1L, 0L); |
| right.writeRemote(CounterId.fromInt(6), 1L, 0L); |
| right.writeRemote(CounterId.fromInt(12), 1L, 0L); |
| |
| assertEquals(Relationship.DISJOINT, cc.diff(left.context, right.context)); |
| |
| // disjoint: equal nodes, but right and left have higher counts in differing nodes |
| left = ContextState.allocate(0, 0, 3); |
| left.writeRemote(CounterId.fromInt(3), 1L, 0L); |
| left.writeRemote(CounterId.fromInt(6), 3L, 0L); |
| left.writeRemote(CounterId.fromInt(9), 1L, 0L); |
| |
| right = ContextState.allocate(0, 0, 3); |
| right.writeRemote(CounterId.fromInt(3), 1L, 0L); |
| right.writeRemote(CounterId.fromInt(6), 1L, 0L); |
| right.writeRemote(CounterId.fromInt(9), 5L, 0L); |
| |
| assertEquals(Relationship.DISJOINT, cc.diff(left.context, right.context)); |
| |
| left = ContextState.allocate(0, 0, 3); |
| left.writeRemote(CounterId.fromInt(3), 2L, 0L); |
| left.writeRemote(CounterId.fromInt(6), 3L, 0L); |
| left.writeRemote(CounterId.fromInt(9), 1L, 0L); |
| |
| right = ContextState.allocate(0, 0, 3); |
| right.writeRemote(CounterId.fromInt(3), 1L, 0L); |
| right.writeRemote(CounterId.fromInt(6), 9L, 0L); |
| right.writeRemote(CounterId.fromInt(9), 5L, 0L); |
| |
| assertEquals(Relationship.DISJOINT, cc.diff(left.context, right.context)); |
| |
| // disjoint: left has more nodes, but lower counts |
| left = ContextState.allocate(0, 0, 4); |
| left.writeRemote(CounterId.fromInt(3), 2L, 0L); |
| left.writeRemote(CounterId.fromInt(6), 3L, 0L); |
| left.writeRemote(CounterId.fromInt(9), 1L, 0L); |
| left.writeRemote(CounterId.fromInt(12), 1L, 0L); |
| |
| right = ContextState.allocate(0, 0, 3); |
| right.writeRemote(CounterId.fromInt(3), 4L, 0L); |
| right.writeRemote(CounterId.fromInt(6), 9L, 0L); |
| right.writeRemote(CounterId.fromInt(9), 5L, 0L); |
| |
| assertEquals(Relationship.DISJOINT, cc.diff(left.context, right.context)); |
| |
| // disjoint: left has less nodes, but higher counts |
| left = ContextState.allocate(0, 0, 3); |
| left.writeRemote(CounterId.fromInt(3), 5L, 0L); |
| left.writeRemote(CounterId.fromInt(6), 3L, 0L); |
| left.writeRemote(CounterId.fromInt(9), 2L, 0L); |
| |
| right = ContextState.allocate(0, 0, 4); |
| right.writeRemote(CounterId.fromInt(3), 4L, 0L); |
| right.writeRemote(CounterId.fromInt(6), 3L, 0L); |
| right.writeRemote(CounterId.fromInt(9), 2L, 0L); |
| right.writeRemote(CounterId.fromInt(12), 1L, 0L); |
| |
| assertEquals(Relationship.DISJOINT, cc.diff(left.context, right.context)); |
| |
| // disjoint: mixed nodes and counts |
| left = ContextState.allocate(0, 0, 3); |
| left.writeRemote(CounterId.fromInt(3), 5L, 0L); |
| left.writeRemote(CounterId.fromInt(6), 2L, 0L); |
| left.writeRemote(CounterId.fromInt(9), 2L, 0L); |
| |
| right = ContextState.allocate(0, 0, 4); |
| right.writeRemote(CounterId.fromInt(3), 4L, 0L); |
| right.writeRemote(CounterId.fromInt(6), 3L, 0L); |
| right.writeRemote(CounterId.fromInt(9), 2L, 0L); |
| right.writeRemote(CounterId.fromInt(12), 1L, 0L); |
| |
| assertEquals(Relationship.DISJOINT, cc.diff(left.context, right.context)); |
| |
| left = ContextState.allocate(0, 0, 4); |
| left.writeRemote(CounterId.fromInt(3), 5L, 0L); |
| left.writeRemote(CounterId.fromInt(6), 2L, 0L); |
| left.writeRemote(CounterId.fromInt(7), 2L, 0L); |
| left.writeRemote(CounterId.fromInt(9), 2L, 0L); |
| |
| right = ContextState.allocate(0, 0, 3); |
| right.writeRemote(CounterId.fromInt(3), 4L, 0L); |
| right.writeRemote(CounterId.fromInt(6), 3L, 0L); |
| right.writeRemote(CounterId.fromInt(9), 2L, 0L); |
| |
| assertEquals(Relationship.DISJOINT, cc.diff(left.context, right.context)); |
| } |
| |
| @Test |
| public void testMerge() |
| { |
| // note: local counts aggregated; remote counts are reconciled (i.e. take max) |
| ContextState left = ContextState.allocate(0, 1, 3); |
| left.writeRemote(CounterId.fromInt(1), 1L, 1L); |
| left.writeRemote(CounterId.fromInt(2), 2L, 2L); |
| left.writeRemote(CounterId.fromInt(4), 6L, 3L); |
| left.writeLocal(CounterId.getLocalId(), 7L, 3L); |
| |
| ContextState right = ContextState.allocate(0, 1, 2); |
| right.writeRemote(CounterId.fromInt(4), 4L, 4L); |
| right.writeRemote(CounterId.fromInt(5), 5L, 5L); |
| right.writeLocal(CounterId.getLocalId(), 2L, 9L); |
| |
| ByteBuffer merged = cc.merge(left.context, right.context); |
| int hd = 4; |
| |
| assertEquals(hd + 5 * stepLength, merged.remaining()); |
| // local node id's counts are aggregated |
| assertTrue(Util.equalsCounterId(CounterId.getLocalId(), merged, hd + 4 * stepLength)); |
| assertEquals(9L, merged.getLong(merged.position() + hd + 4 * stepLength + idLength)); |
| assertEquals(12L, merged.getLong(merged.position() + hd + 4*stepLength + idLength + clockLength)); |
| |
| // remote node id counts are reconciled (i.e. take max) |
| assertTrue(Util.equalsCounterId(CounterId.fromInt(4), merged, hd + 2 * stepLength)); |
| assertEquals(6L, merged.getLong(merged.position() + hd + 2 * stepLength + idLength)); |
| assertEquals( 3L, merged.getLong(merged.position() + hd + 2*stepLength + idLength + clockLength)); |
| |
| assertTrue(Util.equalsCounterId(CounterId.fromInt(5), merged, hd + 3 * stepLength)); |
| assertEquals(5L, merged.getLong(merged.position() + hd + 3 * stepLength + idLength)); |
| assertEquals( 5L, merged.getLong(merged.position() + hd + 3*stepLength + idLength + clockLength)); |
| |
| assertTrue(Util.equalsCounterId(CounterId.fromInt(2), merged, hd + stepLength)); |
| assertEquals(2L, merged.getLong(merged.position() + hd + stepLength + idLength)); |
| assertEquals( 2L, merged.getLong(merged.position() + hd + stepLength + idLength + clockLength)); |
| |
| assertTrue(Util.equalsCounterId(CounterId.fromInt(1), merged, hd)); |
| assertEquals( 1L, merged.getLong(merged.position() + hd + idLength)); |
| assertEquals( 1L, merged.getLong(merged.position() + hd + idLength + clockLength)); |
| |
| // |
| // Test merging two exclusively global contexts |
| // |
| left = ContextState.allocate(3, 0, 0); |
| left.writeGlobal(CounterId.fromInt(1), 1L, 1L); |
| left.writeGlobal(CounterId.fromInt(2), 2L, 2L); |
| left.writeGlobal(CounterId.fromInt(3), 3L, 3L); |
| |
| right = ContextState.allocate(3, 0, 0); |
| right.writeGlobal(CounterId.fromInt(3), 6L, 6L); |
| right.writeGlobal(CounterId.fromInt(4), 4L, 4L); |
| right.writeGlobal(CounterId.fromInt(5), 5L, 5L); |
| |
| merged = cc.merge(left.context, right.context); |
| assertEquals(headerSizeLength + 5 * headerEltLength + 5 * stepLength, merged.remaining()); |
| assertEquals(18L, cc.total(merged)); |
| assertEquals(5, merged.getShort(merged.position())); |
| |
| int headerLength = headerSizeLength + 5 * headerEltLength; |
| assertTrue(Util.equalsCounterId(CounterId.fromInt(1), merged, headerLength)); |
| assertEquals(1L, merged.getLong(merged.position() + headerLength + idLength)); |
| assertEquals(1L, merged.getLong(merged.position() + headerLength + idLength + clockLength)); |
| assertTrue(Util.equalsCounterId(CounterId.fromInt(2), merged, headerLength + stepLength)); |
| assertEquals(2L, merged.getLong(merged.position() + headerLength + stepLength + idLength)); |
| assertEquals(2L, merged.getLong(merged.position() + headerLength + stepLength + idLength + clockLength)); |
| // pick the global shard with the largest clock |
| assertTrue(Util.equalsCounterId(CounterId.fromInt(3), merged, headerLength + 2 * stepLength)); |
| assertEquals(6L, merged.getLong(merged.position() + headerLength + 2 * stepLength + idLength)); |
| assertEquals(6L, merged.getLong(merged.position() + headerLength + 2 * stepLength + idLength + clockLength)); |
| assertTrue(Util.equalsCounterId(CounterId.fromInt(4), merged, headerLength + 3 * stepLength)); |
| assertEquals(4L, merged.getLong(merged.position() + headerLength + 3 * stepLength + idLength)); |
| assertEquals(4L, merged.getLong(merged.position() + headerLength + 3 * stepLength + idLength + clockLength)); |
| assertTrue(Util.equalsCounterId(CounterId.fromInt(5), merged, headerLength + 4 * stepLength)); |
| assertEquals(5L, merged.getLong(merged.position() + headerLength + 4 * stepLength + idLength)); |
| assertEquals(5L, merged.getLong(merged.position() + headerLength + 4 * stepLength + idLength + clockLength)); |
| |
| // |
| // Test merging two global contexts w/ 'invalid shards' |
| // |
| left = ContextState.allocate(1, 0, 0); |
| left.writeGlobal(CounterId.fromInt(1), 10L, 20L); |
| |
| right = ContextState.allocate(1, 0, 0); |
| right.writeGlobal(CounterId.fromInt(1), 10L, 30L); |
| |
| merged = cc.merge(left.context, right.context); |
| headerLength = headerSizeLength + headerEltLength; |
| assertEquals(headerLength + stepLength, merged.remaining()); |
| assertEquals(30L, cc.total(merged)); |
| assertEquals(1, merged.getShort(merged.position())); |
| assertTrue(Util.equalsCounterId(CounterId.fromInt(1), merged, headerLength)); |
| assertEquals(10L, merged.getLong(merged.position() + headerLength + idLength)); |
| // with equal clock, we should pick the largest value |
| assertEquals(30L, merged.getLong(merged.position() + headerLength + idLength + clockLength)); |
| |
| // |
| // Test merging global w/ mixed contexts |
| // |
| left = ContextState.allocate(2, 0, 0); |
| left.writeGlobal(CounterId.fromInt(1), 1L, 1L); |
| left.writeGlobal(CounterId.fromInt(2), 1L, 1L); |
| |
| right = ContextState.allocate(0, 1, 1); |
| right.writeLocal(CounterId.fromInt(1), 100L, 100L); |
| right.writeRemote(CounterId.fromInt(2), 100L, 100L); |
| |
| // global shards should dominate local/remote, even with lower clock and value |
| merged = cc.merge(left.context, right.context); |
| headerLength = headerSizeLength + 2 * headerEltLength; |
| assertEquals(headerLength + 2 * stepLength, merged.remaining()); |
| assertEquals(2L, cc.total(merged)); |
| assertEquals(2, merged.getShort(merged.position())); |
| assertTrue(Util.equalsCounterId(CounterId.fromInt(1), merged, headerLength)); |
| assertEquals(1L, merged.getLong(merged.position() + headerLength + idLength)); |
| assertEquals(1L, merged.getLong(merged.position() + headerLength + idLength + clockLength)); |
| assertTrue(Util.equalsCounterId(CounterId.fromInt(2), merged, headerLength + stepLength)); |
| assertEquals(1L, merged.getLong(merged.position() + headerLength + stepLength + idLength)); |
| assertEquals(1L, merged.getLong(merged.position() + headerLength + stepLength + idLength + clockLength)); |
| } |
| |
| @Test |
| public void testTotal() |
| { |
| ContextState mixed = ContextState.allocate(0, 1, 4); |
| mixed.writeRemote(CounterId.fromInt(1), 1L, 1L); |
| mixed.writeRemote(CounterId.fromInt(2), 2L, 2L); |
| mixed.writeRemote(CounterId.fromInt(4), 4L, 4L); |
| mixed.writeRemote(CounterId.fromInt(5), 5L, 5L); |
| mixed.writeLocal(CounterId.getLocalId(), 12L, 12L); |
| assertEquals(24L, cc.total(mixed.context)); |
| |
| ContextState global = ContextState.allocate(3, 0, 0); |
| global.writeGlobal(CounterId.fromInt(1), 1L, 1L); |
| global.writeGlobal(CounterId.fromInt(2), 2L, 2L); |
| global.writeGlobal(CounterId.fromInt(3), 3L, 3L); |
| assertEquals(6L, cc.total(global.context)); |
| } |
| |
| @Test |
| public void testClearLocal() |
| { |
| ContextState state; |
| ByteBuffer marked; |
| ByteBuffer cleared; |
| |
| // mark/clear for remote-only contexts is a no-op |
| state = ContextState.allocate(0, 0, 1); |
| state.writeRemote(CounterId.fromInt(1), 1L, 1L); |
| |
| assertFalse(cc.shouldClearLocal(state.context)); |
| marked = cc.markLocalToBeCleared(state.context); |
| assertEquals(0, marked.getShort(marked.position())); |
| assertSame(state.context, marked); // should return the original context |
| |
| cleared = cc.clearAllLocal(marked); |
| assertSame(cleared, marked); // shouldn't alter anything either |
| |
| // a single local shard |
| state = ContextState.allocate(0, 1, 0); |
| state.writeLocal(CounterId.fromInt(1), 1L, 1L); |
| |
| assertFalse(cc.shouldClearLocal(state.context)); |
| marked = cc.markLocalToBeCleared(state.context); |
| assertTrue(cc.shouldClearLocal(marked)); |
| assertEquals(-1, marked.getShort(marked.position())); |
| assertNotSame(state.context, marked); // shouldn't alter in place, as it used to do |
| |
| cleared = cc.clearAllLocal(marked); |
| assertFalse(cc.shouldClearLocal(cleared)); |
| assertEquals(0, cleared.getShort(cleared.position())); |
| |
| // 2 global + 1 local shard |
| state = ContextState.allocate(2, 1, 0); |
| state.writeLocal(CounterId.fromInt(1), 1L, 1L); |
| state.writeGlobal(CounterId.fromInt(2), 2L, 2L); |
| state.writeGlobal(CounterId.fromInt(3), 3L, 3L); |
| |
| assertFalse(cc.shouldClearLocal(state.context)); |
| marked = cc.markLocalToBeCleared(state.context); |
| assertTrue(cc.shouldClearLocal(marked)); |
| |
| assertEquals(-3, marked.getShort(marked.position())); |
| assertEquals(0, marked.getShort(marked.position() + headerSizeLength)); |
| assertEquals(Short.MIN_VALUE + 1, marked.getShort(marked.position() + headerSizeLength + headerEltLength)); |
| assertEquals(Short.MIN_VALUE + 2, marked.getShort(marked.position() + headerSizeLength + 2 * headerEltLength)); |
| |
| int headerLength = headerSizeLength + 3 * headerEltLength; |
| assertTrue(Util.equalsCounterId(CounterId.fromInt(1), marked, headerLength)); |
| assertEquals(1L, marked.getLong(marked.position() + headerLength + idLength)); |
| assertEquals(1L, marked.getLong(marked.position() + headerLength + idLength + clockLength)); |
| |
| assertTrue(Util.equalsCounterId(CounterId.fromInt(2), marked, headerLength + stepLength)); |
| assertEquals(2L, marked.getLong(marked.position() + headerLength + stepLength + idLength)); |
| assertEquals(2L, marked.getLong(marked.position() + headerLength + stepLength + idLength + clockLength)); |
| |
| assertTrue(Util.equalsCounterId(CounterId.fromInt(3), marked, headerLength + 2 * stepLength)); |
| assertEquals(3L, marked.getLong(marked.position() + headerLength + 2 * stepLength + idLength)); |
| assertEquals(3L, marked.getLong(marked.position() + headerLength + 2 * stepLength + idLength + clockLength)); |
| |
| cleared = cc.clearAllLocal(marked); |
| assertFalse(cc.shouldClearLocal(cleared)); |
| |
| assertEquals(2, cleared.getShort(cleared.position())); // 2 global shards |
| assertEquals(Short.MIN_VALUE + 1, cleared.getShort(marked.position() + headerEltLength)); |
| assertEquals(Short.MIN_VALUE + 2, cleared.getShort(marked.position() + headerSizeLength + headerEltLength)); |
| |
| headerLength = headerSizeLength + 2 * headerEltLength; |
| assertTrue(Util.equalsCounterId(CounterId.fromInt(1), cleared, headerLength)); |
| assertEquals(1L, cleared.getLong(cleared.position() + headerLength + idLength)); |
| assertEquals(1L, cleared.getLong(cleared.position() + headerLength + idLength + clockLength)); |
| |
| assertTrue(Util.equalsCounterId(CounterId.fromInt(2), cleared, headerLength + stepLength)); |
| assertEquals(2L, cleared.getLong(cleared.position() + headerLength + stepLength + idLength)); |
| assertEquals(2L, cleared.getLong(cleared.position() + headerLength + stepLength + idLength + clockLength)); |
| |
| assertTrue(Util.equalsCounterId(CounterId.fromInt(3), cleared, headerLength + 2 * stepLength)); |
| assertEquals(3L, cleared.getLong(cleared.position() + headerLength + 2 * stepLength + idLength)); |
| assertEquals(3L, cleared.getLong(cleared.position() + headerLength + 2 * stepLength + idLength + clockLength)); |
| |
| // a single global shard - no-op |
| state = ContextState.allocate(1, 0, 0); |
| state.writeGlobal(CounterId.fromInt(1), 1L, 1L); |
| |
| assertFalse(cc.shouldClearLocal(state.context)); |
| marked = cc.markLocalToBeCleared(state.context); |
| assertEquals(1, marked.getShort(marked.position())); |
| assertSame(state.context, marked); |
| |
| cleared = cc.clearAllLocal(marked); |
| assertSame(cleared, marked); |
| } |
| |
| @Test |
| public void testFindPositionOf() |
| { |
| ContextState state = ContextState.allocate(3, 3, 3); |
| |
| state.writeGlobal(CounterId.fromInt(1), 1L, 1L); |
| state.writeRemote(CounterId.fromInt(2), 2L, 2L); |
| state.writeLocal( CounterId.fromInt(3), 3L, 3L); |
| state.writeGlobal(CounterId.fromInt(4), 4L, 4L); |
| state.writeRemote(CounterId.fromInt(5), 5L, 5L); |
| state.writeLocal( CounterId.fromInt(6), 6L, 6L); |
| state.writeGlobal(CounterId.fromInt(7), 7L, 7L); |
| state.writeRemote(CounterId.fromInt(8), 8L, 8L); |
| state.writeLocal(CounterId.fromInt(9), 9L, 9L); |
| |
| int headerLength = headerSizeLength + 6 * headerEltLength; |
| assertEquals(headerLength, cc.findPositionOf(state.context, CounterId.fromInt(1))); |
| assertEquals(headerLength + stepLength, cc.findPositionOf(state.context, CounterId.fromInt(2))); |
| assertEquals(headerLength + 2 * stepLength, cc.findPositionOf(state.context, CounterId.fromInt(3))); |
| assertEquals(headerLength + 3 * stepLength, cc.findPositionOf(state.context, CounterId.fromInt(4))); |
| assertEquals(headerLength + 4 * stepLength, cc.findPositionOf(state.context, CounterId.fromInt(5))); |
| assertEquals(headerLength + 5 * stepLength, cc.findPositionOf(state.context, CounterId.fromInt(6))); |
| assertEquals(headerLength + 6 * stepLength, cc.findPositionOf(state.context, CounterId.fromInt(7))); |
| assertEquals(headerLength + 7 * stepLength, cc.findPositionOf(state.context, CounterId.fromInt(8))); |
| assertEquals(headerLength + 8 * stepLength, cc.findPositionOf(state.context, CounterId.fromInt(9))); |
| |
| assertEquals(-1, cc.findPositionOf(state.context, CounterId.fromInt(0))); |
| assertEquals(-1, cc.findPositionOf(state.context, CounterId.fromInt(10))); |
| assertEquals(-1, cc.findPositionOf(state.context, CounterId.fromInt(15))); |
| assertEquals(-1, cc.findPositionOf(state.context, CounterId.fromInt(20))); |
| } |
| |
| @Test |
| public void testGetGlockAndCountOf() |
| { |
| ContextState state = ContextState.allocate(3, 3, 3); |
| |
| state.writeGlobal(CounterId.fromInt(1), 1L, 1L); |
| state.writeRemote(CounterId.fromInt(2), 2L, 2L); |
| state.writeLocal( CounterId.fromInt(3), 3L, 3L); |
| state.writeGlobal(CounterId.fromInt(4), 4L, 4L); |
| state.writeRemote(CounterId.fromInt(5), 5L, 5L); |
| state.writeLocal( CounterId.fromInt(6), 6L, 6L); |
| state.writeGlobal(CounterId.fromInt(7), 7L, 7L); |
| state.writeRemote(CounterId.fromInt(8), 8L, 8L); |
| state.writeLocal(CounterId.fromInt(9), 9L, 9L); |
| |
| assertEquals(ClockAndCount.create(1L, 1L), cc.getClockAndCountOf(state.context, CounterId.fromInt(1))); |
| assertEquals(ClockAndCount.create(2L, 2L), cc.getClockAndCountOf(state.context, CounterId.fromInt(2))); |
| assertEquals(ClockAndCount.create(3L, 3L), cc.getClockAndCountOf(state.context, CounterId.fromInt(3))); |
| assertEquals(ClockAndCount.create(4L, 4L), cc.getClockAndCountOf(state.context, CounterId.fromInt(4))); |
| assertEquals(ClockAndCount.create(5L, 5L), cc.getClockAndCountOf(state.context, CounterId.fromInt(5))); |
| assertEquals(ClockAndCount.create(6L, 6L), cc.getClockAndCountOf(state.context, CounterId.fromInt(6))); |
| assertEquals(ClockAndCount.create(7L, 7L), cc.getClockAndCountOf(state.context, CounterId.fromInt(7))); |
| assertEquals(ClockAndCount.create(8L, 8L), cc.getClockAndCountOf(state.context, CounterId.fromInt(8))); |
| assertEquals(ClockAndCount.create(9L, 9L), cc.getClockAndCountOf(state.context, CounterId.fromInt(9))); |
| |
| assertEquals(ClockAndCount.create(0L, 0L), cc.getClockAndCountOf(state.context, CounterId.fromInt(0))); |
| assertEquals(ClockAndCount.create(0L, 0L), cc.getClockAndCountOf(state.context, CounterId.fromInt(10))); |
| assertEquals(ClockAndCount.create(0L, 0L), cc.getClockAndCountOf(state.context, CounterId.fromInt(15))); |
| assertEquals(ClockAndCount.create(0L, 0L), cc.getClockAndCountOf(state.context, CounterId.fromInt(20))); |
| } |
| |
| @Test // see CASSANDRA-13691 |
| public void testCounterUpdate() |
| { |
| /* |
| * a context with just one 'update' shard - a local shard with a hardcoded value of CounterContext.UPDATE_CLOCK_ID |
| */ |
| |
| ByteBuffer updateContext = CounterContext.instance().createUpdate(10L); |
| |
| assertEquals(ClockAndCount.create(1L, 10L), cc.getClockAndCountOf(updateContext, CounterContext.UPDATE_CLOCK_ID)); |
| assertTrue(cc.isUpdate(updateContext)); |
| LegacyCell updateCell = LegacyCell.counter(null, updateContext); |
| assertTrue(updateCell.isCounterUpdate()); |
| |
| |
| /* |
| * a context with a regular local shard sorting first and a couple others in it - should *not* be identified as an update |
| */ |
| |
| ContextState notUpdateContextState = ContextState.allocate(1, 1, 1); |
| notUpdateContextState.writeLocal( CounterId.fromInt(1), 1L, 10L); |
| notUpdateContextState.writeRemote(CounterId.fromInt(2), 1L, 10L); |
| notUpdateContextState.writeGlobal(CounterId.fromInt(3), 1L, 10L); |
| ByteBuffer notUpdateContext = notUpdateContextState.context; |
| |
| assertFalse(cc.isUpdate(notUpdateContext)); |
| LegacyCell notUpdateCell = LegacyCell.counter(null, notUpdateContext); |
| assertFalse(notUpdateCell.isCounterUpdate()); |
| } |
| } |