package com.linkedin.databus.client.pub;
/*
*
* Copyright 2013 LinkedIn Corp. All rights reserved
*
* 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.
*
*/
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;
import org.I0Itec.zkclient.ZkServer;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.testng.Assert;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import com.linkedin.databus.client.pub.ClusterCheckpointPersistenceProvider.ClusterCheckpointException;
import com.linkedin.databus.core.Checkpoint;
import com.linkedin.databus.core.DbusClientMode;
import com.linkedin.databus.core.util.FileUtils;
import com.linkedin.databus.core.util.InvalidConfigException;
import com.linkedin.databus.core.util.RngUtils;
import com.linkedin.databus.core.util.Utils;
import com.linkedin.databus2.test.TestUtil;
public class TestClusterCheckpointPersistenceProvider
{
protected static final Logger LOG = Logger.getLogger(TestClusterCheckpointPersistenceProvider.class);
static int localZkPort = Utils.getAvailablePort(2193);
static final String zkAddr = "localhost:" + localZkPort;
static final String clusterName = "test-databus-cluster-cp";
static List<ZkServer> _localZkServers = null;
@BeforeClass
public void startZookeeper() throws IOException
{
TestUtil.setupLoggingWithTimestampedFile(true, "/tmp/TestClusterCheckpointPersistenceProvider_",
".log", Level.WARN);
File zkroot = FileUtils.createTempDir("TestClusterCheckpointPersistenceProvider_zkroot");
LOG.info("starting ZK on port " + localZkPort + " and datadir " + zkroot.getAbsolutePath());
ZkServer zkServer = TestUtil.startZkServer(zkroot.getAbsolutePath(), 0,
localZkPort , 2000);
if (zkServer != null)
{
_localZkServers = new Vector<ZkServer>(1);
_localZkServers.add(zkServer);
}
}
@AfterClass
public void stopZookeeper()
{
if (_localZkServers != null)
{
TestUtil.stopLocalZookeeper(_localZkServers);
}
}
@Test
public void testClusterCheckpointPersistence()
{
Checkpoint cp = new Checkpoint();
cp.setWindowScn(50532L);
cp.setWindowOffset(-1);
cp.setConsumptionMode(DbusClientMode.ONLINE_CONSUMPTION);
String id = "4";
String clusterName = "test-cluster-persistence";
ClusterCheckpointPersistenceProvider.createCluster(zkAddr,clusterName);
ClusterCheckpointPersistenceProvider.Config conf = new ClusterCheckpointPersistenceProvider.Config();
conf.setClusterName(clusterName);
conf.setZkAddr(zkAddr);
ArrayList<String> sources= new ArrayList<String>(3);
sources.add("source1");
sources.add("source2");
sources.add("source3");
try
{
ClusterCheckpointPersistenceProvider ccp = new ClusterCheckpointPersistenceProvider(id,conf);
ccp.storeCheckpoint(sources, cp);
Checkpoint newCp = ccp.loadCheckpoint(sources);
Assert.assertTrue(newCp != null);
Assert.assertTrue(newCp.getWindowOffset()==cp.getWindowOffset());
Assert.assertTrue(newCp.getWindowScn()==cp.getWindowScn());
Assert.assertTrue(newCp.getConsumptionMode()==cp.getConsumptionMode());
}
catch (InvalidConfigException e)
{
System.err.println("Invalid config: " + e);
Assert.assertTrue(false);
}
catch (IOException e)
{
System.err.println("Error storing checkpoint: " + e);
Assert.assertTrue(false);
}
catch (ClusterCheckpointException e)
{
Assert.assertTrue(false);
}
finally
{
ClusterCheckpointPersistenceProvider.close(clusterName);
}
}
@Test
public void testFrequencyOfCheckpoints() throws Exception
{
Checkpoint cp = new Checkpoint();
long startWindowScn = 50532L;
cp.setWindowScn(startWindowScn);
cp.setWindowOffset(-1);
cp.setConsumptionMode(DbusClientMode.ONLINE_CONSUMPTION);
final int checkPointIntervalMs = 75;
final long delayMs = 31;
final int numAttemptedWrites = 7;
// We should write at 0, 31, 62, 93, 123, 155, 186, but only at at 0, 93, 155
// Persistent provider clock: 0 75 150 225
// checkpoint store clock 0 31 62 93 123 155 186
final int expectedActualStores = 3;
String id = "5";
String clusterName = "test-cluster-freq";
ClusterCheckpointPersistenceProvider.createCluster(zkAddr, clusterName);
ClusterCheckpointPersistenceProvider.Config conf = new ClusterCheckpointPersistenceProvider.Config();
conf.setClusterName(clusterName);
conf.setZkAddr(zkAddr);
conf.setCheckpointIntervalMs(checkPointIntervalMs);
ArrayList<String> sources = new ArrayList<String>(3);
sources.add("source1");
sources.add("source2");
sources.add("source3");
try
{
TestFrequencyCPP ccp = new TestFrequencyCPP(id, conf);
for (int i = 0; i < numAttemptedWrites; ++i)
{
cp.setWindowScn(startWindowScn + i);
ccp.storeCheckpoint(sources, cp);
Checkpoint newCp = ccp.getStoredCheckpoint();
// cp integrity checks
Assert.assertTrue(newCp != null);
Assert.assertTrue(newCp.getWindowOffset() == cp
.getWindowOffset());
Assert.assertTrue(newCp.getConsumptionMode() == cp
.getConsumptionMode());
// skipped store test;
Thread.sleep(delayMs);
}
Assert.assertEquals(ccp.getnStores(), expectedActualStores);
}
finally
{
ClusterCheckpointPersistenceProvider.close(clusterName);
}
}
@Test
public void testMultipleClusterCheckpointPersistence()
{
try
{
String[] partitionIds = { "1", "2", "3", "4", "5", "6" };
String[] clusters = { "tcluster1", "tcluster2", "tcluster3" };
ArrayList<CheckpointRW> cpRws = new ArrayList<TestClusterCheckpointPersistenceProvider.CheckpointRW>();
for (String c : clusters)
{
// create clusters;
ClusterCheckpointPersistenceProvider.createCluster(zkAddr, c);
for (String p : partitionIds)
{
cpRws.add(new CheckpointRW(c, p, RngUtils
.randomPositiveLong()));
}
}
for (CheckpointRW cpRW : cpRws)
{
cpRW.start();
}
for (CheckpointRW cpRW : cpRws)
{
cpRW.join(10000);
Assert.assertFalse(cpRW.hasError());
}
}
catch (Exception e)
{
Assert.assertTrue(false);
}
}
/**
* thread that writes Checkpoints to clusters
*
*/
public class CheckpointRW extends Thread
{
private final String _clusterName;
private final String _partitionId;
private final long _startScn;
private final long _durationMs = 5000;
private final long _delayMs = 200;
private boolean _hasError = false;
public CheckpointRW(String cluster, String partitionId, long startScn)
{
_clusterName = cluster;
_partitionId = partitionId;
_startScn = startScn;
}
public boolean hasError()
{
return _hasError;
}
public String getClusterName()
{
return _clusterName;
}
@Override
public void run()
{
try
{
ArrayList<String> sources = new ArrayList<String>(3);
sources.add("src1");
sources.add("src2");
sources.add("src3");
long endTimeMs = System.currentTimeMillis() + _durationMs;
while (System.currentTimeMillis() < endTimeMs)
{
ClusterCheckpointPersistenceProvider.Config conf = new ClusterCheckpointPersistenceProvider.Config();
conf.setClusterName(_clusterName);
conf.setZkAddr(zkAddr);
conf.setCheckpointIntervalMs(_delayMs - 10);
Checkpoint cp = new Checkpoint();
cp.setWindowScn(_startScn);
cp.setWindowOffset(-1);
cp.setConsumptionMode(DbusClientMode.ONLINE_CONSUMPTION);
// cluster creation code
ClusterCheckpointPersistenceProvider ccp = new ClusterCheckpointPersistenceProvider(
_partitionId, conf);
ccp.storeCheckpoint(sources, cp);
Checkpoint newCp = ccp.loadCheckpoint(sources);
Assert.assertTrue(newCp != null);
Assert.assertTrue(newCp.getWindowOffset() == cp
.getWindowOffset());
Assert.assertTrue(newCp.getWindowScn() == cp.getWindowScn());
Assert.assertTrue(newCp.getConsumptionMode() == cp
.getConsumptionMode());
Thread.sleep(_delayMs);
}
}
catch (Exception e)
{
LOG.error("Exception caught " + e, e);
_hasError = true;
}
finally
{
ClusterCheckpointPersistenceProvider.close(_clusterName);
}
}
}
public static class TestFrequencyCPP extends ClusterCheckpointPersistenceProvider
{
private int nStores = 0;
private Checkpoint storedCheckpoint = null;
public TestFrequencyCPP(String id, Config config)
throws InvalidConfigException, ClusterCheckpointException
{
super(id, config);
}
@Override
protected void storeZkRecord(List<String> sourceNames, Checkpoint checkpoint)
{
storedCheckpoint = checkpoint;
nStores++;
}
public int getnStores()
{
return nStores;
}
public Checkpoint getStoredCheckpoint()
{
return storedCheckpoint;
}
}
}