Skip to content

Commit 98194a8

Browse files
committed
Experimental block store
1 parent a84bd08 commit 98194a8

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+4433
-0
lines changed

cloudata-blocks/pom.xml

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4+
<modelVersion>4.0.0</modelVersion>
5+
6+
<parent>
7+
<groupId>com.cloudata</groupId>
8+
<artifactId>cloudata-parent</artifactId>
9+
<version>1.0-SNAPSHOT</version>
10+
</parent>
11+
12+
<artifactId>cloudata-blocks</artifactId>
13+
14+
15+
<dependencies>
16+
<dependency>
17+
<groupId>com.cloudata</groupId>
18+
<artifactId>cloudata-server-shared</artifactId>
19+
<version>${project.version}</version>
20+
</dependency>
21+
22+
<dependency>
23+
<groupId>junit</groupId>
24+
<artifactId>junit</artifactId>
25+
<scope>test</scope>
26+
</dependency>
27+
28+
<dependency>
29+
<groupId>redis.clients</groupId>
30+
<artifactId>jedis</artifactId>
31+
<scope>test</scope>
32+
</dependency>
33+
</dependencies>
34+
35+
<build>
36+
<plugins>
37+
<plugin>
38+
<artifactId>maven-assembly-plugin</artifactId>
39+
<version>2.2-beta-2</version>
40+
<configuration>
41+
<descriptors>
42+
<descriptor>src/main/assembly/assembly.xml</descriptor>
43+
</descriptors>
44+
</configuration>
45+
</plugin>
46+
</plugins>
47+
</build>
48+
</project>
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<assembly>
2+
<id>bundle</id>
3+
<formats>
4+
<format>tar.gz</format>
5+
<format>dir</format>
6+
</formats>
7+
<includeBaseDirectory>false</includeBaseDirectory>
8+
<fileSets>
9+
<fileSet>
10+
<directory>src/main/bin</directory>
11+
<outputDirectory>bin</outputDirectory>
12+
<includes>
13+
<include>*.sh</include>
14+
</includes>
15+
<lineEnding>unix</lineEnding>
16+
<fileMode>0744</fileMode>
17+
</fileSet>
18+
</fileSets>
19+
<dependencySets>
20+
<dependencySet>
21+
<scope>runtime</scope>
22+
<useProjectArtifact>true</useProjectArtifact>
23+
<outputDirectory>lib</outputDirectory>
24+
<unpack>false</unpack>
25+
</dependencySet>
26+
</dependencySets>
27+
</assembly>
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#!/bin/bash
2+
3+
# Find Java
4+
if [ "$JAVA_HOME" = "" ] ; then
5+
JAVA="java -server"
6+
else
7+
JAVA="$JAVA_HOME/bin/java -server"
8+
fi
9+
10+
PREFIX=$( echo `dirname $0`/.. )
11+
LIB_DIR=$PREFIX/lib
12+
13+
# Set Java options
14+
if [ "$JAVA_OPTIONS" = "" ] ; then
15+
JAVA_OPTIONS=" \
16+
-XX:+UseConcMarkSweepGC \
17+
-d64"
18+
fi
19+
20+
export BASE_DIR=$*
21+
22+
# Launch the application
23+
cd $PREFIX
24+
25+
export PREFIX
26+
export CLASSPATH=$( echo $LIB_DIR/*.jar . | sed 's/ /:/g')
27+
exec $JAVA $JAVA_OPTIONS com.cloudata.keyvalue.KeyValueServer $*
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
package com.cloudata.blockstore;
2+
3+
import java.io.File;
4+
import java.net.InetSocketAddress;
5+
import java.net.SocketAddress;
6+
import java.util.EnumSet;
7+
import java.util.List;
8+
9+
import javax.servlet.DispatcherType;
10+
11+
import org.eclipse.jetty.server.Server;
12+
import org.eclipse.jetty.servlet.FilterHolder;
13+
import org.eclipse.jetty.servlet.ServletContextHandler;
14+
import org.robotninjas.barge.ClusterConfig;
15+
import org.robotninjas.barge.RaftService;
16+
import org.robotninjas.barge.Replica;
17+
import org.slf4j.Logger;
18+
import org.slf4j.LoggerFactory;
19+
20+
import com.cloudata.blockstore.iscsi.IscsiEndpoint;
21+
import com.cloudata.blockstore.iscsi.IscsiServer;
22+
import com.cloudata.blockstore.web.WebModule;
23+
import com.google.common.base.Throwables;
24+
import com.google.common.collect.Lists;
25+
import com.google.inject.Guice;
26+
import com.google.inject.Injector;
27+
import com.google.inject.servlet.GuiceFilter;
28+
29+
public class BlockStoreServer {
30+
private static final Logger log = LoggerFactory.getLogger(BlockStoreServer.class);
31+
32+
final File baseDir;
33+
final int httpPort;
34+
private final Replica local;
35+
private final List<Replica> peers;
36+
private RaftService raft;
37+
private final SocketAddress iscsiSocketAddress;
38+
private IscsiEndpoint redisEndpoint;
39+
private Server jetty;
40+
41+
public BlockStoreServer(File baseDir, Replica local, List<Replica> peers, int httpPort,
42+
SocketAddress iscsiSocketAddress) {
43+
this.baseDir = baseDir;
44+
this.local = local;
45+
this.peers = peers;
46+
this.httpPort = httpPort;
47+
this.iscsiSocketAddress = iscsiSocketAddress;
48+
}
49+
50+
public synchronized void start() throws Exception {
51+
if (raft != null || jetty != null) {
52+
throw new IllegalStateException();
53+
}
54+
55+
File logDir = new File(baseDir, "logs");
56+
File stateDir = new File(baseDir, "state");
57+
58+
logDir.mkdirs();
59+
stateDir.mkdirs();
60+
61+
KeyValueStateMachine stateMachine = new KeyValueStateMachine();
62+
63+
ClusterConfig config = ClusterConfig.from(local, peers);
64+
this.raft = RaftService.newBuilder(config).logDir(logDir).timeout(300).build(stateMachine);
65+
66+
stateMachine.init(raft, stateDir);
67+
68+
raft.startAsync().awaitRunning();
69+
70+
// final String baseUri = getHttpUrl();
71+
72+
Injector injector = Guice.createInjector(new KeyValueModule(stateMachine), new WebModule());
73+
74+
// ResourceConfig rc = new PackagesResourceConfig(WebModule.class.getPackage().getName());
75+
// IoCComponentProviderFactory ioc = new GuiceComponentProviderFactory(rc, injector);
76+
77+
// this.selector = GrizzlyServerFactory.create(baseUri, rc, ioc);
78+
79+
this.jetty = new Server(httpPort);
80+
81+
ServletContextHandler context = new ServletContextHandler();
82+
context.setContextPath("/");
83+
84+
FilterHolder filterHolder = new FilterHolder(injector.getInstance(GuiceFilter.class));
85+
context.addFilter(filterHolder, "*", EnumSet.of(DispatcherType.REQUEST));
86+
87+
jetty.setHandler(context);
88+
89+
jetty.start();
90+
91+
if (iscsiSocketAddress != null) {
92+
long storeId = 1;
93+
IscsiServer iscsiServer = new IscsiServer(stateMachine, storeId);
94+
95+
this.redisEndpoint = new IscsiEndpoint(iscsiSocketAddress, iscsiServer);
96+
this.redisEndpoint.start();
97+
}
98+
}
99+
100+
public String getHttpUrl() {
101+
return "http://localhost:" + httpPort + "/";
102+
}
103+
104+
public static void main(String... args) throws Exception {
105+
final int port = Integer.parseInt(args[0]);
106+
107+
Replica local = Replica.fromString("localhost:" + (10000 + port));
108+
List<Replica> members = Lists.newArrayList(Replica.fromString("localhost:10001"));
109+
// Replica.fromString("localhost:10002"), Replica.fromString("localhost:10003"));
110+
members.remove(local);
111+
112+
File baseDir = new File(args[0]);
113+
int httpPort = (9990 + port);
114+
int iscsiPort = 3260 + port;
115+
116+
SocketAddress iscsiSocketAddress = new InetSocketAddress(iscsiPort);
117+
final BlockStoreServer server = new BlockStoreServer(baseDir, local, members, httpPort, iscsiSocketAddress);
118+
server.start();
119+
120+
Runtime.getRuntime().addShutdownHook(new Thread() {
121+
@Override
122+
public void run() {
123+
try {
124+
server.stop();
125+
} catch (Exception e) {
126+
log.error("Error stopping server", e);
127+
}
128+
}
129+
});
130+
}
131+
132+
public synchronized void stop() throws Exception {
133+
if (jetty != null) {
134+
jetty.stop();
135+
jetty = null;
136+
}
137+
138+
if (redisEndpoint != null) {
139+
try {
140+
redisEndpoint.stop();
141+
} catch (InterruptedException e) {
142+
Thread.currentThread().interrupt();
143+
throw Throwables.propagate(e);
144+
}
145+
redisEndpoint = null;
146+
}
147+
148+
if (raft != null) {
149+
raft.stopAsync().awaitTerminated();
150+
raft = null;
151+
}
152+
}
153+
154+
public SocketAddress getRedisSocketAddress() {
155+
return iscsiSocketAddress;
156+
}
157+
158+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package com.cloudata.blockstore;
2+
3+
import io.netty.buffer.ByteBuf;
4+
import io.netty.buffer.Unpooled;
5+
6+
import org.slf4j.Logger;
7+
import org.slf4j.LoggerFactory;
8+
9+
import com.google.common.base.Preconditions;
10+
import com.google.common.primitives.Ints;
11+
import com.google.common.util.concurrent.Futures;
12+
import com.google.common.util.concurrent.ListenableFuture;
13+
14+
public class DummyVolume implements Volume {
15+
16+
private static final Logger log = LoggerFactory.getLogger(DummyVolume.class);
17+
private static final int CHUNK_SIZE = 256 * 1024;
18+
19+
private final long lun;
20+
21+
public DummyVolume(long lun) {
22+
this.lun = lun;
23+
}
24+
25+
@Override
26+
public ListenableFuture<ByteBuf> read(long offset, long length) {
27+
log.warn("DUMMY: read {} {}", offset, length);
28+
ByteBuf buf = Unpooled.buffer(Ints.checkedCast(length));
29+
return Futures.immediateFuture(buf);
30+
}
31+
32+
@Override
33+
public ListenableFuture<Void> write(long offset, long length, ByteBuf buf) {
34+
Preconditions.checkState(length == buf.readableBytes());
35+
log.warn("DUMMY: write {} {}", offset, length);
36+
return Futures.immediateFuture(null);
37+
}
38+
39+
@Override
40+
public ListenableFuture<Void> sync() {
41+
log.warn("DUMMY: sync");
42+
return Futures.immediateFuture(null);
43+
}
44+
45+
@Override
46+
public int getChunkSize() {
47+
return CHUNK_SIZE;
48+
}
49+
50+
}

0 commit comments

Comments
 (0)