/test/unit/org/apache/cassandra/db/context/CounterContextTest.java

https://github.com/yuvrajm/cassandra · Java · 457 lines · 330 code · 84 blank · 43 comment · 13 complexity · 520d6ebad2faf9ebb0518f09734df7ce MD5 · raw file

  1. /*
  2. *
  3. * Licensed to the Apache Software Foundation (ASF) under one
  4. * or more contributor license agreements. See the NOTICE file
  5. * distributed with this work for additional information
  6. * regarding copyright ownership. The ASF licenses this file
  7. * to you under the Apache License, Version 2.0 (the
  8. * "License"); you may not use this file except in compliance
  9. * with the License. You may obtain a copy of the License at
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * Unless required by applicable law or agreed to in writing,
  14. * software distributed under the License is distributed on an
  15. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  16. * KIND, either express or implied. See the License for the
  17. * specific language governing permissions and limitations
  18. * under the License.
  19. *
  20. */
  21. package org.apache.cassandra.db.context;
  22. import static org.junit.Assert.*;
  23. import java.net.InetAddress;
  24. import java.net.UnknownHostException;
  25. import java.nio.ByteBuffer;
  26. import java.util.ArrayList;
  27. import java.util.List;
  28. import org.junit.Test;
  29. import org.apache.cassandra.Util;
  30. import org.apache.cassandra.db.context.IContext.ContextRelationship;
  31. import static org.apache.cassandra.db.context.CounterContext.ContextState;
  32. import org.apache.cassandra.utils.*;
  33. public class CounterContextTest
  34. {
  35. private static final CounterContext cc = new CounterContext();
  36. private static final int idLength;
  37. private static final int clockLength;
  38. private static final int countLength;
  39. private static final int stepLength;
  40. static
  41. {
  42. idLength = NodeId.LENGTH; // size of int
  43. clockLength = 8; // size of long
  44. countLength = 8; // size of long
  45. stepLength = idLength + clockLength + countLength;
  46. }
  47. /** Allocates 1 byte from a new SlabAllocator and returns it. */
  48. private Allocator bumpedSlab()
  49. {
  50. SlabAllocator allocator = new SlabAllocator();
  51. allocator.allocate(1);
  52. return allocator;
  53. }
  54. @Test
  55. public void testCreate()
  56. {
  57. runCreate(HeapAllocator.instance);
  58. runCreate(bumpedSlab());
  59. }
  60. private void runCreate(Allocator allocator)
  61. {
  62. ByteBuffer bytes = cc.create(4, allocator);
  63. assertEquals(stepLength + 4, bytes.remaining());
  64. }
  65. @Test
  66. public void testDiff()
  67. {
  68. runDiff(HeapAllocator.instance);
  69. runDiff(bumpedSlab());
  70. }
  71. private void runDiff(Allocator allocator)
  72. {
  73. ContextState left = ContextState.allocate(3, 0, allocator);
  74. ContextState right;
  75. // equality: equal nodes, all counts same
  76. left.writeElement(NodeId.fromInt(3), 3L, 0L);
  77. left.writeElement(NodeId.fromInt(6), 2L, 0L);
  78. left.writeElement(NodeId.fromInt(9), 1L, 0L);
  79. right = new ContextState(ByteBufferUtil.clone(left.context), left.headerLength);
  80. assert ContextRelationship.EQUAL ==
  81. cc.diff(left.context, right.context);
  82. // greater than: left has superset of nodes (counts equal)
  83. left = ContextState.allocate(4, 0, allocator);
  84. left.writeElement(NodeId.fromInt(3), 3L, 0L);
  85. left.writeElement(NodeId.fromInt(6), 2L, 0L);
  86. left.writeElement(NodeId.fromInt(9), 1L, 0L);
  87. left.writeElement(NodeId.fromInt(12), 0L, 0L);
  88. right = ContextState.allocate(3, 0, allocator);
  89. right.writeElement(NodeId.fromInt(3), 3L, 0L);
  90. right.writeElement(NodeId.fromInt(6), 2L, 0L);
  91. right.writeElement(NodeId.fromInt(9), 1L, 0L);
  92. assert ContextRelationship.GREATER_THAN ==
  93. cc.diff(left.context, right.context);
  94. // less than: left has subset of nodes (counts equal)
  95. left = ContextState.allocate(3, 0, allocator);
  96. left.writeElement(NodeId.fromInt(3), 3L, 0L);
  97. left.writeElement(NodeId.fromInt(6), 2L, 0L);
  98. left.writeElement(NodeId.fromInt(9), 1L, 0L);
  99. right = ContextState.allocate(4, 0, allocator);
  100. right.writeElement(NodeId.fromInt(3), 3L, 0L);
  101. right.writeElement(NodeId.fromInt(6), 2L, 0L);
  102. right.writeElement(NodeId.fromInt(9), 1L, 0L);
  103. right.writeElement(NodeId.fromInt(12), 0L, 0L);
  104. assert ContextRelationship.LESS_THAN ==
  105. cc.diff(left.context, right.context);
  106. // greater than: equal nodes, but left has higher counts
  107. left = ContextState.allocate(3, 0, allocator);
  108. left.writeElement(NodeId.fromInt(3), 3L, 0L);
  109. left.writeElement(NodeId.fromInt(6), 2L, 0L);
  110. left.writeElement(NodeId.fromInt(9), 3L, 0L);
  111. right = ContextState.allocate(3, 0, allocator);
  112. right.writeElement(NodeId.fromInt(3), 3L, 0L);
  113. right.writeElement(NodeId.fromInt(6), 2L, 0L);
  114. right.writeElement(NodeId.fromInt(9), 1L, 0L);
  115. assert ContextRelationship.GREATER_THAN ==
  116. cc.diff(left.context, right.context);
  117. // less than: equal nodes, but right has higher counts
  118. left = ContextState.allocate(3, 0, allocator);
  119. left.writeElement(NodeId.fromInt(3), 3L, 0L);
  120. left.writeElement(NodeId.fromInt(6), 2L, 0L);
  121. left.writeElement(NodeId.fromInt(9), 3L, 0L);
  122. right = ContextState.allocate(3, 0, allocator);
  123. right.writeElement(NodeId.fromInt(3), 3L, 0L);
  124. right.writeElement(NodeId.fromInt(6), 9L, 0L);
  125. right.writeElement(NodeId.fromInt(9), 3L, 0L);
  126. assert ContextRelationship.LESS_THAN ==
  127. cc.diff(left.context, right.context);
  128. // disjoint: right and left have disjoint node sets
  129. left = ContextState.allocate(3, 0, allocator);
  130. left.writeElement(NodeId.fromInt(3), 1L, 0L);
  131. left.writeElement(NodeId.fromInt(4), 1L, 0L);
  132. left.writeElement(NodeId.fromInt(9), 1L, 0L);
  133. right = ContextState.allocate(3, 0, allocator);
  134. right.writeElement(NodeId.fromInt(3), 1L, 0L);
  135. right.writeElement(NodeId.fromInt(6), 1L, 0L);
  136. right.writeElement(NodeId.fromInt(9), 1L, 0L);
  137. assert ContextRelationship.DISJOINT ==
  138. cc.diff(left.context, right.context);
  139. left = ContextState.allocate(3, 0, allocator);
  140. left.writeElement(NodeId.fromInt(3), 1L, 0L);
  141. left.writeElement(NodeId.fromInt(4), 1L, 0L);
  142. left.writeElement(NodeId.fromInt(9), 1L, 0L);
  143. right = ContextState.allocate(3, 0, allocator);
  144. right.writeElement(NodeId.fromInt(2), 1L, 0L);
  145. right.writeElement(NodeId.fromInt(6), 1L, 0L);
  146. right.writeElement(NodeId.fromInt(12), 1L, 0L);
  147. assert ContextRelationship.DISJOINT ==
  148. cc.diff(left.context, right.context);
  149. // disjoint: equal nodes, but right and left have higher counts in differing nodes
  150. left = ContextState.allocate(3, 0, allocator);
  151. left.writeElement(NodeId.fromInt(3), 1L, 0L);
  152. left.writeElement(NodeId.fromInt(6), 3L, 0L);
  153. left.writeElement(NodeId.fromInt(9), 1L, 0L);
  154. right = ContextState.allocate(3, 0, allocator);
  155. right.writeElement(NodeId.fromInt(3), 1L, 0L);
  156. right.writeElement(NodeId.fromInt(6), 1L, 0L);
  157. right.writeElement(NodeId.fromInt(9), 5L, 0L);
  158. assert ContextRelationship.DISJOINT ==
  159. cc.diff(left.context, right.context);
  160. left = ContextState.allocate(3, 0, allocator);
  161. left.writeElement(NodeId.fromInt(3), 2L, 0L);
  162. left.writeElement(NodeId.fromInt(6), 3L, 0L);
  163. left.writeElement(NodeId.fromInt(9), 1L, 0L);
  164. right = ContextState.allocate(3, 0, allocator);
  165. right.writeElement(NodeId.fromInt(3), 1L, 0L);
  166. right.writeElement(NodeId.fromInt(6), 9L, 0L);
  167. right.writeElement(NodeId.fromInt(9), 5L, 0L);
  168. assert ContextRelationship.DISJOINT ==
  169. cc.diff(left.context, right.context);
  170. // disjoint: left has more nodes, but lower counts
  171. left = ContextState.allocate(4, 0, allocator);
  172. left.writeElement(NodeId.fromInt(3), 2L, 0L);
  173. left.writeElement(NodeId.fromInt(6), 3L, 0L);
  174. left.writeElement(NodeId.fromInt(9), 1L, 0L);
  175. left.writeElement(NodeId.fromInt(12), 1L, 0L);
  176. right = ContextState.allocate(3, 0, allocator);
  177. right.writeElement(NodeId.fromInt(3), 4L, 0L);
  178. right.writeElement(NodeId.fromInt(6), 9L, 0L);
  179. right.writeElement(NodeId.fromInt(9), 5L, 0L);
  180. assert ContextRelationship.DISJOINT ==
  181. cc.diff(left.context, right.context);
  182. // disjoint: left has less nodes, but higher counts
  183. left = ContextState.allocate(3, 0, allocator);
  184. left.writeElement(NodeId.fromInt(3), 5L, 0L);
  185. left.writeElement(NodeId.fromInt(6), 3L, 0L);
  186. left.writeElement(NodeId.fromInt(9), 2L, 0L);
  187. right = ContextState.allocate(4, 0, allocator);
  188. right.writeElement(NodeId.fromInt(3), 4L, 0L);
  189. right.writeElement(NodeId.fromInt(6), 3L, 0L);
  190. right.writeElement(NodeId.fromInt(9), 2L, 0L);
  191. right.writeElement(NodeId.fromInt(12), 1L, 0L);
  192. assert ContextRelationship.DISJOINT ==
  193. cc.diff(left.context, right.context);
  194. // disjoint: mixed nodes and counts
  195. left = ContextState.allocate(3, 0, allocator);
  196. left.writeElement(NodeId.fromInt(3), 5L, 0L);
  197. left.writeElement(NodeId.fromInt(6), 2L, 0L);
  198. left.writeElement(NodeId.fromInt(9), 2L, 0L);
  199. right = ContextState.allocate(4, 0, allocator);
  200. right.writeElement(NodeId.fromInt(3), 4L, 0L);
  201. right.writeElement(NodeId.fromInt(6), 3L, 0L);
  202. right.writeElement(NodeId.fromInt(9), 2L, 0L);
  203. right.writeElement(NodeId.fromInt(12), 1L, 0L);
  204. assert ContextRelationship.DISJOINT ==
  205. cc.diff(left.context, right.context);
  206. left = ContextState.allocate(4, 0, allocator);
  207. left.writeElement(NodeId.fromInt(3), 5L, 0L);
  208. left.writeElement(NodeId.fromInt(6), 2L, 0L);
  209. left.writeElement(NodeId.fromInt(7), 2L, 0L);
  210. left.writeElement(NodeId.fromInt(9), 2L, 0L);
  211. right = ContextState.allocate(3, 0, allocator);
  212. right.writeElement(NodeId.fromInt(3), 4L, 0L);
  213. right.writeElement(NodeId.fromInt(6), 3L, 0L);
  214. right.writeElement(NodeId.fromInt(9), 2L, 0L);
  215. assert ContextRelationship.DISJOINT ==
  216. cc.diff(left.context, right.context);
  217. }
  218. @Test
  219. public void testMerge()
  220. {
  221. runMerge(HeapAllocator.instance);
  222. runMerge(bumpedSlab());
  223. }
  224. private void runMerge(Allocator allocator)
  225. {
  226. // note: local counts aggregated; remote counts are reconciled (i.e. take max)
  227. ContextState left = ContextState.allocate(4, 1, allocator);
  228. left.writeElement(NodeId.fromInt(1), 1L, 1L);
  229. left.writeElement(NodeId.fromInt(2), 2L, 2L);
  230. left.writeElement(NodeId.fromInt(4), 6L, 3L);
  231. left.writeElement(NodeId.getLocalId(), 7L, 3L, true);
  232. ContextState right = ContextState.allocate(3, 1, allocator);
  233. right.writeElement(NodeId.fromInt(4), 4L, 4L);
  234. right.writeElement(NodeId.fromInt(5), 5L, 5L);
  235. right.writeElement(NodeId.getLocalId(), 2L, 9L, true);
  236. ByteBuffer merged = cc.merge(left.context, right.context, allocator);
  237. int hd = 4;
  238. assertEquals(hd + 5 * stepLength, merged.remaining());
  239. // local node id's counts are aggregated
  240. assert Util.equalsNodeId(NodeId.getLocalId(), merged, hd + 4*stepLength);
  241. assertEquals( 9L, merged.getLong(merged.position() + hd + 4*stepLength + idLength));
  242. assertEquals(12L, merged.getLong(merged.position() + hd + 4*stepLength + idLength + clockLength));
  243. // remote node id counts are reconciled (i.e. take max)
  244. assert Util.equalsNodeId(NodeId.fromInt(4), merged, hd + 2*stepLength);
  245. assertEquals( 6L, merged.getLong(merged.position() + hd + 2*stepLength + idLength));
  246. assertEquals( 3L, merged.getLong(merged.position() + hd + 2*stepLength + idLength + clockLength));
  247. assert Util.equalsNodeId(NodeId.fromInt(5), merged, hd + 3*stepLength);
  248. assertEquals( 5L, merged.getLong(merged.position() + hd + 3*stepLength + idLength));
  249. assertEquals( 5L, merged.getLong(merged.position() + hd + 3*stepLength + idLength + clockLength));
  250. assert Util.equalsNodeId(NodeId.fromInt(2), merged, hd + 1*stepLength);
  251. assertEquals( 2L, merged.getLong(merged.position() + hd + 1*stepLength + idLength));
  252. assertEquals( 2L, merged.getLong(merged.position() + hd + 1*stepLength + idLength + clockLength));
  253. assert Util.equalsNodeId(NodeId.fromInt(1), merged, hd + 0*stepLength);
  254. assertEquals( 1L, merged.getLong(merged.position() + hd + 0*stepLength + idLength));
  255. assertEquals( 1L, merged.getLong(merged.position() + hd + 0*stepLength + idLength + clockLength));
  256. }
  257. @Test
  258. public void testTotal()
  259. {
  260. runTotal(HeapAllocator.instance);
  261. runTotal(bumpedSlab());
  262. }
  263. private void runTotal(Allocator allocator)
  264. {
  265. ContextState left = ContextState.allocate(4, 1, allocator);
  266. left.writeElement(NodeId.fromInt(1), 1L, 1L);
  267. left.writeElement(NodeId.fromInt(2), 2L, 2L);
  268. left.writeElement(NodeId.fromInt(4), 3L, 3L);
  269. left.writeElement(NodeId.getLocalId(), 3L, 3L, true);
  270. ContextState right = ContextState.allocate(3, 1, allocator);
  271. right.writeElement(NodeId.fromInt(4), 4L, 4L);
  272. right.writeElement(NodeId.fromInt(5), 5L, 5L);
  273. right.writeElement(NodeId.getLocalId(), 9L, 9L, true);
  274. ByteBuffer merged = cc.merge(left.context, right.context, allocator);
  275. // 127.0.0.1: 12 (3+9)
  276. // 0.0.0.1: 1
  277. // 0.0.0.2: 2
  278. // 0.0.0.4: 4
  279. // 0.0.0.5: 5
  280. assertEquals(24L, cc.total(merged));
  281. }
  282. @Test
  283. public void testMergeOldShards()
  284. {
  285. runMergeOldShards(HeapAllocator.instance);
  286. runMergeOldShards(bumpedSlab());
  287. }
  288. private void runMergeOldShards(Allocator allocator)
  289. {
  290. long now = System.currentTimeMillis();
  291. NodeId id1 = NodeId.fromInt(1);
  292. NodeId id3 = NodeId.fromInt(3);
  293. List<NodeId.NodeIdRecord> records = new ArrayList<NodeId.NodeIdRecord>();
  294. records.add(new NodeId.NodeIdRecord(id1, 2L));
  295. records.add(new NodeId.NodeIdRecord(id3, 4L));
  296. // Destination of merge is a delta
  297. ContextState ctx = ContextState.allocate(5, 2, allocator);
  298. ctx.writeElement(id1, 1L, 1L);
  299. ctx.writeElement(NodeId.fromInt(2), 2L, 2L);
  300. ctx.writeElement(id3, 3L, 3L, true);
  301. ctx.writeElement(NodeId.fromInt(4), 6L, 3L);
  302. ctx.writeElement(NodeId.fromInt(5), 7L, 3L, true);
  303. ByteBuffer merger = cc.computeOldShardMerger(ctx.context, records);
  304. ContextState m = new ContextState(merger);
  305. assert m.getNodeId().equals(id1);
  306. assert m.getClock() <= -now;
  307. assert m.getCount() == 0;
  308. m.moveToNext();
  309. assert m.getNodeId().equals(id3);
  310. assert m.getClock() == 4L;
  311. assert m.getCount() == 1L;
  312. assert cc.total(ctx.context) == cc.total(cc.merge(ctx.context, merger, allocator));
  313. // Source of merge is a delta
  314. ctx = ContextState.allocate(4, 1, allocator);
  315. ctx.writeElement(id1, 1L, 1L, true);
  316. ctx.writeElement(NodeId.fromInt(2), 2L, 2L);
  317. ctx.writeElement(id3, 3L, 3L);
  318. ctx.writeElement(NodeId.fromInt(4), 6L, 3L);
  319. merger = cc.computeOldShardMerger(ctx.context, records);
  320. assert cc.total(ctx.context) == cc.total(cc.merge(ctx.context, merger, allocator));
  321. // source and destination of merge are deltas
  322. ctx = ContextState.allocate(4, 2, allocator);
  323. ctx.writeElement(id1, 1L, 1L, true);
  324. ctx.writeElement(NodeId.fromInt(2), 2L, 2L);
  325. ctx.writeElement(id3, 3L, 3L, true);
  326. ctx.writeElement(NodeId.fromInt(4), 6L, 3L);
  327. merger = cc.computeOldShardMerger(ctx.context, records);
  328. assert cc.total(ctx.context) == cc.total(cc.merge(ctx.context, merger, allocator));
  329. // none of source and destination of merge are deltas
  330. ctx = ContextState.allocate(4, 0, allocator);
  331. ctx.writeElement(id1, 1L, 1L);
  332. ctx.writeElement(NodeId.fromInt(2), 2L, 2L);
  333. ctx.writeElement(id3, 3L, 3L);
  334. ctx.writeElement(NodeId.fromInt(4), 6L, 3L);
  335. merger = cc.computeOldShardMerger(ctx.context, records);
  336. assert cc.total(ctx.context) == cc.total(cc.merge(ctx.context, merger, allocator));
  337. }
  338. @Test
  339. public void testRemoveOldShards()
  340. {
  341. runRemoveOldShards(HeapAllocator.instance);
  342. runRemoveOldShards(bumpedSlab());
  343. }
  344. private void runRemoveOldShards(Allocator allocator)
  345. {
  346. NodeId id1 = NodeId.fromInt(1);
  347. NodeId id3 = NodeId.fromInt(3);
  348. NodeId id6 = NodeId.fromInt(6);
  349. List<NodeId.NodeIdRecord> records = new ArrayList<NodeId.NodeIdRecord>();
  350. records.add(new NodeId.NodeIdRecord(id1, 2L));
  351. records.add(new NodeId.NodeIdRecord(id3, 4L));
  352. records.add(new NodeId.NodeIdRecord(id6, 10L));
  353. ContextState ctx = ContextState.allocate(6, 2, allocator);
  354. ctx.writeElement(id1, 1L, 1L);
  355. ctx.writeElement(NodeId.fromInt(2), 2L, 2L);
  356. ctx.writeElement(id3, 3L, 3L, true);
  357. ctx.writeElement(NodeId.fromInt(4), 6L, 3L);
  358. ctx.writeElement(NodeId.fromInt(5), 7L, 3L, true);
  359. ctx.writeElement(id6, 5L, 6L);
  360. ByteBuffer merger = cc.computeOldShardMerger(ctx.context, records);
  361. ByteBuffer merged = cc.merge(ctx.context, merger, allocator);
  362. assert cc.total(ctx.context) == cc.total(merged);
  363. ByteBuffer cleaned = cc.removeOldShards(merged, (int)(System.currentTimeMillis() / 1000) + 1);
  364. assert cc.total(ctx.context) == cc.total(cleaned);
  365. assert cleaned.remaining() == ctx.context.remaining() - stepLength;
  366. merger = cc.computeOldShardMerger(cleaned, records);
  367. merged = cc.merge(cleaned, merger, allocator);
  368. assert cc.total(ctx.context) == cc.total(merged);
  369. cleaned = cc.removeOldShards(merged, (int)(System.currentTimeMillis() / 1000) + 1);
  370. assert cc.total(ctx.context) == cc.total(cleaned);
  371. assert cleaned.remaining() == ctx.context.remaining() - 2 * stepLength - 2;
  372. }
  373. }