Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Reik Schatz
committed
Jan 25, 2013
0 parents
commit a307938
Showing
7 changed files
with
899 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
### Description | ||
|
||
A modified embedded Cassandra based on cassandra-unit. The main difference is that it uses the specified configuration | ||
file (cassandra.yml) in place without making a copy of it in the temp directory. | ||
|
||
### Start Command Example | ||
|
||
java -cp "target/embedded-cassandra-starter-1.0-SNAPSHOT.jar" se.javasplitter.CassandraStarter /home/user/dev/embedded-cassandra-starter/src/test/resources/cassandra.yml |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
<modelVersion>4.0.0</modelVersion> | ||
|
||
<groupId>se.javasplitter</groupId> | ||
<artifactId>embedded-cassandra-starter</artifactId> | ||
<version>1.0-SNAPSHOT</version> | ||
<packaging>jar</packaging> | ||
|
||
<properties> | ||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> | ||
</properties> | ||
|
||
<dependencies> | ||
<dependency> | ||
<groupId>commons-io</groupId> | ||
<artifactId>commons-io</artifactId> | ||
<version>2.4</version> | ||
</dependency> | ||
|
||
<dependency> | ||
<groupId>org.cassandraunit</groupId> | ||
<artifactId>cassandra-unit</artifactId> | ||
<version>1.1.1.2</version> | ||
</dependency> | ||
|
||
<dependency> | ||
<groupId>junit</groupId> | ||
<artifactId>junit</artifactId> | ||
<version>4.10</version> | ||
<scope>test</scope> | ||
</dependency> | ||
</dependencies> | ||
|
||
<build> | ||
<plugins> | ||
<plugin> | ||
<groupId>org.apache.maven.plugins</groupId> | ||
<artifactId>maven-compiler-plugin</artifactId> | ||
<version>3.0</version> | ||
</plugin> | ||
|
||
<plugin> | ||
<groupId>org.apache.maven.plugins</groupId> | ||
<artifactId>maven-source-plugin</artifactId> | ||
<version>2.2.1</version> | ||
</plugin> | ||
|
||
<plugin> | ||
<groupId>org.apache.maven.plugins</groupId> | ||
<artifactId>maven-javadoc-plugin</artifactId> | ||
<version>2.9</version> | ||
</plugin> | ||
|
||
<plugin> | ||
<groupId>org.apache.maven.plugins</groupId> | ||
<artifactId>maven-surefire-plugin</artifactId> | ||
<version>2.12.4</version> | ||
<configuration> | ||
<skipTests>true</skipTests> | ||
</configuration> | ||
</plugin> | ||
|
||
<plugin> | ||
<groupId>org.apache.maven.plugins</groupId> | ||
<artifactId>maven-assembly-plugin</artifactId> | ||
<version>2.4</version> | ||
<configuration> | ||
<archive> | ||
<manifest> | ||
<mainClass>se.javasplitter.CassandraStarter</mainClass> | ||
</manifest> | ||
</archive> | ||
<descriptorRefs> | ||
<descriptorRef>jar-with-dependencies</descriptorRef> | ||
</descriptorRefs> | ||
<appendAssemblyId>false</appendAssemblyId> | ||
</configuration> | ||
<executions> | ||
<execution> | ||
<phase>package</phase> | ||
<goals> | ||
<goal>single</goal> | ||
</goals> | ||
</execution> | ||
</executions> | ||
</plugin> | ||
</plugins> | ||
</build> | ||
</project> |
176 changes: 176 additions & 0 deletions
176
src/main/java/se/javasplitter/BetterEmbeddedCassandraServerHelper.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,176 @@ | ||
package se.javasplitter; | ||
|
||
import me.prettyprint.cassandra.service.CassandraHostConfigurator; | ||
import me.prettyprint.hector.api.Cluster; | ||
import me.prettyprint.hector.api.ddl.KeyspaceDefinition; | ||
import me.prettyprint.hector.api.factory.HFactory; | ||
import org.apache.cassandra.config.ConfigurationException; | ||
import org.apache.cassandra.config.DatabaseDescriptor; | ||
import org.apache.cassandra.db.commitlog.CommitLog; | ||
import org.apache.cassandra.io.util.FileUtils; | ||
import org.apache.cassandra.thrift.CassandraDaemon; | ||
import org.apache.thrift.transport.TTransportException; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
import java.io.*; | ||
import java.util.List; | ||
import java.util.concurrent.CountDownLatch; | ||
import java.util.concurrent.ExecutorService; | ||
import java.util.concurrent.Executors; | ||
|
||
import static java.util.concurrent.TimeUnit.SECONDS; | ||
|
||
/** | ||
* todo: comment me | ||
* | ||
* @author rschatz, 2012-11-22 | ||
*/ | ||
public class BetterEmbeddedCassandraServerHelper { | ||
private static Logger log = LoggerFactory.getLogger(BetterEmbeddedCassandraServerHelper.class); | ||
|
||
public static final String DEFAULT_CASSANDRA_YML_FILE = "cu-cassandra.yaml"; | ||
private static final String INTERNAL_CASSANDRA_KEYSPACE = "system"; | ||
|
||
private static CassandraDaemon cassandraDaemon = null; | ||
static ExecutorService executor; | ||
private static String launchedYamlFile; | ||
|
||
public static void startEmbeddedCassandra(final File file) throws TTransportException, IOException, ConfigurationException { | ||
if (cassandraDaemon != null) { | ||
/* nothing to do Cassandra is already started */ | ||
return; | ||
} | ||
|
||
checkConfigNameForRestart(file.getAbsolutePath()); | ||
|
||
log.debug("Starting cassandra..."); | ||
log.debug("Initialization needed"); | ||
|
||
System.setProperty("cassandra.config", "file:" + file.getAbsolutePath()); | ||
System.setProperty("cassandra-foreground", "true"); | ||
|
||
cleanupAndLeaveDirs(); | ||
final CountDownLatch startupLatch = new CountDownLatch(1); | ||
executor = Executors.newSingleThreadExecutor(); | ||
executor.execute(new Runnable() { | ||
@Override | ||
public void run() { | ||
cassandraDaemon = new CassandraDaemon(); | ||
cassandraDaemon.activate(); | ||
startupLatch.countDown(); | ||
} | ||
}); | ||
try { | ||
startupLatch.await(10, SECONDS); | ||
} catch (InterruptedException e) { | ||
log.error("Interrupted waiting for Cassandra daemon to start:", e); | ||
throw new AssertionError(e); | ||
} | ||
} | ||
|
||
private static void checkConfigNameForRestart(String yamlFile) { | ||
boolean wasPreviouslyLaunched = launchedYamlFile != null; | ||
if (wasPreviouslyLaunched && !launchedYamlFile.equals(yamlFile)) { | ||
throw new UnsupportedOperationException("We can't launch two Cassandra configurations in the same JVM instance"); | ||
} | ||
launchedYamlFile = yamlFile; | ||
} | ||
|
||
/** | ||
* Now deprecated, previous version was not fully operating. | ||
* This is now an empty method, will be pruned in future versions. | ||
*/ | ||
@Deprecated | ||
public static void stopEmbeddedCassandra() { | ||
log.warn("EmbeddedCassandraServerHelper.stopEmbeddedCassandra() is now deprecated, " + | ||
"previous version was not fully operating"); | ||
} | ||
|
||
/** | ||
* drop all keyspaces (expect system) | ||
*/ | ||
public static void cleanEmbeddedCassandra() { | ||
dropKeyspaces(); | ||
} | ||
|
||
private static void dropKeyspaces() { | ||
String host = DatabaseDescriptor.getRpcAddress().getHostName(); | ||
int port = DatabaseDescriptor.getRpcPort(); | ||
log.debug("Cleaning cassandra keyspaces on " + host + ":" + port); | ||
Cluster cluster = HFactory.getOrCreateCluster("TestCluster", new CassandraHostConfigurator(host + ":" + port)); | ||
/* get all keyspace */ | ||
List<KeyspaceDefinition> keyspaces = cluster.describeKeyspaces(); | ||
|
||
/* drop all keyspace except internal cassandra keyspace */ | ||
for (KeyspaceDefinition keyspaceDefinition : keyspaces) { | ||
String keyspaceName = keyspaceDefinition.getName(); | ||
|
||
if (!INTERNAL_CASSANDRA_KEYSPACE.equals(keyspaceName)) { | ||
cluster.dropKeyspace(keyspaceName); | ||
} | ||
} | ||
} | ||
|
||
private static void rmdir(final File dir) throws IOException { | ||
if (dir.exists()) { | ||
FileUtils.deleteRecursive(dir); | ||
} | ||
} | ||
|
||
private static void copy(final String configFile, final File directory) throws IOException { | ||
mkdir(directory); | ||
final InputStream is = new FileInputStream(configFile); | ||
final String fileName = configFile.substring(configFile.lastIndexOf("/") + 1); | ||
final File file = new File(directory + System.getProperty("file.separator") + fileName); | ||
final OutputStream out = new FileOutputStream(file); | ||
byte buf[] = new byte[1024]; | ||
int len; | ||
while ((len = is.read(buf)) > 0) { | ||
out.write(buf, 0, len); | ||
} | ||
out.close(); | ||
is.close(); | ||
} | ||
|
||
private static void mkdir(File dir) throws IOException { | ||
FileUtils.createDirectory(dir); | ||
} | ||
|
||
private static void cleanupAndLeaveDirs() throws IOException { | ||
mkdirs(); | ||
cleanup(); | ||
mkdirs(); | ||
CommitLog.instance.resetUnsafe(); // cleanup screws w/ CommitLog, this | ||
// brings it back to safe state | ||
} | ||
|
||
private static void cleanup() throws IOException { | ||
// clean up commitlog | ||
String[] directoryNames = {DatabaseDescriptor.getCommitLogLocation(),}; | ||
for (String dirName : directoryNames) { | ||
File dir = new File(dirName); | ||
if (!dir.exists()) | ||
throw new RuntimeException("No such directory: " + dir.getAbsolutePath()); | ||
FileUtils.deleteRecursive(dir); | ||
} | ||
|
||
// clean up data directory which are stored as data directory/table/data | ||
// files | ||
for (String dirName : DatabaseDescriptor.getAllDataFileLocations()) { | ||
File dir = new File(dirName); | ||
if (!dir.exists()) | ||
throw new RuntimeException("No such directory: " + dir.getAbsolutePath()); | ||
FileUtils.deleteRecursive(dir); | ||
} | ||
} | ||
|
||
public static void mkdirs() { | ||
try { | ||
DatabaseDescriptor.createAllDirectories(); | ||
} catch (IOException e) { | ||
throw new RuntimeException(e); | ||
} | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
package se.javasplitter; | ||
|
||
import org.apache.cassandra.config.ConfigurationException; | ||
import org.apache.thrift.transport.TTransportException; | ||
|
||
import java.io.File; | ||
import java.io.IOException; | ||
import java.util.concurrent.atomic.AtomicBoolean; | ||
|
||
/** | ||
* Utility class using in tests to properly start up and shut down cassandra. | ||
* | ||
* @author rschatz, 2012-11-08 | ||
*/ | ||
public final class CassandraStarter { | ||
|
||
private CassandraStarter() { } | ||
|
||
private static final AtomicBoolean STARTED = new AtomicBoolean(false); | ||
|
||
public static void main(final String... args) { | ||
if (args == null || args.length == 0) { | ||
throw new IllegalArgumentException("Please specify the location of a cassandra.yml file"); | ||
} | ||
|
||
final String fileName = args[0]; | ||
final File file = new File(fileName); | ||
if (!file.isFile()) { | ||
throw new IllegalArgumentException(String.format("%s does not exist or not accessible", fileName)); | ||
} | ||
|
||
CassandraStarter.startNewEmbeddedCassandra(file); | ||
} | ||
|
||
private static synchronized void startNewEmbeddedCassandra(final File configurationFile) { | ||
if (!STARTED.get()) { | ||
try { | ||
BetterEmbeddedCassandraServerHelper.startEmbeddedCassandra(configurationFile); | ||
} catch (TTransportException e) { | ||
throw new IllegalStateException("Unable to start Cassandra.", e); | ||
} catch (IOException e) { | ||
throw new IllegalStateException("Unable to start Cassandra.", e); | ||
} catch (ConfigurationException e) { | ||
throw new IllegalStateException("Unable to start Cassandra.", e); | ||
} | ||
STARTED.set(true); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
<?xml version="1.0" encoding="UTF-8" ?> | ||
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd"> | ||
|
||
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"> | ||
<appender name="console" class="org.apache.log4j.ConsoleAppender"> | ||
<param name="Target" value="System.out"/> | ||
<layout class="org.apache.log4j.PatternLayout"> | ||
<param name="ConversionPattern" value="%-5p %c{1} - %m%n"/> | ||
</layout> | ||
</appender> | ||
|
||
<root> | ||
<priority value="debug"/> | ||
<appender-ref ref="console"/> | ||
</root> | ||
|
||
</log4j:configuration> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package se.javasplitter; | ||
|
||
import org.junit.Test; | ||
|
||
/** | ||
* Starts Cassandra. | ||
* | ||
* @author rschatz, 2012-11-22 | ||
*/ | ||
public class CassandraStarterTest { | ||
|
||
@Test | ||
public void testStarting() { | ||
final String config = Thread.currentThread().getContextClassLoader().getResource("cassandra.yml").getFile(); | ||
CassandraStarter.main(config); | ||
} | ||
} |
Oops, something went wrong.