/*
* Copyright 2008-2012 LinkedIn, Inc
*
* Licensed 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 voldemort.store.stats;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import org.junit.Before;
import org.junit.Test;
import voldemort.ServerTestUtils;
import voldemort.client.protocol.RequestFormatType;
import voldemort.store.socket.SocketDestination;
import voldemort.store.socket.clientrequest.ClientRequestExecutor;
import voldemort.utils.Time;
import voldemort.utils.pool.QueuedKeyedResourcePool;
public class ClientSocketStatsTest {
private ClientSocketStats masterStats;
private int port;
private SocketDestination dest1;
private SocketDestination dest2;
private QueuedKeyedResourcePool<SocketDestination, ClientRequestExecutor> pool;
private double errorBound = 0.03;
private void assertEqualsWithErrorBound(double expected, double actual) {
assertEquals(expected, actual, expected * errorBound);
}
@Before
public void setUp() throws Exception {
this.port = ServerTestUtils.findFreePort();
this.dest1 = new SocketDestination("localhost", port, RequestFormatType.VOLDEMORT_V1);
this.dest2 = new SocketDestination("localhost", port + 1, RequestFormatType.VOLDEMORT_V1);
this.masterStats = new ClientSocketStats("");
pool = null;
}
@Test
public void testNewNodeStatsObject() {
ClientSocketStats stats = new ClientSocketStats(masterStats, dest1, pool, "");
assertNotNull(stats);
}
@SuppressWarnings("deprecation")
@Test
public void testNewAggrNodeStatsObject() {
ClientSocketStats stats = masterStats;
assertNotNull(stats);
assertEquals(0, stats.getCount(ClientSocketStats.Tracked.CONNECTION_CREATED_EVENT));
assertEquals(0, stats.getCount(ClientSocketStats.Tracked.CONNECTION_DESTROYED_EVENT));
assertEquals(0, stats.getCheckoutCount());
assertEquals(0, (int) stats.getAvgCheckoutWaitMs() * Time.US_PER_MS);
}
@Test
public void testConnectionCreate() {
ClientSocketStats stats = masterStats;
stats.incrementCount(dest1, ClientSocketStats.Tracked.CONNECTION_CREATED_EVENT);
stats.incrementCount(dest2, ClientSocketStats.Tracked.CONNECTION_CREATED_EVENT);
stats.incrementCount(dest1, ClientSocketStats.Tracked.CONNECTION_CREATED_EVENT);
assertEquals(3, stats.getCount(ClientSocketStats.Tracked.CONNECTION_CREATED_EVENT));
assertEquals(2,
stats.getStatsMap()
.get(dest1)
.getCount(ClientSocketStats.Tracked.CONNECTION_CREATED_EVENT));
assertEquals(1,
stats.getStatsMap()
.get(dest2)
.getCount(ClientSocketStats.Tracked.CONNECTION_CREATED_EVENT));
}
@Test
public void testConnectionDestroy() {
ClientSocketStats stats = masterStats;
stats.incrementCount(dest1, ClientSocketStats.Tracked.CONNECTION_DESTROYED_EVENT);
stats.incrementCount(dest2, ClientSocketStats.Tracked.CONNECTION_DESTROYED_EVENT);
stats.incrementCount(dest1, ClientSocketStats.Tracked.CONNECTION_DESTROYED_EVENT);
assertEquals(3, stats.getCount(ClientSocketStats.Tracked.CONNECTION_DESTROYED_EVENT));
assertEquals(2,
stats.getStatsMap()
.get(dest1)
.getCount(ClientSocketStats.Tracked.CONNECTION_DESTROYED_EVENT));
assertEquals(1,
stats.getStatsMap()
.get(dest2)
.getCount(ClientSocketStats.Tracked.CONNECTION_DESTROYED_EVENT));
}
@Test
public void testRecordCheckoutTimeOnce() {
ClientSocketStats stats = masterStats;
assertEquals(0, stats.getCheckoutCount());
stats.recordCheckoutTimeUs(dest1, 100);
// check parent
assertEquals(1, stats.getCheckoutCount());
assertEqualsWithErrorBound(100, (int) (stats.getCheckoutTimeMsQ99th() * Time.US_PER_MS));
// check child
ClientSocketStats child = stats.getStatsMap().get(dest1);
assertNotNull(child);
assertEquals(1, child.getCheckoutCount());
assertEqualsWithErrorBound(100, (int) (child.getCheckoutTimeMsQ99th() * Time.US_PER_MS));
}
@Test
public void testRecordCheckoutTimeMultiple() {
ClientSocketStats stats = masterStats;
assertEquals(0, stats.getCheckoutCount());
// FIXME: 10 values is not enough to have a statistically-significant sample size to measure percentiles off of.
stats.recordCheckoutTimeUs(dest1, 100);
stats.recordCheckoutTimeUs(dest1, 200);
stats.recordCheckoutTimeUs(dest1, 300);
stats.recordCheckoutTimeUs(dest1, 400);
stats.recordCheckoutTimeUs(dest2, 500);
stats.recordCheckoutTimeUs(dest2, 600);
stats.recordCheckoutTimeUs(dest1, 700);
stats.recordCheckoutTimeUs(dest1, 800);
stats.recordCheckoutTimeUs(dest2, 900);
stats.recordCheckoutTimeUs(dest1, 1000);
// check parent
assertEquals(10, stats.getCheckoutCount());
assertEqualsWithErrorBound(1000, (int) (stats.getCheckoutTimeMsQ99th() * Time.US_PER_MS));
// check child1
ClientSocketStats child1 = stats.getStatsMap().get(dest1);
assertNotNull(child1);
assertEquals(7, child1.getCheckoutCount());
assertEqualsWithErrorBound(100, (int) (child1.getCheckoutTimeMsQ10th() * Time.US_PER_MS));
assertEqualsWithErrorBound(400, (int) (child1.getCheckoutTimeMsQ50th() * Time.US_PER_MS));
assertEqualsWithErrorBound(1000, (int) (child1.getCheckoutTimeMsQ99th() * Time.US_PER_MS));
// check child2
ClientSocketStats child2 = stats.getStatsMap().get(dest2);
assertNotNull(child2);
assertEquals(3, child2.getCheckoutCount());
assertEqualsWithErrorBound(500, (int) (child2.getCheckoutTimeMsQ10th() * Time.US_PER_MS));
assertEqualsWithErrorBound(600, (int) (child2.getCheckoutTimeMsQ50th() * Time.US_PER_MS));
assertEqualsWithErrorBound(900, (int) (child2.getCheckoutTimeMsQ99th() * Time.US_PER_MS));
}
@Test
public void testRecordResourceRequestTimeOnce() {
ClientSocketStats stats = masterStats;
assertEquals(0, stats.resourceRequestCount());
stats.recordResourceRequestTimeUs(dest1, 100);
// check parent
assertEquals(1, stats.resourceRequestCount());
assertEqualsWithErrorBound(100, (int) (stats.getResourceRequestTimeMsQ99th() * Time.US_PER_MS));
// check child
ClientSocketStats child = stats.getStatsMap().get(dest1);
assertNotNull(child);
assertEquals(1, child.resourceRequestCount());
assertEqualsWithErrorBound(100, (int) (child.getResourceRequestTimeMsQ99th() * Time.US_PER_MS));
}
@Test
public void testRecordResourceRequestTimeMultiple() {
ClientSocketStats stats = masterStats;
assertEquals(0, stats.resourceRequestCount());
// FIXME: 10 values is not enough to have a statistically-significant sample size to measure percentiles off of.
stats.recordCheckoutTimeUs(dest1, 100);
stats.recordCheckoutTimeUs(dest1, 200);
stats.recordCheckoutTimeUs(dest1, 300);
stats.recordCheckoutTimeUs(dest1, 400);
stats.recordCheckoutTimeUs(dest2, 500);
stats.recordCheckoutTimeUs(dest2, 600);
stats.recordCheckoutTimeUs(dest1, 700);
stats.recordCheckoutTimeUs(dest1, 800);
stats.recordCheckoutTimeUs(dest2, 900);
stats.recordCheckoutTimeUs(dest1, 1000);
// check parent
assertEquals(10, stats.getCheckoutCount());
assertEqualsWithErrorBound(1000, (int) (stats.getCheckoutTimeMsQ99th() * Time.US_PER_MS));
// check child1
ClientSocketStats child1 = stats.getStatsMap().get(dest1);
assertNotNull(child1);
assertEquals(7, child1.getCheckoutCount());
assertEqualsWithErrorBound(100, (int) (child1.getCheckoutTimeMsQ10th() * Time.US_PER_MS));
assertEqualsWithErrorBound(400, (int) (child1.getCheckoutTimeMsQ50th() * Time.US_PER_MS));
assertEqualsWithErrorBound(1000, (int) (child1.getCheckoutTimeMsQ99th() * Time.US_PER_MS));
// check child2
ClientSocketStats child2 = stats.getStatsMap().get(dest2);
assertNotNull(child2);
assertEquals(3, child2.getCheckoutCount());
assertEqualsWithErrorBound(500, (int) (child2.getCheckoutTimeMsQ10th() * Time.US_PER_MS));
assertEqualsWithErrorBound(600, (int) (child2.getCheckoutTimeMsQ50th() * Time.US_PER_MS));
assertEqualsWithErrorBound(900, (int) (child2.getCheckoutTimeMsQ99th() * Time.US_PER_MS));
}
@Test
public void testRecordCheckoutQueueLengthOnce() {
ClientSocketStats stats = masterStats;
assertEquals(0, stats.getCheckoutQueueLengthHistogram().getQuantile(0.99));
stats.recordCheckoutQueueLength(dest1, 50);
// check parent
assertEquals(50, stats.getCheckoutQueueLengthHistogram().getQuantile(0.99));
// check child
ClientSocketStats child = stats.getStatsMap().get(dest1);
assertNotNull(child);
assertEquals(50, child.getCheckoutQueueLengthHistogram().getQuantile(0.99));
}
@Test
public void testRecordCheckoutQueueLengthMultiple() {
ClientSocketStats stats = masterStats;
assertEquals(0, stats.getCheckoutQueueLengthHistogram().getQuantile(0.99));
stats.recordCheckoutQueueLength(dest1, 50);
stats.recordCheckoutQueueLength(dest2, 50);
stats.recordCheckoutQueueLength(dest1, 100);
stats.recordCheckoutQueueLength(dest2, 100);
stats.recordCheckoutQueueLength(dest2, 100);
stats.recordCheckoutQueueLength(dest1, 50);
// check parent
assertEquals(50, stats.getCheckoutQueueLengthHistogram().getQuantile(0.01));
assertEquals(50, stats.getCheckoutQueueLengthHistogram().getQuantile(0.50));
assertEquals(100, stats.getCheckoutQueueLengthHistogram().getQuantile(0.51));
assertEquals(100, stats.getCheckoutQueueLengthHistogram().getQuantile(0.99));
// check child 1
ClientSocketStats child1 = stats.getStatsMap().get(dest1);
assertNotNull(child1);
assertEquals(50, child1.getCheckoutQueueLengthHistogram().getQuantile(0.01));
assertEquals(50, child1.getCheckoutQueueLengthHistogram().getQuantile(0.66));
assertEquals(100, child1.getCheckoutQueueLengthHistogram().getQuantile(0.67));
assertEquals(100, child1.getCheckoutQueueLengthHistogram().getQuantile(0.99));
// check child 2
ClientSocketStats child2 = stats.getStatsMap().get(dest2);
assertNotNull(child2);
assertEquals(50, child2.getCheckoutQueueLengthHistogram().getQuantile(0.01));
assertEquals(50, child2.getCheckoutQueueLengthHistogram().getQuantile(0.33));
assertEquals(100, child2.getCheckoutQueueLengthHistogram().getQuantile(0.34));
assertEquals(100, child2.getCheckoutQueueLengthHistogram().getQuantile(0.99));
}
@Test
public void testRecordResourceRequestQueueLengthOnce() {
ClientSocketStats stats = masterStats;
assertEquals(0, stats.getResourceRequestQueueLengthHistogram().getQuantile(0.99));
stats.recordResourceRequestQueueLength(dest1, 50);
// check parent
assertEquals(50, stats.getResourceRequestQueueLengthHistogram().getQuantile(0.99));
// check child
ClientSocketStats child = stats.getStatsMap().get(dest1);
assertNotNull(child);
assertEquals(50, child.getResourceRequestQueueLengthHistogram().getQuantile(0.99));
}
@Test
public void testRecordResourceRequestQueueLengthMultiple() {
ClientSocketStats stats = masterStats;
assertEquals(0, stats.getResourceRequestQueueLengthHistogram().getQuantile(0.99));
stats.recordResourceRequestQueueLength(dest1, 50);
stats.recordResourceRequestQueueLength(dest2, 50);
stats.recordResourceRequestQueueLength(dest1, 100);
stats.recordResourceRequestQueueLength(dest2, 100);
stats.recordResourceRequestQueueLength(dest2, 100);
stats.recordResourceRequestQueueLength(dest1, 50);
// check parent
assertEquals(50, stats.getResourceRequestQueueLengthHistogram().getQuantile(0.01));
assertEquals(50, stats.getResourceRequestQueueLengthHistogram().getQuantile(0.50));
assertEquals(100, stats.getResourceRequestQueueLengthHistogram().getQuantile(0.51));
assertEquals(100, stats.getResourceRequestQueueLengthHistogram().getQuantile(0.99));
// check child 1
ClientSocketStats child1 = stats.getStatsMap().get(dest1);
assertNotNull(child1);
assertEquals(50, child1.getResourceRequestQueueLengthHistogram().getQuantile(0.01));
assertEquals(50, child1.getResourceRequestQueueLengthHistogram().getQuantile(0.66));
assertEquals(100, child1.getResourceRequestQueueLengthHistogram().getQuantile(0.67));
assertEquals(100, child1.getResourceRequestQueueLengthHistogram().getQuantile(0.99));
// check child 2
ClientSocketStats child2 = stats.getStatsMap().get(dest2);
assertNotNull(child2);
assertEquals(50, child2.getResourceRequestQueueLengthHistogram().getQuantile(0.01));
assertEquals(50, child2.getResourceRequestQueueLengthHistogram().getQuantile(0.33));
assertEquals(100, child2.getResourceRequestQueueLengthHistogram().getQuantile(0.34));
assertEquals(100, child2.getResourceRequestQueueLengthHistogram().getQuantile(0.99));
}
@SuppressWarnings("deprecation")
@Test
public void testSetMonitoringInterval() {
ClientSocketStats stats = masterStats;
stats.setMonitoringInterval(500);
stats.recordCheckoutQueueLength(dest1, 1);
stats.recordCheckoutQueueLength(dest1, 2);
stats.recordCheckoutQueueLength(dest1, 3);
stats.recordCheckoutQueueLength(dest1, 4);
stats.recordCheckoutQueueLength(dest1, 5);
stats.recordCheckoutQueueLength(dest1, 6);
stats.recordCheckoutQueueLength(dest2, 7);
stats.recordCheckoutQueueLength(dest2, 8);
// before reset
// check parent
assertEquals(4.5, (stats.getCheckoutQueueLengthHistogram().getAverage()), 0);
// check child
ClientSocketStats child1 = stats.getStatsMap().get(dest1);
ClientSocketStats child2 = stats.getStatsMap().get(dest2);
assertEquals(3.5, child1.getCheckoutQueueLengthHistogram().getAverage(), 0);
assertEquals(7.5, child2.getCheckoutQueueLengthHistogram().getAverage(), 0);
// Make it sleep for a second
try {
Thread.sleep(1000);
} catch(InterruptedException e) {
e.printStackTrace();
}
// The histogram should be reset by now
assertEquals(0, (stats.getCheckoutQueueLengthHistogram().getAverage()), 0);
stats.recordCheckoutQueueLength(dest1, 1);
stats.recordCheckoutQueueLength(dest1, 1);
stats.recordCheckoutQueueLength(dest2, 4);
// after reset
// check parent
assertEquals(2, (stats.getCheckoutQueueLengthHistogram().getAverage()), 0);
// check child
assertEquals(1, (child1.getCheckoutQueueLengthHistogram().getAverage()), 0);
assertEquals(4, (child2.getCheckoutQueueLengthHistogram().getAverage()), 0);
}
@SuppressWarnings("deprecation")
@Test
public void concurrentTest() {
class TestThread implements Runnable {
SocketDestination dest;
public TestThread(SocketDestination dest) {
this.dest = dest;
}
@Override
public void run() {
masterStats.recordCheckoutTimeUs(dest, 1000);
masterStats.recordCheckoutTimeUs(dest, 2000);
masterStats.recordCheckoutTimeUs(dest, 3000);
masterStats.recordCheckoutTimeUs(dest, 4000);
masterStats.recordCheckoutTimeUs(dest, 5000);
masterStats.recordCheckoutTimeUs(dest, 6000);
masterStats.recordCheckoutTimeUs(dest, 7000);
masterStats.recordCheckoutTimeUs(dest, 8000);
masterStats.recordCheckoutTimeUs(dest, 9000);
}
}
Thread t1 = new Thread(new TestThread(dest1));
Thread t1_1 = new Thread(new TestThread(dest1));
Thread t1_2 = new Thread(new TestThread(dest1));
Thread t1_3 = new Thread(new TestThread(dest1));
Thread t2 = new Thread(new TestThread(dest2));
Thread t2_1 = new Thread(new TestThread(dest2));
t1.start();
t2.start();
t2_1.start();
t1_1.start();
t1_2.start();
t1_3.start();
try {
t1.join();
t2.join();
t2_1.join();
t1_1.join();
t1_2.join();
t1_3.join();
} catch(Exception e) {}
assertEqualsWithErrorBound(1000,
(int) (masterStats.getCheckoutTimeMsQ10th() * Time.US_PER_MS));
assertEqualsWithErrorBound(5000,
(int) (masterStats.getCheckoutTimeMsQ50th() * Time.US_PER_MS));
assertEqualsWithErrorBound(1000,
(int) (masterStats.getStatsMap().get(dest1).getCheckoutTimeMsQ10th() * Time.US_PER_MS));
assertEqualsWithErrorBound(5000,
(int) (masterStats.getStatsMap().get(dest1).getCheckoutTimeMsQ50th() * Time.US_PER_MS));
assertEqualsWithErrorBound(1000,
(int) (masterStats.getStatsMap().get(dest2).getCheckoutTimeMsQ10th() * Time.US_PER_MS));
assertEqualsWithErrorBound(5000,
(int) (masterStats.getStatsMap().get(dest2).getCheckoutTimeMsQ50th() * Time.US_PER_MS));
}
}