Streaming state (#7348)

This commit is contained in:
WuTao
2020-04-28 10:36:32 +08:00
committed by GitHub
parent be5235d982
commit 32c2055c99
81 changed files with 5670 additions and 20 deletions
+30
View File
@@ -6,6 +6,7 @@ exports_files([
])
all_modules = [
"streaming-state",
"streaming-api",
"streaming-runtime",
]
@@ -35,6 +36,7 @@ define_java_module(
define_test_lib = True,
test_deps = [
"//java:io_ray_ray_api",
":io_ray_ray_streaming-state",
":io_ray_ray_streaming-api",
"@ray_streaming_maven//:com_google_guava_guava",
"@ray_streaming_maven//:org_slf4j_slf4j_api",
@@ -43,12 +45,37 @@ define_java_module(
],
visibility = ["//visibility:public"],
deps = [
":io_ray_ray_streaming-state",
"@ray_streaming_maven//:com_google_guava_guava",
"@ray_streaming_maven//:org_slf4j_slf4j_api",
"@ray_streaming_maven//:org_slf4j_slf4j_log4j12",
],
)
define_java_module(
name = "streaming-state",
define_test_lib = True,
test_deps = [
":io_ray_ray_streaming-state",
"@ray_streaming_maven//:com_google_guava_guava",
"@ray_streaming_maven//:org_slf4j_slf4j_api",
"@ray_streaming_maven//:org_slf4j_slf4j_log4j12",
"@ray_streaming_maven//:org_testng_testng",
"@ray_streaming_maven//:org_mockito_mockito_all",
"@ray_streaming_maven//:de_ruedigermoeller_fst",
"@ray_streaming_maven//:org_apache_commons_commons_lang3",
],
visibility = ["//visibility:public"],
deps = [
"@ray_streaming_maven//:com_google_guava_guava",
"@ray_streaming_maven//:de_ruedigermoeller_fst",
"@ray_streaming_maven//:log4j_log4j",
"@ray_streaming_maven//:org_apache_commons_commons_lang3",
"@ray_streaming_maven//:org_slf4j_slf4j_api",
"@ray_streaming_maven//:org_slf4j_slf4j_log4j12",
],
)
# `//streaming:streaming_java` will be located in jar `streaming` directory,
# but we need it located in jar root path.
# resource_strip_prefix = "streaming" will make other resources file located in wrong path.
@@ -98,6 +125,7 @@ define_java_module(
test_deps = [
"//java:io_ray_ray_api",
"//java:io_ray_ray_runtime",
":io_ray_ray_streaming-state",
":io_ray_ray_streaming-api",
":io_ray_ray_streaming-runtime",
"@ray_streaming_maven//:com_google_guava_guava",
@@ -114,6 +142,7 @@ define_java_module(
visibility = ["//visibility:public"],
deps = [
":io_ray_ray_streaming-api",
":io_ray_ray_streaming-state",
"//java:io_ray_ray_api",
"//java:io_ray_ray_runtime",
"@ray_streaming_maven//:com_github_davidmoten_flatbuffers_java",
@@ -136,6 +165,7 @@ java_binary(
":io_ray_ray_streaming-api_test",
":io_ray_ray_streaming-runtime",
":io_ray_ray_streaming-runtime_test",
":io_ray_ray_streaming-state",
"//java:io_ray_ray_runtime",
"@ray_streaming_maven//:com_beust_jcommander",
"@ray_streaming_maven//:org_mockito_mockito_all",
+4
View File
@@ -13,6 +13,10 @@ def gen_streaming_java_deps():
"org.slf4j:slf4j-api:1.7.12",
"org.slf4j:slf4j-log4j12:1.7.25",
"org.apache.logging.log4j:log4j-core:2.8.2",
"org.testng:testng:6.9.10",
"log4j:log4j:1.2.17",
"org.mockito:mockito-all:1.10.19",
"org.apache.commons:commons-lang3:3.3.2",
"org.msgpack:msgpack-core:0.8.20",
"org.testng:testng:6.9.10",
"org.mockito:mockito-all:1.10.19",
+11 -4
View File
@@ -16,34 +16,41 @@
<modules>
<module>streaming-api</module>
<module>streaming-runtime</module>
<module>streaming-state</module>
</modules>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<projetct.version>0.1-SNAPSHOT</projetct.version>
<slf4j.version>1.7.25</slf4j.version>
<log4j.version>1.2.17</log4j.version>
<testng.version>6.9.10</testng.version>
<mockito.version>1.10.19</mockito.version>
<guava.version>27.0.1-jre</guava.version>
<fst.version>2.57</fst.version>
</properties>
<dependencies>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>27.0.1-jre</version>
<version>${guava.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.25</version>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.9.10</version>
<version>${testng.version}</version>
</dependency>
</dependencies>
+6 -1
View File
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- This file is auto-generated by Bazel from pom_template.xml, do not modify it. -->
<!-- This file is auto-generated by Bazel from pom_template.xml, do not modify it. -->
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
@@ -23,6 +23,11 @@
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.ray</groupId>
<artifactId>streaming-state</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>27.0.1-jre</version>
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
{auto_gen_header}
{auto_gen_header}
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
@@ -22,6 +22,11 @@
<artifactId>ray-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.ray</groupId>
<artifactId>streaming-state</artifactId>
<version>${project.version}</version>
</dependency>
{generated_bzl_deps}
</dependencies>
</project>
@@ -1,5 +1,14 @@
package io.ray.streaming.api.context;
import io.ray.streaming.state.backend.KeyStateBackend;
import io.ray.streaming.state.keystate.desc.ListStateDescriptor;
import io.ray.streaming.state.keystate.desc.MapStateDescriptor;
import io.ray.streaming.state.keystate.desc.ValueStateDescriptor;
import io.ray.streaming.state.keystate.state.ListState;
import io.ray.streaming.state.keystate.state.MapState;
import io.ray.streaming.state.keystate.state.ValueState;
import java.util.Map;
/**
* Encapsulate the runtime information of a streaming task.
*/
@@ -11,8 +20,23 @@ public interface RuntimeContext {
int getParallelism();
Long getBatchId();
Long getCheckpointId();
void setCheckpointId(long checkpointId);
Long getMaxBatch();
Map<String, String> getConfig();
void setCurrentKey(Object key);
KeyStateBackend getKeyStateBackend();
void setKeyStateBackend(KeyStateBackend keyStateBackend);
<T> ValueState<T> getValueState(ValueStateDescriptor<T> stateDescriptor);
<T> ListState<T> getListState(ListStateDescriptor<T> stateDescriptor);
<S, T> MapState<S, T> getMapState(MapStateDescriptor<S, T> stateDescriptor);
}
@@ -10,7 +10,6 @@ import io.ray.streaming.operator.StreamOperator;
import java.util.List;
public class SourceOperator<T> extends StreamOperator<SourceFunction<T>> {
private SourceContextImpl sourceContext;
public SourceOperator(SourceFunction<T> function) {
@@ -38,6 +37,7 @@ public class SourceOperator<T> extends StreamOperator<SourceFunction<T>> {
}
class SourceContextImpl implements SourceContext<T> {
private List<Collector> collectors;
public SourceContextImpl(List<Collector> collectors) {
+6 -1
View File
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- This file is auto-generated by Bazel from pom_template.xml, do not modify it. -->
<!-- This file is auto-generated by Bazel from pom_template.xml, do not modify it. -->
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
@@ -71,6 +71,11 @@
<artifactId>powermock-api-mockito</artifactId>
<version>1.6.6</version>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-core</artifactId>
<version>1.6.6</version>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-testng</artifactId>
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
{auto_gen_header}
{auto_gen_header}
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
@@ -14,6 +14,7 @@ import org.slf4j.LoggerFactory;
* @param <P> Type of the specific operator class.
*/
public abstract class StreamProcessor<T, P extends Operator> implements Processor<T> {
private static final Logger LOGGER = LoggerFactory.getLogger(StreamProcessor.class);
protected List<Collector> collectors;
@@ -2,19 +2,39 @@ package io.ray.streaming.runtime.worker.context;
import static io.ray.streaming.util.Config.STREAMING_BATCH_MAX_COUNT;
import com.google.common.base.Preconditions;
import io.ray.streaming.api.context.RuntimeContext;
import io.ray.streaming.runtime.core.graph.ExecutionTask;
import io.ray.streaming.state.backend.AbstractKeyStateBackend;
import io.ray.streaming.state.backend.KeyStateBackend;
import io.ray.streaming.state.backend.OperatorStateBackend;
import io.ray.streaming.state.keystate.desc.AbstractStateDescriptor;
import io.ray.streaming.state.keystate.desc.ListStateDescriptor;
import io.ray.streaming.state.keystate.desc.MapStateDescriptor;
import io.ray.streaming.state.keystate.desc.ValueStateDescriptor;
import io.ray.streaming.state.keystate.state.ListState;
import io.ray.streaming.state.keystate.state.MapState;
import io.ray.streaming.state.keystate.state.ValueState;
import java.util.Map;
/**
* Use Ray to implement RuntimeContext.
*/
public class RayRuntimeContext implements RuntimeContext {
private final Long maxBatch;
/**
* Backend for keyed state. This might be empty if we're not on a keyed stream.
*/
protected transient KeyStateBackend keyStateBackend;
/**
* Backend for operator state. This might be empty
*/
protected transient OperatorStateBackend operatorStateBackend;
private int taskId;
private int taskIndex;
private int parallelism;
private Long batchId;
private final Long maxBatch;
private Long checkpointId;
private Map<String, String> config;
public RayRuntimeContext(ExecutionTask executionTask, Map<String, String> config,
@@ -46,8 +66,19 @@ public class RayRuntimeContext implements RuntimeContext {
}
@Override
public Long getBatchId() {
return batchId;
public Long getCheckpointId() {
return checkpointId;
}
@Override
public void setCheckpointId(long checkpointId) {
if (this.keyStateBackend != null) {
this.keyStateBackend.setCheckpointId(checkpointId);
}
if (this.operatorStateBackend != null) {
this.operatorStateBackend.setCheckpointId(checkpointId);
}
this.checkpointId = checkpointId;
}
@Override
@@ -55,7 +86,48 @@ public class RayRuntimeContext implements RuntimeContext {
return maxBatch;
}
public void setBatchId(Long batchId) {
this.batchId = batchId;
@Override
public Map<String, String> getConfig() {
return config;
}
@Override
public void setCurrentKey(Object key) {
this.keyStateBackend.setCurrentKey(key);
}
@Override
public KeyStateBackend getKeyStateBackend() {
return keyStateBackend;
}
@Override
public void setKeyStateBackend(KeyStateBackend keyStateBackend) {
this.keyStateBackend = keyStateBackend;
}
@Override
public <T> ValueState<T> getValueState(ValueStateDescriptor<T> stateDescriptor) {
stateSanityCheck(stateDescriptor, this.keyStateBackend);
return this.keyStateBackend.getValueState(stateDescriptor);
}
@Override
public <T> ListState<T> getListState(ListStateDescriptor<T> stateDescriptor) {
stateSanityCheck(stateDescriptor, this.keyStateBackend);
return this.keyStateBackend.getListState(stateDescriptor);
}
@Override
public <S, T> MapState<S, T> getMapState(MapStateDescriptor<S, T> stateDescriptor) {
stateSanityCheck(stateDescriptor, this.keyStateBackend);
return this.keyStateBackend.getMapState(stateDescriptor);
}
protected void stateSanityCheck(AbstractStateDescriptor stateDescriptor,
AbstractKeyStateBackend backend) {
Preconditions.checkNotNull(stateDescriptor, "The state properties must not be null");
Preconditions.checkNotNull(backend, "backend must not be null");
}
}
@@ -26,6 +26,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public abstract class StreamTask implements Runnable {
private static final Logger LOG = LoggerFactory.getLogger(StreamTask.class);
protected int taskId;
@@ -41,8 +42,8 @@ public abstract class StreamTask implements Runnable {
this.worker = worker;
prepareTask();
this.thread = new Thread(Ray.wrapRunnable(this), this.getClass().getName()
+ "-" + System.currentTimeMillis());
this.thread = new Thread(Ray.wrapRunnable(this),
this.getClass().getName() + "-" + System.currentTimeMillis());
this.thread.setDaemon(true);
}
@@ -105,8 +106,8 @@ public abstract class StreamTask implements Runnable {
reader = new DataReader(channelIDs, inputActors, queueConf);
}
RuntimeContext runtimeContext = new RayRuntimeContext(
worker.getExecutionTask(), worker.getConfig(), executionNode.getParallelism());
RuntimeContext runtimeContext = new RayRuntimeContext(worker.getExecutionTask(),
worker.getConfig(), executionNode.getParallelism());
processor.open(collectors, runtimeContext);
+95
View File
@@ -0,0 +1,95 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>ray-streaming</artifactId>
<groupId>io.ray</groupId>
<version>0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.ray</groupId>
<artifactId>streaming-state</artifactId>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>${testng.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>${mockito.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
</dependency>
<dependency>
<groupId>de.ruedigermoeller</groupId>
<artifactId>fst</artifactId>
<version>${fst.version}</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.3.2</version>
</dependency>
<dependency>
<groupId>com.beust</groupId>
<artifactId>jcommander</artifactId>
<version>1.27</version>
</dependency>
</dependencies>
</project>
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
{auto_gen_header}
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<artifactId>ray-streaming</artifactId>
<groupId>io.ray</groupId>
<version>0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>streaming-state</artifactId>
<name>ray streaming state</name>
<description>ray streaming state</description>
<packaging>jar</packaging>
<dependencies>
{generated_bzl_deps}
</dependencies>
</project>
@@ -0,0 +1,35 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 io.ray.streaming.state;
/**
* Key Value State interface.
*/
public interface KeyValueState<K, V> {
/**
* get value from state
*/
V get(K key);
/**
* put key and value into state
*/
void put(K k, V v);
}
@@ -0,0 +1,53 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 io.ray.streaming.state;
import java.io.Serializable;
/**
* value record for partition.
*/
public class PartitionRecord<T> implements Serializable {
/**
* The partition number of the partitioned value.
*/
private int partitionID;
private T value;
public PartitionRecord() {
}
public PartitionRecord(int partitionID, T value) {
this.partitionID = partitionID;
this.value = value;
}
public T getValue() {
return value;
}
public int getPartitionID() {
return partitionID;
}
public void setPartitionID(int partitionID) {
this.partitionID = partitionID;
}
}
@@ -0,0 +1,33 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 io.ray.streaming.state;
/**
* RuntimeException wrapper, indicating the exceptions occurs in states.
*/
public class StateException extends RuntimeException {
public StateException(Throwable t) {
super(t);
}
public StateException(String msg) {
super(msg);
}
}
@@ -0,0 +1,52 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 io.ray.streaming.state;
/**
* TransactionState interface.
* <p>
* Streaming State should implement transaction in case of failure,
* which in our case is four default method, finish, commit, ackCommit, rollback.
*/
public interface StateStoreManager {
/**
* The finish method is used when the batched data is all saved in state.
* Normally, serialization job is done here.
*/
void finish(long checkpointId);
/**
* The commit method is used for persistent, and can be used in another thread to reach async
* state commit.
* Normally, data persistent is done here.
*/
void commit(long checkpointId);
/**
* The ackCommit method is used for cleaning the last checkpoint, and must be called after commit
* in the same thread.
*/
void ackCommit(long checkpointId, long timeStamp);
/**
* The rollback method is used for recovering the checkpoint.
*/
void rollBack(long checkpointId);
}
@@ -0,0 +1,59 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 io.ray.streaming.state;
import java.io.Serializable;
/**
* This Class contains a record with some checkpointId.
*/
public class StorageRecord<T> implements Serializable {
private long checkpointId;
private T value;
public StorageRecord() {
}
public StorageRecord(long checkpointId, T value) {
this.checkpointId = checkpointId;
this.value = value;
}
public T getValue() {
return value;
}
public long getCheckpointId() {
return checkpointId;
}
public void setCheckpointId(long checkpointId) {
this.checkpointId = checkpointId;
}
@Override
public String toString() {
if (value != null) {
return "checkpointId:" + checkpointId + ", value:" + value;
} else {
return "checkpointId:" + checkpointId + ", value:null";
}
}
}
@@ -0,0 +1,211 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 io.ray.streaming.state.backend;
import io.ray.streaming.state.StateStoreManager;
import io.ray.streaming.state.keystate.desc.AbstractStateDescriptor;
import io.ray.streaming.state.keystate.desc.AbstractStateDescriptor.StateType;
import io.ray.streaming.state.keystate.state.proxy.ListStateStoreManagerProxy;
import io.ray.streaming.state.keystate.state.proxy.MapStateStoreManagerProxy;
import io.ray.streaming.state.keystate.state.proxy.ValueStateStoreManagerProxy;
import io.ray.streaming.state.store.KeyMapStore;
import io.ray.streaming.state.store.KeyValueStore;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Transaction support primitive operations like finish, commit, ackcommit and rollback.
* <p>
* State value modification is not thread safe! By default, every processing thread has its own
* space to handle state.
*/
public abstract class AbstractKeyStateBackend implements StateStoreManager {
private static final Logger LOG = LoggerFactory.getLogger(AbstractKeyStateBackend.class);
protected long currentCheckpointId;
protected Object currentKey;
protected int keyGroupIndex = -1;
protected Map<String, ValueStateStoreManagerProxy> valueManagerProxyHashMap = new HashMap<>();
protected Map<String, ListStateStoreManagerProxy> listManagerProxyHashMap = new HashMap<>();
protected Map<String, MapStateStoreManagerProxy> mapManagerProxyHashMap = new HashMap<>();
protected Set<String> descNamespace;
/**
* tablename, KeyValueStore key, checkpointId, content
*/
protected Map<String, KeyValueStore<String, Map<Long, byte[]>>> backStorageCache;
private AbstractStateBackend backend;
public AbstractKeyStateBackend(AbstractStateBackend backend) {
this.backStorageCache = new HashMap<>();
this.backend = backend;
this.descNamespace = new HashSet<>();
}
public <K, T> void put(AbstractStateDescriptor descriptor, K key, T value) {
String desc = descriptor.getIdentify();
if (descriptor.getStateType() == StateType.VALUE) {
if (this.valueManagerProxyHashMap.containsKey(desc)) {
valueManagerProxyHashMap.get(desc).put((String) key, value);
}
} else if (descriptor.getStateType() == StateType.LIST) {
if (this.listManagerProxyHashMap.containsKey(desc)) {
listManagerProxyHashMap.get(desc).put((String) key, value);
}
} else if (descriptor.getStateType() == StateType.MAP) {
if (this.mapManagerProxyHashMap.containsKey(desc)) {
mapManagerProxyHashMap.get(desc).put((String) key, value);
}
}
}
public <K, T> T get(AbstractStateDescriptor descriptor, K key) {
String desc = descriptor.getIdentify();
if (descriptor.getStateType() == StateType.VALUE) {
if (this.valueManagerProxyHashMap.containsKey(desc)) {
return (T) valueManagerProxyHashMap.get(desc).get((String) key);
}
} else if (descriptor.getStateType() == StateType.LIST) {
if (this.listManagerProxyHashMap.containsKey(desc)) {
return (T) listManagerProxyHashMap.get(desc).get((String) key);
}
} else if (descriptor.getStateType() == StateType.MAP) {
if (this.mapManagerProxyHashMap.containsKey(desc)) {
return (T) mapManagerProxyHashMap.get(desc).get((String) key);
}
}
return null;
}
@Override
public void finish(long checkpointId) {
for (Entry<String, ValueStateStoreManagerProxy> entry : valueManagerProxyHashMap.entrySet()) {
entry.getValue().finish(checkpointId);
}
for (Entry<String, ListStateStoreManagerProxy> entry : listManagerProxyHashMap.entrySet()) {
entry.getValue().finish(checkpointId);
}
for (Entry<String, MapStateStoreManagerProxy> entry : mapManagerProxyHashMap.entrySet()) {
entry.getValue().finish(checkpointId);
}
}
@Override
public void commit(long checkpointId) {
for (Entry<String, ValueStateStoreManagerProxy> entry : valueManagerProxyHashMap.entrySet()) {
entry.getValue().commit(checkpointId);
}
for (Entry<String, ListStateStoreManagerProxy> entry : listManagerProxyHashMap.entrySet()) {
entry.getValue().commit(checkpointId);
}
for (Entry<String, MapStateStoreManagerProxy> entry : mapManagerProxyHashMap.entrySet()) {
entry.getValue().commit(checkpointId);
}
}
@Override
public void ackCommit(long checkpointId, long timeStamp) {
for (Entry<String, ValueStateStoreManagerProxy> entry : valueManagerProxyHashMap.entrySet()) {
entry.getValue().ackCommit(checkpointId, timeStamp);
}
for (Entry<String, ListStateStoreManagerProxy> entry : listManagerProxyHashMap.entrySet()) {
entry.getValue().ackCommit(checkpointId, timeStamp);
}
for (Entry<String, MapStateStoreManagerProxy> entry : mapManagerProxyHashMap.entrySet()) {
entry.getValue().ackCommit(checkpointId, timeStamp);
}
}
@Override
public void rollBack(long checkpointId) {
for (Entry<String, ValueStateStoreManagerProxy> entry : valueManagerProxyHashMap.entrySet()) {
LOG.warn("backend rollback:{},{}", entry.getKey(), checkpointId);
entry.getValue().rollBack(checkpointId);
}
for (Entry<String, ListStateStoreManagerProxy> entry : listManagerProxyHashMap.entrySet()) {
LOG.warn("backend rollback:{},{}", entry.getKey(), checkpointId);
entry.getValue().rollBack(checkpointId);
}
for (Entry<String, MapStateStoreManagerProxy> entry : mapManagerProxyHashMap.entrySet()) {
LOG.warn("backend rollback:{},{}", entry.getKey(), checkpointId);
entry.getValue().rollBack(checkpointId);
}
}
public KeyValueStore<String, Map<Long, byte[]>> getBackStorage(String tableName) {
if (this.backStorageCache.containsKey(tableName)) {
return this.backStorageCache.get(tableName);
} else {
KeyMapStore<String, Long, byte[]> ikvStore = this.backend.getKeyMapStore(tableName);
this.backStorageCache.put(tableName, ikvStore);
return ikvStore;
}
}
public KeyValueStore<String, Map<Long, byte[]>> getBackStorage(
AbstractStateDescriptor stateDescriptor) {
String tableName = this.backend.getTableName(stateDescriptor);
return getBackStorage(tableName);
}
public StateStrategy getStateStrategy() {
return this.backend.getStateStrategy();
}
public BackendType getBackendType() {
return this.backend.getBackendType();
}
public Object getCurrentKey() {
return this.currentKey;
}
public abstract void setCurrentKey(Object currentKey);
public long getCheckpointId() {
return this.currentCheckpointId;
}
public void setCheckpointId(long checkpointId) {
this.currentCheckpointId = checkpointId;
}
public void setContext(long checkpointId, Object currentKey) {
setCheckpointId(checkpointId);
setCurrentKey(currentKey);
}
public AbstractStateBackend getBackend() {
return backend;
}
public int getKeyGroupIndex() {
return this.keyGroupIndex;
}
public void setKeyGroupIndex(int keyGroupIndex) {
this.keyGroupIndex = keyGroupIndex;
}
}
@@ -0,0 +1,74 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 io.ray.streaming.state.backend;
import static io.ray.streaming.state.config.ConfigKey.DELIMITER;
import io.ray.streaming.state.config.ConfigKey;
import io.ray.streaming.state.keystate.desc.AbstractStateDescriptor;
import io.ray.streaming.state.serialization.KeyMapStoreSerializer;
import io.ray.streaming.state.store.KeyMapStore;
import io.ray.streaming.state.store.KeyValueStore;
import java.io.Serializable;
import java.util.Map;
/**
* This class is the abstract class for different kinds of StateBackend.
*/
public abstract class AbstractStateBackend implements Serializable {
protected final Map<String, String> config;
protected final StateStrategy stateStrategy;
protected final BackendType backendType;
protected int keyGroupIndex = -1;
protected AbstractStateBackend(Map<String, String> config) {
this.stateStrategy = StateStrategy.getEnum(ConfigKey.getStateStrategyEnum(config));
this.backendType = BackendType.getEnum(ConfigKey.getBackendType(config));
this.config = config;
}
public abstract <K, V> KeyValueStore<K, V> getKeyValueStore(String tableName);
public abstract <K, S, T> KeyMapStore<K, S, T> getKeyMapStore(String tableName);
public abstract <K, S, T> KeyMapStore<K, S, T> getKeyMapStore(
String tableName, KeyMapStoreSerializer keyMapStoreSerializer);
public BackendType getBackendType() {
return backendType;
}
public StateStrategy getStateStrategy() {
return stateStrategy;
}
public String getTableName(AbstractStateDescriptor stateDescriptor) {
return stateDescriptor.getTableName();
}
public String getStateKey(String descName, String currentKey) {
return descName + DELIMITER + currentKey;
}
public void setKeyGroupIndex(int keyGroupIndex) {
this.keyGroupIndex = keyGroupIndex;
}
}
@@ -0,0 +1,41 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 io.ray.streaming.state.backend;
/**
* Backend Types.
*/
public enum BackendType {
/**
* Saving the state values in memory
*/
MEMORY;
/**
* get the enum from input string value, ignoring the case
*/
public static BackendType getEnum(String value) {
for (BackendType v : values()) {
if (v.name().equalsIgnoreCase(value)) {
return v;
}
}
return MEMORY;
}
}
@@ -0,0 +1,134 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 io.ray.streaming.state.backend;
import io.ray.streaming.state.keystate.KeyGroup;
import io.ray.streaming.state.keystate.KeyGroupAssignment;
import io.ray.streaming.state.keystate.desc.ListStateDescriptor;
import io.ray.streaming.state.keystate.desc.MapStateDescriptor;
import io.ray.streaming.state.keystate.desc.ValueStateDescriptor;
import io.ray.streaming.state.keystate.state.ListState;
import io.ray.streaming.state.keystate.state.MapState;
import io.ray.streaming.state.keystate.state.ValueState;
import io.ray.streaming.state.keystate.state.proxy.ListStateStoreManagerProxy;
import io.ray.streaming.state.keystate.state.proxy.MapStateStoreManagerProxy;
import io.ray.streaming.state.keystate.state.proxy.ValueStateStoreManagerProxy;
/**
* key state backend manager, managing different kinds of states in different thread.
* This class is not thread safe.
*/
public class KeyStateBackend extends AbstractKeyStateBackend {
protected final int numberOfKeyGroups;
protected final KeyGroup keyGroup;
public KeyStateBackend(int numberOfKeyGroups, KeyGroup keyGroup,
AbstractStateBackend abstractStateBackend) {
super(abstractStateBackend);
this.numberOfKeyGroups = numberOfKeyGroups;
this.keyGroup = keyGroup;
}
/**
* get new value state proxy
*/
protected <T> ValueStateStoreManagerProxy<T> newValueStateProxy(
ValueStateDescriptor<T> stateDescriptor) {
return new ValueStateStoreManagerProxy<>(this, stateDescriptor);
}
public <T> ValueState<T> getValueState(ValueStateDescriptor<T> stateDescriptor) {
String desc = stateDescriptor.getIdentify();
if (valueManagerProxyHashMap.containsKey(desc)) {
return valueManagerProxyHashMap.get(desc).getValueState();
} else {
ValueStateStoreManagerProxy<T> valueStateProxy = newValueStateProxy(stateDescriptor);
valueManagerProxyHashMap.put(desc, valueStateProxy);
return valueStateProxy.getValueState();
}
}
/**
* get new list state proxy
*/
protected <T> ListStateStoreManagerProxy<T> newListStateProxy(
ListStateDescriptor<T> stateDescriptor) {
return new ListStateStoreManagerProxy<>(this, stateDescriptor);
}
public <T> ListState<T> getListState(ListStateDescriptor<T> stateDescriptor) {
String desc = stateDescriptor.getIdentify();
if (listManagerProxyHashMap.containsKey(desc)) {
ListStateStoreManagerProxy<T> listStateProxy = listManagerProxyHashMap.get(desc);
return listStateProxy.getListState();
} else {
ListStateStoreManagerProxy<T> listStateProxy = newListStateProxy(stateDescriptor);
listManagerProxyHashMap.put(desc, listStateProxy);
return listStateProxy.getListState();
}
}
/**
* get map state proxy
*/
protected <S, T> MapStateStoreManagerProxy<S, T> newMapStateProxy(
MapStateDescriptor<S, T> stateDescriptor) {
return new MapStateStoreManagerProxy<>(this, stateDescriptor);
}
public <S, T> MapState<S, T> getMapState(MapStateDescriptor<S, T> stateDescriptor) {
String desc = stateDescriptor.getIdentify();
if (mapManagerProxyHashMap.containsKey(desc)) {
MapStateStoreManagerProxy<S, T> mapStateProxy = mapManagerProxyHashMap.get(desc);
return mapStateProxy.getMapState();
} else {
MapStateStoreManagerProxy<S, T> mapStateProxy = newMapStateProxy(stateDescriptor);
mapManagerProxyHashMap.put(desc, mapStateProxy);
return mapStateProxy.getMapState();
}
}
@Override
public void setCurrentKey(Object currentKey) {
super.keyGroupIndex = KeyGroupAssignment
.assignKeyGroupIndexForKey(currentKey, numberOfKeyGroups);
super.currentKey = currentKey;
}
public int getNumberOfKeyGroups() {
return numberOfKeyGroups;
}
public KeyGroup getKeyGroup() {
return keyGroup;
}
public void close() {
for (ValueStateStoreManagerProxy proxy : valueManagerProxyHashMap.values()) {
proxy.close();
}
for (ListStateStoreManagerProxy proxy : listManagerProxyHashMap.values()) {
proxy.close();
}
for (MapStateStoreManagerProxy proxy : mapManagerProxyHashMap.values()) {
proxy.close();
}
}
}
@@ -0,0 +1,76 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 io.ray.streaming.state.backend;
import io.ray.streaming.state.keystate.desc.ListStateDescriptor;
import io.ray.streaming.state.keystate.state.ListState;
import io.ray.streaming.state.keystate.state.impl.OperatorStateImpl;
import io.ray.streaming.state.keystate.state.proxy.ListStateStoreManagerProxy;
/**
* OperatorState manager for getting split or union list state.
*/
public class OperatorStateBackend extends AbstractKeyStateBackend {
public OperatorStateBackend(AbstractStateBackend backend) {
super(backend);
}
@Override
public void setCurrentKey(Object currentKey) {
super.currentKey = currentKey;
}
protected <T> ListStateStoreManagerProxy<T> newListStateStoreManagerProxy(
ListStateDescriptor<T> stateDescriptor) {
return new ListStateStoreManagerProxy<>(this, stateDescriptor);
}
/**
* get spitted List for different operator instance.
*/
public <T> ListState<T> getSplitListState(ListStateDescriptor<T> stateDescriptor) {
String desc = stateDescriptor.getIdentify();
if (listManagerProxyHashMap.containsKey(desc)) {
ListStateStoreManagerProxy<T> listStateProxy = listManagerProxyHashMap.get(desc);
return listStateProxy.getListState();
} else {
ListStateStoreManagerProxy<T> listStateProxy = newListStateStoreManagerProxy(stateDescriptor);
listManagerProxyHashMap.put(desc, listStateProxy);
((OperatorStateImpl) (listStateProxy.getListState())).setSplit(true);
return listStateProxy.getListState();
}
}
/**
* get a union List for different operator instance.
*/
public <T> ListState<T> getUnionListState(ListStateDescriptor<T> stateDescriptor) {
String desc = stateDescriptor.getIdentify();
if (listManagerProxyHashMap.containsKey(desc)) {
ListStateStoreManagerProxy<T> listStateProxy = listManagerProxyHashMap.get(desc);
return listStateProxy.getListState();
} else {
ListStateStoreManagerProxy<T> listStateProxy = newListStateStoreManagerProxy(stateDescriptor);
listManagerProxyHashMap.put(desc, listStateProxy);
((OperatorStateImpl) (listStateProxy.getListState())).init();
return listStateProxy.getListState();
}
}
}
@@ -0,0 +1,50 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 io.ray.streaming.state.backend;
import io.ray.streaming.state.backend.impl.MemoryStateBackend;
import io.ray.streaming.state.config.ConfigKey;
import java.util.Map;
/**
* State Backend Builder.
*/
public class StateBackendBuilder {
private static AbstractStateBackend getStateBackend(Map<String, String> config,
BackendType type) {
switch (type) {
case MEMORY:
return new MemoryStateBackend(config);
default:
throw new RuntimeException(type.name() + " not supported");
}
}
public static AbstractStateBackend buildStateBackend(Map<String, String> config) {
BackendType type;
if (config == null) {
type = BackendType.MEMORY;
} else {
type = BackendType.getEnum(config.get(ConfigKey.STATE_BACKEND_TYPE));
}
return getStateBackend(config, type);
}
}
@@ -0,0 +1,44 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 io.ray.streaming.state.backend;
/**
* This class describe State Saving Model.
*/
public enum StateStrategy {
/**
* save two version together in case of rollback.
*/
DUAL_VERSION,
/**
* for storage supporting mvcc, we save only current version.
*/
SINGLE_VERSION;
public static StateStrategy getEnum(String value) {
for (StateStrategy v : values()) {
if (v.name().equalsIgnoreCase(value)) {
return v;
}
}
throw new IllegalArgumentException(value + " strategy is not supported");
}
}
@@ -0,0 +1,54 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 io.ray.streaming.state.backend.impl;
import io.ray.streaming.state.backend.AbstractStateBackend;
import io.ray.streaming.state.serialization.KeyMapStoreSerializer;
import io.ray.streaming.state.store.KeyMapStore;
import io.ray.streaming.state.store.KeyValueStore;
import io.ray.streaming.state.store.impl.MemoryKeyMapStore;
import io.ray.streaming.state.store.impl.MemoryKeyValueStore;
import java.util.Map;
/**
* MemoryStateBackend. Supporting memory store.
*/
public class MemoryStateBackend extends AbstractStateBackend {
public MemoryStateBackend(Map<String, String> config) {
super(config);
}
@Override
public <K, V> KeyValueStore<K, V> getKeyValueStore(String tableName) {
return new MemoryKeyValueStore<>();
}
@Override
public <K, S, T> KeyMapStore<K, S, T> getKeyMapStore(String tableName) {
return new MemoryKeyMapStore<>();
}
@Override
public <K, S, T> KeyMapStore<K, S, T> getKeyMapStore(
String tableName, KeyMapStoreSerializer keyMapStoreSerializer) {
return new MemoryKeyMapStore<>();
}
}
@@ -0,0 +1,45 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 io.ray.streaming.state.config;
import java.util.Map;
/**
* Config Helper figure out the config info.
* Todo replace this to config module.
*/
public class ConfigHelper {
public static int getIntegerOrDefault(Map config, String configKey, int defaultValue) {
if (config.containsKey(configKey)) {
return Integer.valueOf(String.valueOf(config.get(configKey)));
} else {
return defaultValue;
}
}
public static String getStringOrDefault(Map config, String configKey, String defaultValue) {
if (config.containsKey(configKey)) {
return String.valueOf(config.get(configKey));
} else {
return defaultValue;
}
}
}
@@ -0,0 +1,58 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 io.ray.streaming.state.config;
import java.util.Map;
/**
* state config keys.
* Todo replace this to config module.
*/
public final class ConfigKey {
/**
* backend
*/
public static final String STATE_BACKEND_TYPE = "state.backend.type";
public static final String STATE_TABLE_NAME = "state.table.name";
public static final String STATE_STRATEGY_MODE = "state.strategy.mode";
public static final String NUMBER_PER_CHECKPOINT = "number.per.checkpoint";
public static final String JOB_MAX_PARALLEL = "job.max.parallel";
public static final String DELIMITER = "\u0001\u0008"; // for String delimiter
private ConfigKey() {
throw new AssertionError();
}
public static String getStateStrategyEnum(Map<String, String> config) {
return ConfigHelper.getStringOrDefault(config, STATE_STRATEGY_MODE, "DUAL_VERSION");
}
public static String getBackendType(Map<String, String> config) {
return ConfigHelper.getStringOrDefault(config, STATE_BACKEND_TYPE, "MEMORY");
}
public static int getNumberPerCheckpoint(Map<String, String> config) {
return ConfigHelper.getIntegerOrDefault(config, NUMBER_PER_CHECKPOINT, 5);
}
public static String getStateTableName(Map<String, String> config) {
return ConfigHelper.getStringOrDefault(config, STATE_TABLE_NAME, "table");
}
}
@@ -0,0 +1,66 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 io.ray.streaming.state.keystate;
import com.google.common.base.Preconditions;
import java.io.Serializable;
/**
* This class defines key-groups. Key-groups is
* the key space in a job, which is partitioned for keyed state processing in state backend.
* The boundaries of the key-group are inclusive.
*/
public class KeyGroup implements Serializable {
private final int startIndex;
private final int endIndex;
/**
* Defines the range [startIndex, endIndex]
*
* @param startIndex start of the range (inclusive)
* @param endIndex end of the range (inclusive)
*/
public KeyGroup(int startIndex, int endIndex) {
Preconditions.checkArgument(startIndex >= 0 && startIndex <= endIndex);
this.startIndex = startIndex;
this.endIndex = endIndex;
Preconditions.checkArgument(size() >= 0, "overflow detected.");
}
/**
* @return The number of key-group in the range
*/
public int size() {
return 1 + endIndex - startIndex;
}
public int getStartIndex() {
return startIndex;
}
public int getEndIndex() {
return endIndex;
}
@Override
public String toString() {
return "KeyGroup{" + "startIndex=" + startIndex + ", endIndex=" + endIndex + '}';
}
}
@@ -0,0 +1,73 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 io.ray.streaming.state.keystate;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* This class defines key-group assignment algorithm。
*/
public final class KeyGroupAssignment {
/**
* Computes the range of key-groups that are assigned for a given operator instance.
*
* @param maxParallelism Maximal parallelism of the job.
* @param parallelism Parallelism for the job. <= maxParallelism.
* @param index index of the operator instance.
*/
public static KeyGroup getKeyGroup(int maxParallelism, int parallelism, int index) {
Preconditions.checkArgument(maxParallelism >= parallelism,
"Maximum parallelism (%s) must not be smaller than parallelism(%s)", maxParallelism,
parallelism);
int start = index == 0 ? 0 : ((index * maxParallelism - 1) / parallelism) + 1;
int end = ((index + 1) * maxParallelism - 1) / parallelism;
return new KeyGroup(start, end);
}
/**
* Assigning the key to a key-group index.
*
* @param key the key to assign.
* @param maxParallelism the maximum parallelism.
* @return the key-group index to which the given key is assigned.
*/
public static int assignKeyGroupIndexForKey(Object key, int maxParallelism) {
return Math.abs(key.hashCode() % maxParallelism);
}
public static Map<Integer, List<Integer>> computeKeyGroupToTask(int maxParallelism,
List<Integer> targetTasks) {
Map<Integer, List<Integer>> keyGroupToTask = new ConcurrentHashMap<>();
for (int index = 0; index < targetTasks.size(); index++) {
KeyGroup taskKeyGroup = getKeyGroup(maxParallelism, targetTasks.size(), index);
for (int groupId = taskKeyGroup.getStartIndex(); groupId <= taskKeyGroup.getEndIndex();
groupId++) {
keyGroupToTask.put(groupId, ImmutableList.of(targetTasks.get(index)));
}
}
return keyGroupToTask;
}
}
@@ -0,0 +1,88 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 io.ray.streaming.state.keystate.desc;
import com.google.common.base.Preconditions;
import io.ray.streaming.state.keystate.state.State;
/**
* This class defines basic data structures of StateDescriptor.
*/
public abstract class AbstractStateDescriptor<S extends State, T> {
private final String name;
private String tableName;
private Class<T> type;
protected AbstractStateDescriptor(String name, Class<T> type) {
this.name = name;
this.type = type;
}
public String getName() {
return name;
}
public Class<T> getType() {
return type;
}
protected Class<T> setType(Class<T> type) {
return type;
}
public String getTableName() {
return tableName;
}
public void setTableName(String tableName) {
this.tableName = tableName;
}
public abstract StateType getStateType();
public String getIdentify() {
Preconditions.checkArgument(this.tableName != null, "table name must not be null.");
Preconditions.checkArgument(this.name != null, "table name must not be null.");
return this.name;
}
@Override
public String toString() {
return "AbstractStateDescriptor{" + "tableName='" + tableName + '\'' + ", name='" + name + '\''
+ ", type=" + type + '}';
}
public enum StateType {
/**
* value state
*/
VALUE,
/**
* list state
*/
LIST,
/**
* map state
*/
MAP
}
}
@@ -0,0 +1,83 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 io.ray.streaming.state.keystate.desc;
import static io.ray.streaming.state.config.ConfigKey.DELIMITER;
import io.ray.streaming.state.keystate.state.ListState;
/**
* ListStateDescriptor.
*/
public class ListStateDescriptor<T> extends AbstractStateDescriptor<ListState<T>, T> {
private final boolean isOperatorList;
private int index;
private int partitionNum;
private ListStateDescriptor(String name, Class<T> type, boolean isOperatorList) {
super(name, type);
this.isOperatorList = isOperatorList;
}
public static <T> ListStateDescriptor<T> build(String name, Class<T> type) {
return build(name, type, false);
}
public static <T> ListStateDescriptor<T> build(String name, Class<T> type,
boolean isOperatorList) {
return new ListStateDescriptor<>(name, type, isOperatorList);
}
public boolean isOperatorList() {
return isOperatorList;
}
public int getIndex() {
return index;
}
public void setIndex(int index) {
this.index = index;
}
public int getPartitionNumber() {
return partitionNum;
}
public void setPartitionNumber(int number) {
this.partitionNum = number;
}
@Override
public StateType getStateType() {
return StateType.LIST;
}
@Override
public String getIdentify() {
if (isOperatorList) {
return String
.format("%s%s%d%s%d", super.getIdentify(), DELIMITER, partitionNum, DELIMITER, index);
} else {
return super.getIdentify();
}
}
}
@@ -0,0 +1,43 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 io.ray.streaming.state.keystate.desc;
import io.ray.streaming.state.keystate.state.MapState;
import java.util.Map;
/**
* MapStateDescriptor.
*/
public class MapStateDescriptor<K, V> extends AbstractStateDescriptor<MapState<K, V>, Map<K, V>> {
public MapStateDescriptor(String name, Class<K> keyType, Class<V> valueType) {
super(name, null);
// TODO: use the types to help serde
}
public static <K, V> MapStateDescriptor<K, V> build(String name, Class<K> keyType,
Class<V> valueType) {
return new MapStateDescriptor<>(name, keyType, valueType);
}
@Override
public StateType getStateType() {
return StateType.MAP;
}
}
@@ -0,0 +1,47 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 io.ray.streaming.state.keystate.desc;
import io.ray.streaming.state.keystate.state.ValueState;
/**
* ValueStateDescriptor.
*/
public class ValueStateDescriptor<T> extends AbstractStateDescriptor<ValueState<T>, T> {
private final T defaultValue;
public ValueStateDescriptor(String name, Class<T> type, T defaultValue) {
super(name, type);
this.defaultValue = defaultValue;
}
public static <T> ValueStateDescriptor<T> build(String name, Class<T> type, T defaultValue) {
return new ValueStateDescriptor<>(name, type, defaultValue);
}
public T getDefaultValue() {
return defaultValue;
}
@Override
public StateType getStateType() {
return StateType.VALUE;
}
}
@@ -0,0 +1,41 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 io.ray.streaming.state.keystate.state;
import java.util.List;
/**
* ListState interface.
*/
public interface ListState<T> extends UnaryState<List<T>> {
/**
* add the value to list
*
* @param value the new value
*/
void add(T value);
/**
* update list state
*
* @param list the new value
*/
void update(List<T> list);
}
@@ -0,0 +1,112 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 io.ray.streaming.state.keystate.state;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
/**
* MapState interface.
*/
public interface MapState<K, V> extends UnaryState<Map<K, V>> {
/**
* Returns the current value associated with the given key.
*
* @param key The key of the mapping
* @return The value of the mapping with the given key
*/
V get(K key);
/**
* Associates a new value with the given key.
*
* @param key The key of the mapping
* @param value The new value of the mapping
*/
void put(K key, V value);
/**
* Resets the state value.
*
* @param map The mappings for reset in this state
*/
void update(Map<K, V> map);
/**
* Copies all of the mappings from the given map into the state.
*
* @param map The mappings to be stored in this state
*/
void putAll(Map<K, V> map);
/**
* Deletes the mapping of the given key.
*
* @param key The key of the mapping
*/
void remove(K key);
/**
* Returns whether there exists the given mapping.
*
* @param key The key of the mapping
* @return True if there exists a mapping whose key equals to the given key
*/
default boolean contains(K key) {
return get().containsKey(key);
}
/**
* Returns all the mappings in the state
*
* @return An iterable view of all the key-value pairs in the state.
*/
default Iterable<Entry<K, V>> entries() {
return get().entrySet();
}
/**
* Returns all the keys in the state
*
* @return An iterable view of all the keys in the state.
*/
default Iterable<K> keys() {
return get().keySet();
}
/**
* Returns all the values in the state.
*
* @return An iterable view of all the values in the state.
*/
default Iterable<V> values() {
return get().values();
}
/**
* Iterates over all the mappings in the state.
*
* @return An iterator over all the mappings in the state
*/
default Iterator<Entry<K, V>> iterator() {
return get().entrySet().iterator();
}
}
@@ -0,0 +1,30 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 io.ray.streaming.state.keystate.state;
/**
* State interface.
*/
public interface State {
/**
* set current key of the state
*/
void setCurrentKey(Object currentKey);
}
@@ -0,0 +1,32 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 io.ray.streaming.state.keystate.state;
/**
* one value per state.
*/
public interface UnaryState<O> extends State {
/**
* get the value in state
*
* @return the value in state
*/
O get();
}
@@ -0,0 +1,32 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 io.ray.streaming.state.keystate.state;
/**
* ValueState interface.
*/
public interface ValueState<T> extends UnaryState<T> {
/**
* update the value
*
* @param value the new value
*/
void update(T value);
}
@@ -0,0 +1,69 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 io.ray.streaming.state.keystate.state.impl;
import io.ray.streaming.state.backend.AbstractKeyStateBackend;
import io.ray.streaming.state.keystate.desc.ListStateDescriptor;
import io.ray.streaming.state.keystate.state.ListState;
import java.util.ArrayList;
import java.util.List;
/**
* ListState implementation.
*/
public class ListStateImpl<V> implements ListState<V> {
private final StateHelper<List<V>> helper;
public ListStateImpl(ListStateDescriptor<V> descriptor, AbstractKeyStateBackend backend) {
this.helper = new StateHelper<>(backend, descriptor);
}
@Override
public List<V> get() {
List<V> list = helper.get();
if (list == null) {
list = new ArrayList<>();
}
return list;
}
@Override
public void add(V value) {
List<V> list = helper.get();
if (list == null) {
list = new ArrayList<>();
}
list.add(value);
helper.put(list);
}
@Override
public void update(List<V> list) {
if (list == null) {
list = new ArrayList<>();
}
helper.put(list);
}
@Override
public void setCurrentKey(Object currentKey) {
helper.setCurrentKey(currentKey);
}
}
@@ -0,0 +1,92 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 io.ray.streaming.state.keystate.state.impl;
import io.ray.streaming.state.backend.KeyStateBackend;
import io.ray.streaming.state.keystate.desc.MapStateDescriptor;
import io.ray.streaming.state.keystate.state.MapState;
import java.util.HashMap;
import java.util.Map;
/**
* MapState implementation.
*/
public class MapStateImpl<K, V> implements MapState<K, V> {
private final StateHelper<Map<K, V>> helper;
public MapStateImpl(MapStateDescriptor<K, V> descriptor, KeyStateBackend backend) {
this.helper = new StateHelper<>(backend, descriptor);
}
@Override
public Map<K, V> get() {
Map<K, V> map = helper.get();
if (map == null) {
map = new HashMap<>();
}
return map;
}
@Override
public V get(K key) {
Map<K, V> map = get();
return map.get(key);
}
@Override
public void put(K key, V value) {
Map<K, V> map = get();
map.put(key, value);
helper.put(map);
}
@Override
public void update(Map<K, V> map) {
if (map == null) {
map = new HashMap<>();
}
helper.put(map);
}
@Override
public void putAll(Map<K, V> newMap) {
Map<K, V> map = get();
map.putAll(newMap);
helper.put(map);
}
@Override
public void remove(K key) {
Map<K, V> map = get();
map.remove(key);
helper.put(map);
}
/**
* set current key of the state
*/
@Override
public void setCurrentKey(Object currentKey) {
helper.setCurrentKey(currentKey);
}
}
@@ -0,0 +1,150 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 io.ray.streaming.state.keystate.state.impl;
import static io.ray.streaming.state.config.ConfigKey.DELIMITER;
import com.google.common.base.Preconditions;
import io.ray.streaming.state.PartitionRecord;
import io.ray.streaming.state.backend.AbstractKeyStateBackend;
import io.ray.streaming.state.keystate.desc.ListStateDescriptor;
import io.ray.streaming.state.keystate.state.ListState;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* This class defines the implementation of operator state.
* When the state is initialized, we must scan the whole table.
* And if the state type is splitList, all the records must be spitted.
*/
public class OperatorStateImpl<V> implements ListState<V> {
private final ListStateDescriptor<V> descriptor;
private StateHelper<List<PartitionRecord<V>>> helper;
private List<PartitionRecord<V>> allList;
private AtomicBoolean hasInit;
private boolean isSplit;
public OperatorStateImpl(ListStateDescriptor<V> descriptor, AbstractKeyStateBackend backend) {
this.descriptor = descriptor;
this.helper = new StateHelper<>(backend, descriptor);
this.isSplit = false;
this.hasInit = new AtomicBoolean(false);
this.allList = new ArrayList<>();
}
private void splitList() {
// fetch target list and save
List<PartitionRecord<V>> list = new ArrayList<>();
int step = descriptor.getPartitionNumber();
Preconditions.checkArgument(step > 0);
for (int round = 0; round * step <= allList.size(); round++) {
int m = round * step + descriptor.getIndex();
if (m < allList.size()) {
PartitionRecord<V> tmp = allList.get(m);
tmp.setPartitionID(descriptor.getPartitionNumber());
list.add(tmp);
}
}
helper.put(list, getStateKey());
allList.clear();
}
private void scan() {
int partitionNum = -1;
int index = 0;
while (true) {
List<PartitionRecord<V>> list = helper.getBackend()
.get(descriptor, getKey(descriptor.getIdentify(), index));
if (list != null && !list.isEmpty()) {
partitionNum = list.get(0).getPartitionID();
allList.addAll(list);
}
if (++index >= partitionNum) {
break;
}
}
}
public void init() {
scan();
if (isSplit) {
splitList();
}
}
private String getKey(String descName, int index) {
String[] stringList = descName.split(DELIMITER);
return String.format("%s%s%s%s%d", stringList[0], DELIMITER, stringList[1], DELIMITER, index);
}
protected String getStateKey() {
return getKey(this.descriptor.getIdentify(), this.descriptor.getIndex());
}
@Override
public void setCurrentKey(Object currentKey) {
throw new UnsupportedOperationException("OperatorState cannot set current key");
}
@Override
public List<V> get() {
if (!hasInit.getAndSet(true)) {
init();
}
List<PartitionRecord<V>> prList = helper.get(getStateKey());
List<V> list = new ArrayList<>();
for (PartitionRecord<V> pr : prList) {
list.add(pr.getValue());
}
return list;
}
@Override
public void add(V value) {
if (!hasInit.getAndSet(true)) {
init();
}
List<PartitionRecord<V>> list = helper.get(getStateKey());
if (list == null) {
list = new ArrayList<>();
}
list.add(new PartitionRecord<>(descriptor.getPartitionNumber(), value));
helper.put(list, getStateKey());
}
@Override
public void update(List<V> list) {
List<PartitionRecord<V>> prList = new ArrayList<>();
if (list != null) {
for (V value : list) {
prList.add(new PartitionRecord<>(descriptor.getPartitionNumber(), value));
}
}
helper.put(prList);
}
public void setSplit(boolean split) {
this.isSplit = split;
}
}
@@ -0,0 +1,80 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 io.ray.streaming.state.keystate.state.impl;
import com.google.common.base.Preconditions;
import io.ray.streaming.state.backend.AbstractKeyStateBackend;
import io.ray.streaming.state.keystate.desc.AbstractStateDescriptor;
/**
* State Helper Class.
*/
public class StateHelper<T> {
private final AbstractKeyStateBackend backend;
private final AbstractStateDescriptor descriptor;
public StateHelper(AbstractKeyStateBackend backend, AbstractStateDescriptor descriptor) {
this.backend = backend;
this.descriptor = descriptor;
}
protected String getStateKey(String descName) {
Preconditions.checkNotNull(backend, "KeyedBackend must not be null");
Preconditions.checkNotNull(backend.getCurrentKey(), "currentKey must not be null");
return this.backend.getBackend().getStateKey(descName, backend.getCurrentKey().toString());
}
public void put(T value, String key) {
backend.put(descriptor, key, value);
}
public void put(T value) {
put(value, getStateKey(descriptor.getIdentify()));
}
public T get(String key) {
return backend.get(descriptor, key);
}
public T get() {
return get(getStateKey(descriptor.getIdentify()));
}
public void setCurrentKey(Object currentKey) {
Preconditions.checkNotNull(backend, "KeyedBackend must not be null");
this.backend.setCurrentKey(currentKey);
}
public void setKeyGroupIndex(int keyGroupIndex) {
this.backend.setKeyGroupIndex(keyGroupIndex);
}
public void resetKeyGroupIndex() {
this.backend.setKeyGroupIndex(-1);
}
public AbstractStateDescriptor getDescriptor() {
return descriptor;
}
public AbstractKeyStateBackend getBackend() {
return backend;
}
}
@@ -0,0 +1,58 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 io.ray.streaming.state.keystate.state.impl;
import io.ray.streaming.state.backend.KeyStateBackend;
import io.ray.streaming.state.keystate.desc.ValueStateDescriptor;
import io.ray.streaming.state.keystate.state.ValueState;
/**
* ValueState implementation.
*/
public class ValueStateImpl<T> implements ValueState<T> {
private final StateHelper<T> helper;
public ValueStateImpl(ValueStateDescriptor<T> descriptor, KeyStateBackend backend) {
this.helper = new StateHelper<>(backend, descriptor);
}
@Override
public void update(T value) {
helper.put(value);
}
@Override
public T get() {
T value = helper.get();
if (null == value) {
return ((ValueStateDescriptor<T>) helper.getDescriptor()).getDefaultValue();
} else {
return value;
}
}
/**
* set current key of the state
*/
@Override
public void setCurrentKey(Object currentKey) {
helper.setCurrentKey(currentKey);
}
}
@@ -0,0 +1,51 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 io.ray.streaming.state.keystate.state.proxy;
import io.ray.streaming.state.KeyValueState;
import io.ray.streaming.state.backend.AbstractKeyStateBackend;
import io.ray.streaming.state.keystate.desc.ListStateDescriptor;
import io.ray.streaming.state.keystate.state.ListState;
import io.ray.streaming.state.keystate.state.impl.ListStateImpl;
import io.ray.streaming.state.keystate.state.impl.OperatorStateImpl;
import io.ray.streaming.state.strategy.StateStoreManagerProxy;
import java.util.List;
/**
* This class defines ListState Wrapper, connecting state and backend.
*/
public class ListStateStoreManagerProxy<T> extends StateStoreManagerProxy<List<T>> implements
KeyValueState<String, List<T>> {
private final ListState<T> listState;
public ListStateStoreManagerProxy(AbstractKeyStateBackend keyStateBackend,
ListStateDescriptor<T> stateDescriptor) {
super(keyStateBackend, stateDescriptor);
if (stateDescriptor.isOperatorList()) {
this.listState = new OperatorStateImpl<>(stateDescriptor, keyStateBackend);
} else {
this.listState = new ListStateImpl<>(stateDescriptor, keyStateBackend);
}
}
public ListState<T> getListState() {
return this.listState;
}
}
@@ -0,0 +1,46 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 io.ray.streaming.state.keystate.state.proxy;
import io.ray.streaming.state.KeyValueState;
import io.ray.streaming.state.backend.KeyStateBackend;
import io.ray.streaming.state.keystate.desc.MapStateDescriptor;
import io.ray.streaming.state.keystate.state.MapState;
import io.ray.streaming.state.keystate.state.impl.MapStateImpl;
import io.ray.streaming.state.strategy.StateStoreManagerProxy;
import java.util.Map;
/**
* This class defines MapState Wrapper, connecting state and backend.
*/
public class MapStateStoreManagerProxy<K, V> extends StateStoreManagerProxy<Map<K, V>> implements
KeyValueState<String, Map<K, V>> {
private final MapStateImpl<K, V> mapState;
public MapStateStoreManagerProxy(KeyStateBackend keyStateBackend,
MapStateDescriptor<K, V> stateDescriptor) {
super(keyStateBackend, stateDescriptor);
this.mapState = new MapStateImpl<>(stateDescriptor, keyStateBackend);
}
public MapState<K, V> getMapState() {
return this.mapState;
}
}
@@ -0,0 +1,45 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 io.ray.streaming.state.keystate.state.proxy;
import io.ray.streaming.state.KeyValueState;
import io.ray.streaming.state.backend.KeyStateBackend;
import io.ray.streaming.state.keystate.desc.ValueStateDescriptor;
import io.ray.streaming.state.keystate.state.ValueState;
import io.ray.streaming.state.keystate.state.impl.ValueStateImpl;
import io.ray.streaming.state.strategy.StateStoreManagerProxy;
/**
* This class defines ValueState Wrapper, connecting state and backend.
*/
public class ValueStateStoreManagerProxy<T> extends StateStoreManagerProxy<T> implements
KeyValueState<String, T> {
private final ValueStateImpl<T> valueState;
public ValueStateStoreManagerProxy(KeyStateBackend keyStateBackend,
ValueStateDescriptor<T> stateDescriptor) {
super(keyStateBackend, stateDescriptor);
this.valueState = new ValueStateImpl<>(stateDescriptor, keyStateBackend);
}
public ValueState<T> getValueState() {
return this.valueState;
}
}
@@ -0,0 +1,36 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 io.ray.streaming.state.serialization;
/**
* Key Map Serialization and Deserialization.
*/
public interface KeyMapStoreSerializer<K, S, T> {
byte[] serializeKey(K key);
byte[] serializeUKey(S uk);
S deserializeUKey(byte[] ukArray);
byte[] serializeUValue(T uv);
T deserializeUValue(byte[] uvArray);
}
@@ -0,0 +1,31 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 io.ray.streaming.state.serialization;
/**
* Key Value Serialization and Deserialization.
*/
public interface KeyValueStoreSerialization<K, V> {
byte[] serializeKey(K key);
byte[] serializeValue(V value);
V deserializeValue(byte[] valueArray);
}
@@ -0,0 +1,38 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 io.ray.streaming.state.serialization;
import org.nustaq.serialization.FSTConfiguration;
/**
* fst wrapper.
*/
public class Serializer {
private static final ThreadLocal<FSTConfiguration> conf = ThreadLocal
.withInitial(FSTConfiguration::createDefaultConfiguration);
public static byte[] object2Bytes(Object value) {
return conf.get().asByteArray(value);
}
public static Object bytes2Object(byte[] buffer) {
return conf.get().asObject(buffer);
}
}
@@ -0,0 +1,46 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 io.ray.streaming.state.serialization.impl;
import com.google.common.hash.Hashing;
import io.ray.streaming.state.StateException;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* AbstractSerialization. Generate row key.
*/
public abstract class AbstractSerialization {
private static final Logger LOG = LoggerFactory.getLogger(AbstractSerialization.class);
public String generateRowKeyPrefix(String key) {
if (StringUtils.isNotEmpty(key)) {
String md5 = Hashing.md5().hashUnencodedChars(key).toString();
if ("".equals(md5)) {
throw new StateException("Invalid value to md5:" + key);
}
return StringUtils.substring(md5, 0, 4) + ":" + key;
} else {
LOG.warn("key is empty");
return key;
}
}
}
@@ -0,0 +1,55 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 io.ray.streaming.state.serialization.impl;
import io.ray.streaming.state.serialization.KeyMapStoreSerializer;
import io.ray.streaming.state.serialization.Serializer;
/**
* Default Key Map Serialization and Deserialization.
*/
public class DefaultKeyMapStoreSerializer<K, S, T> extends AbstractSerialization implements
KeyMapStoreSerializer<K, S, T> {
@Override
public byte[] serializeKey(K key) {
String keyWithPrefix = generateRowKeyPrefix(key.toString());
return keyWithPrefix.getBytes();
}
@Override
public byte[] serializeUKey(S uk) {
return Serializer.object2Bytes(uk);
}
@Override
public S deserializeUKey(byte[] ukArray) {
return (S) Serializer.bytes2Object(ukArray);
}
@Override
public byte[] serializeUValue(T uv) {
return Serializer.object2Bytes(uv);
}
@Override
public T deserializeUValue(byte[] uvArray) {
return (T) Serializer.bytes2Object(uvArray);
}
}
@@ -0,0 +1,45 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 io.ray.streaming.state.serialization.impl;
import io.ray.streaming.state.serialization.KeyValueStoreSerialization;
import io.ray.streaming.state.serialization.Serializer;
/**
* KV Store Serialization and Deserialization.
*/
public class DefaultKeyValueStoreSerialization<K, V> extends AbstractSerialization implements
KeyValueStoreSerialization<K, V> {
@Override
public byte[] serializeKey(K key) {
String keyWithPrefix = generateRowKeyPrefix(key.toString());
return keyWithPrefix.getBytes();
}
@Override
public byte[] serializeValue(V value) {
return Serializer.object2Bytes(value);
}
@Override
public V deserializeValue(byte[] valueArray) {
return (V) Serializer.bytes2Object(valueArray);
}
}
@@ -0,0 +1,38 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 io.ray.streaming.state.store;
import java.io.IOException;
import java.util.Map;
/**
* Key Map Store interface.
*/
public interface KeyMapStore<K, S, T> extends KeyValueStore<K, Map<S, T>> {
/**
* put sub key value into the store incrementally.
*/
void put(K key, S subKey, T value) throws IOException;
/**
* get subValue from store.
*/
T get(K key, S subKey) throws IOException;
}
@@ -0,0 +1,58 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 io.ray.streaming.state.store;
import java.io.IOException;
import java.io.Serializable;
/**
* Key Value Store interface.
*/
public interface KeyValueStore<K, V> extends Serializable {
/**
* put key value into store.
*/
void put(K key, V value) throws IOException;
/**
* get value from store.
*/
V get(K key) throws IOException;
/**
* remove key in the store.
*/
void remove(K key) throws IOException;
/**
* flush to disk.
*/
void flush() throws IOException;
/**
* clear all cache.
*/
void clearCache();
/**
* close the store.
*/
void close() throws IOException;
}
@@ -0,0 +1,89 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 io.ray.streaming.state.store.impl;
import com.google.common.collect.Maps;
import io.ray.streaming.state.store.KeyMapStore;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/**
* Memory Key Map Store.
*/
public class MemoryKeyMapStore<K, S, T> implements KeyMapStore<K, S, T> {
private Map<K, Map<S, T>> memoryStore;
public MemoryKeyMapStore() {
this.memoryStore = Maps.newConcurrentMap();
}
@Override
public void put(K key, Map<S, T> value) throws IOException {
this.memoryStore.put(key, value);
}
@Override
public void put(K key, S subKey, T value) throws IOException {
if (memoryStore.containsKey(key)) {
memoryStore.get(key).put(subKey, value);
} else {
Map<S, T> map = new HashMap<>();
map.put(subKey, value);
memoryStore.put(key, map);
}
}
@Override
public Map<S, T> get(K key) throws IOException {
return this.memoryStore.get(key);
}
@Override
public T get(K key, S subKey) throws IOException {
if (memoryStore.containsKey(key)) {
return memoryStore.get(key).get(subKey);
}
return null;
}
@Override
public void remove(K key) throws IOException {
this.memoryStore.remove(key);
}
@Override
public void flush() throws IOException {
}
@Override
public void clearCache() {
}
@Override
public void close() throws IOException {
if (memoryStore != null) {
memoryStore.clear();
}
}
}
@@ -0,0 +1,68 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 io.ray.streaming.state.store.impl;
import com.google.common.collect.Maps;
import io.ray.streaming.state.store.KeyValueStore;
import java.io.IOException;
import java.util.Map;
/**
* Memory Key Value Store.
*/
public class MemoryKeyValueStore<K, V> implements KeyValueStore<K, V> {
private Map<K, V> memoryStore;
public MemoryKeyValueStore() {
this.memoryStore = Maps.newConcurrentMap();
}
@Override
public void put(K key, V value) throws IOException {
this.memoryStore.put(key, value);
}
@Override
public V get(K key) throws IOException {
return this.memoryStore.get(key);
}
@Override
public void remove(K key) throws IOException {
this.memoryStore.remove(key);
}
@Override
public void flush() throws IOException {
}
@Override
public void clearCache() {
}
@Override
public void close() throws IOException {
if (memoryStore != null) {
memoryStore.clear();
}
}
}
@@ -0,0 +1,93 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 io.ray.streaming.state.strategy;
import io.ray.streaming.state.StateException;
import io.ray.streaming.state.StateStoreManager;
import io.ray.streaming.state.StorageRecord;
import io.ray.streaming.state.serialization.Serializer;
import io.ray.streaming.state.store.KeyValueStore;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* This class defines the StoreManager Abstract class.
* We use three layer to store the state, frontStore, middleStore and keyValueStore(remote).
*/
public abstract class AbstractStateStoreManager<V> implements StateStoreManager {
/**
* read-write
*/
protected Map<String, StorageRecord<V>> frontStore = new ConcurrentHashMap<>();
/**
* remote-storage
*/
protected KeyValueStore<String, Map<Long, byte[]>> kvStore;
/**
* read-only
*/
protected Map<Long, Map<String, byte[]>> middleStore = new ConcurrentHashMap<>();
protected int keyGroupIndex = -1;
public AbstractStateStoreManager(KeyValueStore<String, Map<Long, byte[]>> backStore) {
kvStore = backStore;
}
public byte[] toBytes(StorageRecord storageRecord) {
return Serializer.object2Bytes(storageRecord);
}
public StorageRecord<V> toStorageRecord(byte[] data) {
return (StorageRecord<V>) Serializer.bytes2Object(data);
}
public abstract V get(long checkpointId, String key);
public void put(long checkpointId, String k, V v) {
frontStore.put(k, new StorageRecord<>(checkpointId, v));
}
@Override
public void ackCommit(long checkpointId, long timeStamp) {
ackCommit(checkpointId);
}
public abstract void ackCommit(long checkpointId);
public void setKeyGroupIndex(int keyGroupIndex) {
this.keyGroupIndex = keyGroupIndex;
}
public void close() {
frontStore.clear();
middleStore.clear();
if (kvStore != null) {
kvStore.clearCache();
try {
kvStore.close();
} catch (IOException e) {
throw new StateException(e);
}
}
}
}
@@ -0,0 +1,167 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 io.ray.streaming.state.strategy;
import com.google.common.primitives.Longs;
import io.ray.streaming.state.StateException;
import io.ray.streaming.state.StorageRecord;
import io.ray.streaming.state.store.KeyValueStore;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This class define the checkpoint store strategy, which saves two-version data once.
*/
public class DualStateStoreManager<V> extends AbstractStateStoreManager<V> {
private static final Logger LOG = LoggerFactory.getLogger(DualStateStoreManager.class);
public DualStateStoreManager(KeyValueStore<String, Map<Long, byte[]>> backStore) {
super(backStore);
}
@Override
public void finish(long checkpointId) {
LOG.info("do finish checkpointId:{}", checkpointId);
Map<String, byte[]> cpStore = new HashMap<>();
for (Entry<String, StorageRecord<V>> entry : frontStore.entrySet()) {
String key = entry.getKey();
StorageRecord<V> value = entry.getValue();
cpStore.put(key, toBytes(value));
}
middleStore.put(checkpointId, cpStore);
frontStore.clear();
}
@Override
public void commit(long checkpointId) {
try {
LOG.info("do commit checkpointId:{}", checkpointId);
Map<String, byte[]> cpStore = middleStore.get(checkpointId);
if (cpStore == null) {
throw new StateException("why cp store is null");
}
for (Entry<String, byte[]> entry : cpStore.entrySet()) {
String key = entry.getKey();
byte[] value = entry.getValue();
/**
* 2 is specific key in kv store and indicates that new value
* should be stored with this key after overwriting old value in key 1. i.e.
*
* -2 -1 1 2
* k1 6 5 a b
* k2 9 7 d e
*
* k1's value for checkpoint 5 is a, and b for checkpoint 6.
*/
Map<Long, byte[]> remoteData = super.kvStore.get(key);
if (remoteData == null || remoteData.size() == 0) {
remoteData = new HashMap<>();
remoteData.put(2L, value);
remoteData.put(-2L, Longs.toByteArray(checkpointId));
} else {
long oldBatchId = Longs.fromByteArray(remoteData.get(-2L));
if (oldBatchId < checkpointId) {
//move the old data
remoteData.put(1L, remoteData.get(2L));
remoteData.put(-1L, remoteData.get(-2L));
}
//put the new data here
remoteData.put(2L, value);
remoteData.put(-2L, Longs.toByteArray(checkpointId));
}
super.kvStore.put(key, remoteData);
}
super.kvStore.flush();
} catch (Exception e) {
LOG.error(e.getMessage(), e);
throw new StateException(e);
}
}
@Override
public void rollBack(long checkpointId) {
LOG.info("do rollBack checkpointId:{}", checkpointId);
this.frontStore.clear();
this.middleStore.clear();
this.kvStore.clearCache();
}
@Override
public V get(long checkpointId, String key) {
// get from current cp cache
StorageRecord<V> storageRecord = frontStore.get(key);
if (storageRecord != null) {
return storageRecord.getValue();
}
//get from not commit cp info
List<Long> checkpointIds = new ArrayList<>(middleStore.keySet());
Collections.sort(checkpointIds);
for (int i = checkpointIds.size() - 1; i >= 0; i--) {
Map<String, byte[]> cpStore = middleStore.get(checkpointIds.get(i));
if (cpStore != null) {
if (cpStore.containsKey(key)) {
byte[] cpData = cpStore.get(key);
storageRecord = toStorageRecord(cpData);
return storageRecord.getValue();
}
}
}
try {
Map<Long, byte[]> remoteData = super.kvStore.get(key);
if (remoteData != null) {
for (Entry<Long, byte[]> entry : remoteData.entrySet()) {
if (entry.getKey() > 0) {
StorageRecord<V> tmp = toStorageRecord(entry.getValue());
if (tmp.getCheckpointId() < checkpointId) {
if (storageRecord == null) {
storageRecord = tmp;
} else if (storageRecord.getCheckpointId() < tmp.getCheckpointId()) {
storageRecord = tmp;
}
}
}
}
if (storageRecord != null) {
return storageRecord.getValue();
}
}
} catch (Exception e) {
LOG.error("get checkpointId:" + checkpointId + " key:" + key, e);
throw new StateException(e);
}
return null;
}
@Override
public void ackCommit(long checkpointId) {
LOG.info("do ackCommit checkpointId:{}", checkpointId);
middleStore.remove(checkpointId);
}
}
@@ -0,0 +1,157 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 io.ray.streaming.state.strategy;
import io.ray.streaming.state.StateException;
import io.ray.streaming.state.StorageRecord;
import io.ray.streaming.state.store.KeyValueStore;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
/**
* This class define the multi-version store strategy, which leverages external storage's mvcc.
*/
public class MVStateStoreManager<V> extends AbstractStateStoreManager<V> {
public MVStateStoreManager(KeyValueStore<String, Map<Long, byte[]>> kvStore) {
super(kvStore);
}
@Override
public void finish(long checkpointId) {
Map<String, byte[]> currentStateRecords = new HashMap<>();
for (Entry<String, StorageRecord<V>> entry : frontStore.entrySet()) {
currentStateRecords.put(entry.getKey(), toBytes(entry.getValue()));
}
middleStore.put(checkpointId, currentStateRecords);
frontStore.clear();
}
@Override
public void commit(long checkpointId) {
// write to external storage
List<Long> checkpointIds = new ArrayList<>(middleStore.keySet());
Collections.sort(checkpointIds);
for (int i = checkpointIds.size() - 1; i >= 0; i--) {
long commitBatchId = checkpointIds.get(i);
if (commitBatchId > checkpointId) {
continue;
}
Map<String, byte[]> commitRecords = middleStore.get(commitBatchId);
try {
for (Entry<String, byte[]> entry : commitRecords.entrySet()) {
Map<Long, byte[]> remoteData = this.kvStore.get(entry.getKey());
if (remoteData == null) {
remoteData = new HashMap<>();
}
remoteData.put(commitBatchId, entry.getValue());
this.kvStore.put(entry.getKey(), remoteData);
}
this.kvStore.flush();
} catch (Exception e) {
throw new StateException(e);
}
}
}
@Override
public void rollBack(long checkpointId) {
this.frontStore.clear();
this.middleStore.clear();
this.kvStore.clearCache();
}
@Override
public V get(long checkpointId, String key) {
StorageRecord<V> valueArray = frontStore.get(key);
if (valueArray != null) {
return valueArray.getValue();
} else {
List<Long> checkpointIds = new ArrayList<>(middleStore.keySet());
Collections.sort(checkpointIds);
for (int i = checkpointIds.size() - 1; i >= 0; i--) {
if (checkpointIds.get(i) > checkpointId) {
continue;
}
Map<String, byte[]> records = middleStore.get(checkpointIds.get(i));
if (records != null) {
if (records.containsKey(key)) {
byte[] bytes = records.get(key);
return toStorageRecord(bytes).getValue();
}
}
}
// get from external storage
try {
Map<Long, byte[]> remoteData = this.kvStore.get(key);
if (remoteData != null) {
checkpointIds = new ArrayList<>(remoteData.keySet());
Collections.sort(checkpointIds);
for (int i = checkpointIds.size() - 1; i >= 0; i--) {
if (checkpointIds.get(i) > checkpointId) {
continue;
}
byte[] bytes = remoteData.get(checkpointIds.get(i));
return toStorageRecord(bytes).getValue();
}
}
} catch (Exception e) {
throw new StateException(e);
}
}
return null;
}
@Override
public void put(long checkpointId, String k, V v) {
frontStore.put(k, new StorageRecord<>(checkpointId, v));
}
@Override
public void ackCommit(long checkpointId) {
List<Long> checkpointIds = new ArrayList<>(middleStore.keySet());
Collections.sort(checkpointIds);
for (int i = checkpointIds.size() - 1; i >= 0; i--) {
long commitBatchId = checkpointIds.get(i);
if (commitBatchId > checkpointId) {
continue;
}
this.middleStore.remove(commitBatchId);
}
}
}
@@ -0,0 +1,102 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 io.ray.streaming.state.strategy;
import io.ray.streaming.state.StateStoreManager;
import io.ray.streaming.state.backend.AbstractKeyStateBackend;
import io.ray.streaming.state.backend.StateStrategy;
import io.ray.streaming.state.keystate.desc.AbstractStateDescriptor;
import io.ray.streaming.state.store.KeyValueStore;
import java.util.Map;
/**
* This class support ITransactionState.
* <p>
* Based on the given StorageMode, different implementation instance of the AbstractStateStrategy
* class will be created. All method calls will be delegated to the strategy instance.
*/
public abstract class StateStoreManagerProxy<V> implements StateStoreManager {
protected final AbstractStateStoreManager<V> stateStrategy;
private final AbstractKeyStateBackend keyStateBackend;
public StateStoreManagerProxy(AbstractKeyStateBackend keyStateBackend,
AbstractStateDescriptor stateDescriptor) {
this.keyStateBackend = keyStateBackend;
KeyValueStore<String, Map<Long, byte[]>> backStorage = keyStateBackend
.getBackStorage(stateDescriptor);
StateStrategy stateStrategy = keyStateBackend.getStateStrategy();
switch (stateStrategy) {
case DUAL_VERSION:
this.stateStrategy = new DualStateStoreManager<>(backStorage);
break;
case SINGLE_VERSION:
this.stateStrategy = new MVStateStoreManager<>(backStorage);
break;
default:
throw new UnsupportedOperationException("store vertexType not support");
}
}
protected void setKeyGroupIndex(int index) {
this.stateStrategy.setKeyGroupIndex(index);
}
@Override
public void finish(long checkpointId) {
this.stateStrategy.finish(checkpointId);
}
/**
* The commit can be used in another thread to reach async state commit.
*/
@Override
public void commit(long checkpointId) {
this.stateStrategy.commit(checkpointId);
}
/**
* The ackCommit must be called after commit in the same thread.
*/
@Override
public void ackCommit(long checkpointId, long timeStamp) {
this.stateStrategy.ackCommit(checkpointId);
}
@Override
public void rollBack(long checkpointId) {
this.stateStrategy.rollBack(checkpointId);
}
public void close() {
this.stateStrategy.close();
}
public V get(String key) {
this.stateStrategy.setKeyGroupIndex(keyStateBackend.getKeyGroupIndex());
return this.stateStrategy.get(this.keyStateBackend.getCheckpointId(), key);
}
public void put(String key, V value) {
this.stateStrategy.setKeyGroupIndex(keyStateBackend.getKeyGroupIndex());
this.stateStrategy.put(this.keyStateBackend.getCheckpointId(), key, value);
}
}
@@ -0,0 +1,315 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 io.ray.streaming.state.backend;
import io.ray.streaming.state.keystate.KeyGroup;
import io.ray.streaming.state.keystate.desc.ListStateDescriptor;
import io.ray.streaming.state.keystate.desc.MapStateDescriptor;
import io.ray.streaming.state.keystate.desc.ValueStateDescriptor;
import io.ray.streaming.state.keystate.state.ListState;
import io.ray.streaming.state.keystate.state.MapState;
import io.ray.streaming.state.keystate.state.ValueState;
import java.util.Arrays;
import java.util.HashMap;
import org.testng.Assert;
import org.testng.annotations.Test;
public class KeyStateBackendTest {
private AbstractStateBackend stateBackend;
private KeyStateBackend keyStateBackend;
public void testGetValueState() {
keyStateBackend.setCheckpointId(1L);
ValueStateDescriptor<String> valueStateDescriptor = ValueStateDescriptor
.build("value", String.class, null);
valueStateDescriptor.setTableName("kepler_hlg_ut");
ValueState<String> valueState = keyStateBackend.getValueState(valueStateDescriptor);
valueState.setCurrentKey("1");
valueState.update("hello");
Assert.assertEquals(valueState.get(), "hello");
valueState.update("hello1");
Assert.assertEquals(valueState.get(), "hello1");
valueState.setCurrentKey("2");
Assert.assertEquals(valueState.get(), null);
valueState.update("eagle");
Assert.assertEquals(valueState.get(), "eagle");
keyStateBackend.rollBack(1);
valueState.setCurrentKey("1");
Assert.assertEquals(valueState.get(), null);
valueState.setCurrentKey("2");
Assert.assertEquals(valueState.get(), null);
valueState.setCurrentKey("1");
valueState.update("eagle");
keyStateBackend.finish(1);
keyStateBackend.setCheckpointId(2);
valueState.setCurrentKey("2");
valueState.update("tim");
valueState.setCurrentKey("2-1");
valueState.update("jim");
keyStateBackend.finish(2);
keyStateBackend.setCheckpointId(3);
valueState.setCurrentKey("3");
valueState.update("lucy");
keyStateBackend.finish(3);
keyStateBackend.setCheckpointId(4);
valueState.setCurrentKey("4");
valueState.update("eric");
keyStateBackend.finish(4);
keyStateBackend.setCheckpointId(5);
valueState.setCurrentKey("4");
valueState.update("eric-1");
valueState.setCurrentKey("5");
valueState.update("jack");
keyStateBackend.finish(5);
keyStateBackend.commit(5);
keyStateBackend.setCheckpointId(6);
valueState.setCurrentKey("5");
Assert.assertEquals(valueState.get(), "jack");
valueState.setCurrentKey("4");
Assert.assertEquals(valueState.get(), "eric-1");
valueState.setCurrentKey(4);
valueState.update("if-ttt");
Assert.assertEquals(valueState.get(), "if-ttt");
keyStateBackend.setCheckpointId(7);
valueState.setCurrentKey(9);
valueState.update("6666");
keyStateBackend.rollBack(5);
keyStateBackend.setCheckpointId(6);
valueState.setCurrentKey("4");
Assert.assertEquals(valueState.get(), "eric-1");
valueState.setCurrentKey("5");
Assert.assertEquals(valueState.get(), "jack");
valueState.setCurrentKey("9");
Assert.assertNull(valueState.get());
}
public void testGetListState() {
keyStateBackend.setCheckpointId(1l);
ListStateDescriptor<String> listStateDescriptor = ListStateDescriptor
.build("list", String.class);
listStateDescriptor.setTableName("kepler_hlg_ut");
ListState<String> listState = keyStateBackend.getListState(listStateDescriptor);
listState.setCurrentKey("1");
listState.add("hello1");
Assert.assertEquals(listState.get(), Arrays.asList("hello1"));
listState.add("hello2");
Assert.assertEquals(listState.get(), Arrays.asList("hello1", "hello2"));
listState.setCurrentKey("2");
Assert.assertEquals(listState.get(), Arrays.asList());
listState.setCurrentKey("2");
listState.add("eagle");
listState.setCurrentKey("1");
Assert.assertEquals(listState.get(), Arrays.asList("hello1", "hello2"));
listState.setCurrentKey("2");
Assert.assertEquals(listState.get(), Arrays.asList("eagle"));
keyStateBackend.rollBack(1);
listState.setCurrentKey("1");
Assert.assertEquals(listState.get(), Arrays.asList());
listState.setCurrentKey("2");
Assert.assertEquals(listState.get(), Arrays.asList());
listState.setCurrentKey("1");
listState.add("eagle");
listState.add("eagle-2");
keyStateBackend.finish(1);
keyStateBackend.setCheckpointId(2);
listState.setCurrentKey("2");
listState.add("tim");
listState.setCurrentKey("2-1");
listState.add("jim");
keyStateBackend.finish(2);
keyStateBackend.setCheckpointId(3);
listState.setCurrentKey("3");
listState.add("lucy");
keyStateBackend.finish(3);
keyStateBackend.setCheckpointId(4);
listState.setCurrentKey("4");
listState.add("eric");
keyStateBackend.finish(4);
keyStateBackend.setCheckpointId(5);
listState.setCurrentKey("4");
listState.add("eric-1");
Assert.assertEquals(listState.get(), Arrays.asList("eric", "eric-1"));
listState.setCurrentKey("5");
listState.add("jack");
keyStateBackend.finish(5);
keyStateBackend.commit(5);
keyStateBackend.setCheckpointId(6);
listState.setCurrentKey("5");
Assert.assertEquals(listState.get(), Arrays.asList("jack"));
listState.setCurrentKey("4");
Assert.assertEquals(listState.get(), Arrays.asList("eric", "eric-1"));
listState.setCurrentKey(4);
listState.add("if-ttt");
Assert.assertEquals(listState.get(), Arrays.asList("eric", "eric-1", "if-ttt"));
keyStateBackend.setCheckpointId(7);
listState.setCurrentKey(9);
listState.add("6666");
keyStateBackend.rollBack(5);
keyStateBackend.setCheckpointId(6);
listState.setCurrentKey("4");
Assert.assertEquals(listState.get(), Arrays.asList("eric", "eric-1"));
listState.setCurrentKey("5");
Assert.assertEquals(listState.get(), Arrays.asList("jack"));
listState.setCurrentKey("9");
Assert.assertEquals(listState.get(), Arrays.asList());
}
public void testGetMapState() {
keyStateBackend.setCheckpointId(1l);
MapStateDescriptor<String, String> mapStateDescriptor = MapStateDescriptor
.build("map", String.class, String.class);
mapStateDescriptor.setTableName("kepler_hlg_ut");
MapState<String, String> mapState = keyStateBackend.getMapState(mapStateDescriptor);
mapState.setCurrentKey("1");
mapState.put("hello1", "world1");
Assert.assertEquals(mapState.get("hello1"), "world1");
mapState.put("hello2", "world2");
Assert.assertEquals(mapState.get("hello2"), "world2");
Assert.assertEquals(mapState.get("hello1"), "world1");
Assert.assertEquals(mapState.get("hello3"), null);
mapState.setCurrentKey("2");
//Assert.assertEquals(mapState.iterator(), (new HashMap()));
mapState.setCurrentKey("2");
mapState.put("eagle", "eagle-1");
mapState.setCurrentKey("1");
Assert.assertEquals(mapState.get("hello1"), "world1");
mapState.setCurrentKey("2");
Assert.assertEquals(mapState.get("eagle"), "eagle-1");
Assert.assertEquals(mapState.get("xxx"), null);
keyStateBackend.rollBack(1);
mapState.setCurrentKey("1");
Assert.assertEquals(mapState.iterator(), (new HashMap()).entrySet().iterator());
mapState.setCurrentKey("2");
Assert.assertEquals(mapState.iterator(), (new HashMap()).entrySet().iterator());
mapState.setCurrentKey("1");
mapState.put("eagle", "eagle-1");
mapState.put("eagle-2", "eagle-3");
keyStateBackend.finish(1);
keyStateBackend.setCheckpointId(2);
mapState.setCurrentKey("2");
mapState.put("tim", "tina");
mapState.setCurrentKey("2-1");
mapState.put("jim", "tick");
keyStateBackend.finish(2);
keyStateBackend.setCheckpointId(3);
mapState.setCurrentKey("3");
mapState.put("lucy", "ja");
keyStateBackend.finish(3);
keyStateBackend.setCheckpointId(4);
mapState.setCurrentKey("4");
mapState.put("eric", "sam");
keyStateBackend.finish(4);
keyStateBackend.setCheckpointId(5);
mapState.setCurrentKey("4");
mapState.put("eric-1", "zxy");
Assert.assertEquals(mapState.get("eric-1"), "zxy");
Assert.assertEquals(mapState.get("eric"), "sam");
mapState.setCurrentKey("5");
mapState.put("jack", "zhang");
keyStateBackend.finish(5);
keyStateBackend.commit(5);
keyStateBackend.setCheckpointId(6);
mapState.setCurrentKey("5");
Assert.assertEquals(mapState.get("jack"), "zhang");
mapState.put("hlll", "gggg");
mapState.setCurrentKey("4");
Assert.assertEquals(mapState.get("eric-1"), "zxy");
Assert.assertEquals(mapState.get("eric"), "sam");
mapState.setCurrentKey(4);
mapState.put("if-ttt", "if-ggg");
Assert.assertEquals(mapState.get("if-ttt"), "if-ggg");
keyStateBackend.setCheckpointId(7);
mapState.setCurrentKey(9);
mapState.put("6666", "7777");
keyStateBackend.rollBack(5);
keyStateBackend.setCheckpointId(6);
mapState.setCurrentKey("4");
Assert.assertEquals(mapState.get("eric-1"), "zxy");
Assert.assertEquals(mapState.get("eric"), "sam");
Assert.assertNull(mapState.get("if-ttt"));
mapState.setCurrentKey("5");
Assert.assertNull(mapState.get("hlll"));
mapState.setCurrentKey("9");
Assert.assertNull(mapState.get("6666"));
}
@Test
public void testMem() {
stateBackend = StateBackendBuilder.buildStateBackend(new HashMap<>());
keyStateBackend = new KeyStateBackend(4, new KeyGroup(2, 3), stateBackend);
testGetValueState();
testGetListState();
testGetMapState();
}
}
@@ -0,0 +1,60 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 io.ray.streaming.state.impl;
import io.ray.streaming.state.serialization.impl.DefaultKeyMapStoreSerializer;
import java.util.HashMap;
import java.util.Map;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
public class DefaultKeyMapStoreSerializationTest {
private DefaultKeyMapStoreSerializer<String, String, Map<String, String>> defaultKMapStoreSerDe;
@BeforeClass
public void setUp() {
this.defaultKMapStoreSerDe = new DefaultKeyMapStoreSerializer<>();
}
@Test
public void testSerKey() {
String key = "hello";
byte[] result = this.defaultKMapStoreSerDe.serializeKey(key);
String keyWithPrefix = this.defaultKMapStoreSerDe.generateRowKeyPrefix(key.toString());
Assert.assertEquals(result, keyWithPrefix.getBytes());
}
@Test
public void testSerUKey() {
String subKey = "hell1";
byte[] result = this.defaultKMapStoreSerDe.serializeUKey(subKey);
Assert.assertEquals(subKey, this.defaultKMapStoreSerDe.deserializeUKey(result));
}
@Test
public void testSerUValue() {
Map<String, String> value = new HashMap<>();
value.put("foo", "bar");
byte[] result = this.defaultKMapStoreSerDe.serializeUValue(value);
Assert.assertEquals(value, this.defaultKMapStoreSerDe.deserializeUValue(result));
}
}
@@ -0,0 +1,43 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 io.ray.streaming.state.impl;
import io.ray.streaming.state.serialization.impl.DefaultKeyValueStoreSerialization;
import org.testng.Assert;
import org.testng.annotations.Test;
public class DefaultKeyValueStoreSerializationTest {
DefaultKeyValueStoreSerialization<String, Integer> serDe = new DefaultKeyValueStoreSerialization<>();
byte[] ret;
@Test
public void testSerKey() throws Exception {
ret = serDe.serializeKey("key");
String key = new String(ret);
Assert.assertEquals(key.indexOf("key"), 5);
}
@Test
public void testSerValue() throws Exception {
ret = serDe.serializeValue(5);
Assert.assertEquals(ret.length, 2);
Assert.assertEquals((int) serDe.deserializeValue(ret), 5);
}
}
@@ -0,0 +1,66 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 io.ray.streaming.state.impl;
import com.google.common.collect.Maps;
import io.ray.streaming.state.backend.AbstractStateBackend;
import io.ray.streaming.state.backend.StateBackendBuilder;
import io.ray.streaming.state.store.KeyMapStore;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
public class MemoryKeyMapStoreTest {
private AbstractStateBackend stateBackend;
private KeyMapStore<String, String, String> IKeyMapStore;
@BeforeClass
public void setUp() {
stateBackend = StateBackendBuilder.buildStateBackend(new HashMap<String, String>());
IKeyMapStore = stateBackend.getKeyMapStore("test-table");
}
@Test
public void testCase() {
try {
Assert.assertNull(IKeyMapStore.get("hello"));
Map<String, String> map = Maps.newHashMap();
map.put("1", "1-1");
map.put("2", "2-1");
IKeyMapStore.put("hello", map);
Assert.assertEquals(IKeyMapStore.get("hello"), map);
Map<String, String> map2 = Maps.newHashMap();
map.put("3", "3-1");
map.put("4", "4-1");
IKeyMapStore.put("hello", map2);
Assert.assertNotEquals(IKeyMapStore.get("hello"), map);
Assert.assertEquals(IKeyMapStore.get("hello"), map2);
} catch (IOException e) {
e.printStackTrace();
}
}
}
@@ -0,0 +1,54 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 io.ray.streaming.state.impl;
import io.ray.streaming.state.backend.AbstractStateBackend;
import io.ray.streaming.state.backend.StateBackendBuilder;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
public class MemoryKeyValueStoreTest {
private AbstractStateBackend stateBackend;
private io.ray.streaming.state.store.KeyValueStore<String, String> KeyValueStore;
@BeforeClass
public void setUp() {
Map<String, String> config = new HashMap<>();
stateBackend = StateBackendBuilder.buildStateBackend(config);
KeyValueStore = stateBackend.getKeyValueStore("kepler_hlg_ut");
}
@Test
public void testCase() {
try {
KeyValueStore.put("hello", "world");
Assert.assertEquals(KeyValueStore.get("hello"), "world");
KeyValueStore.put("hello", "world1");
Assert.assertEquals(KeyValueStore.get("hello"), "world1");
Assert.assertNull(KeyValueStore.get("hello1"));
} catch (IOException e) {
e.printStackTrace();
}
}
}
@@ -0,0 +1,56 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 io.ray.streaming.state.keystate;
import static org.testng.Assert.assertEquals;
import org.testng.annotations.Test;
public class KeyGroupAssignmentTest {
@Test
public void testComputeKeyGroupRangeForOperatorIndex() throws Exception {
KeyGroup keyGroup = KeyGroupAssignment.getKeyGroup(4096, 1, 0);
assertEquals(keyGroup.getStartIndex(), 0);
assertEquals(keyGroup.getEndIndex(), 4095);
assertEquals(keyGroup.size(), 4096);
KeyGroup keyGroup2 = KeyGroupAssignment.getKeyGroup(4096, 2, 0);
assertEquals(keyGroup2.getStartIndex(), 0);
assertEquals(keyGroup2.getEndIndex(), 2047);
assertEquals(keyGroup2.size(), 2048);
keyGroup = KeyGroupAssignment.getKeyGroup(4096, 3, 0);
assertEquals(keyGroup.getStartIndex(), 0);
assertEquals(keyGroup.getEndIndex(), 1365);
assertEquals(keyGroup.size(), 1366);
keyGroup2 = KeyGroupAssignment.getKeyGroup(4096, 3, 1);
assertEquals(keyGroup2.getStartIndex(), 1366);
assertEquals(keyGroup2.getEndIndex(), 2730);
assertEquals(keyGroup2.size(), 1365);
KeyGroup keyGroup3 = KeyGroupAssignment.getKeyGroup(4096, 3, 2);
assertEquals(keyGroup3.getStartIndex(), 2731);
assertEquals(keyGroup3.getEndIndex(), 4095);
assertEquals(keyGroup3.size(), 1365);
}
}
@@ -0,0 +1,43 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 io.ray.streaming.state.keystate.desc;
import io.ray.streaming.state.config.ConfigKey;
import org.testng.Assert;
import org.testng.annotations.Test;
public class ListStateDescriptorTest {
@Test
public void test() {
ListStateDescriptor<Integer> descriptor = ListStateDescriptor
.build("lsdTest", Integer.class, true);
descriptor.setTableName("table");
Assert.assertTrue(descriptor.isOperatorList());
descriptor.setPartitionNumber(3);
descriptor.setIndex(0);
Assert.assertEquals(descriptor.getPartitionNumber(), 3);
Assert.assertEquals(descriptor.getIndex(), 0);
Assert.assertEquals(descriptor.getIdentify(),
"lsdTest" + ConfigKey.DELIMITER + "3" + ConfigKey.DELIMITER + "0");
}
}
@@ -0,0 +1,36 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 io.ray.streaming.state.keystate.desc;
import org.testng.Assert;
import org.testng.annotations.Test;
public class MapStateDescriptorTest {
@Test
public void test() {
MapStateDescriptor<String, Integer> descriptor = MapStateDescriptor
.build("msdTest", String.class, Integer.class);
descriptor.setTableName("table");
Assert.assertEquals(descriptor.getTableName(), "table");
Assert.assertEquals(descriptor.getName(), "msdTest");
}
}
@@ -0,0 +1,32 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 io.ray.streaming.state.keystate.desc;
import org.testng.Assert;
import org.testng.annotations.Test;
public class ValueStateDescriptorTest {
@Test
public void test() {
ValueStateDescriptor<Integer> descriptor = ValueStateDescriptor
.build("vsdTest", Integer.class, 0);
Assert.assertEquals(descriptor.getDefaultValue().intValue(), 0);
}
}
@@ -0,0 +1,92 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 io.ray.streaming.state.keystate.state.impl;
import io.ray.streaming.state.backend.KeyStateBackend;
import io.ray.streaming.state.backend.impl.MemoryStateBackend;
import io.ray.streaming.state.keystate.KeyGroup;
import io.ray.streaming.state.keystate.desc.ListStateDescriptor;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
public class ListStateImplTest {
ListStateImpl<Integer> listState;
KeyStateBackend keyStateBackend;
@BeforeClass
public void setUp() throws Exception {
keyStateBackend = new KeyStateBackend(1, new KeyGroup(1, 2),
new MemoryStateBackend(new HashMap<>()));
ListStateDescriptor<Integer> descriptor = ListStateDescriptor
.build("ListStateImplTest", Integer.class);
descriptor.setTableName("table");
listState = (ListStateImpl<Integer>) keyStateBackend.getListState(descriptor);
}
@Test
public void testAddGet() throws Exception {
keyStateBackend.setContext(1L, 1);
List<Integer> list = listState.get();
Assert.assertEquals(list.size(), 0);
listState.add(1);
listState.add(2);
Assert.assertEquals(listState.get(), Arrays.asList(1, 2));
listState.add(3);
Assert.assertEquals(listState.get(), Arrays.asList(1, 2, 3));
list = listState.get();
list.set(1, -1);
listState.add(4);
Assert.assertEquals(listState.get(), Arrays.asList(1, -1, 3, 4));
keyStateBackend.setCurrentKey(2);
listState.add(5);
listState.add(6);
Assert.assertEquals(listState.get(), Arrays.asList(5, 6));
}
@Test(dependsOnMethods = {"testAddGet"})
public void testUpdate() throws Exception {
Assert.assertEquals(listState.get(), Arrays.asList(5, 6));
listState.update(Arrays.asList(7, 8, 9));
List<Integer> list = listState.get();
Assert.assertEquals(list, Arrays.asList(7, 8, 9));
list.set(1, 10);
listState.update(list);
Assert.assertEquals(list, Arrays.asList(7, 10, 9));
listState.update(null);
Assert.assertEquals(listState.get().size(), 0);
}
}
@@ -0,0 +1,137 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 io.ray.streaming.state.keystate.state.impl;
import com.google.common.collect.ImmutableMap;
import io.ray.streaming.state.backend.KeyStateBackend;
import io.ray.streaming.state.backend.impl.MemoryStateBackend;
import io.ray.streaming.state.keystate.KeyGroup;
import io.ray.streaming.state.keystate.desc.MapStateDescriptor;
import java.util.HashMap;
import java.util.Map;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
public class MapStateImplTest {
MapStateImpl<Integer, String> mapState;
KeyStateBackend keyStateBackend;
@BeforeClass
public void setUp() throws Exception {
keyStateBackend = new KeyStateBackend(1, new KeyGroup(1, 2),
new MemoryStateBackend(new HashMap<>()));
MapStateDescriptor<Integer, String> descriptor = MapStateDescriptor
.build("MapStateImplTest", Integer.class, String.class);
descriptor.setTableName("table");
mapState = (MapStateImpl<Integer, String>) keyStateBackend.getMapState(descriptor);
}
@Test
public void testPuTGet() throws Exception {
keyStateBackend.setContext(1L, 1);
Assert.assertEquals(mapState.get().size(), 0);
mapState.put(1, "1");
mapState.put(2, "2");
Assert.assertTrue(mapState.contains(1));
Assert.assertTrue(mapState.contains(2));
Assert.assertFalse(mapState.contains(3));
Assert.assertEquals("1", mapState.get(1));
Assert.assertEquals("2", mapState.get(2));
mapState.remove(1);
Assert.assertFalse(mapState.contains(1));
Assert.assertTrue(mapState.contains(2));
mapState.remove(2);
mapState.putAll(ImmutableMap.of(1, "1", 2, "2"));
Assert.assertEquals("1", mapState.get(1));
Assert.assertEquals("2", mapState.get(2));
}
@Test(dependsOnMethods = {"testPuTGet"})
public void testUpdate() throws Exception {
Assert.assertEquals(mapState.get().size(), 2);
mapState.update(ImmutableMap.of(3, "3", 4, "4"));
Assert.assertEquals(mapState.get(3), "3");
Assert.assertEquals(mapState.get(4), "4");
Assert.assertEquals(mapState.get().size(), 2);
Map<Integer, String> map = ImmutableMap.of(5, "5", 6, "6");
mapState.update(map);
Assert.assertEquals(mapState.get(), map);
mapState.update(null);
Assert.assertEquals(mapState.get().size(), 0);
}
@Test
public void testFailover() throws Exception {
keyStateBackend.setContext(1L, 1);
Assert.assertEquals(mapState.get().size(), 0);
mapState.put(1, "1");
mapState.put(2, "2");
Assert.assertTrue(mapState.contains(1));
Assert.assertTrue(mapState.contains(2));
Assert.assertFalse(mapState.contains(3));
Assert.assertEquals("1", mapState.get(1));
Assert.assertEquals("2", mapState.get(2));
mapState.remove(1);
Assert.assertFalse(mapState.contains(1));
Assert.assertTrue(mapState.contains(2));
mapState.remove(2);
mapState.putAll(ImmutableMap.of(1, "1", 2, "2"));
Assert.assertEquals("1", mapState.get(1));
Assert.assertEquals("2", mapState.get(2));
keyStateBackend.finish(5);
Assert.assertEquals("1", mapState.get(1));
Assert.assertEquals("2", mapState.get(2));
mapState.put(2, "3");
Assert.assertEquals("3", mapState.get(2));
keyStateBackend.finish(6);
keyStateBackend.commit(5);
Assert.assertEquals("3", mapState.get(2));
keyStateBackend.commit(6);
keyStateBackend.ackCommit(5, 0);
keyStateBackend.ackCommit(6, 1);
mapState.put(2, "5");
Assert.assertEquals("5", mapState.get(2));
mapState.update(null);
}
}
@@ -0,0 +1,71 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 io.ray.streaming.state.keystate.state.impl;
import io.ray.streaming.state.backend.OperatorStateBackend;
import io.ray.streaming.state.backend.impl.MemoryStateBackend;
import io.ray.streaming.state.keystate.desc.ListStateDescriptor;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
public class OperatorStateImplTest {
OperatorStateImpl<Integer> operatorState;
ListStateDescriptor<Integer> descriptor;
OperatorStateBackend operatorStateBackend;
@BeforeClass
public void setUp() {
String table_name = "operatorState";
Map config = new HashMap<>();
operatorStateBackend = new OperatorStateBackend(new MemoryStateBackend(config));
descriptor = ListStateDescriptor
.build("OperatorStateImplTest" + System.currentTimeMillis(), Integer.class, true);
descriptor.setPartitionNumber(1);
descriptor.setIndex(0);
descriptor.setTableName(table_name);
operatorState = (OperatorStateImpl<Integer>) operatorStateBackend.getSplitListState(descriptor);
}
@Test
public void testInit() throws Exception {
operatorStateBackend.setCheckpointId(1L);
List<Integer> list = operatorState.get();
Assert.assertEquals(list.size(), 0);
for (int i = 0; i < 100; i++) {
operatorState.add(i);
}
Assert.assertEquals(operatorState.get().size(), 100);
operatorStateBackend.finish(1L);
operatorStateBackend.commit(1L);
operatorStateBackend.ackCommit(1L, 0);
operatorStateBackend.finish(5L);
operatorStateBackend.commit(5L);
operatorStateBackend.ackCommit(5L, 0);
}
}
@@ -0,0 +1,57 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 io.ray.streaming.state.keystate.state.impl;
import io.ray.streaming.state.backend.KeyStateBackend;
import io.ray.streaming.state.backend.impl.MemoryStateBackend;
import io.ray.streaming.state.keystate.KeyGroup;
import io.ray.streaming.state.keystate.desc.ValueStateDescriptor;
import java.util.HashMap;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
public class ValueStateImplTest {
ValueStateImpl<String> valueState;
KeyStateBackend keyStateBackend;
@BeforeClass
public void setUp() throws Exception {
keyStateBackend = new KeyStateBackend(1, new KeyGroup(1, 2),
new MemoryStateBackend(new HashMap<>()));
ValueStateDescriptor<String> descriptor = ValueStateDescriptor
.build("ValueStateImplTest", String.class, "hello");
descriptor.setTableName("table");
valueState = (ValueStateImpl<String>) keyStateBackend.getValueState(descriptor);
}
@Test
public void testUpdateGet() throws Exception {
keyStateBackend.setContext(1L, 1);
Assert.assertEquals(valueState.get(), "hello");
String str = valueState.get();
valueState.update(str + " world");
Assert.assertEquals(valueState.get(), "hello world");
}
}
@@ -0,0 +1,55 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 io.ray.streaming.state.keystate.state.proxy;
import io.ray.streaming.state.keystate.desc.ListStateDescriptor;
import java.util.Arrays;
import java.util.List;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
public class ListStateStoreManagerTest extends StateStoreManagerTest {
ListStateStoreManagerProxy<Integer> proxy;
@BeforeClass
public void setUp() {
ListStateDescriptor<Integer> descriptor = ListStateDescriptor.build("list", Integer.class);
descriptor.setTableName("tableName");
keyStateBackend.setContext(1L, "key");
proxy = new ListStateStoreManagerProxy<>(keyStateBackend, descriptor);
}
@Test
public void test() throws Exception {
Assert.assertEquals(proxy.getListState().get().size(), 0);
List<Integer> list = Arrays.asList(1, 2, 3);
proxy.put("key1", list);
Assert.assertEquals(proxy.get("key1"), list);
proxy.put("key1", Arrays.asList(1, 3));
proxy.put("key2", Arrays.asList(4, 5));
Assert.assertEquals(proxy.get("key2"), Arrays.asList(4, 5));
Assert.assertEquals(proxy.get("key1"), Arrays.asList(1, 3));
}
}
@@ -0,0 +1,56 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 io.ray.streaming.state.keystate.state.proxy;
import io.ray.streaming.state.keystate.desc.MapStateDescriptor;
import java.util.HashMap;
import java.util.Map;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
public class MapStateStoreManagerTest extends StateStoreManagerTest {
MapStateStoreManagerProxy<String, Integer> facade;
@BeforeClass
public void setUp() {
MapStateDescriptor<String, Integer> descriptor = MapStateDescriptor
.build("map", String.class, Integer.class);
descriptor.setTableName("tableName");
keyStateBackend.setContext(1L, "key");
facade = new MapStateStoreManagerProxy<>(keyStateBackend, descriptor);
}
@Test
public void test() throws Exception {
Assert.assertEquals(facade.getMapState().get().size(), 0);
Map<String, Integer> map = new HashMap<>();
map.put("key1", 1);
map.put("key2", 2);
facade.put("key1", map);
Assert.assertEquals(facade.get("key1"), map);
map.remove("key1");
facade.put("key2", map);
Assert.assertEquals(facade.get("key2"), map);
}
}
@@ -0,0 +1,30 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 io.ray.streaming.state.keystate.state.proxy;
import io.ray.streaming.state.backend.KeyStateBackend;
import io.ray.streaming.state.backend.impl.MemoryStateBackend;
import io.ray.streaming.state.keystate.KeyGroup;
import java.util.HashMap;
public class StateStoreManagerTest {
protected KeyStateBackend keyStateBackend = new KeyStateBackend(1, new KeyGroup(1, 1),
new MemoryStateBackend(new HashMap<String, String>()));
}
@@ -0,0 +1,57 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 io.ray.streaming.state.keystate.state.proxy;
import io.ray.streaming.state.keystate.desc.ValueStateDescriptor;
import io.ray.streaming.state.keystate.state.ValueState;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
public class ValueStateStoreManagerTest extends StateStoreManagerTest {
ValueStateStoreManagerProxy<Integer> proxy;
@BeforeClass
public void setUp() {
ValueStateDescriptor<Integer> descriptor = ValueStateDescriptor
.build("value", Integer.class, 0);
descriptor.setTableName("tableName");
keyStateBackend.setContext(1L, "key");
proxy = new ValueStateStoreManagerProxy<>(keyStateBackend, descriptor);
}
@Test
public void test() throws Exception {
ValueState<Integer> state = proxy.getValueState();
Assert.assertEquals(state.get().intValue(), 0);
proxy.put("key1", 2);
Assert.assertEquals(proxy.get("key1").intValue(), 2);
proxy.put("key1", 3);
Assert.assertEquals(proxy.get("key1").intValue(), 3);
proxy.put("key2", 9);
Assert.assertEquals(proxy.get("key2").intValue(), 9);
proxy.put("key2", 6);
Assert.assertEquals(proxy.get("key2").intValue(), 6);
}
}
@@ -0,0 +1,434 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 io.ray.streaming.state.strategy;
import com.google.common.collect.Lists;
import io.ray.streaming.state.backend.BackendType;
import io.ray.streaming.state.backend.KeyStateBackend;
import io.ray.streaming.state.backend.StateBackendBuilder;
import io.ray.streaming.state.backend.StateStrategy;
import io.ray.streaming.state.config.ConfigKey;
import io.ray.streaming.state.keystate.KeyGroup;
import io.ray.streaming.state.keystate.desc.ListStateDescriptor;
import io.ray.streaming.state.keystate.desc.MapStateDescriptor;
import io.ray.streaming.state.keystate.desc.ValueStateDescriptor;
import io.ray.streaming.state.keystate.state.ListState;
import io.ray.streaming.state.keystate.state.MapState;
import io.ray.streaming.state.keystate.state.ValueState;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
public class DualStateStrategyTest {
private final String table = "kepler_cp_store";
private final String defaultValue = "default";
protected KeyStateBackend keyStateBackend;
Map<String, String> config = new HashMap<>();
private String currentTime;
@BeforeClass
public void setUp() {
config.put(ConfigKey.STATE_STRATEGY_MODE, StateStrategy.DUAL_VERSION.name());
currentTime = Long.toString(System.currentTimeMillis());
}
public void caseKV() {
ValueStateDescriptor<String> valueStateDescriptor = ValueStateDescriptor
.build("VALUE-" + currentTime, String.class, defaultValue);
valueStateDescriptor.setTableName(table);
ValueState<String> state = this.keyStateBackend.getValueState(valueStateDescriptor);
this.keyStateBackend.setCheckpointId(1l);
state.setCurrentKey("1");
state.update("hello");
state.setCurrentKey("2");
state.update("world");
state.setCurrentKey(("1"));
Assert.assertEquals(state.get(), "hello");
state.setCurrentKey(("2"));
Assert.assertEquals(state.get(), "world");
this.keyStateBackend.finish(1);
this.keyStateBackend.setCheckpointId(2);
state.setCurrentKey(("3"));
state.update("eagle");
state.setCurrentKey(("4"));
state.update("alex");
state.setCurrentKey(("3"));
Assert.assertEquals(state.get(), "eagle");
state.setCurrentKey(("4"));
Assert.assertEquals(state.get(), "alex");
this.keyStateBackend.commit(1);
this.keyStateBackend.ackCommit(1, 1);
this.keyStateBackend.finish(2);
this.keyStateBackend.setCheckpointId(3);
state.setCurrentKey(("1"));
state.update("tim");
state.setCurrentKey(("4"));
state.update("scala");
this.keyStateBackend.finish(3);
this.keyStateBackend.setCheckpointId(4);
state.setCurrentKey(("3"));
state.update("cook");
state.setCurrentKey(("2"));
state.update("inf");
state.setCurrentKey(("1"));
Assert.assertEquals(state.get(), "tim");
state.setCurrentKey(("2"));
Assert.assertEquals(state.get(), "inf");
state.setCurrentKey(("3"));
Assert.assertEquals(state.get(), "cook");
state.setCurrentKey(("4"));
Assert.assertEquals(state.get(), "scala");
this.keyStateBackend.commit(2);
this.keyStateBackend.ackCommit(2, 2);
//do rollback, all memory data is deleted.
this.keyStateBackend.rollBack(1);
this.keyStateBackend.setCheckpointId(1);
state.setCurrentKey(("1"));
Assert.assertEquals(state.get(), defaultValue);
state.setCurrentKey(("2"));
Assert.assertEquals(state.get(), defaultValue);
state.setCurrentKey(("3"));
Assert.assertEquals(state.get(), defaultValue);
state.setCurrentKey(("4"));
Assert.assertEquals(state.get(), defaultValue);
this.keyStateBackend.setCheckpointId(4);
this.keyStateBackend.setCurrentKey("1");
state.update("tim");
this.keyStateBackend.finish(4);
this.keyStateBackend.setCheckpointId(5);
this.keyStateBackend.setCurrentKey("2");
state.update("info");
this.keyStateBackend.finish(5);
this.keyStateBackend.setCheckpointId(6);
state.update("cook");
this.keyStateBackend.finish(6);
this.keyStateBackend.setCheckpointId(7);
this.keyStateBackend.setCurrentKey("1");
Assert.assertEquals(state.get(), "tim");
this.keyStateBackend.setCurrentKey("2");
Assert.assertEquals(state.get(), "cook");
this.keyStateBackend.commit(5);
this.keyStateBackend.ackCommit(5, 5);
this.keyStateBackend.setCurrentKey("1");
Assert.assertEquals(state.get(), "tim");
this.keyStateBackend.rollBack(6);
}
public void caseKVGap() {
ValueStateDescriptor<String> valueStateDescriptor = ValueStateDescriptor
.build("value2-" + currentTime, String.class, defaultValue);
valueStateDescriptor.setTableName(table);
ValueState<String> state = this.keyStateBackend.getValueState(valueStateDescriptor);
this.keyStateBackend.setCheckpointId(5L);
state.setCurrentKey("1");
state.update("hello");
state.setCurrentKey(("1"));
Assert.assertEquals(state.get(), "hello");
this.keyStateBackend.setCheckpointId(5);
this.keyStateBackend.setCurrentKey("1");
state.update("info");
this.keyStateBackend.finish(5);
this.keyStateBackend.commit(5);
this.keyStateBackend.ackCommit(5, 5);
this.keyStateBackend.setCheckpointId(10);
Assert.assertEquals(state.get(), "info");
this.keyStateBackend.finish(10);
this.keyStateBackend.commit(10);
this.keyStateBackend.ackCommit(10, 10);
this.keyStateBackend.setCheckpointId(15);
state.update("world");
this.keyStateBackend.finish(15);
this.keyStateBackend.commit(15);
this.keyStateBackend.ackCommit(15, 15);
this.keyStateBackend.setCheckpointId(11);
this.keyStateBackend.rollBack(11);
Assert.assertEquals(state.get(), "info");
this.keyStateBackend.setCheckpointId(15);
state.update("world2");
this.keyStateBackend.finish(15);
this.keyStateBackend.commit(15);
this.keyStateBackend.ackCommit(15, 15);
this.keyStateBackend.setCheckpointId(11);
this.keyStateBackend.rollBack(11);
Assert.assertEquals(state.get(), "info");
}
public void caseKList() {
ListStateDescriptor<Integer> listStateDescriptor = ListStateDescriptor
.build("LIST-" + currentTime, Integer.class);
listStateDescriptor.setTableName(table);
ListState<Integer> state = this.keyStateBackend.getListState(listStateDescriptor);
this.keyStateBackend.setCheckpointId(1l);
state.setCurrentKey("1");
state.add(1);
state.setCurrentKey("2");
state.add(2);
state.setCurrentKey("1");
List<Integer> result = state.get();
Assert.assertEquals(result, Arrays.asList(1));
state.setCurrentKey("2");
Assert.assertEquals(state.get(), Arrays.asList(2));
this.keyStateBackend.finish(1);
this.keyStateBackend.setCheckpointId(2);
state.setCurrentKey(("3"));
state.add(3);
state.setCurrentKey(("4"));
state.add(4);
state.setCurrentKey(("3"));
Assert.assertEquals(state.get(), Arrays.asList(3));
state.setCurrentKey(("4"));
Assert.assertEquals(state.get(), Arrays.asList(4));
this.keyStateBackend.commit(1);
this.keyStateBackend.ackCommit(1, 1);
this.keyStateBackend.finish(2);
this.keyStateBackend.setCheckpointId(3);
state.setCurrentKey(("1"));
state.add(2);
state.setCurrentKey(("4"));
state.add(5);
this.keyStateBackend.finish(3);
this.keyStateBackend.setCheckpointId(4);
state.setCurrentKey(("3"));
state.add(4);
state.setCurrentKey(("2"));
state.add(3);
state.setCurrentKey(("1"));
Assert.assertEquals(state.get(), Arrays.asList(1, 2));
state.setCurrentKey(("2"));
Assert.assertEquals(state.get(), Arrays.asList(2, 3));
state.setCurrentKey(("3"));
Assert.assertEquals(state.get(), Arrays.asList(3, 4));
state.setCurrentKey(("4"));
Assert.assertEquals(state.get(), Arrays.asList(4, 5));
this.keyStateBackend.commit(2);
this.keyStateBackend.ackCommit(2, 2);
//do rollback, all memory data is deleted.
this.keyStateBackend.rollBack(1);
this.keyStateBackend.setCheckpointId(1);
state.setCurrentKey(("1"));
Assert.assertEquals(state.get(), Lists.newArrayList());
state.setCurrentKey(("2"));
Assert.assertEquals(state.get(), Lists.newArrayList());
state.setCurrentKey(("3"));
Assert.assertEquals(state.get(), Lists.newArrayList());
state.setCurrentKey(("4"));
Assert.assertEquals(state.get(), Lists.newArrayList());
this.keyStateBackend.setCheckpointId(4);
this.keyStateBackend.setCurrentKey("1");
state.add(1);
this.keyStateBackend.finish(4);
this.keyStateBackend.setCheckpointId(5);
this.keyStateBackend.setCurrentKey("2");
state.add(2);
this.keyStateBackend.finish(5);
this.keyStateBackend.setCheckpointId(6);
state.add(3);
this.keyStateBackend.finish(6);
this.keyStateBackend.setCheckpointId(7);
this.keyStateBackend.setCurrentKey("2");
Assert.assertEquals(state.get(), Arrays.asList(2, 2, 3));
this.keyStateBackend.commit(5);
this.keyStateBackend.ackCommit(5, 5);
this.keyStateBackend.rollBack(5);
this.keyStateBackend.setCurrentKey("1");
Assert.assertEquals(state.get(), Arrays.asList(1));
}
public void caseKMap() {
MapStateDescriptor<Integer, Integer> mapStateDescriptor = MapStateDescriptor
.build("MAP-" + currentTime, Integer.class, Integer.class);
mapStateDescriptor.setTableName(table);
MapState<Integer, Integer> state = this.keyStateBackend.getMapState(mapStateDescriptor);
this.keyStateBackend.setCheckpointId(1l);
state.setCurrentKey("1");
state.put(1, 1);
state.setCurrentKey("2");
state.put(2, 2);
state.setCurrentKey(("1"));
Assert.assertEquals(state.get(1), Integer.valueOf(1));
state.setCurrentKey(("2"));
Assert.assertEquals(state.get(2), Integer.valueOf(2));
this.keyStateBackend.finish(1);
this.keyStateBackend.setCheckpointId(2);
state.setCurrentKey(("3"));
state.put(3, 3);
state.setCurrentKey(("4"));
state.put(4, 4);
state.setCurrentKey(("3"));
Assert.assertEquals(state.get(3), Integer.valueOf(3));
state.setCurrentKey(("4"));
Assert.assertEquals(state.get(4), Integer.valueOf(4));
this.keyStateBackend.commit(1);
this.keyStateBackend.ackCommit(1, 1);
this.keyStateBackend.finish(2);
this.keyStateBackend.setCheckpointId(3);
state.setCurrentKey(("1"));
state.put(5, 5);
state.setCurrentKey(("4"));
state.put(6, 6);
this.keyStateBackend.finish(3);
this.keyStateBackend.setCheckpointId(4);
state.setCurrentKey(("3"));
state.put(7, 7);
state.setCurrentKey(("2"));
state.put(8, 8);
state.setCurrentKey(("1"));
Assert.assertEquals(state.get(1), Integer.valueOf(1));
Assert.assertEquals(state.get(5), Integer.valueOf(5));
state.setCurrentKey(("2"));
Assert.assertEquals(state.get(2), Integer.valueOf(2));
Assert.assertEquals(state.get(8), Integer.valueOf(8));
state.setCurrentKey(("3"));
Assert.assertEquals(state.get(3), Integer.valueOf(3));
Assert.assertEquals(state.get(7), Integer.valueOf(7));
state.setCurrentKey(("4"));
Assert.assertEquals(state.get(4), Integer.valueOf(4));
Assert.assertEquals(state.get(6), Integer.valueOf(6));
this.keyStateBackend.commit(2);
this.keyStateBackend.ackCommit(2, 2);
//do rollback, memory data is deleted.
this.keyStateBackend.rollBack(1);
this.keyStateBackend.setCheckpointId(1);
state.setCurrentKey(("1"));
Assert.assertEquals(state.entries(), (new HashMap()).entrySet());
state.setCurrentKey(("2"));
Assert.assertEquals(state.entries(), (new HashMap()).entrySet());
state.setCurrentKey(("3"));
Assert.assertEquals(state.entries(), (new HashMap()).entrySet());
state.setCurrentKey(("4"));
Assert.assertEquals(state.entries(), (new HashMap()).entrySet());
this.keyStateBackend.setCheckpointId(4);
this.keyStateBackend.setCurrentKey("1");
state.put(1, 1);
this.keyStateBackend.finish(4);
this.keyStateBackend.setCheckpointId(5);
this.keyStateBackend.setCurrentKey("2");
state.put(2, 2);
this.keyStateBackend.finish(5);
this.keyStateBackend.setCheckpointId(6);
state.put(3, 3);
this.keyStateBackend.finish(6);
this.keyStateBackend.setCheckpointId(7);
this.keyStateBackend.setCurrentKey("1");
Assert.assertEquals(state.get(1), Integer.valueOf(1));
this.keyStateBackend.setCurrentKey("2");
Assert.assertEquals(state.get(2), Integer.valueOf(2));
Assert.assertEquals(state.get(3), Integer.valueOf(3));
this.keyStateBackend.commit(5);
this.keyStateBackend.ackCommit(5, 5);
this.keyStateBackend.rollBack(5);
this.keyStateBackend.setCurrentKey("1");
Assert.assertEquals(state.get(1), Integer.valueOf(1));
this.keyStateBackend.setCurrentKey("2");
Assert.assertEquals(state.get(2), Integer.valueOf(2));
Assert.assertEquals(state.get(3), null);
}
@Test
public void testMem() {
config.put(ConfigKey.STATE_BACKEND_TYPE, BackendType.MEMORY.name());
this.keyStateBackend = new KeyStateBackend(10, new KeyGroup(1, 3),
StateBackendBuilder.buildStateBackend(config));
caseKV();
caseKVGap();
caseKList();
caseKMap();
}
}
@@ -0,0 +1,405 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 io.ray.streaming.state.strategy;
import io.ray.streaming.state.backend.BackendType;
import io.ray.streaming.state.backend.KeyStateBackend;
import io.ray.streaming.state.backend.StateBackendBuilder;
import io.ray.streaming.state.backend.StateStrategy;
import io.ray.streaming.state.config.ConfigKey;
import io.ray.streaming.state.keystate.KeyGroup;
import io.ray.streaming.state.keystate.desc.ListStateDescriptor;
import io.ray.streaming.state.keystate.desc.MapStateDescriptor;
import io.ray.streaming.state.keystate.desc.ValueStateDescriptor;
import io.ray.streaming.state.keystate.state.ListState;
import io.ray.streaming.state.keystate.state.MapState;
import io.ray.streaming.state.keystate.state.ValueState;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
public class MVStateStrategyTest {
private final String table = "kepler_hlg_ut";
Map<String, String> config = new HashMap<>();
private KeyStateBackend keyStateBackend;
private String currentTime;
@BeforeClass
public void setUp() {
config.put(ConfigKey.STATE_STRATEGY_MODE, StateStrategy.SINGLE_VERSION.name());
currentTime = Long.toString(System.currentTimeMillis());
}
public void caseKV() {
ValueStateDescriptor<String> valueStateDescriptor = ValueStateDescriptor
.build("mvint-" + currentTime, String.class, "");
valueStateDescriptor.setTableName(table);
ValueState<String> state = this.keyStateBackend.getValueState(valueStateDescriptor);
this.keyStateBackend.setCheckpointId(1l);
state.setCurrentKey("1");
state.update("hello");
state.setCurrentKey("2");
state.update("world");
state.setCurrentKey(("1"));
Assert.assertEquals(state.get(), "hello");
state.setCurrentKey(("2"));
Assert.assertEquals(state.get(), "world");
this.keyStateBackend.finish(1);
this.keyStateBackend.setCheckpointId(2);
state.setCurrentKey(("3"));
state.update("eagle");
state.setCurrentKey(("4"));
state.update("alex");
state.setCurrentKey(("3"));
Assert.assertEquals(state.get(), "eagle");
state.setCurrentKey(("4"));
Assert.assertEquals(state.get(), "alex");
this.keyStateBackend.commit(1);
this.keyStateBackend.ackCommit(1, 1);
this.keyStateBackend.finish(2);
this.keyStateBackend.setCheckpointId(3);
state.setCurrentKey(("1"));
state.update("tim");
state.setCurrentKey(("4"));
state.update("scala");
this.keyStateBackend.finish(3);
this.keyStateBackend.setCheckpointId(4);
state.setCurrentKey(("3"));
state.update("cook");
state.setCurrentKey(("2"));
state.update("inf");
state.setCurrentKey(("1"));
Assert.assertEquals(state.get(), "tim");
state.setCurrentKey(("2"));
Assert.assertEquals(state.get(), "inf");
state.setCurrentKey(("3"));
Assert.assertEquals(state.get(), "cook");
state.setCurrentKey(("4"));
Assert.assertEquals(state.get(), "scala");
this.keyStateBackend.commit(2);
this.keyStateBackend.ackCommit(2, 2);
this.keyStateBackend.rollBack(2);
this.keyStateBackend.setCheckpointId(3);
state.setCurrentKey(("1"));
Assert.assertEquals(state.get(), "hello");
state.setCurrentKey(("2"));
Assert.assertEquals(state.get(), "world");
state.setCurrentKey(("3"));
Assert.assertEquals(state.get(), "eagle");
state.setCurrentKey(("4"));
Assert.assertEquals(state.get(), "alex");
state.setCurrentKey(("1"));
state.update("tim");
this.keyStateBackend.finish(3);
this.keyStateBackend.setCheckpointId(4l);
state.setCurrentKey(("4"));
state.update("scala");
this.keyStateBackend.finish(4);
this.keyStateBackend.setCheckpointId(5l);
state.setCurrentKey(("3"));
state.update("cook");
this.keyStateBackend.finish(5);
state.setCurrentKey(("2"));
state.update("info");
this.keyStateBackend.finish(6);
this.keyStateBackend.setCheckpointId(6);
state.setCurrentKey(("1"));
Assert.assertEquals(state.get(), "tim");
state.setCurrentKey(("2"));
Assert.assertEquals(state.get(), "info");
state.setCurrentKey(("3"));
Assert.assertEquals(state.get(), "cook");
state.setCurrentKey(("4"));
Assert.assertEquals(state.get(), "scala");
this.keyStateBackend.commit(5);
this.keyStateBackend.ackCommit(5, 5);
this.keyStateBackend.rollBack(5);
this.keyStateBackend.setCheckpointId(6);
state.setCurrentKey(("1"));
Assert.assertEquals(state.get(), "tim");
state.setCurrentKey(("2"));
Assert.assertEquals(state.get(), "world");
state.setCurrentKey(("3"));
Assert.assertEquals(state.get(), "cook");
state.setCurrentKey(("4"));
Assert.assertEquals(state.get(), "scala");
}
public void caseKList() {
ListStateDescriptor<Integer> listStateDescriptor = ListStateDescriptor
.build("mvlist-" + currentTime, Integer.class);
listStateDescriptor.setTableName(table);
ListState<Integer> state = this.keyStateBackend.getListState(listStateDescriptor);
this.keyStateBackend.setCheckpointId(1l);
state.setCurrentKey("1");
state.add(1);
state.setCurrentKey("2");
state.add(2);
state.setCurrentKey(("1"));
Assert.assertEquals(state.get(), Arrays.asList(1));
state.setCurrentKey(("2"));
Assert.assertEquals(state.get(), Arrays.asList(2));
this.keyStateBackend.finish(1);
this.keyStateBackend.setCheckpointId(2);
state.setCurrentKey(("3"));
state.add(3);
state.setCurrentKey(("4"));
state.add(4);
state.setCurrentKey(("3"));
Assert.assertEquals(state.get(), Arrays.asList(3));
state.setCurrentKey(("4"));
Assert.assertEquals(state.get(), Arrays.asList(4));
this.keyStateBackend.commit(1);
this.keyStateBackend.ackCommit(1, 1);
this.keyStateBackend.finish(2);
this.keyStateBackend.setCheckpointId(3);
state.setCurrentKey(("1"));
state.add(2);
state.setCurrentKey(("4"));
state.add(5);
this.keyStateBackend.finish(3);
this.keyStateBackend.setCheckpointId(4);
state.setCurrentKey(("3"));
state.add(4);
state.setCurrentKey(("2"));
state.add(3);
state.setCurrentKey(("1"));
Assert.assertEquals(state.get(), Arrays.asList(1, 2));
state.setCurrentKey(("2"));
Assert.assertEquals(state.get(), Arrays.asList(2, 3));
state.setCurrentKey(("3"));
Assert.assertEquals(state.get(), Arrays.asList(3, 4));
state.setCurrentKey(("4"));
Assert.assertEquals(state.get(), Arrays.asList(4, 5));
this.keyStateBackend.commit(2);
this.keyStateBackend.ackCommit(2, 2);
this.keyStateBackend.rollBack(2);
state.setCurrentKey(("1"));
Assert.assertEquals(state.get(), Arrays.asList(1));
state.setCurrentKey(("2"));
Assert.assertEquals(state.get(), Arrays.asList(2));
state.setCurrentKey(("3"));
Assert.assertEquals(state.get(), Arrays.asList(3));
state.setCurrentKey(("4"));
Assert.assertEquals(state.get(), Arrays.asList(4));
this.keyStateBackend.setCheckpointId(4);
this.keyStateBackend.setCurrentKey("1");
state.add(1);
this.keyStateBackend.finish(4);
this.keyStateBackend.setCheckpointId(5);
this.keyStateBackend.setCurrentKey("2");
state.add(2);
this.keyStateBackend.finish(5);
this.keyStateBackend.setCheckpointId(6);
state.add(3);
this.keyStateBackend.finish(6);
this.keyStateBackend.setCheckpointId(7);
this.keyStateBackend.setCurrentKey("1");
Assert.assertEquals(state.get(), Arrays.asList(1, 1));
this.keyStateBackend.setCurrentKey("2");
Assert.assertEquals(state.get(), Arrays.asList(2, 2, 3));
this.keyStateBackend.commit(5);
this.keyStateBackend.ackCommit(5, 5);
this.keyStateBackend.rollBack(5);
this.keyStateBackend.setCurrentKey("1");
Assert.assertEquals(state.get(), Arrays.asList(1, 1));
this.keyStateBackend.setCurrentKey("2");
Assert.assertEquals(state.get(), Arrays.asList(2, 2));
}
public void caseKMap() {
MapStateDescriptor<Integer, Integer> mapStateDescriptor = MapStateDescriptor
.build("mvmap-" + currentTime, Integer.class, Integer.class);
mapStateDescriptor.setTableName(table);
MapState<Integer, Integer> state = this.keyStateBackend.getMapState(mapStateDescriptor);
this.keyStateBackend.setCheckpointId(1l);
state.setCurrentKey("1");
state.put(1, 1);
state.setCurrentKey("2");
state.put(2, 2);
state.setCurrentKey(("1"));
Assert.assertEquals(state.get(1), Integer.valueOf(1));
state.setCurrentKey(("2"));
Assert.assertEquals(state.get(2), Integer.valueOf(2));
this.keyStateBackend.finish(1);
this.keyStateBackend.setCheckpointId(2);
state.setCurrentKey(("3"));
state.put(3, 3);
state.setCurrentKey(("4"));
state.put(4, 4);
state.setCurrentKey(("3"));
Assert.assertEquals(state.get(3), Integer.valueOf(3));
state.setCurrentKey(("4"));
Assert.assertEquals(state.get(4), Integer.valueOf(4));
this.keyStateBackend.commit(1);
this.keyStateBackend.ackCommit(1, 1);
this.keyStateBackend.finish(2);
this.keyStateBackend.setCheckpointId(3);
state.setCurrentKey(("1"));
state.put(5, 5);
state.setCurrentKey(("4"));
state.put(6, 6);
this.keyStateBackend.finish(3);
this.keyStateBackend.setCheckpointId(4);
state.setCurrentKey(("3"));
state.put(7, 7);
state.setCurrentKey(("2"));
state.put(8, 8);
state.setCurrentKey(("1"));
Assert.assertEquals(state.get(1), Integer.valueOf(1));
Assert.assertEquals(state.get(5), Integer.valueOf(5));
state.setCurrentKey(("2"));
Assert.assertEquals(state.get(2), Integer.valueOf(2));
Assert.assertEquals(state.get(8), Integer.valueOf(8));
state.setCurrentKey(("3"));
Assert.assertEquals(state.get(3), Integer.valueOf(3));
Assert.assertEquals(state.get(7), Integer.valueOf(7));
state.setCurrentKey(("4"));
Assert.assertEquals(state.get(4), Integer.valueOf(4));
Assert.assertEquals(state.get(6), Integer.valueOf(6));
this.keyStateBackend.commit(2);
this.keyStateBackend.ackCommit(2, 2);
this.keyStateBackend.rollBack(2);
state.setCurrentKey(("1"));
Assert.assertEquals(state.get(1), Integer.valueOf(1));
Assert.assertNull(state.get(5));
state.setCurrentKey(("2"));
Assert.assertEquals(state.get(2), Integer.valueOf(2));
Assert.assertNull(state.get(8));
state.setCurrentKey(("3"));
Assert.assertEquals(state.get(3), Integer.valueOf(3));
Assert.assertNull(state.get(7));
state.setCurrentKey(("4"));
Assert.assertEquals(state.get(4), Integer.valueOf(4));
Assert.assertNull(state.get(6));
this.keyStateBackend.setCheckpointId(4);
this.keyStateBackend.setCurrentKey("1");
state.put(5, 5);
this.keyStateBackend.finish(4);
this.keyStateBackend.setCheckpointId(5);
this.keyStateBackend.setCurrentKey("2");
state.put(8, 8);
this.keyStateBackend.finish(5);
this.keyStateBackend.setCheckpointId(6);
state.put(7, 7);
this.keyStateBackend.finish(6);
this.keyStateBackend.setCheckpointId(7);
this.keyStateBackend.setCurrentKey("1");
Assert.assertEquals(state.get(1), Integer.valueOf(1));
Assert.assertEquals(state.get(5), Integer.valueOf(5));
this.keyStateBackend.setCurrentKey("2");
Assert.assertEquals(state.get(2), Integer.valueOf(2));
Assert.assertEquals(state.get(8), Integer.valueOf(8));
Assert.assertEquals(state.get(7), Integer.valueOf(7));
this.keyStateBackend.commit(5);
this.keyStateBackend.ackCommit(5, 5);
this.keyStateBackend.rollBack(5);
this.keyStateBackend.setCurrentKey("1");
Assert.assertEquals(state.get(1), Integer.valueOf(1));
Assert.assertEquals(state.get(5), Integer.valueOf(5));
this.keyStateBackend.setCurrentKey("2");
Assert.assertEquals(state.get(2), Integer.valueOf(2));
Assert.assertEquals(state.get(8), Integer.valueOf(8));
Assert.assertNull(state.get(7));
}
@Test
public void testMemMV() {
config.put(ConfigKey.STATE_BACKEND_TYPE, BackendType.MEMORY.name());
this.keyStateBackend = new KeyStateBackend(10, new KeyGroup(1, 3),
StateBackendBuilder.buildStateBackend(config));
caseKV();
caseKList();
caseKMap();
}
}