blob: 9d451dcde4ef8dfaf6c1fdea96725b9380eb3f9b [file] [log] [blame]
Yuta HIGUCHId47eac32014-04-07 13:44:47 -07001package net.onrc.onos.core.datastore;
2
3import static org.junit.Assert.*;
4
5import java.util.ArrayList;
6import java.util.List;
7import java.util.concurrent.Callable;
8import java.util.concurrent.ConcurrentLinkedQueue;
9import java.util.concurrent.ConcurrentMap;
10import java.util.concurrent.ConcurrentNavigableMap;
11import java.util.concurrent.ConcurrentSkipListMap;
12import java.util.concurrent.ExecutionException;
13import java.util.concurrent.ExecutorService;
14import java.util.concurrent.Executors;
15import java.util.concurrent.Future;
16
17import net.onrc.onos.core.datastore.DataStoreClient;
18import net.onrc.onos.core.datastore.IKVClient;
19import net.onrc.onos.core.datastore.IKVTableID;
20import net.onrc.onos.core.datastore.ObjectDoesntExistException;
21import net.onrc.onos.core.datastore.ObjectExistsException;
22
23import org.junit.After;
24import org.junit.Before;
25import org.junit.Test;
26
27public class AtomicCounterTest {
28
29 private static final String TEST_COUNTER = "TestCounter";
30 private static final byte[] LONG_ZERO = {0, 0, 0, 0, 0, 0, 0, 0}; // 0L
31 private static final IKVTableID counterID = DataStoreClient.getClient().getTable(TEST_COUNTER).getTableId();
32
33 @After
34 @Before
35 public void resetCounter() {
36 IKVClient client = DataStoreClient.getClient();
37 client.setCounter(counterID, LONG_ZERO, 0L);
38 client.destroyCounter(counterID, LONG_ZERO);
39 }
40
41 @Test
42 public void testSetCounter() throws ObjectExistsException, ObjectDoesntExistException {
43 IKVClient client = DataStoreClient.getClient();
44
45 final long five = 5;
46 client.createCounter(counterID, LONG_ZERO, five);
47
48 final long three = 3;
49 client.setCounter(counterID, LONG_ZERO, three);
50
51 final long four = client.incrementCounter(counterID, LONG_ZERO, 1);
52 assertEquals(4, four);
53 }
54
55 @Test
56 public void testIncrementCounter() throws ObjectExistsException, ObjectDoesntExistException {
57
58 IKVClient client = DataStoreClient.getClient();
59
60 final long five = 5;
61 client.createCounter(counterID, LONG_ZERO, five);
62
63 final long six = client.incrementCounter(counterID, LONG_ZERO, 1);
64 assertEquals(6, six);
65
66
67 final long nine = client.incrementCounter(counterID, LONG_ZERO, 3);
68 assertEquals(9, nine);
69 }
70
71
Yuta HIGUCHI69200352014-04-11 12:32:44 -070072 private static final int NUM_INCREMENTS = Math.max(1, Integer
73 .valueOf(System.getProperty("AtomicCounterTest.NUM_INCREMENTS",
74 "500")));
75 private static final int NUM_THREADS = Math.max(1, Integer.valueOf(System
76 .getProperty("AtomicCounterTest.NUM_THREADS", "3")));
Yuta HIGUCHId47eac32014-04-07 13:44:47 -070077
78 class Incrementor implements Callable<Long> {
79 private final ConcurrentMap<Long,Long> uniquenessTestSet;
80 private final ConcurrentLinkedQueue<Long> incrementTimes;
81
82 public Incrementor(ConcurrentMap<Long, Long> uniquenessTestSet, ConcurrentLinkedQueue<Long> incrementTimes) {
83 super();
84 this.uniquenessTestSet = uniquenessTestSet;
85 this.incrementTimes = incrementTimes;
86 }
87
88 @Override
89 public Long call() throws ObjectDoesntExistException {
90 IKVClient client = DataStoreClient.getClient();
91 for (int i = 0 ; i < NUM_INCREMENTS ; ++i) {
92 final long start = System.nanoTime();
93 final long incremented = client.incrementCounter(counterID, LONG_ZERO, 1);
94 incrementTimes.add( System.nanoTime() - start );
95 final Long expectNull = uniquenessTestSet.putIfAbsent(incremented, incremented);
96 assertNull(expectNull);
97 }
98 return null;
99 }
100 }
101
102 @Test
Yuta HIGUCHI69200352014-04-11 12:32:44 -0700103 public void testParallelIncrementCounter() throws ObjectExistsException,
104 InterruptedException, ExecutionException {
105
Yuta HIGUCHId47eac32014-04-07 13:44:47 -0700106 IKVClient client = DataStoreClient.getClient();
107
108 client.createCounter(counterID, LONG_ZERO, 0L);
109
Yuta HIGUCHI69200352014-04-11 12:32:44 -0700110 ExecutorService executor = Executors.newFixedThreadPool(NUM_THREADS);
111 final int initThreads = Math.max(1, Integer.valueOf(System
112 .getProperty("AtomicCounterTest.initThreads",
113 String.valueOf(NUM_THREADS))));
114 for (int num_threads = initThreads; num_threads <= NUM_THREADS; ++num_threads) {
115 client.setCounter(counterID, LONG_ZERO, 0L);
116 parallelIncrementCounter(executor, num_threads);
117 }
118
119 executor.shutdown();
120 }
121
122 private void parallelIncrementCounter(final ExecutorService executor,
123 final int num_threads) throws InterruptedException, ExecutionException {
124
Yuta HIGUCHId47eac32014-04-07 13:44:47 -0700125 ConcurrentNavigableMap<Long,Long> uniquenessTestSet = new ConcurrentSkipListMap<>();
126 ConcurrentLinkedQueue<Long> incrementTimes = new ConcurrentLinkedQueue<Long>();
127
Yuta HIGUCHI69200352014-04-11 12:32:44 -0700128 List<Callable<Long>> tasks = new ArrayList<>(num_threads);
129 for (int i = 0 ; i < num_threads ; ++i) {
Yuta HIGUCHId47eac32014-04-07 13:44:47 -0700130 tasks.add(new Incrementor(uniquenessTestSet, incrementTimes));
131 }
132 List<Future<Long>> futures = executor.invokeAll(tasks);
133
134 // wait for all tasks to end
135 for (Future<Long> future : futures) {
136 future.get();
137 }
138
Yuta HIGUCHI69200352014-04-11 12:32:44 -0700139 assertEquals(num_threads * NUM_INCREMENTS , uniquenessTestSet.size());
Yuta HIGUCHId47eac32014-04-07 13:44:47 -0700140 long prevValue = 0;
141 for (Long value : uniquenessTestSet.keySet() ) {
Yuta HIGUCHI69200352014-04-11 12:32:44 -0700142 assertEquals( (prevValue + 1), value.longValue() );
Yuta HIGUCHId47eac32014-04-07 13:44:47 -0700143 prevValue = value;
144 }
145
146 long max = 0L;
147 long min = Long.MAX_VALUE;
148 long sum = 0L;
149 for (Long time : incrementTimes) {
150 sum += time;
151 max = Math.max(max, time);
152 min = Math.min(min, time);
153 }
Yuta HIGUCHI69200352014-04-11 12:32:44 -0700154 System.err.printf("incrementCounter(th:%d , incs:%d ) N:%d\tavg:%f (ns) min:%d (ns) max:%d (ns)\n",
155 num_threads, NUM_INCREMENTS, incrementTimes.size(),
156 sum/(double)incrementTimes.size(), min, max );
Yuta HIGUCHId47eac32014-04-07 13:44:47 -0700157 }
158
159}