Compare commits

...

17 Commits

Author SHA1 Message Date
birdstorm 41b24bb877 release v3.1.0
Signed-off-by: birdstorm <samuelwyf@hotmail.com>
2021-06-24 13:11:11 +08:00
ti-srebot 05f1559eab
cherry pick #207 to release-3.1 (#210)
Signed-off-by: ti-srebot <ti-srebot@pingcap.com>

Co-authored-by: Wallace <bupt2013211450@gmail.com>
Co-authored-by: birdstorm <samuelwyf@hotmail.com>
2021-06-23 21:53:42 +08:00
ti-srebot c7d9ff151b
pd-client grpc forward (#203) (#206)
* pd-client grpc forward (#203)

* forward pd leader

Signed-off-by: Little-Wallace <bupt2013211450@gmail.com>
Signed-off-by: birdstorm <samuelwyf@hotmail.com>

* fix test

Signed-off-by: birdstorm <samuelwyf@hotmail.com>

Co-authored-by: Wallace <bupt2013211450@gmail.com>
Co-authored-by: birdstorm <samuelwyf@hotmail.com>
2021-06-23 16:21:17 +08:00
ti-srebot 3aa9a5665b
Support grpc forward (#198) (#208)
* Support grpc forward (#198)

* support grpc forward for tikv client

Signed-off-by: Little-Wallace <bupt2013211450@gmail.com>
Signed-off-by: birdstorm <samuelwyf@hotmail.com>

* fix compile

Signed-off-by: birdstorm <samuelwyf@hotmail.com>

Co-authored-by: Wallace <bupt2013211450@gmail.com>
Co-authored-by: birdstorm <samuelwyf@hotmail.com>
2021-06-23 15:43:37 +08:00
ti-srebot 35493c468a
cherry pick #151 to release-3.1 (#211)
Signed-off-by: ti-srebot <ti-srebot@pingcap.com>

Co-authored-by: Liangliang Gu <marsishandsome@gmail.com>
2021-06-23 15:14:22 +08:00
ti-srebot 031745b41b
refactor follower read (#126) (#209)
* cherry pick #126 to release-3.1

Signed-off-by: ti-srebot <ti-srebot@pingcap.com>

* fix conflict

Signed-off-by: birdstorm <samuelwyf@hotmail.com>

Co-authored-by: Liangliang Gu <marsishandsome@gmail.com>
Co-authored-by: birdstorm <samuelwyf@hotmail.com>
2021-06-23 15:02:51 +08:00
ti-srebot 7f468277c3
cherry pick #199 to release-3.1 (#200)
Signed-off-by: birdstorm <samuelwyf@hotmail.com>

Co-authored-by: birdstorm <samuelwyf@hotmail.com>
2021-06-18 11:48:17 +08:00
ti-srebot 71de93d73d
cherry pick #185 to release-3.1 (#201)
Signed-off-by: ti-srebot <ti-srebot@pingcap.com>

Co-authored-by: Lifu Wu <purelind@users.noreply.github.com>
2021-06-17 16:31:02 +08:00
ti-srebot 2913008410
cherry pick #182 to release-3.1 (#189)
Signed-off-by: ti-srebot <ti-srebot@pingcap.com>

Co-authored-by: birdstorm <samuelwyf@hotmail.com>
2021-06-09 16:10:34 +08:00
ti-srebot 6a5ea6fb8b
cherry pick #183 to release-3.1 (#184)
Signed-off-by: ti-srebot <ti-srebot@pingcap.com>

Co-authored-by: birdstorm <samuelwyf@hotmail.com>
2021-06-07 10:02:41 +08:00
ti-srebot 01b391ff2f
cherry pick #172 to release-3.1 (#175)
Signed-off-by: ti-srebot <ti-srebot@pingcap.com>

Co-authored-by: birdstorm <samuelwyf@hotmail.com>
2021-06-04 12:24:23 +08:00
birdstorm 490b4a1e01
invalidate all region cache on store when store id not found (#170)
Signed-off-by: birdstorm <samuelwyf@hotmail.com>
2021-05-20 15:39:31 +08:00
ti-srebot c6398badfe
cherry pick #167 to release-3.1 (#168)
Signed-off-by: ti-srebot <ti-srebot@pingcap.com>

Co-authored-by: Qishang Zhong <zhongqishang@gmail.com>
2021-04-26 11:16:31 +08:00
ti-srebot 4db2ac1ad7
Remove unused files (#165) #166
Signed-off-by: ti-srebot <ti-srebot@pingcap.com>

Co-authored-by: tison <wander4096@gmail.com>
2021-04-19 16:02:23 +08:00
ti-srebot cd3ddc121a
cherry pick #160 to release-3.1 (#161) 2021-04-01 19:03:03 +08:00
birdstorm 06da8d0830
add issue and pr template (#157) (#158)
Signed-off-by: birdstorm <samuelwyf@hotmail.com>
2021-03-30 13:53:19 +08:00
birdstorm 131693bf8a
Update version to 3.1.0-SNAPSHAOT (#152) (#156)
Signed-off-by: birdstorm <samuelwyf@hotmail.com>
2021-03-29 16:21:00 +08:00
63 changed files with 1411 additions and 1071 deletions

View File

@ -9,6 +9,7 @@ def call(ghprbActualCommit, ghprbPullId, ghprbPullTitle, ghprbPullLink, ghprbPul
if (m1) { if (m1) {
TIDB_BRANCH = "${m1[0][1]}" TIDB_BRANCH = "${m1[0][1]}"
} }
m1 = null
println "TIDB_BRANCH=${TIDB_BRANCH}" println "TIDB_BRANCH=${TIDB_BRANCH}"
// parse pd branch // parse pd branch
@ -16,6 +17,7 @@ def call(ghprbActualCommit, ghprbPullId, ghprbPullTitle, ghprbPullLink, ghprbPul
if (m2) { if (m2) {
PD_BRANCH = "${m2[0][1]}" PD_BRANCH = "${m2[0][1]}"
} }
m2 = null
println "PD_BRANCH=${PD_BRANCH}" println "PD_BRANCH=${PD_BRANCH}"
// parse tikv branch // parse tikv branch
@ -23,6 +25,7 @@ def call(ghprbActualCommit, ghprbPullId, ghprbPullTitle, ghprbPullLink, ghprbPul
if (m3) { if (m3) {
TIKV_BRANCH = "${m3[0][1]}" TIKV_BRANCH = "${m3[0][1]}"
} }
m3 = null
println "TIKV_BRANCH=${TIKV_BRANCH}" println "TIKV_BRANCH=${TIKV_BRANCH}"
catchError { catchError {
@ -61,13 +64,13 @@ def call(ghprbActualCommit, ghprbPullId, ghprbPullTitle, ghprbPullLink, ghprbPul
killall -9 pd-server || true killall -9 pd-server || true
killall -9 java || true killall -9 java || true
sleep 10 sleep 10
bin/pd-server --name=pd --data-dir=pd --config=../.ci/config/pd.toml &>pd.log & bin/pd-server --name=pd --data-dir=pd --config=../config/pd.toml &>pd.log &
sleep 10 sleep 10
bin/tikv-server --pd=127.0.0.1:2379 -s tikv --addr=0.0.0.0:20160 --advertise-addr=127.0.0.1:20160 --config=../.ci/config/tikv.toml &>tikv.log & bin/tikv-server --pd=127.0.0.1:2379 -s tikv --addr=0.0.0.0:20160 --advertise-addr=127.0.0.1:20160 --config=../config/tikv.toml &>tikv.log &
sleep 10 sleep 10
ps aux | grep '-server' || true ps aux | grep '-server' || true
curl -s 127.0.0.1:2379/pd/api/v1/status || true curl -s 127.0.0.1:2379/pd/api/v1/status || true
bin/tidb-server --store=tikv --path="127.0.0.1:2379" --config=../.ci/config/tidb.toml &>tidb.log & bin/tidb-server --store=tikv --path="127.0.0.1:2379" --config=../config/tidb.toml &>tidb.log &
sleep 60 sleep 60
""" """
} }

36
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@ -0,0 +1,36 @@
---
name: Bug report
about: Create a report to help us improve
title: "[BUG] Title of Bug Report"
labels: type/bug
assignees: ''
---
**Describe the bug**
<!-- A clear and concise description of what the bug is. -->
**What did you do**
<!--
If possible, please provide a code receipt to produce this issue.
-->
**What do you expect**
<!-- A clear and concise description of what you expected to happen. -->
**What happens instead**
<!-- If an error occurs, please provide complete error stack. -->
<!--
**Screenshots**
If applicable, add screenshots to help explain your problem.
-->
**Java Client and TiDB/TiKV version info**
<!-- What version of Spark and TiSpark are you using? (Provide Spark version and run `spark.sql(“select ti_version()”).show(false)` in spark-shell) -->
<!--
**Additional context**
Add any other context about the problem here.
You may also provide TiDB version here if it is related to the issue.
-->

View File

@ -0,0 +1,20 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: type/feature-request
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

33
.github/pull_request_template.md vendored Normal file
View File

@ -0,0 +1,33 @@
### What problem does this PR solve? <!--add issue link with summary if exists-->
### What is changed and how it works?
### Check List <!--REMOVE the items that are not applicable-->
Tests <!-- At least one of them must be included. -->
- Unit test
- Integration test
- Manual test (add detailed scripts or steps below)
- No code
Code changes
- Has exported function/method change
- Has exported variable/fields change
- Has interface methods change
- Has persistent data change
Side effects
- Possible performance regression
- Increased code complexity
- Breaking backward compatibility
Related changes
- Need to cherry-pick to the release branch
- Need to update the documentation
- Need to be included in the release note

4
config/pd.toml Normal file
View File

@ -0,0 +1,4 @@
# PD Configuration.
[replication]
enable-placement-rules = true
max-replicas = 1

1
config/tidb.toml Normal file
View File

@ -0,0 +1 @@
# TiDB Configuration.

5
config/tikv.toml Normal file
View File

@ -0,0 +1,5 @@
# TiKV Configuration.
[raftstore]
# set store capacity, if no set, use disk capacity.
capacity = "8G"

View File

@ -5,7 +5,7 @@
<groupId>org.tikv</groupId> <groupId>org.tikv</groupId>
<artifactId>tikv-client-java</artifactId> <artifactId>tikv-client-java</artifactId>
<version>3.0.2-SNAPSHOT</version> <version>3.1.0</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<name>TiKV Java Client</name> <name>TiKV Java Client</name>
<description>A Java Client for TiKV</description> <description>A Java Client for TiKV</description>
@ -126,6 +126,11 @@
<artifactId>grpc-stub</artifactId> <artifactId>grpc-stub</artifactId>
<version>${grpc.version}</version> <version>${grpc.version}</version>
</dependency> </dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-services</artifactId>
<version>${grpc.version}</version>
</dependency>
<dependency> <dependency>
<groupId>io.grpc</groupId> <groupId>io.grpc</groupId>
<artifactId>grpc-testing</artifactId> <artifactId>grpc-testing</artifactId>

View File

@ -1,34 +0,0 @@
package(default_visibility = ["//visibility:public"])
java_library(
name = "tikv-java-client-lib",
srcs = glob(
["**/*.java"],
),
deps = [
"//:java",
"@com_fasterxml_jackson_core_jackson_annotations//jar",
"@com_fasterxml_jackson_core_jackson_core//jar",
"@com_fasterxml_jackson_core_jackson_databind//jar",
"@com_google_code_findbugs_jsr305//jar",
"@com_google_code_gson_gson//jar",
"@com_google_errorprone_error_prone_annotations//jar",
"@com_google_guava_guava//jar",
"@com_google_protobuf_protobuf_java//jar",
"@joda_time//jar",
# the following are defined in rules_protobuf
"@org_pubref_rules_protobuf//java:grpc_compiletime_deps",
"@org_pubref_rules_protobuf//java:netty_runtime_deps",
"@org_slf4j_slf4j_api//jar",
"@org_slf4j_jcl_over_slf4j//jar",
"@org_slf4j_jul_to_slf4j//jar",
"@log4j_log4j//jar",
"@net_sf_trove4j_trove4j//jar",
],
)
filegroup(
name = "srcs",
srcs = ["BUILD"] + glob(["**/*.java"]),
)

View File

@ -1,5 +0,0 @@
package org.tikv;
public class Main {
public static void main(String args[]) throws Exception {}
}

View File

@ -18,10 +18,15 @@ package org.tikv.common;
import static io.grpc.stub.ClientCalls.asyncBidiStreamingCall; import static io.grpc.stub.ClientCalls.asyncBidiStreamingCall;
import static io.grpc.stub.ClientCalls.blockingServerStreamingCall; import static io.grpc.stub.ClientCalls.blockingServerStreamingCall;
import io.grpc.ManagedChannel;
import io.grpc.MethodDescriptor; import io.grpc.MethodDescriptor;
import io.grpc.health.v1.HealthCheckRequest;
import io.grpc.health.v1.HealthCheckResponse;
import io.grpc.health.v1.HealthGrpc;
import io.grpc.stub.AbstractStub; import io.grpc.stub.AbstractStub;
import io.grpc.stub.ClientCalls; import io.grpc.stub.ClientCalls;
import io.grpc.stub.StreamObserver; import io.grpc.stub.StreamObserver;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier; import java.util.function.Supplier;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -171,4 +176,20 @@ public abstract class AbstractGRPCClient<
protected abstract BlockingStubT getBlockingStub(); protected abstract BlockingStubT getBlockingStub();
protected abstract StubT getAsyncStub(); protected abstract StubT getAsyncStub();
protected boolean checkHealth(String addressStr, HostMapping hostMapping) {
ManagedChannel channel = channelFactory.getChannel(addressStr, hostMapping);
HealthGrpc.HealthBlockingStub stub =
HealthGrpc.newBlockingStub(channel).withDeadlineAfter(getTimeout(), TimeUnit.MILLISECONDS);
HealthCheckRequest req = HealthCheckRequest.newBuilder().build();
try {
HealthCheckResponse resp = stub.check(req);
if (resp.getStatus() != HealthCheckResponse.ServingStatus.SERVING) {
return false;
}
} catch (Exception e) {
return false;
}
return true;
}
} }

View File

@ -42,16 +42,19 @@ public class ConfigUtils {
public static final String TIKV_KV_CLIENT_CONCURRENCY = "tikv.kv_client_concurrency"; public static final String TIKV_KV_CLIENT_CONCURRENCY = "tikv.kv_client_concurrency";
public static final String TIKV_KV_MODE = "tikv.kv_mode"; public static final String TIKV_KV_MODE = "tikv.kv_mode";
public static final String TIKV_IS_REPLICA_READ = "tikv.is_replica_read"; public static final String TIKV_REPLICA_READ = "tikv.replica_read";
public static final String TIKV_METRICS_ENABLE = "tikv.metrics.enable"; public static final String TIKV_METRICS_ENABLE = "tikv.metrics.enable";
public static final String TIKV_METRICS_PORT = "tikv.metrics.port"; public static final String TIKV_METRICS_PORT = "tikv.metrics.port";
public static final String TIKV_NETWORK_MAPPING_NAME = "tikv.network.mapping"; public static final String TIKV_NETWORK_MAPPING_NAME = "tikv.network.mapping";
public static final String TIKV_ENABLE_GRPC_FORWARD = "tikv.enable_grpc_forward";
public static final String TIKV_GRPC_HEALTH_CHECK_TIMEOUT = "tikv.grpc.health_check_timeout";
public static final String DEF_PD_ADDRESSES = "127.0.0.1:2379"; public static final String DEF_PD_ADDRESSES = "127.0.0.1:2379";
public static final String DEF_TIMEOUT = "600ms"; public static final String DEF_TIMEOUT = "600ms";
public static final String DEF_SCAN_TIMEOUT = "20s"; public static final String DEF_SCAN_TIMEOUT = "20s";
public static final int DEF_CHECK_HEALTH_TIMEOUT = 40;
public static final int DEF_SCAN_BATCH_SIZE = 10240; public static final int DEF_SCAN_BATCH_SIZE = 10240;
public static final int DEF_MAX_FRAME_SIZE = 268435456 * 2; // 256 * 2 MB public static final int DEF_MAX_FRAME_SIZE = 268435456 * 2; // 256 * 2 MB
public static final int DEF_INDEX_SCAN_BATCH_SIZE = 20000; public static final int DEF_INDEX_SCAN_BATCH_SIZE = 20000;
@ -72,10 +75,11 @@ public class ConfigUtils {
public static final String DEF_DB_PREFIX = ""; public static final String DEF_DB_PREFIX = "";
public static final int DEF_KV_CLIENT_CONCURRENCY = 10; public static final int DEF_KV_CLIENT_CONCURRENCY = 10;
public static final TiConfiguration.KVMode DEF_KV_MODE = TiConfiguration.KVMode.TXN; public static final TiConfiguration.KVMode DEF_KV_MODE = TiConfiguration.KVMode.TXN;
public static final boolean DEF_IS_REPLICA_READ = false; public static final String DEF_REPLICA_READ = "LEADER";
public static final boolean DEF_METRICS_ENABLE = false; public static final boolean DEF_METRICS_ENABLE = false;
public static final int DEF_METRICS_PORT = 3140; public static final int DEF_METRICS_PORT = 3140;
public static final String DEF_TIKV_NETWORK_MAPPING_NAME = ""; public static final String DEF_TIKV_NETWORK_MAPPING_NAME = "";
public static final boolean DEF_GRPC_FORWARD_ENABLE = true;
public static final String NORMAL_COMMAND_PRIORITY = "NORMAL"; public static final String NORMAL_COMMAND_PRIORITY = "NORMAL";
public static final String LOW_COMMAND_PRIORITY = "LOW"; public static final String LOW_COMMAND_PRIORITY = "LOW";
@ -86,4 +90,8 @@ public class ConfigUtils {
public static final String RAW_KV_MODE = "RAW"; public static final String RAW_KV_MODE = "RAW";
public static final String TXN_KV_MODE = "TXN"; public static final String TXN_KV_MODE = "TXN";
public static final String LEADER = "LEADER";
public static final String FOLLOWER = "FOLLOWER";
public static final String LEADER_AND_FOLLOWER = "LEADER_AND_FOLLOWER";
} }

View File

@ -30,6 +30,8 @@ import io.etcd.jetcd.KeyValue;
import io.etcd.jetcd.kv.GetResponse; import io.etcd.jetcd.kv.GetResponse;
import io.etcd.jetcd.options.GetOption; import io.etcd.jetcd.options.GetOption;
import io.grpc.ManagedChannel; import io.grpc.ManagedChannel;
import io.grpc.Metadata;
import io.grpc.stub.MetadataUtils;
import io.prometheus.client.Histogram; import io.prometheus.client.Histogram;
import java.net.URI; import java.net.URI;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
@ -39,10 +41,10 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.function.Supplier; import java.util.function.Supplier;
import java.util.stream.Collectors;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.tikv.common.TiConfiguration.KVMode; import org.tikv.common.TiConfiguration.KVMode;
@ -59,11 +61,11 @@ import org.tikv.common.util.BackOffFunction.BackOffFuncType;
import org.tikv.common.util.BackOffer; import org.tikv.common.util.BackOffer;
import org.tikv.common.util.ChannelFactory; import org.tikv.common.util.ChannelFactory;
import org.tikv.common.util.ConcreteBackOffer; import org.tikv.common.util.ConcreteBackOffer;
import org.tikv.common.util.FutureObserver;
import org.tikv.kvproto.Metapb.Store; import org.tikv.kvproto.Metapb.Store;
import org.tikv.kvproto.PDGrpc; import org.tikv.kvproto.PDGrpc;
import org.tikv.kvproto.PDGrpc.PDBlockingStub; import org.tikv.kvproto.PDGrpc.PDBlockingStub;
import org.tikv.kvproto.PDGrpc.PDStub; import org.tikv.kvproto.PDGrpc.PDStub;
import org.tikv.kvproto.Pdpb;
import org.tikv.kvproto.Pdpb.Error; import org.tikv.kvproto.Pdpb.Error;
import org.tikv.kvproto.Pdpb.ErrorType; import org.tikv.kvproto.Pdpb.ErrorType;
import org.tikv.kvproto.Pdpb.GetAllStoresRequest; import org.tikv.kvproto.Pdpb.GetAllStoresRequest;
@ -91,7 +93,7 @@ public class PDClient extends AbstractGRPCClient<PDBlockingStub, PDStub>
private final Logger logger = LoggerFactory.getLogger(PDClient.class); private final Logger logger = LoggerFactory.getLogger(PDClient.class);
private RequestHeader header; private RequestHeader header;
private TsoRequest tsoReq; private TsoRequest tsoReq;
private volatile LeaderWrapper leaderWrapper; private volatile PDClientWrapper pdClientWrapper;
private ScheduledExecutorService service; private ScheduledExecutorService service;
private ScheduledExecutorService tiflashReplicaService; private ScheduledExecutorService tiflashReplicaService;
private List<URI> pdAddrs; private List<URI> pdAddrs;
@ -241,37 +243,16 @@ public class PDClient extends AbstractGRPCClient<PDBlockingStub, PDStub>
return new TiRegion( return new TiRegion(
resp.getRegion(), resp.getRegion(),
resp.getLeader(), resp.getLeader(),
null,
conf.getIsolationLevel(), conf.getIsolationLevel(),
conf.getCommandPriority(), conf.getCommandPriority(),
conf.getKvMode(), conf.getKvMode(),
conf.isReplicaRead()); conf.getReplicaSelector());
} finally { } finally {
requestTimer.observeDuration(); requestTimer.observeDuration();
} }
} }
@Override
public Future<TiRegion> getRegionByKeyAsync(BackOffer backOffer, ByteString key) {
FutureObserver<TiRegion, GetRegionResponse> responseObserver =
new FutureObserver<>(
resp ->
new TiRegion(
resp.getRegion(),
resp.getLeader(),
conf.getIsolationLevel(),
conf.getCommandPriority(),
conf.getKvMode(),
conf.isReplicaRead()));
Supplier<GetRegionRequest> request =
() -> GetRegionRequest.newBuilder().setHeader(header).setRegionKey(key).build();
PDErrorHandler<GetRegionResponse> handler =
new PDErrorHandler<>(getRegionResponseErrorExtractor, this);
callAsyncWithRetry(backOffer, PDGrpc.getGetRegionMethod(), request, responseObserver, handler);
return responseObserver.getFuture();
}
@Override @Override
public TiRegion getRegionByID(BackOffer backOffer, long id) { public TiRegion getRegionByID(BackOffer backOffer, long id) {
Supplier<GetRegionByIDRequest> request = Supplier<GetRegionByIDRequest> request =
@ -285,33 +266,11 @@ public class PDClient extends AbstractGRPCClient<PDBlockingStub, PDStub>
return new TiRegion( return new TiRegion(
resp.getRegion(), resp.getRegion(),
resp.getLeader(), resp.getLeader(),
null,
conf.getIsolationLevel(), conf.getIsolationLevel(),
conf.getCommandPriority(), conf.getCommandPriority(),
conf.getKvMode(), conf.getKvMode(),
conf.isReplicaRead()); conf.getReplicaSelector());
}
@Override
public Future<TiRegion> getRegionByIDAsync(BackOffer backOffer, long id) {
FutureObserver<TiRegion, GetRegionResponse> responseObserver =
new FutureObserver<>(
resp ->
new TiRegion(
resp.getRegion(),
resp.getLeader(),
conf.getIsolationLevel(),
conf.getCommandPriority(),
conf.getKvMode(),
conf.isReplicaRead()));
Supplier<GetRegionByIDRequest> request =
() -> GetRegionByIDRequest.newBuilder().setHeader(header).setRegionId(id).build();
PDErrorHandler<GetRegionResponse> handler =
new PDErrorHandler<>(getRegionResponseErrorExtractor, this);
callAsyncWithRetry(
backOffer, PDGrpc.getGetRegionByIDMethod(), request, responseObserver, handler);
return responseObserver.getFuture();
} }
private Supplier<GetStoreRequest> buildGetStoreReq(long storeId) { private Supplier<GetStoreRequest> buildGetStoreReq(long storeId) {
@ -334,20 +293,6 @@ public class PDClient extends AbstractGRPCClient<PDBlockingStub, PDStub>
.getStore(); .getStore();
} }
@Override
public Future<Store> getStoreAsync(BackOffer backOffer, long storeId) {
FutureObserver<Store, GetStoreResponse> responseObserver =
new FutureObserver<>(GetStoreResponse::getStore);
callAsyncWithRetry(
backOffer,
PDGrpc.getGetStoreMethod(),
buildGetStoreReq(storeId),
responseObserver,
buildPDErrorHandler());
return responseObserver.getFuture();
}
@Override @Override
public List<Store> getAllStores(BackOffer backOffer) { public List<Store> getAllStores(BackOffer backOffer) {
return callWithRetry( return callWithRetry(
@ -361,8 +306,8 @@ public class PDClient extends AbstractGRPCClient<PDBlockingStub, PDStub>
} }
@Override @Override
public boolean isReplicaRead() { public TiConfiguration.ReplicaRead getReplicaRead() {
return conf.isReplicaRead(); return conf.getReplicaRead();
} }
@Override @Override
@ -385,8 +330,8 @@ public class PDClient extends AbstractGRPCClient<PDBlockingStub, PDStub>
} }
@VisibleForTesting @VisibleForTesting
LeaderWrapper getLeaderWrapper() { PDClientWrapper getPdClientWrapper() {
return leaderWrapper; return pdClientWrapper;
} }
private GetMembersResponse getMembers(URI uri) { private GetMembersResponse getMembers(URI uri) {
@ -407,50 +352,127 @@ public class PDClient extends AbstractGRPCClient<PDBlockingStub, PDStub>
return null; return null;
} }
synchronized boolean switchLeader(List<String> leaderURLs) { // return whether the leader has changed to target address `leaderUrlStr`.
if (leaderURLs.isEmpty()) return false; synchronized boolean trySwitchLeader(String leaderUrlStr) {
String leaderUrlStr = leaderURLs.get(0); if (pdClientWrapper != null) {
// TODO: Why not strip protocol info on server side since grpc does not need it if (leaderUrlStr.equals(pdClientWrapper.getLeaderInfo())) {
if (leaderWrapper != null && leaderUrlStr.equals(leaderWrapper.getLeaderInfo())) { // The message to leader is not forwarded by follower.
return true; if (leaderUrlStr.equals(pdClientWrapper.getStoreAddress())) {
return true;
}
}
// If leader has transfered to another member, we can create another leaderwrapper.
} }
// switch leader // switch leader
return createLeaderWrapper(leaderUrlStr); return createLeaderClientWrapper(leaderUrlStr);
} }
private boolean createLeaderWrapper(String leaderUrlStr) { private synchronized boolean createLeaderClientWrapper(String leaderUrlStr) {
try { try {
URI newLeader = addrToUri(leaderUrlStr);
leaderUrlStr = uriToAddr(newLeader);
if (leaderWrapper != null && leaderUrlStr.equals(leaderWrapper.getLeaderInfo())) {
return true;
}
// create new Leader // create new Leader
ManagedChannel clientChannel = channelFactory.getChannel(leaderUrlStr, hostMapping); ManagedChannel clientChannel = channelFactory.getChannel(leaderUrlStr, hostMapping);
leaderWrapper = pdClientWrapper =
new LeaderWrapper( new PDClientWrapper(leaderUrlStr, leaderUrlStr, clientChannel, System.nanoTime());
leaderUrlStr,
PDGrpc.newBlockingStub(clientChannel),
PDGrpc.newStub(clientChannel),
System.nanoTime());
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
logger.error("Error updating leader. " + leaderUrlStr, e); logger.error("Error updating leader. " + leaderUrlStr, e);
return false; return false;
} }
logger.info(String.format("Switched to new leader: %s", leaderWrapper)); logger.info(String.format("Switched to new leader: %s", pdClientWrapper));
return true; return true;
} }
public void updateLeader() { synchronized boolean createFollowerClientWrapper(String followerUrlStr, String leaderUrls) {
// TODO: Why not strip protocol info on server side since grpc does not need it
try {
if (!checkHealth(followerUrlStr, hostMapping)) {
return false;
}
// create new Leader
ManagedChannel channel = channelFactory.getChannel(followerUrlStr, hostMapping);
pdClientWrapper = new PDClientWrapper(leaderUrls, followerUrlStr, channel, System.nanoTime());
} catch (IllegalArgumentException e) {
logger.error("Error updating follower. " + followerUrlStr, e);
return false;
}
logger.info(String.format("Switched to new leader by follower forward: %s", pdClientWrapper));
return true;
}
public synchronized void updateLeaderOrforwardFollower() {
for (URI url : this.pdAddrs) { for (URI url : this.pdAddrs) {
// since resp is null, we need update leader's address by walking through all pd server. // since resp is null, we need update leader's address by walking through all pd server.
GetMembersResponse resp = getMembers(url); GetMembersResponse resp = getMembers(url);
if (resp == null) { if (resp == null) {
continue; continue;
} }
if (resp.getLeader().getClientUrlsList().isEmpty()) {
continue;
}
String leaderUrlStr = resp.getLeader().getClientUrlsList().get(0);
leaderUrlStr = uriToAddr(addrToUri(leaderUrlStr));
// if leader is switched, just return. // if leader is switched, just return.
if (switchLeader(resp.getLeader().getClientUrlsList())) { if (checkHealth(leaderUrlStr, hostMapping) && trySwitchLeader(leaderUrlStr)) {
return;
}
if (!conf.getEnableGrpcForward()) {
continue;
}
List<Pdpb.Member> members = resp.getMembersList();
boolean hasReachNextMember = false;
// If we have not used follower forward, try the first follower.
if (pdClientWrapper != null && pdClientWrapper.getStoreAddress().equals(leaderUrlStr)) {
hasReachNextMember = true;
}
for (int i = 0; i < members.size() * 2; i++) {
Pdpb.Member member = members.get(i % members.size());
if (member.getMemberId() == resp.getLeader().getMemberId()) {
continue;
}
String followerUrlStr = member.getClientUrlsList().get(0);
followerUrlStr = uriToAddr(addrToUri(followerUrlStr));
if (pdClientWrapper != null && pdClientWrapper.getStoreAddress().equals(followerUrlStr)) {
hasReachNextMember = true;
continue;
}
if (hasReachNextMember && createFollowerClientWrapper(followerUrlStr, leaderUrlStr)) {
return;
}
}
}
if (pdClientWrapper == null) {
throw new TiClientInternalException(
"already tried all address on file, but not leader found yet.");
}
}
public void tryUpdateLeader() {
for (URI url : this.pdAddrs) {
// since resp is null, we need update leader's address by walking through all pd server.
GetMembersResponse resp = getMembers(url);
if (resp == null) {
continue;
}
List<URI> urls =
resp.getMembersList()
.stream()
.map(mem -> addrToUri(mem.getClientUrls(0)))
.collect(Collectors.toList());
String leaderUrlStr = resp.getLeader().getClientUrlsList().get(0);
leaderUrlStr = uriToAddr(addrToUri(leaderUrlStr));
// If leader is not change but becomes available, we can cancel follower forward.
if (checkHealth(leaderUrlStr, hostMapping) && trySwitchLeader(leaderUrlStr)) {
if (!urls.equals(this.pdAddrs)) {
tryUpdateMembers(urls);
}
return; return;
} }
} }
@ -458,6 +480,10 @@ public class PDClient extends AbstractGRPCClient<PDBlockingStub, PDStub>
"already tried all address on file, but not leader found yet."); "already tried all address on file, but not leader found yet.");
} }
private synchronized void tryUpdateMembers(List<URI> members) {
this.pdAddrs = members;
}
public void updateTiFlashReplicaStatus() { public void updateTiFlashReplicaStatus() {
ByteSequence prefix = ByteSequence prefix =
ByteSequence.from(TIFLASH_TABLE_SYNC_PROGRESS_PATH, StandardCharsets.UTF_8); ByteSequence.from(TIFLASH_TABLE_SYNC_PROGRESS_PATH, StandardCharsets.UTF_8);
@ -513,25 +539,34 @@ public class PDClient extends AbstractGRPCClient<PDBlockingStub, PDStub>
@Override @Override
protected PDBlockingStub getBlockingStub() { protected PDBlockingStub getBlockingStub() {
if (leaderWrapper == null) { if (pdClientWrapper == null) {
throw new GrpcException("PDClient may not be initialized"); throw new GrpcException("PDClient may not be initialized");
} }
return leaderWrapper.getBlockingStub().withDeadlineAfter(getTimeout(), TimeUnit.MILLISECONDS); return pdClientWrapper.getBlockingStub().withDeadlineAfter(getTimeout(), TimeUnit.MILLISECONDS);
} }
@Override @Override
protected PDStub getAsyncStub() { protected PDStub getAsyncStub() {
if (leaderWrapper == null) { if (pdClientWrapper == null) {
throw new GrpcException("PDClient may not be initialized"); throw new GrpcException("PDClient may not be initialized");
} }
return leaderWrapper.getAsyncStub().withDeadlineAfter(getTimeout(), TimeUnit.MILLISECONDS); return pdClientWrapper.getAsyncStub().withDeadlineAfter(getTimeout(), TimeUnit.MILLISECONDS);
} }
private void initCluster() { private void initCluster() {
GetMembersResponse resp = null; GetMembersResponse resp = null;
List<URI> pdAddrs = getConf().getPdAddrs(); List<URI> pdAddrs = getConf().getPdAddrs();
this.pdAddrs = pdAddrs; this.pdAddrs = pdAddrs;
this.etcdClient = Client.builder().endpoints(pdAddrs).build(); this.etcdClient =
Client.builder()
.endpoints(pdAddrs)
.executorService(
Executors.newCachedThreadPool(
new ThreadFactoryBuilder()
.setNameFormat("etcd-conn-manager-pool-%d")
.setDaemon(true)
.build()))
.build();
this.hostMapping = new HostMapping(this.etcdClient, conf.getNetworkMappingName()); this.hostMapping = new HostMapping(this.etcdClient, conf.getNetworkMappingName());
for (URI u : pdAddrs) { for (URI u : pdAddrs) {
resp = getMembers(u); resp = getMembers(u);
@ -544,43 +579,65 @@ public class PDClient extends AbstractGRPCClient<PDBlockingStub, PDStub>
header = RequestHeader.newBuilder().setClusterId(clusterId).build(); header = RequestHeader.newBuilder().setClusterId(clusterId).build();
tsoReq = TsoRequest.newBuilder().setHeader(header).setCount(1).build(); tsoReq = TsoRequest.newBuilder().setHeader(header).setCount(1).build();
this.tiflashReplicaMap = new ConcurrentHashMap<>(); this.tiflashReplicaMap = new ConcurrentHashMap<>();
createLeaderWrapper(resp.getLeader().getClientUrls(0)); this.pdAddrs =
resp.getMembersList()
.stream()
.map(mem -> addrToUri(mem.getClientUrls(0)))
.collect(Collectors.toList());
logger.info("init cluster with address: " + this.pdAddrs);
String leaderUrlStr = resp.getLeader().getClientUrls(0);
leaderUrlStr = uriToAddr(addrToUri(leaderUrlStr));
createLeaderClientWrapper(leaderUrlStr);
service = service =
Executors.newSingleThreadScheduledExecutor( Executors.newSingleThreadScheduledExecutor(
new ThreadFactoryBuilder().setDaemon(true).build()); new ThreadFactoryBuilder()
.setNameFormat("PDClient-update-leader-pool-%d")
.setDaemon(true)
.build());
service.scheduleAtFixedRate( service.scheduleAtFixedRate(
() -> { () -> {
// Wrap this with a try catch block in case schedule update fails // Wrap this with a try catch block in case schedule update fails
try { try {
updateLeader(); tryUpdateLeader();
} catch (Exception e) { } catch (Exception e) {
logger.warn("Update leader failed", e); logger.warn("Update leader failed", e);
} }
}, },
1, 10,
1, 10,
TimeUnit.MINUTES); TimeUnit.SECONDS);
tiflashReplicaService = tiflashReplicaService =
Executors.newSingleThreadScheduledExecutor( Executors.newSingleThreadScheduledExecutor(
new ThreadFactoryBuilder().setDaemon(true).build()); new ThreadFactoryBuilder()
.setNameFormat("PDClient-tiflash-replica-pool-%d")
.setDaemon(true)
.build());
tiflashReplicaService.scheduleAtFixedRate( tiflashReplicaService.scheduleAtFixedRate(
this::updateTiFlashReplicaStatus, 10, 10, TimeUnit.SECONDS); this::updateTiFlashReplicaStatus, 10, 10, TimeUnit.SECONDS);
} }
static class LeaderWrapper { static class PDClientWrapper {
private final String leaderInfo; private final String leaderInfo;
private final PDBlockingStub blockingStub; private final PDBlockingStub blockingStub;
private final PDStub asyncStub; private final PDStub asyncStub;
private final long createTime; private final long createTime;
private final String storeAddress;
LeaderWrapper( PDClientWrapper(
String leaderInfo, String leaderInfo, String storeAddress, ManagedChannel clientChannel, long createTime) {
PDGrpc.PDBlockingStub blockingStub, if (!storeAddress.equals(leaderInfo)) {
PDGrpc.PDStub asyncStub, Metadata header = new Metadata();
long createTime) { header.put(TiConfiguration.PD_FORWARD_META_DATA_KEY, addrToUri(leaderInfo).toString());
this.blockingStub =
MetadataUtils.attachHeaders(PDGrpc.newBlockingStub(clientChannel), header);
this.asyncStub = MetadataUtils.attachHeaders(PDGrpc.newStub(clientChannel), header);
} else {
this.blockingStub = PDGrpc.newBlockingStub(clientChannel);
this.asyncStub = PDGrpc.newStub(clientChannel);
}
this.leaderInfo = leaderInfo; this.leaderInfo = leaderInfo;
this.blockingStub = blockingStub; this.storeAddress = storeAddress;
this.asyncStub = asyncStub;
this.createTime = createTime; this.createTime = createTime;
} }
@ -588,6 +645,10 @@ public class PDClient extends AbstractGRPCClient<PDBlockingStub, PDStub>
return leaderInfo; return leaderInfo;
} }
String getStoreAddress() {
return storeAddress;
}
PDBlockingStub getBlockingStub() { PDBlockingStub getBlockingStub() {
return blockingStub; return blockingStub;
} }

View File

@ -17,7 +17,6 @@ package org.tikv.common;
import com.google.protobuf.ByteString; import com.google.protobuf.ByteString;
import java.util.List; import java.util.List;
import java.util.concurrent.Future;
import org.tikv.common.meta.TiTimestamp; import org.tikv.common.meta.TiTimestamp;
import org.tikv.common.region.TiRegion; import org.tikv.common.region.TiRegion;
import org.tikv.common.util.BackOffer; import org.tikv.common.util.BackOffer;
@ -40,8 +39,6 @@ public interface ReadOnlyPDClient {
*/ */
TiRegion getRegionByKey(BackOffer backOffer, ByteString key); TiRegion getRegionByKey(BackOffer backOffer, ByteString key);
Future<TiRegion> getRegionByKeyAsync(BackOffer backOffer, ByteString key);
/** /**
* Get Region by Region Id * Get Region by Region Id
* *
@ -50,8 +47,6 @@ public interface ReadOnlyPDClient {
*/ */
TiRegion getRegionByID(BackOffer backOffer, long id); TiRegion getRegionByID(BackOffer backOffer, long id);
Future<TiRegion> getRegionByIDAsync(BackOffer backOffer, long id);
HostMapping getHostMapping(); HostMapping getHostMapping();
/** /**
@ -62,9 +57,7 @@ public interface ReadOnlyPDClient {
*/ */
Store getStore(BackOffer backOffer, long storeId); Store getStore(BackOffer backOffer, long storeId);
Future<Store> getStoreAsync(BackOffer backOffer, long storeId);
List<Store> getAllStores(BackOffer backOffer); List<Store> getAllStores(BackOffer backOffer);
boolean isReplicaRead(); TiConfiguration.ReplicaRead getReplicaRead();
} }

View File

@ -17,6 +17,7 @@ package org.tikv.common;
import static org.tikv.common.ConfigUtils.*; import static org.tikv.common.ConfigUtils.*;
import io.grpc.Metadata;
import java.io.Serializable; import java.io.Serializable;
import java.net.URI; import java.net.URI;
import java.util.*; import java.util.*;
@ -24,6 +25,7 @@ import java.util.concurrent.ConcurrentHashMap;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.tikv.common.pd.PDUtils; import org.tikv.common.pd.PDUtils;
import org.tikv.common.replica.ReplicaSelector;
import org.tikv.kvproto.Kvrpcpb.CommandPri; import org.tikv.kvproto.Kvrpcpb.CommandPri;
import org.tikv.kvproto.Kvrpcpb.IsolationLevel; import org.tikv.kvproto.Kvrpcpb.IsolationLevel;
@ -31,6 +33,10 @@ public class TiConfiguration implements Serializable {
private static final Logger logger = LoggerFactory.getLogger(TiConfiguration.class); private static final Logger logger = LoggerFactory.getLogger(TiConfiguration.class);
private static final ConcurrentHashMap<String, String> settings = new ConcurrentHashMap<>(); private static final ConcurrentHashMap<String, String> settings = new ConcurrentHashMap<>();
public static final Metadata.Key FORWARD_META_DATA_KEY =
Metadata.Key.of("tikv-forwarded-host", Metadata.ASCII_STRING_MARSHALLER);
public static final Metadata.Key PD_FORWARD_META_DATA_KEY =
Metadata.Key.of("pd-forwarded-host", Metadata.ASCII_STRING_MARSHALLER);
static { static {
loadFromSystemProperties(); loadFromSystemProperties();
@ -67,10 +73,12 @@ public class TiConfiguration implements Serializable {
setIfMissing(TIKV_DB_PREFIX, DEF_DB_PREFIX); setIfMissing(TIKV_DB_PREFIX, DEF_DB_PREFIX);
setIfMissing(TIKV_KV_CLIENT_CONCURRENCY, DEF_KV_CLIENT_CONCURRENCY); setIfMissing(TIKV_KV_CLIENT_CONCURRENCY, DEF_KV_CLIENT_CONCURRENCY);
setIfMissing(TIKV_KV_MODE, TXN_KV_MODE); setIfMissing(TIKV_KV_MODE, TXN_KV_MODE);
setIfMissing(TIKV_IS_REPLICA_READ, DEF_IS_REPLICA_READ); setIfMissing(TIKV_REPLICA_READ, DEF_REPLICA_READ);
setIfMissing(TIKV_METRICS_ENABLE, DEF_METRICS_ENABLE); setIfMissing(TIKV_METRICS_ENABLE, DEF_METRICS_ENABLE);
setIfMissing(TIKV_METRICS_PORT, DEF_METRICS_PORT); setIfMissing(TIKV_METRICS_PORT, DEF_METRICS_PORT);
setIfMissing(TIKV_NETWORK_MAPPING_NAME, DEF_TIKV_NETWORK_MAPPING_NAME); setIfMissing(TIKV_NETWORK_MAPPING_NAME, DEF_TIKV_NETWORK_MAPPING_NAME);
setIfMissing(TIKV_ENABLE_GRPC_FORWARD, DEF_GRPC_FORWARD_ENABLE);
setIfMissing(TIKV_GRPC_HEALTH_CHECK_TIMEOUT, DEF_CHECK_HEALTH_TIMEOUT);
} }
public static void listAll() { public static void listAll() {
@ -216,6 +224,17 @@ public class TiConfiguration implements Serializable {
} }
} }
private static ReplicaRead getReplicaRead(String key) {
String value = get(key).toUpperCase(Locale.ROOT);
if (FOLLOWER.equals(value)) {
return ReplicaRead.FOLLOWER;
} else if (LEADER_AND_FOLLOWER.equals(value)) {
return ReplicaRead.LEADER_AND_FOLLOWER;
} else {
return ReplicaRead.LEADER;
}
}
private long timeout = getTimeAsMs(TIKV_GRPC_TIMEOUT); private long timeout = getTimeAsMs(TIKV_GRPC_TIMEOUT);
private long scanTimeout = getTimeAsMs(TIKV_GRPC_SCAN_TIMEOUT); private long scanTimeout = getTimeAsMs(TIKV_GRPC_SCAN_TIMEOUT);
private int maxFrameSize = getInt(TIKV_GRPC_MAX_FRAME_SIZE); private int maxFrameSize = getInt(TIKV_GRPC_MAX_FRAME_SIZE);
@ -233,12 +252,16 @@ public class TiConfiguration implements Serializable {
private boolean showRowId = getBoolean(TIKV_SHOW_ROWID); private boolean showRowId = getBoolean(TIKV_SHOW_ROWID);
private String dbPrefix = get(TIKV_DB_PREFIX); private String dbPrefix = get(TIKV_DB_PREFIX);
private KVMode kvMode = getKvMode(TIKV_KV_MODE); private KVMode kvMode = getKvMode(TIKV_KV_MODE);
private boolean enableGrpcForward = getBoolean(TIKV_ENABLE_GRPC_FORWARD);
private int kvClientConcurrency = getInt(TIKV_KV_CLIENT_CONCURRENCY); private int kvClientConcurrency = getInt(TIKV_KV_CLIENT_CONCURRENCY);
private boolean isReplicaRead = getBoolean(TIKV_IS_REPLICA_READ); private ReplicaRead replicaRead = getReplicaRead(TIKV_REPLICA_READ);
private ReplicaSelector internalReplicaSelector = getReplicaSelector(replicaRead);
private ReplicaSelector replicaSelector;
private boolean metricsEnable = getBoolean(TIKV_METRICS_ENABLE); private boolean metricsEnable = getBoolean(TIKV_METRICS_ENABLE);
private int metricsPort = getInt(TIKV_METRICS_PORT); private int metricsPort = getInt(TIKV_METRICS_PORT);
private int grpcHealthCheckTimeout = getInt(TIKV_GRPC_HEALTH_CHECK_TIMEOUT);
private final String networkMappingName = get(TIKV_NETWORK_MAPPING_NAME); private final String networkMappingName = get(TIKV_NETWORK_MAPPING_NAME);
@ -247,6 +270,12 @@ public class TiConfiguration implements Serializable {
RAW RAW
} }
public enum ReplicaRead {
LEADER,
FOLLOWER,
LEADER_AND_FOLLOWER
}
public static TiConfiguration createDefault() { public static TiConfiguration createDefault() {
return new TiConfiguration(); return new TiConfiguration();
} }
@ -457,15 +486,40 @@ public class TiConfiguration implements Serializable {
return this; return this;
} }
public boolean isReplicaRead() { public ReplicaRead getReplicaRead() {
return isReplicaRead; return replicaRead;
} }
public TiConfiguration setReplicaRead(boolean isReplicaRead) { public TiConfiguration setReplicaRead(ReplicaRead replicaRead) {
this.isReplicaRead = isReplicaRead; this.replicaRead = replicaRead;
this.internalReplicaSelector = getReplicaSelector(this.replicaRead);
return this; return this;
} }
private ReplicaSelector getReplicaSelector(ReplicaRead replicaRead) {
if (TiConfiguration.ReplicaRead.LEADER.equals(replicaRead)) {
return ReplicaSelector.LEADER;
} else if (TiConfiguration.ReplicaRead.FOLLOWER.equals(replicaRead)) {
return ReplicaSelector.FOLLOWER;
} else if (TiConfiguration.ReplicaRead.LEADER_AND_FOLLOWER.equals(replicaRead)) {
return ReplicaSelector.LEADER_AND_FOLLOWER;
} else {
return null;
}
}
public ReplicaSelector getReplicaSelector() {
if (replicaSelector != null) {
return replicaSelector;
} else {
return internalReplicaSelector;
}
}
public void setReplicaSelector(ReplicaSelector replicaSelector) {
this.replicaSelector = replicaSelector;
}
public boolean isMetricsEnable() { public boolean isMetricsEnable() {
return metricsEnable; return metricsEnable;
} }
@ -487,4 +541,12 @@ public class TiConfiguration implements Serializable {
public String getNetworkMappingName() { public String getNetworkMappingName() {
return this.networkMappingName; return this.networkMappingName;
} }
public boolean getEnableGrpcForward() {
return this.enableGrpcForward;
}
public long getGrpcHealthCheckTimeout() {
return this.grpcHealthCheckTimeout;
}
} }

View File

@ -43,8 +43,8 @@ import org.tikv.common.region.RegionManager;
import org.tikv.common.region.RegionStoreClient; import org.tikv.common.region.RegionStoreClient;
import org.tikv.common.region.RegionStoreClient.RegionStoreClientBuilder; import org.tikv.common.region.RegionStoreClient.RegionStoreClientBuilder;
import org.tikv.common.region.TiRegion; import org.tikv.common.region.TiRegion;
import org.tikv.common.region.TiStore;
import org.tikv.common.util.*; import org.tikv.common.util.*;
import org.tikv.kvproto.Metapb;
import org.tikv.raw.RawKVClient; import org.tikv.raw.RawKVClient;
import org.tikv.txn.KVClient; import org.tikv.txn.KVClient;
import org.tikv.txn.TxnKVClient; import org.tikv.txn.TxnKVClient;
@ -71,6 +71,7 @@ public class TiSession implements AutoCloseable {
private volatile ExecutorService batchScanThreadPool; private volatile ExecutorService batchScanThreadPool;
private volatile ExecutorService deleteRangeThreadPool; private volatile ExecutorService deleteRangeThreadPool;
private volatile RegionManager regionManager; private volatile RegionManager regionManager;
private volatile boolean enableGrpcForward;
private volatile RegionStoreClient.RegionStoreClientBuilder clientBuilder; private volatile RegionStoreClient.RegionStoreClientBuilder clientBuilder;
private boolean isClosed = false; private boolean isClosed = false;
private HTTPServer server; private HTTPServer server;
@ -80,6 +81,7 @@ public class TiSession implements AutoCloseable {
this.conf = conf; this.conf = conf;
this.channelFactory = new ChannelFactory(conf.getMaxFrameSize()); this.channelFactory = new ChannelFactory(conf.getMaxFrameSize());
this.client = PDClient.createRaw(conf, channelFactory); this.client = PDClient.createRaw(conf, channelFactory);
this.enableGrpcForward = conf.getEnableGrpcForward();
if (conf.isMetricsEnable()) { if (conf.isMetricsEnable()) {
try { try {
this.collectorRegistry = new CollectorRegistry(); this.collectorRegistry = new CollectorRegistry();
@ -90,6 +92,7 @@ public class TiSession implements AutoCloseable {
this.collectorRegistry.register(RetryPolicy.GRPC_SINGLE_REQUEST_LATENCY); this.collectorRegistry.register(RetryPolicy.GRPC_SINGLE_REQUEST_LATENCY);
this.collectorRegistry.register(RegionManager.GET_REGION_BY_KEY_REQUEST_LATENCY); this.collectorRegistry.register(RegionManager.GET_REGION_BY_KEY_REQUEST_LATENCY);
this.collectorRegistry.register(PDClient.PD_GET_REGION_BY_KEY_REQUEST_LATENCY); this.collectorRegistry.register(PDClient.PD_GET_REGION_BY_KEY_REQUEST_LATENCY);
this.enableGrpcForward = conf.getEnableGrpcForward();
this.server = this.server =
new HTTPServer( new HTTPServer(
new InetSocketAddress(conf.getMetricsPort()), this.collectorRegistry, true); new InetSocketAddress(conf.getMetricsPort()), this.collectorRegistry, true);
@ -194,12 +197,17 @@ public class TiSession implements AutoCloseable {
return res; return res;
} }
public synchronized RegionManager getRegionManager() { public RegionManager getRegionManager() {
RegionManager res = regionManager; RegionManager res = regionManager;
if (res == null) { if (res == null) {
synchronized (this) { synchronized (this) {
if (regionManager == null) { if (regionManager == null) {
regionManager = new RegionManager(getPDClient(), this.cacheInvalidateCallback); regionManager =
new RegionManager(
getPDClient(),
this.cacheInvalidateCallback,
this.channelFactory,
this.enableGrpcForward);
} }
res = regionManager; res = regionManager;
} }
@ -415,10 +423,10 @@ public class TiSession implements AutoCloseable {
groupKeysByRegion(regionManager, splitKeys, backOffer); groupKeysByRegion(regionManager, splitKeys, backOffer);
for (Map.Entry<TiRegion, List<ByteString>> entry : groupKeys.entrySet()) { for (Map.Entry<TiRegion, List<ByteString>> entry : groupKeys.entrySet()) {
Pair<TiRegion, Metapb.Store> pair = Pair<TiRegion, TiStore> pair =
getRegionManager().getRegionStorePairByKey(entry.getKey().getStartKey()); getRegionManager().getRegionStorePairByKey(entry.getKey().getStartKey());
TiRegion region = pair.first; TiRegion region = pair.first;
Metapb.Store store = pair.second; TiStore store = pair.second;
List<ByteString> splits = List<ByteString> splits =
entry entry
.getValue() .getValue()
@ -466,7 +474,9 @@ public class TiSession implements AutoCloseable {
synchronized (sessionCachedMap) { synchronized (sessionCachedMap) {
sessionCachedMap.remove(conf.getPdAddrsString()); sessionCachedMap.remove(conf.getPdAddrsString());
} }
if (regionManager != null) {
regionManager.close();
}
if (tableScanThreadPool != null) { if (tableScanThreadPool != null) {
tableScanThreadPool.shutdownNow(); tableScanThreadPool.shutdownNow();
} }

View File

@ -1,258 +0,0 @@
/*
* Copyright 2019 PingCAP, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.tikv.common.allocator;
import com.google.common.primitives.UnsignedLongs;
import com.google.protobuf.ByteString;
import java.io.Serializable;
import java.util.Arrays;
import java.util.function.Function;
import org.tikv.common.Snapshot;
import org.tikv.common.TiSession;
import org.tikv.common.codec.CodecDataInput;
import org.tikv.common.codec.CodecDataOutput;
import org.tikv.common.codec.MetaCodec;
import org.tikv.common.exception.AllocateRowIDOverflowException;
import org.tikv.common.exception.TiBatchWriteException;
import org.tikv.common.meta.TiTableInfo;
import org.tikv.common.util.BackOffer;
import org.tikv.common.util.ConcreteBackOffer;
import org.tikv.txn.TwoPhaseCommitter;
/**
* RowIDAllocator read current start from TiKV and write back 'start+step' back to TiKV. It designs
* to allocate all id for data to be written at once, hence it does not need run inside a txn.
*
* <p>(start, end] is allocated
*/
public final class RowIDAllocator implements Serializable {
private final long maxShardRowIDBits;
private final long dbId;
private final TiSession session;
private final long step;
private long end;
private RowIDAllocator(long maxShardRowIDBits, long dbId, long step, TiSession session) {
this.maxShardRowIDBits = maxShardRowIDBits;
this.dbId = dbId;
this.step = step;
this.session = session;
}
/**
* @param index should >= 1
* @return
*/
public long getShardRowId(long index) {
return getShardRowId(maxShardRowIDBits, index, index + getStart());
}
static long getShardRowId(long maxShardRowIDBits, long partitionIndex, long rowID) {
if (maxShardRowIDBits <= 0 || maxShardRowIDBits >= 16) {
return rowID;
}
// assert rowID < Math.pow(2, 64 - maxShardRowIDBits)
long partition = partitionIndex & ((1L << maxShardRowIDBits) - 1);
return rowID | (partition << (64 - maxShardRowIDBits - 1));
}
public static RowIDAllocator create(
long dbId, TiTableInfo table, TiSession session, boolean unsigned, long step) {
RowIDAllocator allocator =
new RowIDAllocator(table.getMaxShardRowIDBits(), dbId, step, session);
if (unsigned) {
allocator.initUnsigned(session.createSnapshot(), table.getId(), table.getMaxShardRowIDBits());
} else {
allocator.initSigned(session.createSnapshot(), table.getId(), table.getMaxShardRowIDBits());
}
return allocator;
}
public long getStart() {
return end - step;
}
public long getEnd() {
return end;
}
// set key value pair to tikv via two phase committer protocol.
private void set(ByteString key, byte[] value) {
TwoPhaseCommitter twoPhaseCommitter =
new TwoPhaseCommitter(session, session.getTimestamp().getVersion());
twoPhaseCommitter.prewritePrimaryKey(
ConcreteBackOffer.newCustomBackOff(BackOffer.PREWRITE_MAX_BACKOFF),
key.toByteArray(),
value);
twoPhaseCommitter.commitPrimaryKey(
ConcreteBackOffer.newCustomBackOff(BackOffer.BATCH_COMMIT_BACKOFF),
key.toByteArray(),
session.getTimestamp().getVersion());
try {
twoPhaseCommitter.close();
} catch (Throwable ignored) {
}
}
private void updateMeta(ByteString key, byte[] oldVal, Snapshot snapshot) {
// 1. encode hash meta key
// 2. load meta via hash meta key from TiKV
// 3. update meta's filed count and set it back to TiKV
CodecDataOutput cdo = new CodecDataOutput();
ByteString metaKey = MetaCodec.encodeHashMetaKey(cdo, key.toByteArray());
long fieldCount;
ByteString metaVal = snapshot.get(metaKey);
// decode long from bytes
// big endian the 8 bytes
fieldCount = new CodecDataInput(metaVal.toByteArray()).readLong();
// update meta field count only oldVal is null
if (oldVal == null || oldVal.length == 0) {
fieldCount++;
cdo.reset();
cdo.writeLong(fieldCount);
set(metaKey, cdo.toBytes());
}
}
private long updateHash(
ByteString key,
ByteString field,
Function<byte[], byte[]> calculateNewVal,
Snapshot snapshot) {
// 1. encode hash data key
// 2. get value in byte from get operation
// 3. calculate new value via calculateNewVal
// 4. check old value equals to new value or not
// 5. set the new value back to TiKV via 2pc
// 6. encode a hash meta key
// 7. update a hash meta field count if needed
CodecDataOutput cdo = new CodecDataOutput();
MetaCodec.encodeHashDataKey(cdo, key.toByteArray(), field.toByteArray());
ByteString dataKey = cdo.toByteString();
byte[] oldVal = snapshot.get(dataKey.toByteArray());
byte[] newVal = calculateNewVal.apply(oldVal);
if (Arrays.equals(newVal, oldVal)) {
// not need to update
return 0L;
}
set(dataKey, newVal);
updateMeta(key, oldVal, snapshot);
return Long.parseLong(new String(newVal));
}
private static boolean isDBExisted(long dbId, Snapshot snapshot) {
ByteString dbKey = MetaCodec.encodeDatabaseID(dbId);
ByteString json = MetaCodec.hashGet(MetaCodec.KEY_DBs, dbKey, snapshot);
return json != null && !json.isEmpty();
}
private static boolean isTableExisted(long dbId, long tableId, Snapshot snapshot) {
ByteString dbKey = MetaCodec.encodeDatabaseID(dbId);
ByteString tableKey = MetaCodec.tableKey(tableId);
return !MetaCodec.hashGet(dbKey, tableKey, snapshot).isEmpty();
}
public static boolean shardRowBitsOverflow(
long base, long step, long shardRowBits, boolean reservedSignBit) {
long signBit = reservedSignBit ? 1 : 0;
long mask = ((1L << shardRowBits) - 1) << (64 - shardRowBits - signBit);
if (reservedSignBit) {
return ((base + step) & mask) > 0;
} else {
return Long.compareUnsigned((base + step) & mask, 0) > 0;
}
}
/**
* read current row id from TiKV and write the calculated value back to TiKV. The calculation rule
* is start(read from TiKV) + step.
*/
public long udpateAllocateId(
long dbId, long tableId, long step, Snapshot snapshot, long shard, boolean hasSignedBit) {
if (isDBExisted(dbId, snapshot) && isTableExisted(dbId, tableId, snapshot)) {
return updateHash(
MetaCodec.encodeDatabaseID(dbId),
MetaCodec.autoTableIDKey(tableId),
(oldVal) -> {
long base = 0;
if (oldVal != null && oldVal.length != 0) {
base = Long.parseLong(new String(oldVal));
}
if (shard >= 1 && shardRowBitsOverflow(base, step, shard, hasSignedBit)) {
throw new AllocateRowIDOverflowException(base, step, shard);
}
base += step;
return String.valueOf(base).getBytes();
},
snapshot);
}
throw new IllegalArgumentException("table or database is not existed");
}
/** read current row id from TiKV according to database id and table id. */
public static long getAllocateId(long dbId, long tableId, Snapshot snapshot) {
if (isDBExisted(dbId, snapshot) && isTableExisted(dbId, tableId, snapshot)) {
ByteString dbKey = MetaCodec.encodeDatabaseID(dbId);
ByteString tblKey = MetaCodec.autoTableIDKey(tableId);
ByteString val = MetaCodec.hashGet(dbKey, tblKey, snapshot);
if (val.isEmpty()) return 0L;
return Long.parseLong(val.toStringUtf8());
}
throw new IllegalArgumentException("table or database is not existed");
}
private void initSigned(Snapshot snapshot, long tableId, long shard) {
// get new start from TiKV, and calculate new end and set it back to TiKV.
long newStart = getAllocateId(dbId, tableId, snapshot);
long tmpStep = Math.min(Long.MAX_VALUE - newStart, step);
if (tmpStep != step) {
throw new TiBatchWriteException("cannot allocate ids for this write");
}
if (newStart == Long.MAX_VALUE) {
throw new TiBatchWriteException("cannot allocate more ids since it ");
}
end = udpateAllocateId(dbId, tableId, tmpStep, snapshot, shard, true);
}
private void initUnsigned(Snapshot snapshot, long tableId, long shard) {
// get new start from TiKV, and calculate new end and set it back to TiKV.
long newStart = getAllocateId(dbId, tableId, snapshot);
// for unsigned long, -1L is max value.
long tmpStep = UnsignedLongs.min(-1L - newStart, step);
if (tmpStep != step) {
throw new TiBatchWriteException("cannot allocate ids for this write");
}
// when compare unsigned long, the min value is largest value.
if (UnsignedLongs.compare(newStart, -1L) == 0) {
throw new TiBatchWriteException(
"cannot allocate more ids since the start reaches " + "unsigned long's max value ");
}
end = udpateAllocateId(dbId, tableId, tmpStep, snapshot, shard, false);
}
}

View File

@ -24,7 +24,7 @@ public class RegionException extends TiKVException {
private final Error regionErr; private final Error regionErr;
public RegionException(Error regionErr) { public RegionException(Error regionErr) {
super("Region Exception occurred" + regionErr.getMessage()); super("Region Exception occurred " + regionErr.getMessage());
this.regionErr = regionErr; this.regionErr = regionErr;
} }

View File

@ -123,9 +123,7 @@ public class KVErrorHandler<RespT> implements ErrorHandler<RespT> {
@Override @Override
public boolean handleResponseError(BackOffer backOffer, RespT resp) { public boolean handleResponseError(BackOffer backOffer, RespT resp) {
if (resp == null) { if (resp == null) {
String msg = String msg = String.format("Request Failed with unknown reason for [%s]", recv.getRegion());
String.format(
"Request Failed with unknown reason for region region [%s]", recv.getRegion());
logger.warn(msg); logger.warn(msg);
return handleRequestError(backOffer, new GrpcException(msg)); return handleRequestError(backOffer, new GrpcException(msg));
} }
@ -158,9 +156,7 @@ public class KVErrorHandler<RespT> implements ErrorHandler<RespT> {
// onNotLeader is only needed when updateLeader succeeds, thus switch // onNotLeader is only needed when updateLeader succeeds, thus switch
// to a new store address. // to a new store address.
TiRegion newRegion = this.regionManager.updateLeader(recv.getRegion(), newStoreId); TiRegion newRegion = this.regionManager.updateLeader(recv.getRegion(), newStoreId);
retry = retry = newRegion != null && recv.onNotLeader(newRegion);
newRegion != null
&& recv.onNotLeader(this.regionManager.getStoreById(newStoreId), newRegion);
backOffFuncType = BackOffFunction.BackOffFuncType.BoUpdateLeader; backOffFuncType = BackOffFunction.BackOffFuncType.BoUpdateLeader;
} else { } else {

View File

@ -48,7 +48,9 @@ public class PDErrorHandler<RespT> implements ErrorHandler<RespT> {
@Override @Override
public boolean handleResponseError(BackOffer backOffer, RespT resp) { public boolean handleResponseError(BackOffer backOffer, RespT resp) {
if (resp == null) { if (resp == null) {
return false; String msg = String.format("PD Request Failed with unknown reason");
logger.warn(msg);
return handleRequestError(backOffer, new GrpcException(msg));
} }
PDError error = getError.apply(resp); PDError error = getError.apply(resp);
if (error != null) { if (error != null) {
@ -56,7 +58,7 @@ public class PDErrorHandler<RespT> implements ErrorHandler<RespT> {
case PD_ERROR: case PD_ERROR:
backOffer.doBackOff( backOffer.doBackOff(
BackOffFunction.BackOffFuncType.BoPDRPC, new GrpcException(error.toString())); BackOffFunction.BackOffFuncType.BoPDRPC, new GrpcException(error.toString()));
client.updateLeader(); client.updateLeaderOrforwardFollower();
return true; return true;
case REGION_PEER_NOT_ELECTED: case REGION_PEER_NOT_ELECTED:
logger.debug(error.getMessage()); logger.debug(error.getMessage());
@ -73,6 +75,7 @@ public class PDErrorHandler<RespT> implements ErrorHandler<RespT> {
@Override @Override
public boolean handleRequestError(BackOffer backOffer, Exception e) { public boolean handleRequestError(BackOffer backOffer, Exception e) {
backOffer.doBackOff(BackOffFunction.BackOffFuncType.BoPDRPC, e); backOffer.doBackOff(BackOffFunction.BackOffFuncType.BoPDRPC, e);
client.updateLeaderOrforwardFollower();
return true; return true;
} }
} }

View File

@ -27,11 +27,11 @@ import org.tikv.common.key.Key;
import org.tikv.common.region.RegionStoreClient; import org.tikv.common.region.RegionStoreClient;
import org.tikv.common.region.RegionStoreClient.RegionStoreClientBuilder; import org.tikv.common.region.RegionStoreClient.RegionStoreClientBuilder;
import org.tikv.common.region.TiRegion; import org.tikv.common.region.TiRegion;
import org.tikv.common.region.TiStore;
import org.tikv.common.util.BackOffer; import org.tikv.common.util.BackOffer;
import org.tikv.common.util.ConcreteBackOffer; import org.tikv.common.util.ConcreteBackOffer;
import org.tikv.common.util.Pair; import org.tikv.common.util.Pair;
import org.tikv.kvproto.Kvrpcpb; import org.tikv.kvproto.Kvrpcpb;
import org.tikv.kvproto.Metapb;
public class ConcreteScanIterator extends ScanIterator { public class ConcreteScanIterator extends ScanIterator {
private final long version; private final long version;
@ -82,10 +82,10 @@ public class ConcreteScanIterator extends ScanIterator {
private ByteString resolveCurrentLock(Kvrpcpb.KvPair current) { private ByteString resolveCurrentLock(Kvrpcpb.KvPair current) {
logger.warn(String.format("resolve current key error %s", current.getError().toString())); logger.warn(String.format("resolve current key error %s", current.getError().toString()));
Pair<TiRegion, Metapb.Store> pair = Pair<TiRegion, TiStore> pair =
builder.getRegionManager().getRegionStorePairByKey(current.getKey()); builder.getRegionManager().getRegionStorePairByKey(current.getKey());
TiRegion region = pair.first; TiRegion region = pair.first;
Metapb.Store store = pair.second; TiStore store = pair.second;
BackOffer backOffer = ConcreteBackOffer.newGetBackOff(); BackOffer backOffer = ConcreteBackOffer.newGetBackOff();
try (RegionStoreClient client = builder.build(region, store)) { try (RegionStoreClient client = builder.build(region, store)) {
return client.get(backOffer, current.getKey(), version); return client.get(backOffer, current.getKey(), version);

View File

@ -27,7 +27,11 @@ import java.util.List;
import org.tikv.common.TiSession; import org.tikv.common.TiSession;
import org.tikv.common.codec.Codec.IntegerCodec; import org.tikv.common.codec.Codec.IntegerCodec;
import org.tikv.common.codec.CodecDataInput; import org.tikv.common.codec.CodecDataInput;
import org.tikv.common.columnar.*; import org.tikv.common.columnar.BatchedTiChunkColumnVector;
import org.tikv.common.columnar.TiChunk;
import org.tikv.common.columnar.TiChunkColumnVector;
import org.tikv.common.columnar.TiColumnVector;
import org.tikv.common.columnar.TiRowColumnVector;
import org.tikv.common.columnar.datatypes.CHType; import org.tikv.common.columnar.datatypes.CHType;
import org.tikv.common.meta.TiDAGRequest; import org.tikv.common.meta.TiDAGRequest;
import org.tikv.common.operation.SchemaInfer; import org.tikv.common.operation.SchemaInfer;

View File

@ -32,12 +32,12 @@ import org.tikv.common.meta.TiDAGRequest.PushDownType;
import org.tikv.common.operation.SchemaInfer; import org.tikv.common.operation.SchemaInfer;
import org.tikv.common.region.RegionStoreClient; import org.tikv.common.region.RegionStoreClient;
import org.tikv.common.region.TiRegion; import org.tikv.common.region.TiRegion;
import org.tikv.common.region.TiStore;
import org.tikv.common.region.TiStoreType; import org.tikv.common.region.TiStoreType;
import org.tikv.common.util.BackOffer; import org.tikv.common.util.BackOffer;
import org.tikv.common.util.ConcreteBackOffer; import org.tikv.common.util.ConcreteBackOffer;
import org.tikv.common.util.RangeSplitter; import org.tikv.common.util.RangeSplitter;
import org.tikv.kvproto.Coprocessor; import org.tikv.kvproto.Coprocessor;
import org.tikv.kvproto.Metapb;
public abstract class DAGIterator<T> public abstract class DAGIterator<T>
extends org.tikv.common.operation.iterator.CoprocessorIterator<T> { extends org.tikv.common.operation.iterator.CoprocessorIterator<T> {
@ -204,7 +204,7 @@ public abstract class DAGIterator<T>
} }
List<Coprocessor.KeyRange> ranges = task.getRanges(); List<Coprocessor.KeyRange> ranges = task.getRanges();
TiRegion region = task.getRegion(); TiRegion region = task.getRegion();
Metapb.Store store = task.getStore(); TiStore store = task.getStore();
try { try {
RegionStoreClient client = RegionStoreClient client =
@ -246,7 +246,7 @@ public abstract class DAGIterator<T>
private Iterator<SelectResponse> processByStreaming(RangeSplitter.RegionTask regionTask) { private Iterator<SelectResponse> processByStreaming(RangeSplitter.RegionTask regionTask) {
List<Coprocessor.KeyRange> ranges = regionTask.getRanges(); List<Coprocessor.KeyRange> ranges = regionTask.getRanges();
TiRegion region = regionTask.getRegion(); TiRegion region = regionTask.getRegion();
Metapb.Store store = regionTask.getStore(); TiStore store = regionTask.getStore();
RegionStoreClient client; RegionStoreClient client;
try { try {

View File

@ -78,26 +78,22 @@ public class RawScanIterator extends ScanIterator {
endOfScan = true; endOfScan = true;
return false; return false;
} }
// continue when cache is empty but not null
while (currentCache != null && currentCache.isEmpty()) {
if (cacheLoadFails()) {
return false;
}
}
return notEndOfScan(); return notEndOfScan();
} }
private Kvrpcpb.KvPair getCurrent() { private Kvrpcpb.KvPair getCurrent() {
if (isCacheDrained()) {
return null;
}
--limit; --limit;
return currentCache.get(index++); return currentCache.get(index++);
} }
@Override @Override
public Kvrpcpb.KvPair next() { public Kvrpcpb.KvPair next() {
Kvrpcpb.KvPair kv; return getCurrent();
// continue when cache is empty but not null
for (kv = getCurrent(); currentCache != null && kv == null; kv = getCurrent()) {
if (cacheLoadFails()) {
return null;
}
}
return kv;
} }
} }

View File

@ -50,11 +50,8 @@ public abstract class ScanIterator implements Iterator<Kvrpcpb.KvPair> {
int limit, int limit,
boolean keyOnly) { boolean keyOnly) {
this.startKey = requireNonNull(startKey, "start key is null"); this.startKey = requireNonNull(startKey, "start key is null");
if (startKey.isEmpty()) {
throw new IllegalArgumentException("start key cannot be empty");
}
this.endKey = Key.toRawKey(requireNonNull(endKey, "end key is null")); this.endKey = Key.toRawKey(requireNonNull(endKey, "end key is null"));
this.hasEndKey = !endKey.equals(ByteString.EMPTY); this.hasEndKey = !endKey.isEmpty();
this.limit = limit; this.limit = limit;
this.keyOnly = keyOnly; this.keyOnly = keyOnly;
this.conf = conf; this.conf = conf;
@ -74,7 +71,7 @@ public abstract class ScanIterator implements Iterator<Kvrpcpb.KvPair> {
if (endOfScan || processingLastBatch) { if (endOfScan || processingLastBatch) {
return true; return true;
} }
if (startKey == null || startKey.isEmpty()) { if (startKey == null) {
return true; return true;
} }
try { try {
@ -107,7 +104,8 @@ public abstract class ScanIterator implements Iterator<Kvrpcpb.KvPair> {
startKey = lastKey.next().toByteString(); startKey = lastKey.next().toByteString();
} }
// notify last batch if lastKey is greater than or equal to endKey // notify last batch if lastKey is greater than or equal to endKey
if (hasEndKey && lastKey.compareTo(endKey) >= 0) { // if startKey is empty, it indicates +
if (hasEndKey && lastKey.compareTo(endKey) >= 0 || startKey.isEmpty()) {
processingLastBatch = true; processingLastBatch = true;
startKey = null; startKey = null;
} }

View File

@ -17,6 +17,7 @@ package org.tikv.common.policy;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import io.grpc.Status; import io.grpc.Status;
import io.prometheus.client.Counter;
import io.prometheus.client.Histogram; import io.prometheus.client.Histogram;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
import org.tikv.common.exception.GrpcException; import org.tikv.common.exception.GrpcException;
@ -32,6 +33,12 @@ public abstract class RetryPolicy<RespT> {
.help("grpc request latency.") .help("grpc request latency.")
.labelNames("type") .labelNames("type")
.register(); .register();
public static final Counter GRPC_REQUEST_RETRY_NUM =
Counter.build()
.name("client_java_grpc_requests_retry_num")
.help("grpc request retry num.")
.labelNames("type")
.register();
// handles PD and TiKV's error. // handles PD and TiKV's error.
private ErrorHandler<RespT> handler; private ErrorHandler<RespT> handler;
@ -70,6 +77,7 @@ public abstract class RetryPolicy<RespT> {
// Handle request call error // Handle request call error
boolean retry = handler.handleRequestError(backOffer, e); boolean retry = handler.handleRequestError(backOffer, e);
if (retry) { if (retry) {
GRPC_REQUEST_RETRY_NUM.labels(methodName).inc();
continue; continue;
} }
} }
@ -78,7 +86,7 @@ public abstract class RetryPolicy<RespT> {
if (handler != null) { if (handler != null) {
boolean retry = handler.handleResponseError(backOffer, result); boolean retry = handler.handleResponseError(backOffer, result);
if (retry) { if (retry) {
// add retry counter GRPC_REQUEST_RETRY_NUM.labels(methodName).inc();
continue; continue;
} }
} }

View File

@ -21,6 +21,12 @@ import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import io.grpc.ManagedChannel; import io.grpc.ManagedChannel;
import io.grpc.Metadata;
import io.grpc.health.v1.HealthCheckRequest;
import io.grpc.health.v1.HealthCheckResponse;
import io.grpc.health.v1.HealthGrpc;
import io.grpc.stub.MetadataUtils;
import java.util.List;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.tikv.common.AbstractGRPCClient; import org.tikv.common.AbstractGRPCClient;
import org.tikv.common.TiConfiguration; import org.tikv.common.TiConfiguration;
@ -35,10 +41,12 @@ public abstract class AbstractRegionStoreClient
protected final RegionManager regionManager; protected final RegionManager regionManager;
protected TiRegion region; protected TiRegion region;
protected TiStore targetStore;
protected AbstractRegionStoreClient( protected AbstractRegionStoreClient(
TiConfiguration conf, TiConfiguration conf,
TiRegion region, TiRegion region,
TiStore store,
ChannelFactory channelFactory, ChannelFactory channelFactory,
TikvGrpc.TikvBlockingStub blockingStub, TikvGrpc.TikvBlockingStub blockingStub,
TikvGrpc.TikvStub asyncStub, TikvGrpc.TikvStub asyncStub,
@ -49,6 +57,7 @@ public abstract class AbstractRegionStoreClient
checkArgument(region.getLeader() != null, "Leader Peer is null"); checkArgument(region.getLeader() != null, "Leader Peer is null");
this.region = region; this.region = region;
this.regionManager = regionManager; this.regionManager = regionManager;
this.targetStore = store;
} }
public TiRegion getRegion() { public TiRegion getRegion() {
@ -71,13 +80,13 @@ public abstract class AbstractRegionStoreClient
/** /**
* onNotLeader deals with NotLeaderError and returns whether re-splitting key range is needed * onNotLeader deals with NotLeaderError and returns whether re-splitting key range is needed
* *
* @param newStore the new store presented by NotLeader Error * @param newRegion the new region presented by NotLeader Error
* @return false when re-split is needed. * @return false when re-split is needed.
*/ */
@Override @Override
public boolean onNotLeader(Metapb.Store newStore, TiRegion newRegion) { public boolean onNotLeader(TiRegion newRegion) {
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug(region + ", new leader = " + newStore.getId()); logger.debug(region + ", new leader = " + newRegion.getLeader().getStoreId());
} }
// When switch leader fails or the region changed its region epoch, // When switch leader fails or the region changed its region epoch,
// it would be necessary to re-split task's key range for new region. // it would be necessary to re-split task's key range for new region.
@ -85,7 +94,8 @@ public abstract class AbstractRegionStoreClient
return false; return false;
} }
region = newRegion; region = newRegion;
String addressStr = regionManager.getStoreById(region.getLeader().getStoreId()).getAddress(); targetStore = regionManager.getStoreById(region.getLeader().getStoreId());
String addressStr = targetStore.getStore().getAddress();
ManagedChannel channel = ManagedChannel channel =
channelFactory.getChannel(addressStr, regionManager.getPDClient().getHostMapping()); channelFactory.getChannel(addressStr, regionManager.getPDClient().getHostMapping());
blockingStub = TikvGrpc.newBlockingStub(channel); blockingStub = TikvGrpc.newBlockingStub(channel);
@ -94,20 +104,84 @@ public abstract class AbstractRegionStoreClient
} }
@Override @Override
public void onStoreNotMatch(Metapb.Store store) { public boolean onStoreUnreachable() {
String addressStr = store.getAddress(); if (!conf.getEnableGrpcForward()) {
return false;
}
if (region.getProxyStore() == null) {
if (!targetStore.isUnreachable()) {
if (checkHealth(targetStore)) {
return true;
} else {
if (targetStore.markUnreachable()) {
this.regionManager.scheduleHealthCheckJob(targetStore);
}
}
}
}
TiRegion proxyRegion = switchProxyStore();
if (proxyRegion == null) {
return false;
}
regionManager.updateRegion(region, proxyRegion);
region = proxyRegion;
String addressStr = region.getProxyStore().getStore().getAddress();
ManagedChannel channel = ManagedChannel channel =
channelFactory.getChannel(addressStr, regionManager.getPDClient().getHostMapping()); channelFactory.getChannel(addressStr, regionManager.getPDClient().getHostMapping());
blockingStub = TikvGrpc.newBlockingStub(channel); Metadata header = new Metadata();
asyncStub = TikvGrpc.newStub(channel); header.put(TiConfiguration.FORWARD_META_DATA_KEY, targetStore.getStore().getAddress());
if (region.getLeader().getStoreId() != store.getId()) { blockingStub = MetadataUtils.attachHeaders(TikvGrpc.newBlockingStub(channel), header);
logger.warn( asyncStub = MetadataUtils.attachHeaders(TikvGrpc.newStub(channel), header);
"store_not_match may occur? " return true;
+ region }
+ ", original store = "
+ store.getId() private boolean checkHealth(TiStore store) {
+ " address = " if (store.getStore() == null) {
+ addressStr); return false;
} }
String addressStr = store.getStore().getAddress();
ManagedChannel channel =
channelFactory.getChannel(addressStr, regionManager.getPDClient().getHostMapping());
HealthGrpc.HealthBlockingStub stub =
HealthGrpc.newBlockingStub(channel)
.withDeadlineAfter(conf.getGrpcHealthCheckTimeout(), TimeUnit.MILLISECONDS);
HealthCheckRequest req = HealthCheckRequest.newBuilder().build();
try {
HealthCheckResponse resp = stub.check(req);
if (resp.getStatus() != HealthCheckResponse.ServingStatus.SERVING) {
return false;
}
} catch (Exception e) {
return false;
}
return true;
}
private TiRegion switchProxyStore() {
boolean hasVisitedStore = false;
List<Metapb.Peer> peers = region.getFollowerList();
for (int i = 0; i < peers.size() * 2; i++) {
int idx = i % peers.size();
Metapb.Peer peer = peers.get(idx);
if (peer.getStoreId() != region.getLeader().getStoreId()) {
if (region.getProxyStore() == null) {
TiStore store = regionManager.getStoreById(peer.getStoreId());
if (checkHealth(store)) {
return region.switchProxyStore(store);
}
} else {
TiStore proxyStore = region.getProxyStore();
if (peer.getStoreId() == proxyStore.getStore().getId()) {
hasVisitedStore = true;
} else if (hasVisitedStore) {
proxyStore = regionManager.getStoreById(peer.getStoreId());
if (!proxyStore.isUnreachable() && checkHealth(proxyStore)) {
return region.switchProxyStore(proxyStore);
}
}
}
}
}
return null;
} }
} }

View File

@ -17,12 +17,11 @@
package org.tikv.common.region; package org.tikv.common.region;
import org.tikv.kvproto.Metapb.Store;
public interface RegionErrorReceiver { public interface RegionErrorReceiver {
boolean onNotLeader(Store store, TiRegion region); boolean onNotLeader(TiRegion region);
void onStoreNotMatch(Store store); /// return whether we need to retry this request.
boolean onStoreUnreachable();
TiRegion getRegion(); TiRegion getRegion();
} }

View File

@ -28,6 +28,9 @@ import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.function.Function; import java.util.function.Function;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -37,11 +40,11 @@ import org.tikv.common.exception.GrpcException;
import org.tikv.common.exception.TiClientInternalException; import org.tikv.common.exception.TiClientInternalException;
import org.tikv.common.key.Key; import org.tikv.common.key.Key;
import org.tikv.common.util.BackOffer; import org.tikv.common.util.BackOffer;
import org.tikv.common.util.ChannelFactory;
import org.tikv.common.util.ConcreteBackOffer; import org.tikv.common.util.ConcreteBackOffer;
import org.tikv.common.util.Pair; import org.tikv.common.util.Pair;
import org.tikv.kvproto.Metapb; import org.tikv.kvproto.Metapb;
import org.tikv.kvproto.Metapb.Peer; import org.tikv.kvproto.Metapb.Peer;
import org.tikv.kvproto.Metapb.Store;
import org.tikv.kvproto.Metapb.StoreState; import org.tikv.kvproto.Metapb.StoreState;
@SuppressWarnings("UnstableApiUsage") @SuppressWarnings("UnstableApiUsage")
@ -50,7 +53,8 @@ public class RegionManager {
// TODO: the region cache logic need rewrite. // TODO: the region cache logic need rewrite.
// https://github.com/pingcap/tispark/issues/1170 // https://github.com/pingcap/tispark/issues/1170
private final RegionCache cache; private final RegionCache cache;
private final boolean isReplicaRead; private final ScheduledExecutorService executor;
private final UnreachableStoreChecker storeChecker;
private final Function<CacheInvalidateEvent, Void> cacheInvalidateCallback; private final Function<CacheInvalidateEvent, Void> cacheInvalidateCallback;
@ -65,14 +69,40 @@ public class RegionManager {
public RegionManager( public RegionManager(
ReadOnlyPDClient pdClient, Function<CacheInvalidateEvent, Void> cacheInvalidateCallback) { ReadOnlyPDClient pdClient, Function<CacheInvalidateEvent, Void> cacheInvalidateCallback) {
this.cache = new RegionCache(pdClient); this.cache = new RegionCache(pdClient);
this.isReplicaRead = pdClient.isReplicaRead();
this.cacheInvalidateCallback = cacheInvalidateCallback; this.cacheInvalidateCallback = cacheInvalidateCallback;
this.executor = null;
this.storeChecker = null;
}
public RegionManager(
ReadOnlyPDClient pdClient,
Function<CacheInvalidateEvent, Void> cacheInvalidateCallback,
ChannelFactory channelFactory,
boolean enableGrpcForward) {
this.cache = new RegionCache(pdClient);
this.cacheInvalidateCallback = cacheInvalidateCallback;
if (enableGrpcForward) {
UnreachableStoreChecker storeChecker = new UnreachableStoreChecker(channelFactory, pdClient);
this.storeChecker = storeChecker;
this.executor = Executors.newScheduledThreadPool(1);
this.executor.scheduleAtFixedRate(storeChecker, 10, 10, TimeUnit.SECONDS);
} else {
this.storeChecker = null;
this.executor = null;
}
} }
public RegionManager(ReadOnlyPDClient pdClient) { public RegionManager(ReadOnlyPDClient pdClient) {
this.cache = new RegionCache(pdClient); this.cache = new RegionCache(pdClient);
this.isReplicaRead = pdClient.isReplicaRead();
this.cacheInvalidateCallback = null; this.cacheInvalidateCallback = null;
this.storeChecker = null;
this.executor = null;
}
public synchronized void close() {
if (this.executor != null) {
this.executor.shutdownNow();
}
} }
public Function<CacheInvalidateEvent, Void> getCacheInvalidateCallback() { public Function<CacheInvalidateEvent, Void> getCacheInvalidateCallback() {
@ -102,19 +132,19 @@ public class RegionManager {
return cache.getRegionById(ConcreteBackOffer.newGetBackOff(), regionId); return cache.getRegionById(ConcreteBackOffer.newGetBackOff(), regionId);
} }
public Pair<TiRegion, Store> getRegionStorePairByKey(ByteString key, BackOffer backOffer) { public Pair<TiRegion, TiStore> getRegionStorePairByKey(ByteString key, BackOffer backOffer) {
return getRegionStorePairByKey(key, TiStoreType.TiKV, backOffer); return getRegionStorePairByKey(key, TiStoreType.TiKV, backOffer);
} }
public Pair<TiRegion, Store> getRegionStorePairByKey(ByteString key) { public Pair<TiRegion, TiStore> getRegionStorePairByKey(ByteString key) {
return getRegionStorePairByKey(key, TiStoreType.TiKV); return getRegionStorePairByKey(key, TiStoreType.TiKV);
} }
public Pair<TiRegion, Store> getRegionStorePairByKey(ByteString key, TiStoreType storeType) { public Pair<TiRegion, TiStore> getRegionStorePairByKey(ByteString key, TiStoreType storeType) {
return getRegionStorePairByKey(key, storeType, ConcreteBackOffer.newGetBackOff()); return getRegionStorePairByKey(key, storeType, ConcreteBackOffer.newGetBackOff());
} }
public Pair<TiRegion, Store> getRegionStorePairByKey( public Pair<TiRegion, TiStore> getRegionStorePairByKey(
ByteString key, TiStoreType storeType, BackOffer backOffer) { ByteString key, TiStoreType storeType, BackOffer backOffer) {
TiRegion region = cache.getRegionByKey(key, backOffer); TiRegion region = cache.getRegionByKey(key, backOffer);
if (region == null) { if (region == null) {
@ -124,20 +154,15 @@ public class RegionManager {
throw new TiClientInternalException("Region invalid: " + region.toString()); throw new TiClientInternalException("Region invalid: " + region.toString());
} }
Store store = null; TiStore store = null;
if (storeType == TiStoreType.TiKV) { if (storeType == TiStoreType.TiKV) {
if (isReplicaRead) { Peer peer = region.getCurrentReplica();
Peer peer = region.getCurrentFollower(); store = cache.getStoreById(peer.getStoreId(), backOffer);
store = cache.getStoreById(peer.getStoreId(), backOffer);
} else {
Peer leader = region.getLeader();
store = cache.getStoreById(leader.getStoreId(), backOffer);
}
} else { } else {
outerLoop: outerLoop:
for (Peer peer : region.getLearnerList()) { for (Peer peer : region.getLearnerList()) {
Store s = getStoreById(peer.getStoreId(), backOffer); TiStore s = getStoreById(peer.getStoreId(), backOffer);
for (Metapb.StoreLabel label : s.getLabelsList()) { for (Metapb.StoreLabel label : s.getStore().getLabelsList()) {
if (label.getKey().equals(storeType.getLabelKey()) if (label.getKey().equals(storeType.getLabelKey())
&& label.getValue().equals(storeType.getLabelValue())) { && label.getValue().equals(storeType.getLabelValue())) {
store = s; store = s;
@ -159,11 +184,11 @@ public class RegionManager {
return Pair.create(region, store); return Pair.create(region, store);
} }
public Store getStoreById(long id) { public TiStore getStoreById(long id) {
return getStoreById(id, ConcreteBackOffer.newGetBackOff()); return getStoreById(id, ConcreteBackOffer.newGetBackOff());
} }
public Store getStoreById(long id, BackOffer backOffer) { public TiStore getStoreById(long id, BackOffer backOffer) {
return cache.getStoreById(id, backOffer); return cache.getStoreById(id, backOffer);
} }
@ -172,23 +197,25 @@ public class RegionManager {
} }
public synchronized TiRegion updateLeader(TiRegion region, long storeId) { public synchronized TiRegion updateLeader(TiRegion region, long storeId) {
TiRegion r = cache.getRegionFromCache(region.getId()); TiRegion newRegion = region.switchPeer(storeId);
if (r != null) { if (cache.updateRegion(region, newRegion)) {
if (r.getLeader().getStoreId() == storeId) { return newRegion;
return r;
}
TiRegion newRegion = r.switchPeer(storeId);
if (newRegion != null) {
cache.putRegion(newRegion);
return newRegion;
}
// failed to switch leader, possibly region is outdated, we need to drop region cache from
// regionCache
logger.warn("Cannot find peer when updating leader (" + region.getId() + "," + storeId + ")");
} }
// failed to switch leader, possibly region is outdated, we need to drop region cache from
// regionCache
logger.warn("Cannot find peer when updating leader (" + region.getId() + "," + storeId + ")");
return null; return null;
} }
public synchronized boolean updateRegion(TiRegion oldRegion, TiRegion region) {
return cache.updateRegion(oldRegion, region);
}
/** Clears all cache when some unexpected error occurs. */
public void clearRegionCache() {
cache.clearAll();
}
/** /**
* Clears all cache when a TiKV server does not respond * Clears all cache when a TiKV server does not respond
* *
@ -199,8 +226,10 @@ public class RegionManager {
} }
private void onRequestFail(TiRegion region, long storeId) { private void onRequestFail(TiRegion region, long storeId) {
cache.invalidateRegion(region); if (this.storeChecker != null) {
cache.invalidateAllRegionForStore(storeId); cache.invalidateRegion(region);
cache.invalidateAllRegionForStore(storeId);
}
} }
public void invalidateStore(long storeId) { public void invalidateStore(long storeId) {
@ -211,9 +240,13 @@ public class RegionManager {
cache.invalidateRegion(region); cache.invalidateRegion(region);
} }
public void scheduleHealthCheckJob(TiStore store) {
this.storeChecker.scheduleStoreHealthCheck(store);
}
public static class RegionCache { public static class RegionCache {
private final Map<Long, TiRegion> regionCache; private final Map<Long, TiRegion> regionCache;
private final Map<Long, Store> storeCache; private final Map<Long, TiStore> storeCache;
private final RangeMap<Key, Long> keyToRegionIdCache; private final RangeMap<Key, Long> keyToRegionIdCache;
private final ReadOnlyPDClient pdClient; private final ReadOnlyPDClient pdClient;
@ -303,6 +336,26 @@ public class RegionManager {
} }
} }
public synchronized boolean updateRegion(TiRegion expected, TiRegion region) {
try {
if (logger.isDebugEnabled()) {
logger.debug(String.format("invalidateRegion ID[%s]", region.getId()));
}
TiRegion oldRegion = regionCache.get(region.getId());
if (expected != oldRegion) {
return false;
} else {
if (oldRegion != null) {
keyToRegionIdCache.remove(makeRange(oldRegion.getStartKey(), oldRegion.getEndKey()));
}
putRegion(region);
return true;
}
} catch (Exception ignore) {
return false;
}
}
public synchronized void invalidateAllRegionForStore(long storeId) { public synchronized void invalidateAllRegionForStore(long storeId) {
List<TiRegion> regionToRemove = new ArrayList<>(); List<TiRegion> regionToRemove = new ArrayList<>();
for (TiRegion r : regionCache.values()) { for (TiRegion r : regionCache.values()) {
@ -316,22 +369,25 @@ public class RegionManager {
// remove region // remove region
for (TiRegion r : regionToRemove) { for (TiRegion r : regionToRemove) {
regionCache.remove(r.getId());
keyToRegionIdCache.remove(makeRange(r.getStartKey(), r.getEndKey())); keyToRegionIdCache.remove(makeRange(r.getStartKey(), r.getEndKey()));
regionCache.remove(r.getId());
} }
} }
public synchronized void invalidateStore(long storeId) { public synchronized void invalidateStore(long storeId) {
storeCache.remove(storeId); TiStore store = storeCache.remove(storeId);
if (store != null) {
store.markReachable();
}
} }
public synchronized Store getStoreById(long id, BackOffer backOffer) { public synchronized TiStore getStoreById(long id, BackOffer backOffer) {
try { try {
Store store = storeCache.get(id); TiStore store = storeCache.get(id);
if (store == null) { if (store == null) {
store = pdClient.getStore(backOffer, id); store = new TiStore(pdClient.getStore(backOffer, id));
} }
if (store.getState().equals(StoreState.Tombstone)) { if (store.getStore().getState().equals(StoreState.Tombstone)) {
return null; return null;
} }
storeCache.put(id, store); storeCache.put(id, store);
@ -340,5 +396,10 @@ public class RegionManager {
throw new GrpcException(e); throw new GrpcException(e);
} }
} }
public synchronized void clearAll() {
keyToRegionIdCache.clear();
regionCache.clear();
}
} }
} }

View File

@ -26,6 +26,8 @@ import com.google.protobuf.InvalidProtocolBufferException;
import com.pingcap.tidb.tipb.DAGRequest; import com.pingcap.tidb.tipb.DAGRequest;
import com.pingcap.tidb.tipb.SelectResponse; import com.pingcap.tidb.tipb.SelectResponse;
import io.grpc.ManagedChannel; import io.grpc.ManagedChannel;
import io.grpc.Metadata;
import io.grpc.stub.MetadataUtils;
import io.prometheus.client.Histogram; import io.prometheus.client.Histogram;
import java.util.*; import java.util.*;
import java.util.function.Supplier; import java.util.function.Supplier;
@ -43,7 +45,6 @@ import org.tikv.common.util.*;
import org.tikv.kvproto.Coprocessor; import org.tikv.kvproto.Coprocessor;
import org.tikv.kvproto.Errorpb; import org.tikv.kvproto.Errorpb;
import org.tikv.kvproto.Kvrpcpb.*; import org.tikv.kvproto.Kvrpcpb.*;
import org.tikv.kvproto.Metapb.Store;
import org.tikv.kvproto.TikvGrpc; import org.tikv.kvproto.TikvGrpc;
import org.tikv.kvproto.TikvGrpc.TikvBlockingStub; import org.tikv.kvproto.TikvGrpc.TikvBlockingStub;
import org.tikv.kvproto.TikvGrpc.TikvStub; import org.tikv.kvproto.TikvGrpc.TikvStub;
@ -87,7 +88,7 @@ public class RegionStoreClient extends AbstractRegionStoreClient {
private RegionStoreClient( private RegionStoreClient(
TiConfiguration conf, TiConfiguration conf,
TiRegion region, TiRegion region,
String storeVersion, TiStore store,
TiStoreType storeType, TiStoreType storeType,
ChannelFactory channelFactory, ChannelFactory channelFactory,
TikvBlockingStub blockingStub, TikvBlockingStub blockingStub,
@ -95,15 +96,15 @@ public class RegionStoreClient extends AbstractRegionStoreClient {
RegionManager regionManager, RegionManager regionManager,
PDClient pdClient, PDClient pdClient,
RegionStoreClient.RegionStoreClientBuilder clientBuilder) { RegionStoreClient.RegionStoreClientBuilder clientBuilder) {
super(conf, region, channelFactory, blockingStub, asyncStub, regionManager); super(conf, region, store, channelFactory, blockingStub, asyncStub, regionManager);
this.storeType = storeType; this.storeType = storeType;
if (this.storeType == TiStoreType.TiKV) { if (this.storeType == TiStoreType.TiKV) {
this.lockResolverClient = this.lockResolverClient =
AbstractLockResolverClient.getInstance( AbstractLockResolverClient.getInstance(
storeVersion,
conf, conf,
region, region,
store,
this.blockingStub, this.blockingStub,
this.asyncStub, this.asyncStub,
channelFactory, channelFactory,
@ -112,10 +113,10 @@ public class RegionStoreClient extends AbstractRegionStoreClient {
clientBuilder); clientBuilder);
} else { } else {
Store tikvStore = TiStore tikvStore =
regionManager.getRegionStorePairByKey(region.getStartKey(), TiStoreType.TiKV).second; regionManager.getRegionStorePairByKey(region.getStartKey(), TiStoreType.TiKV).second;
String addressStr = tikvStore.getAddress(); String addressStr = tikvStore.getStore().getAddress();
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug(String.format("Create region store client on address %s", addressStr)); logger.debug(String.format("Create region store client on address %s", addressStr));
} }
@ -126,9 +127,9 @@ public class RegionStoreClient extends AbstractRegionStoreClient {
this.lockResolverClient = this.lockResolverClient =
AbstractLockResolverClient.getInstance( AbstractLockResolverClient.getInstance(
tikvStore.getVersion(),
conf, conf,
region, region,
tikvStore,
tikvBlockingStub, tikvBlockingStub,
tikvAsyncStub, tikvAsyncStub,
channelFactory, channelFactory,
@ -169,7 +170,7 @@ public class RegionStoreClient extends AbstractRegionStoreClient {
Supplier<GetRequest> factory = Supplier<GetRequest> factory =
() -> () ->
GetRequest.newBuilder() GetRequest.newBuilder()
.setContext(region.getContext(getResolvedLocks(version))) .setContext(region.getReplicaContext(getResolvedLocks(version), this.storeType))
.setKey(key) .setKey(key)
.setVersion(version) .setVersion(version)
.build(); .build();
@ -214,7 +215,7 @@ public class RegionStoreClient extends AbstractRegionStoreClient {
Supplier<BatchGetRequest> request = Supplier<BatchGetRequest> request =
() -> () ->
BatchGetRequest.newBuilder() BatchGetRequest.newBuilder()
.setContext(region.getContext(getResolvedLocks(version))) .setContext(region.getReplicaContext(getResolvedLocks(version), this.storeType))
.addAllKeys(keys) .addAllKeys(keys)
.setVersion(version) .setVersion(version)
.build(); .build();
@ -277,7 +278,7 @@ public class RegionStoreClient extends AbstractRegionStoreClient {
Supplier<ScanRequest> request = Supplier<ScanRequest> request =
() -> () ->
ScanRequest.newBuilder() ScanRequest.newBuilder()
.setContext(region.getContext(getResolvedLocks(version))) .setContext(region.getReplicaContext(getResolvedLocks(version), this.storeType))
.setStartKey(startKey) .setStartKey(startKey)
.setVersion(version) .setVersion(version)
.setKeyOnly(keyOnly) .setKeyOnly(keyOnly)
@ -379,7 +380,7 @@ public class RegionStoreClient extends AbstractRegionStoreClient {
() -> () ->
getIsV4() getIsV4()
? PrewriteRequest.newBuilder() ? PrewriteRequest.newBuilder()
.setContext(region.getContext()) .setContext(region.getReplicaContext(storeType))
.setStartVersion(startTs) .setStartVersion(startTs)
.setPrimaryLock(primaryLock) .setPrimaryLock(primaryLock)
.addAllMutations(mutations) .addAllMutations(mutations)
@ -389,7 +390,7 @@ public class RegionStoreClient extends AbstractRegionStoreClient {
.setTxnSize(16) .setTxnSize(16)
.build() .build()
: PrewriteRequest.newBuilder() : PrewriteRequest.newBuilder()
.setContext(region.getContext()) .setContext(region.getReplicaContext(storeType))
.setStartVersion(startTs) .setStartVersion(startTs)
.setPrimaryLock(primaryLock) .setPrimaryLock(primaryLock)
.addAllMutations(mutations) .addAllMutations(mutations)
@ -469,7 +470,7 @@ public class RegionStoreClient extends AbstractRegionStoreClient {
Supplier<TxnHeartBeatRequest> factory = Supplier<TxnHeartBeatRequest> factory =
() -> () ->
TxnHeartBeatRequest.newBuilder() TxnHeartBeatRequest.newBuilder()
.setContext(region.getContext()) .setContext(region.getReplicaContext(storeType))
.setStartVersion(startTs) .setStartVersion(startTs)
.setPrimaryLock(primaryLock) .setPrimaryLock(primaryLock)
.setAdviseLockTtl(ttl) .setAdviseLockTtl(ttl)
@ -527,7 +528,7 @@ public class RegionStoreClient extends AbstractRegionStoreClient {
.setStartVersion(startTs) .setStartVersion(startTs)
.setCommitVersion(commitTs) .setCommitVersion(commitTs)
.addAllKeys(keys) .addAllKeys(keys)
.setContext(region.getContext()) .setContext(region.getReplicaContext(storeType))
.build(); .build();
KVErrorHandler<CommitResponse> handler = KVErrorHandler<CommitResponse> handler =
new KVErrorHandler<>( new KVErrorHandler<>(
@ -588,7 +589,7 @@ public class RegionStoreClient extends AbstractRegionStoreClient {
Supplier<Coprocessor.Request> reqToSend = Supplier<Coprocessor.Request> reqToSend =
() -> () ->
Coprocessor.Request.newBuilder() Coprocessor.Request.newBuilder()
.setContext(region.getContext(getResolvedLocks(startTs))) .setContext(region.getReplicaContext(getResolvedLocks(startTs), this.storeType))
.setTp(REQ_TYPE_DAG.getValue()) .setTp(REQ_TYPE_DAG.getValue())
.setStartTs(startTs) .setStartTs(startTs)
.setData(req.toByteString()) .setData(req.toByteString())
@ -711,7 +712,7 @@ public class RegionStoreClient extends AbstractRegionStoreClient {
Supplier<Coprocessor.Request> reqToSend = Supplier<Coprocessor.Request> reqToSend =
() -> () ->
Coprocessor.Request.newBuilder() Coprocessor.Request.newBuilder()
.setContext(region.getContext(getResolvedLocks(startTs))) .setContext(region.getReplicaContext(getResolvedLocks(startTs), this.storeType))
// TODO: If no executors...? // TODO: If no executors...?
.setTp(REQ_TYPE_DAG.getValue()) .setTp(REQ_TYPE_DAG.getValue())
.setData(req.toByteString()) .setData(req.toByteString())
@ -749,7 +750,7 @@ public class RegionStoreClient extends AbstractRegionStoreClient {
Supplier<SplitRegionRequest> request = Supplier<SplitRegionRequest> request =
() -> () ->
SplitRegionRequest.newBuilder() SplitRegionRequest.newBuilder()
.setContext(region.getContext()) .setContext(region.getReplicaContext(storeType))
.addAllSplitKeys(splitKeys) .addAllSplitKeys(splitKeys)
.build(); .build();
@ -787,10 +788,11 @@ public class RegionStoreClient extends AbstractRegionStoreClient {
new TiRegion( new TiRegion(
region, region,
null, null,
null,
conf.getIsolationLevel(), conf.getIsolationLevel(),
conf.getCommandPriority(), conf.getCommandPriority(),
conf.getKvMode(), conf.getKvMode(),
conf.isReplicaRead())) conf.getReplicaSelector()))
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
@ -801,7 +803,11 @@ public class RegionStoreClient extends AbstractRegionStoreClient {
GRPC_RAW_REQUEST_LATENCY.labels("client_grpc_raw_get").startTimer(); GRPC_RAW_REQUEST_LATENCY.labels("client_grpc_raw_get").startTimer();
try { try {
Supplier<RawGetRequest> factory = Supplier<RawGetRequest> factory =
() -> RawGetRequest.newBuilder().setContext(region.getContext()).setKey(key).build(); () ->
RawGetRequest.newBuilder()
.setContext(region.getReplicaContext(storeType))
.setKey(key)
.build();
KVErrorHandler<RawGetResponse> handler = KVErrorHandler<RawGetResponse> handler =
new KVErrorHandler<>( new KVErrorHandler<>(
regionManager, this, resp -> resp.hasRegionError() ? resp.getRegionError() : null); regionManager, this, resp -> resp.hasRegionError() ? resp.getRegionError() : null);
@ -833,7 +839,10 @@ public class RegionStoreClient extends AbstractRegionStoreClient {
try { try {
Supplier<RawGetKeyTTLRequest> factory = Supplier<RawGetKeyTTLRequest> factory =
() -> () ->
RawGetKeyTTLRequest.newBuilder().setContext(region.getContext()).setKey(key).build(); RawGetKeyTTLRequest.newBuilder()
.setContext(region.getReplicaContext(storeType))
.setKey(key)
.build();
KVErrorHandler<RawGetKeyTTLResponse> handler = KVErrorHandler<RawGetKeyTTLResponse> handler =
new KVErrorHandler<>( new KVErrorHandler<>(
regionManager, this, resp -> resp.hasRegionError() ? resp.getRegionError() : null); regionManager, this, resp -> resp.hasRegionError() ? resp.getRegionError() : null);
@ -868,7 +877,11 @@ public class RegionStoreClient extends AbstractRegionStoreClient {
GRPC_RAW_REQUEST_LATENCY.labels("client_grpc_raw_delete").startTimer(); GRPC_RAW_REQUEST_LATENCY.labels("client_grpc_raw_delete").startTimer();
try { try {
Supplier<RawDeleteRequest> factory = Supplier<RawDeleteRequest> factory =
() -> RawDeleteRequest.newBuilder().setContext(region.getContext()).setKey(key).build(); () ->
RawDeleteRequest.newBuilder()
.setContext(region.getReplicaContext(storeType))
.setKey(key)
.build();
KVErrorHandler<RawDeleteResponse> handler = KVErrorHandler<RawDeleteResponse> handler =
new KVErrorHandler<>( new KVErrorHandler<>(
@ -902,7 +915,7 @@ public class RegionStoreClient extends AbstractRegionStoreClient {
Supplier<RawPutRequest> factory = Supplier<RawPutRequest> factory =
() -> () ->
RawPutRequest.newBuilder() RawPutRequest.newBuilder()
.setContext(region.getContext()) .setContext(region.getReplicaContext(storeType))
.setKey(key) .setKey(key)
.setValue(value) .setValue(value)
.setTtl(ttl) .setTtl(ttl)
@ -940,7 +953,7 @@ public class RegionStoreClient extends AbstractRegionStoreClient {
Supplier<RawCASRequest> factory = Supplier<RawCASRequest> factory =
() -> () ->
RawCASRequest.newBuilder() RawCASRequest.newBuilder()
.setContext(region.getContext()) .setContext(region.getReplicaContext(storeType))
.setKey(key) .setKey(key)
.setValue(value) .setValue(value)
.setPreviousNotExist(true) .setPreviousNotExist(true)
@ -986,7 +999,7 @@ public class RegionStoreClient extends AbstractRegionStoreClient {
Supplier<RawBatchGetRequest> factory = Supplier<RawBatchGetRequest> factory =
() -> () ->
RawBatchGetRequest.newBuilder() RawBatchGetRequest.newBuilder()
.setContext(region.getContext()) .setContext(region.getReplicaContext(storeType))
.addAllKeys(keys) .addAllKeys(keys)
.build(); .build();
KVErrorHandler<RawBatchGetResponse> handler = KVErrorHandler<RawBatchGetResponse> handler =
@ -1021,7 +1034,7 @@ public class RegionStoreClient extends AbstractRegionStoreClient {
Supplier<RawBatchPutRequest> factory = Supplier<RawBatchPutRequest> factory =
() -> () ->
RawBatchPutRequest.newBuilder() RawBatchPutRequest.newBuilder()
.setContext(region.getContext()) .setContext(region.getReplicaContext(storeType))
.addAllPairs(kvPairs) .addAllPairs(kvPairs)
.setTtl(ttl) .setTtl(ttl)
.setForCas(atomic) .setForCas(atomic)
@ -1073,7 +1086,7 @@ public class RegionStoreClient extends AbstractRegionStoreClient {
Supplier<RawBatchDeleteRequest> factory = Supplier<RawBatchDeleteRequest> factory =
() -> () ->
RawBatchDeleteRequest.newBuilder() RawBatchDeleteRequest.newBuilder()
.setContext(region.getContext()) .setContext(region.getReplicaContext(storeType))
.addAllKeys(keys) .addAllKeys(keys)
.setForCas(atomic) .setForCas(atomic)
.build(); .build();
@ -1118,7 +1131,7 @@ public class RegionStoreClient extends AbstractRegionStoreClient {
Supplier<RawScanRequest> factory = Supplier<RawScanRequest> factory =
() -> () ->
RawScanRequest.newBuilder() RawScanRequest.newBuilder()
.setContext(region.getContext()) .setContext(region.getReplicaContext(storeType))
.setStartKey(key) .setStartKey(key)
.setKeyOnly(keyOnly) .setKeyOnly(keyOnly)
.setLimit(limit) .setLimit(limit)
@ -1164,7 +1177,7 @@ public class RegionStoreClient extends AbstractRegionStoreClient {
Supplier<RawDeleteRangeRequest> factory = Supplier<RawDeleteRangeRequest> factory =
() -> () ->
RawDeleteRangeRequest.newBuilder() RawDeleteRangeRequest.newBuilder()
.setContext(region.getContext()) .setContext(region.getReplicaContext(storeType))
.setStartKey(startKey) .setStartKey(startKey)
.setEndKey(endKey) .setEndKey(endKey)
.build(); .build();
@ -1232,25 +1245,48 @@ public class RegionStoreClient extends AbstractRegionStoreClient {
this.pdClient = pdClient; this.pdClient = pdClient;
} }
public RegionStoreClient build(TiRegion region, Store store, TiStoreType storeType) public RegionStoreClient build(TiRegion region, TiStore store, TiStoreType storeType)
throws GrpcException { throws GrpcException {
Objects.requireNonNull(region, "region is null"); Objects.requireNonNull(region, "region is null");
Objects.requireNonNull(store, "store is null"); Objects.requireNonNull(store, "store is null");
Objects.requireNonNull(storeType, "storeType is null"); Objects.requireNonNull(storeType, "storeType is null");
String addressStr = store.getAddress(); String addressStr = store.getStore().getAddress();
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug(String.format("Create region store client on address %s", addressStr)); logger.debug(String.format("Create region store client on address %s", addressStr));
} }
ManagedChannel channel = channelFactory.getChannel(addressStr, pdClient.getHostMapping()); ManagedChannel channel = null;
TikvBlockingStub blockingStub = TikvGrpc.newBlockingStub(channel); TikvBlockingStub blockingStub = null;
TikvStub asyncStub = TikvGrpc.newStub(channel); TikvStub asyncStub = null;
if (conf.getEnableGrpcForward() && region.getProxyStore() != null && store.isUnreachable()) {
addressStr = region.getProxyStore().getStore().getAddress();
channel =
channelFactory.getChannel(addressStr, regionManager.getPDClient().getHostMapping());
Metadata header = new Metadata();
header.put(TiConfiguration.FORWARD_META_DATA_KEY, store.getStore().getAddress());
blockingStub = MetadataUtils.attachHeaders(TikvGrpc.newBlockingStub(channel), header);
asyncStub = MetadataUtils.attachHeaders(TikvGrpc.newStub(channel), header);
} else {
// If the store is reachable, which is update by check-health thread
if (!store.isUnreachable()) {
if (region.getProxyStore() != null) {
TiRegion newRegion = region.switchProxyStore(null);
if (regionManager.updateRegion(region, newRegion)) {
region = newRegion;
}
}
}
channel = channelFactory.getChannel(addressStr, pdClient.getHostMapping());
blockingStub = TikvGrpc.newBlockingStub(channel);
asyncStub = TikvGrpc.newStub(channel);
}
return new RegionStoreClient( return new RegionStoreClient(
conf, conf,
region, region,
store.getVersion(), store,
storeType, storeType,
channelFactory, channelFactory,
blockingStub, blockingStub,
@ -1260,7 +1296,8 @@ public class RegionStoreClient extends AbstractRegionStoreClient {
this); this);
} }
public synchronized RegionStoreClient build(TiRegion region, Store store) throws GrpcException { public synchronized RegionStoreClient build(TiRegion region, TiStore store)
throws GrpcException {
return build(region, store, TiStoreType.TiKV); return build(region, store, TiStoreType.TiKV);
} }
@ -1270,12 +1307,12 @@ public class RegionStoreClient extends AbstractRegionStoreClient {
public synchronized RegionStoreClient build(ByteString key, TiStoreType storeType) public synchronized RegionStoreClient build(ByteString key, TiStoreType storeType)
throws GrpcException { throws GrpcException {
Pair<TiRegion, Store> pair = regionManager.getRegionStorePairByKey(key, storeType); Pair<TiRegion, TiStore> pair = regionManager.getRegionStorePairByKey(key, storeType);
return build(pair.first, pair.second, storeType); return build(pair.first, pair.second, storeType);
} }
public synchronized RegionStoreClient build(TiRegion region) throws GrpcException { public synchronized RegionStoreClient build(TiRegion region) throws GrpcException {
Store store = regionManager.getStoreById(region.getLeader().getStoreId()); TiStore store = regionManager.getStoreById(region.getLeader().getStoreId());
return build(region, store, TiStoreType.TiKV); return build(region, store, TiStoreType.TiKV);
} }

View File

@ -22,14 +22,16 @@ import java.io.Serializable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.Random;
import java.util.Set; import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.tikv.common.TiConfiguration.KVMode; import org.tikv.common.TiConfiguration.KVMode;
import org.tikv.common.codec.Codec.BytesCodec; import org.tikv.common.codec.Codec.BytesCodec;
import org.tikv.common.codec.CodecDataInput; import org.tikv.common.codec.CodecDataInput;
import org.tikv.common.codec.KeyUtils; import org.tikv.common.codec.KeyUtils;
import org.tikv.common.exception.TiClientInternalException; import org.tikv.common.exception.TiClientInternalException;
import org.tikv.common.key.Key; import org.tikv.common.key.Key;
import org.tikv.common.replica.ReplicaSelector;
import org.tikv.common.util.FastByteComparisons; import org.tikv.common.util.FastByteComparisons;
import org.tikv.common.util.KeyRangeUtils; import org.tikv.common.util.KeyRangeUtils;
import org.tikv.kvproto.Kvrpcpb; import org.tikv.kvproto.Kvrpcpb;
@ -39,44 +41,33 @@ import org.tikv.kvproto.Metapb.Peer;
import org.tikv.kvproto.Metapb.Region; import org.tikv.kvproto.Metapb.Region;
public class TiRegion implements Serializable { public class TiRegion implements Serializable {
private static final Logger logger = LoggerFactory.getLogger(TiRegion.class);
private final Region meta; private final Region meta;
private final KVMode kvMode;
private final IsolationLevel isolationLevel; private final IsolationLevel isolationLevel;
private final Kvrpcpb.CommandPri commandPri; private final Kvrpcpb.CommandPri commandPri;
private final Peer leader; private final Peer leader;
private int followerIdx = 0; private final ReplicaSelector replicaSelector;
private final boolean isReplicaRead; private final List<Peer> replicaList;
private final TiStore proxyStore;
public TiRegion( private int replicaIdx;
Region meta,
Peer leader,
IsolationLevel isolationLevel,
Kvrpcpb.CommandPri commandPri,
KVMode kvMode) {
this(meta, leader, isolationLevel, commandPri, kvMode, false);
}
private TiRegion(
Region meta,
Peer leader,
IsolationLevel isolationLevel,
Kvrpcpb.CommandPri commandPri,
boolean isReplicaRead) {
this.meta = meta;
this.leader = leader;
this.isolationLevel = isolationLevel;
this.commandPri = commandPri;
this.isReplicaRead = isReplicaRead;
}
public TiRegion( public TiRegion(
Region meta, Region meta,
Peer leader, Peer leader,
TiStore proxyStore,
IsolationLevel isolationLevel, IsolationLevel isolationLevel,
Kvrpcpb.CommandPri commandPri, Kvrpcpb.CommandPri commandPri,
KVMode kvMode, KVMode kvMode,
boolean isReplicaRead) { ReplicaSelector replicaSelector) {
Objects.requireNonNull(meta, "meta is null"); Objects.requireNonNull(meta, "meta is null");
this.meta = decodeRegion(meta, kvMode == KVMode.RAW); this.meta = decodeRegion(meta, kvMode == KVMode.RAW);
this.kvMode = kvMode;
this.isolationLevel = isolationLevel;
this.commandPri = commandPri;
this.replicaSelector = replicaSelector;
this.proxyStore = proxyStore;
if (leader == null || leader.getId() == 0) { if (leader == null || leader.getId() == 0) {
if (meta.getPeersCount() == 0) { if (meta.getPeersCount() == 0) {
throw new TiClientInternalException("Empty peer list for region " + meta.getId()); throw new TiClientInternalException("Empty peer list for region " + meta.getId());
@ -86,17 +77,10 @@ public class TiRegion implements Serializable {
} else { } else {
this.leader = leader; this.leader = leader;
} }
if (isReplicaRead && meta.getPeersCount() > 0) {
// try to get first follower // init replicaList
try { replicaList = replicaSelector.select(this.leader, getFollowerList(), getLearnerList());
chooseRandomFollower(); replicaIdx = 0;
} catch (Exception ignore) {
// ignore
}
}
this.isolationLevel = isolationLevel;
this.commandPri = commandPri;
this.isReplicaRead = isReplicaRead;
} }
private Region decodeRegion(Region region, boolean isRawRegion) { private Region decodeRegion(Region region, boolean isRawRegion) {
@ -127,36 +111,41 @@ public class TiRegion implements Serializable {
return leader; return leader;
} }
public Peer getCurrentFollower() { public List<Peer> getFollowerList() {
return meta.getPeers(followerIdx); List<Peer> peers = new ArrayList<>();
} for (Peer peer : getMeta().getPeersList()) {
if (!peer.equals(this.leader)) {
private boolean isValidFollower(Peer peer) { if (peer.getRole().equals(Metapb.PeerRole.Voter)) {
return Metapb.PeerRole.valueOf(peer.getRole().getValueDescriptor()) == Metapb.PeerRole.Voter; peers.add(peer);
} }
private void chooseRandomFollower() {
int cnt = meta.getPeersCount();
followerIdx = new Random().nextInt(cnt);
for (int retry = cnt - 1; retry > 0; retry--) {
followerIdx = (followerIdx + 1) % cnt;
Peer cur = meta.getPeers(followerIdx);
if (isValidFollower(cur)) {
return;
} }
} }
return peers;
} }
public List<Peer> getLearnerList() { public List<Peer> getLearnerList() {
List<Peer> peers = new ArrayList<>(); List<Peer> peers = new ArrayList<>();
for (Peer peer : getMeta().getPeersList()) { for (Peer peer : getMeta().getPeersList()) {
if (isValidFollower(peer)) { if (peer.getRole().equals(Metapb.PeerRole.Learner)) {
peers.add(peer); peers.add(peer);
} }
} }
return peers; return peers;
} }
public Peer getCurrentReplica() {
return replicaList.get(replicaIdx);
}
public Peer getNextReplica() {
replicaIdx = (replicaIdx + 1) % replicaList.size();
return getCurrentReplica();
}
private boolean isLeader(Peer peer) {
return getLeader().equals(peer);
}
public long getId() { public long getId() {
return this.meta.getId(); return this.meta.getId();
} }
@ -177,26 +166,30 @@ public class TiRegion implements Serializable {
return Key.toRawKey(getEndKey()); return Key.toRawKey(getEndKey());
} }
public Kvrpcpb.Context getContext() { public Kvrpcpb.Context getLeaderContext() {
return getContext(java.util.Collections.emptySet()); return getContext(this.leader, java.util.Collections.emptySet(), TiStoreType.TiKV);
} }
public Kvrpcpb.Context getContext(Set<Long> resolvedLocks) { public Kvrpcpb.Context getReplicaContext(TiStoreType storeType) {
return getContext(getCurrentReplica(), java.util.Collections.emptySet(), storeType);
}
public Kvrpcpb.Context getReplicaContext(Set<Long> resolvedLocks, TiStoreType storeType) {
return getContext(getCurrentReplica(), resolvedLocks, storeType);
}
private Kvrpcpb.Context getContext(
Peer currentPeer, Set<Long> resolvedLocks, TiStoreType storeType) {
boolean replicaRead = !isLeader(getCurrentReplica()) && TiStoreType.TiKV.equals(storeType);
Kvrpcpb.Context.Builder builder = Kvrpcpb.Context.newBuilder(); Kvrpcpb.Context.Builder builder = Kvrpcpb.Context.newBuilder();
builder.setIsolationLevel(this.isolationLevel); builder
builder.setPriority(this.commandPri); .setIsolationLevel(this.isolationLevel)
if (isReplicaRead) { .setPriority(this.commandPri)
builder .setRegionId(meta.getId())
.setRegionId(meta.getId()) .setPeer(currentPeer)
.setPeer(getCurrentFollower()) .setReplicaRead(replicaRead)
.setReplicaRead(true) .setRegionEpoch(this.meta.getRegionEpoch());
.setRegionEpoch(this.meta.getRegionEpoch());
} else {
builder
.setRegionId(meta.getId())
.setPeer(this.leader)
.setRegionEpoch(this.meta.getRegionEpoch());
}
builder.addAllResolvedLocks(resolvedLocks); builder.addAllResolvedLocks(resolvedLocks);
return builder.build(); return builder.build();
} }
@ -207,6 +200,10 @@ public class TiRegion implements Serializable {
meta.getId(), meta.getRegionEpoch().getConfVer(), meta.getRegionEpoch().getVersion()); meta.getId(), meta.getRegionEpoch().getConfVer(), meta.getRegionEpoch().getVersion());
} }
public TiStore getProxyStore() {
return proxyStore;
}
/** /**
* switches current peer to the one on specific store. It return false if no peer matches the * switches current peer to the one on specific store. It return false if no peer matches the
* storeID. * storeID.
@ -218,12 +215,30 @@ public class TiRegion implements Serializable {
List<Peer> peers = meta.getPeersList(); List<Peer> peers = meta.getPeersList();
for (Peer p : peers) { for (Peer p : peers) {
if (p.getStoreId() == leaderStoreID) { if (p.getStoreId() == leaderStoreID) {
return new TiRegion(this.meta, p, this.isolationLevel, this.commandPri, this.isReplicaRead); return new TiRegion(
this.meta,
p,
this.proxyStore,
this.isolationLevel,
this.commandPri,
this.kvMode,
this.replicaSelector);
} }
} }
return null; return null;
} }
public TiRegion switchProxyStore(TiStore store) {
return new TiRegion(
this.meta,
this.leader,
store,
this.isolationLevel,
this.commandPri,
this.kvMode,
this.replicaSelector);
}
public boolean isMoreThan(ByteString key) { public boolean isMoreThan(ByteString key) {
return FastByteComparisons.compareTo( return FastByteComparisons.compareTo(
meta.getStartKey().toByteArray(), meta.getStartKey().toByteArray(),

View File

@ -0,0 +1,34 @@
package org.tikv.common.region;
import java.util.concurrent.atomic.AtomicBoolean;
import org.tikv.kvproto.Metapb;
public class TiStore {
private final Metapb.Store store;
private AtomicBoolean unreachable;
public TiStore(Metapb.Store store) {
this.store = store;
this.unreachable = new AtomicBoolean(false);
}
public boolean markUnreachable() {
return this.unreachable.compareAndSet(false, true);
}
public void markReachable() {
this.unreachable.set(false);
}
public boolean isUnreachable() {
return this.unreachable.get();
}
public Metapb.Store getStore() {
return this.store;
}
public long getId() {
return this.store.getId();
}
}

View File

@ -0,0 +1,84 @@
package org.tikv.common.region;
import io.grpc.ManagedChannel;
import io.grpc.health.v1.HealthCheckRequest;
import io.grpc.health.v1.HealthCheckResponse;
import io.grpc.health.v1.HealthGrpc;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingQueue;
import org.tikv.common.ReadOnlyPDClient;
import org.tikv.common.util.ChannelFactory;
import org.tikv.common.util.ConcreteBackOffer;
import org.tikv.kvproto.Metapb;
public class UnreachableStoreChecker implements Runnable {
private ConcurrentHashMap<Long, TiStore> stores;
private BlockingQueue<TiStore> taskQueue;
private final ChannelFactory channelFactory;
private final ReadOnlyPDClient pdClient;
public UnreachableStoreChecker(ChannelFactory channelFactory, ReadOnlyPDClient pdClient) {
this.stores = new ConcurrentHashMap();
this.taskQueue = new LinkedBlockingQueue<>();
this.channelFactory = channelFactory;
this.pdClient = pdClient;
}
public void scheduleStoreHealthCheck(TiStore store) {
TiStore oldStore = this.stores.get(Long.valueOf(store.getId()));
if (oldStore == store) {
return;
}
this.stores.put(Long.valueOf(store.getId()), store);
if (!this.taskQueue.add(store)) {
// add queue false, mark it reachable so that it can be put again.
store.markReachable();
}
}
private List<TiStore> getUnhealthStore() {
List<TiStore> unhealthStore = new LinkedList<>();
while (!this.taskQueue.isEmpty()) {
try {
TiStore store = this.taskQueue.take();
unhealthStore.add(store);
} catch (Exception e) {
return unhealthStore;
}
}
return unhealthStore;
}
@Override
public void run() {
List<TiStore> unhealthStore = getUnhealthStore();
for (TiStore store : unhealthStore) {
if (!store.isUnreachable()) {
continue;
}
String addressStr = store.getStore().getAddress();
ManagedChannel channel = channelFactory.getChannel(addressStr, pdClient.getHostMapping());
HealthGrpc.HealthBlockingStub stub = HealthGrpc.newBlockingStub(channel);
HealthCheckRequest req = HealthCheckRequest.newBuilder().build();
try {
HealthCheckResponse resp = stub.check(req);
if (resp.getStatus() == HealthCheckResponse.ServingStatus.SERVING) {
store.markReachable();
this.stores.remove(Long.valueOf(store.getId()));
continue;
}
Metapb.Store newStore =
pdClient.getStore(ConcreteBackOffer.newRawKVBackOff(), store.getId());
if (newStore.getState() == Metapb.StoreState.Tombstone) {
continue;
}
this.taskQueue.add(store);
} catch (Exception e) {
this.taskQueue.add(store);
}
}
}
}

View File

@ -0,0 +1,31 @@
/*
* Copyright 2021 PingCAP, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.tikv.common.replica;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.tikv.kvproto.Metapb;
public class FollowerReplicaSelector implements ReplicaSelector {
@Override
public List<Metapb.Peer> select(
Metapb.Peer leader, List<Metapb.Peer> followers, List<Metapb.Peer> learners) {
List<Metapb.Peer> list = new ArrayList<>(followers);
Collections.shuffle(list);
return list;
}
}

View File

@ -0,0 +1,32 @@
/*
* Copyright 2021 PingCAP, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.tikv.common.replica;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.tikv.kvproto.Metapb;
public class LeaderFollowerReplicaSelector implements ReplicaSelector {
@Override
public List<Metapb.Peer> select(
Metapb.Peer leader, List<Metapb.Peer> followers, List<Metapb.Peer> learners) {
List<Metapb.Peer> list = new ArrayList<>(followers);
Collections.shuffle(list);
list.add(leader);
return list;
}
}

View File

@ -0,0 +1,30 @@
/*
* Copyright 2021 PingCAP, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.tikv.common.replica;
import java.util.ArrayList;
import java.util.List;
import org.tikv.kvproto.Metapb;
public class LeaderReplicaSelector implements ReplicaSelector {
@Override
public List<Metapb.Peer> select(
Metapb.Peer leader, List<Metapb.Peer> followers, List<Metapb.Peer> learners) {
List<Metapb.Peer> list = new ArrayList<>();
list.add(leader);
return list;
}
}

View File

@ -0,0 +1,29 @@
/*
* Copyright 2021 PingCAP, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.tikv.common.replica;
import java.io.Serializable;
import java.util.List;
import org.tikv.kvproto.Metapb;
public interface ReplicaSelector extends Serializable {
public static final ReplicaSelector LEADER = new LeaderReplicaSelector();
public static final ReplicaSelector FOLLOWER = new FollowerReplicaSelector();
public static final ReplicaSelector LEADER_AND_FOLLOWER = new LeaderFollowerReplicaSelector();
List<Metapb.Peer> select(
Metapb.Peer leader, List<Metapb.Peer> followers, List<Metapb.Peer> learners);
}

View File

@ -56,7 +56,7 @@ public class Batch {
} }
public BackOffer getBackOffer() { public BackOffer getBackOffer() {
return backOffer; return ConcreteBackOffer.create(backOffer);
} }
public TiRegion getRegion() { public TiRegion getRegion() {

View File

@ -121,7 +121,7 @@ public class ClientUtils {
public static Map<TiRegion, List<ByteString>> groupKeysByRegion( public static Map<TiRegion, List<ByteString>> groupKeysByRegion(
RegionManager regionManager, List<ByteString> keys, BackOffer backoffer) { RegionManager regionManager, List<ByteString> keys, BackOffer backoffer) {
return groupKeysByRegion(regionManager, new ArrayList<>(keys), backoffer, false); return groupKeysByRegion(regionManager, keys, backoffer, false);
} }
/** /**

View File

@ -29,9 +29,9 @@ import org.tikv.common.key.RowKey;
import org.tikv.common.pd.PDUtils; import org.tikv.common.pd.PDUtils;
import org.tikv.common.region.RegionManager; import org.tikv.common.region.RegionManager;
import org.tikv.common.region.TiRegion; import org.tikv.common.region.TiRegion;
import org.tikv.common.region.TiStore;
import org.tikv.common.region.TiStoreType; import org.tikv.common.region.TiStoreType;
import org.tikv.kvproto.Coprocessor.KeyRange; import org.tikv.kvproto.Coprocessor.KeyRange;
import org.tikv.kvproto.Metapb;
public class RangeSplitter { public class RangeSplitter {
private final RegionManager regionManager; private final RegionManager regionManager;
@ -51,12 +51,11 @@ public class RangeSplitter {
* @param handles Handle list * @param handles Handle list
* @return <Region, HandleList> map * @return <Region, HandleList> map
*/ */
public Map<Pair<TiRegion, Metapb.Store>, TLongArrayList> groupByAndSortHandlesByRegionId( public Map<Pair<TiRegion, TiStore>, TLongArrayList> groupByAndSortHandlesByRegionId(
long tableId, TLongArrayList handles) { long tableId, TLongArrayList handles) {
TLongObjectHashMap<TLongArrayList> regionHandles = new TLongObjectHashMap<>(); TLongObjectHashMap<TLongArrayList> regionHandles = new TLongObjectHashMap<>();
TLongObjectHashMap<Pair<TiRegion, Metapb.Store>> idToRegionStorePair = TLongObjectHashMap<Pair<TiRegion, TiStore>> idToRegionStorePair = new TLongObjectHashMap<>();
new TLongObjectHashMap<>(); Map<Pair<TiRegion, TiStore>, TLongArrayList> result = new HashMap<>();
Map<Pair<TiRegion, Metapb.Store>, TLongArrayList> result = new HashMap<>();
handles.sort(); handles.sort();
byte[] endKey = null; byte[] endKey = null;
@ -71,7 +70,7 @@ public class RangeSplitter {
regionHandles.put(curRegion.getId(), handlesInCurRegion); regionHandles.put(curRegion.getId(), handlesInCurRegion);
handlesInCurRegion = new TLongArrayList(); handlesInCurRegion = new TLongArrayList();
} }
Pair<TiRegion, Metapb.Store> regionStorePair = Pair<TiRegion, TiStore> regionStorePair =
regionManager.getRegionStorePairByKey(ByteString.copyFrom(key.getBytes())); regionManager.getRegionStorePairByKey(ByteString.copyFrom(key.getBytes()));
curRegion = regionStorePair.first; curRegion = regionStorePair.first;
idToRegionStorePair.put(curRegion.getId(), regionStorePair); idToRegionStorePair.put(curRegion.getId(), regionStorePair);
@ -84,7 +83,7 @@ public class RangeSplitter {
} }
regionHandles.forEachEntry( regionHandles.forEachEntry(
(k, v) -> { (k, v) -> {
Pair<TiRegion, Metapb.Store> regionStorePair = idToRegionStorePair.get(k); Pair<TiRegion, TiStore> regionStorePair = idToRegionStorePair.get(k);
result.put(regionStorePair, v); result.put(regionStorePair, v);
return true; return true;
}); });
@ -110,7 +109,7 @@ public class RangeSplitter {
// Max value for current index handle range // Max value for current index handle range
ImmutableList.Builder<RegionTask> regionTasks = ImmutableList.builder(); ImmutableList.Builder<RegionTask> regionTasks = ImmutableList.builder();
Map<Pair<TiRegion, Metapb.Store>, TLongArrayList> regionHandlesMap = Map<Pair<TiRegion, TiStore>, TLongArrayList> regionHandlesMap =
groupByAndSortHandlesByRegionId(tableId, handles); groupByAndSortHandlesByRegionId(tableId, handles);
regionHandlesMap.forEach((k, v) -> createTask(0, v.size(), tableId, v, k, regionTasks)); regionHandlesMap.forEach((k, v) -> createTask(0, v.size(), tableId, v, k, regionTasks));
@ -123,7 +122,7 @@ public class RangeSplitter {
int endPos, int endPos,
long tableId, long tableId,
TLongArrayList handles, TLongArrayList handles,
Pair<TiRegion, Metapb.Store> regionStorePair, Pair<TiRegion, TiStore> regionStorePair,
ImmutableList.Builder<RegionTask> regionTasks) { ImmutableList.Builder<RegionTask> regionTasks) {
List<KeyRange> newKeyRanges = new ArrayList<>(endPos - startPos + 1); List<KeyRange> newKeyRanges = new ArrayList<>(endPos - startPos + 1);
long startHandle = handles.get(startPos); long startHandle = handles.get(startPos);
@ -163,10 +162,10 @@ public class RangeSplitter {
int i = 0; int i = 0;
KeyRange range = keyRanges.get(i++); KeyRange range = keyRanges.get(i++);
Map<Long, List<KeyRange>> idToRange = new HashMap<>(); // region id to keyRange list Map<Long, List<KeyRange>> idToRange = new HashMap<>(); // region id to keyRange list
Map<Long, Pair<TiRegion, Metapb.Store>> idToRegion = new HashMap<>(); Map<Long, Pair<TiRegion, TiStore>> idToRegion = new HashMap<>();
while (true) { while (true) {
Pair<TiRegion, Metapb.Store> regionStorePair = Pair<TiRegion, TiStore> regionStorePair =
regionManager.getRegionStorePairByKey(range.getStart(), storeType); regionManager.getRegionStorePairByKey(range.getStart(), storeType);
if (regionStorePair == null) { if (regionStorePair == null) {
@ -203,7 +202,7 @@ public class RangeSplitter {
ImmutableList.Builder<RegionTask> resultBuilder = ImmutableList.builder(); ImmutableList.Builder<RegionTask> resultBuilder = ImmutableList.builder();
idToRange.forEach( idToRange.forEach(
(k, v) -> { (k, v) -> {
Pair<TiRegion, Metapb.Store> regionStorePair = idToRegion.get(k); Pair<TiRegion, TiStore> regionStorePair = idToRegion.get(k);
resultBuilder.add(new RegionTask(regionStorePair.first, regionStorePair.second, v)); resultBuilder.add(new RegionTask(regionStorePair.first, regionStorePair.second, v));
}); });
return resultBuilder.build(); return resultBuilder.build();
@ -221,24 +220,23 @@ public class RangeSplitter {
public static class RegionTask implements Serializable { public static class RegionTask implements Serializable {
private final TiRegion region; private final TiRegion region;
private final Metapb.Store store; private final TiStore store;
private final List<KeyRange> ranges; private final List<KeyRange> ranges;
private final String host; private final String host;
RegionTask(TiRegion region, Metapb.Store store, List<KeyRange> ranges) { RegionTask(TiRegion region, TiStore store, List<KeyRange> ranges) {
this.region = region; this.region = region;
this.store = store; this.store = store;
this.ranges = ranges; this.ranges = ranges;
String host = null; String host = null;
try { try {
host = PDUtils.addrToUri(store.getAddress()).getHost(); host = PDUtils.addrToUri(store.getStore().getAddress()).getHost();
} catch (Exception ignored) { } catch (Exception ignored) {
} }
this.host = host; this.host = host;
} }
public static RegionTask newInstance( public static RegionTask newInstance(TiRegion region, TiStore store, List<KeyRange> ranges) {
TiRegion region, Metapb.Store store, List<KeyRange> ranges) {
return new RegionTask(region, store, ranges); return new RegionTask(region, store, ranges);
} }
@ -246,7 +244,7 @@ public class RangeSplitter {
return region; return region;
} }
public Metapb.Store getStore() { public TiStore getStore() {
return store; return store;
} }

View File

@ -627,7 +627,7 @@ public class RawKVClient implements AutoCloseable {
} catch (final TiKVException e) { } catch (final TiKVException e) {
// TODO: any elegant way to re-split the ranges if fails? // TODO: any elegant way to re-split the ranges if fails?
backOffer.doBackOff(BackOffFunction.BackOffFuncType.BoRegionMiss, e); backOffer.doBackOff(BackOffFunction.BackOffFuncType.BoRegionMiss, e);
logger.warn("ReSplitting ranges for BatchPutRequest"); logger.debug("ReSplitting ranges for BatchPutRequest");
// retry // retry
return doSendBatchPutWithRefetchRegion(backOffer, batch); return doSendBatchPutWithRefetchRegion(backOffer, batch);
} }
@ -685,7 +685,7 @@ public class RawKVClient implements AutoCloseable {
} catch (final TiKVException e) { } catch (final TiKVException e) {
backOffer.doBackOff(BackOffFunction.BackOffFuncType.BoRegionMiss, e); backOffer.doBackOff(BackOffFunction.BackOffFuncType.BoRegionMiss, e);
clientBuilder.getRegionManager().invalidateRegion(batch.getRegion()); clientBuilder.getRegionManager().invalidateRegion(batch.getRegion());
logger.warn("ReSplitting ranges for BatchGetRequest", e); logger.debug("ReSplitting ranges for BatchGetRequest", e);
// retry // retry
return Pair.create(doSendBatchGetWithRefetchRegion(backOffer, batch), new ArrayList<>()); return Pair.create(doSendBatchGetWithRefetchRegion(backOffer, batch), new ArrayList<>());
@ -726,7 +726,7 @@ public class RawKVClient implements AutoCloseable {
} catch (final TiKVException e) { } catch (final TiKVException e) {
backOffer.doBackOff(BackOffFunction.BackOffFuncType.BoRegionMiss, e); backOffer.doBackOff(BackOffFunction.BackOffFuncType.BoRegionMiss, e);
clientBuilder.getRegionManager().invalidateRegion(batch.getRegion()); clientBuilder.getRegionManager().invalidateRegion(batch.getRegion());
logger.warn("ReSplitting ranges for BatchGetRequest", e); logger.debug("ReSplitting ranges for BatchGetRequest", e);
// retry // retry
return doSendBatchDeleteWithRefetchRegion(backOffer, batch); return doSendBatchDeleteWithRefetchRegion(backOffer, batch);
@ -776,7 +776,7 @@ public class RawKVClient implements AutoCloseable {
} catch (final TiKVException e) { } catch (final TiKVException e) {
backOffer.doBackOff(BackOffFunction.BackOffFuncType.BoRegionMiss, e); backOffer.doBackOff(BackOffFunction.BackOffFuncType.BoRegionMiss, e);
clientBuilder.getRegionManager().invalidateRegion(range.getRegion()); clientBuilder.getRegionManager().invalidateRegion(range.getRegion());
logger.warn("ReSplitting ranges for BatchDeleteRangeRequest", e); logger.debug("ReSplitting ranges for BatchDeleteRangeRequest", e);
// retry // retry
return doSendDeleteRangeWithRefetchRegion(backOffer, range); return doSendDeleteRangeWithRefetchRegion(backOffer, range);
@ -810,7 +810,9 @@ public class RawKVClient implements AutoCloseable {
private List<TiRegion> fetchRegionsFromRange( private List<TiRegion> fetchRegionsFromRange(
BackOffer backOffer, ByteString startKey, ByteString endKey) { BackOffer backOffer, ByteString startKey, ByteString endKey) {
List<TiRegion> regions = new ArrayList<>(); List<TiRegion> regions = new ArrayList<>();
while (startKey.isEmpty() || Key.toRawKey(startKey).compareTo(Key.toRawKey(endKey)) < 0) { while (startKey.isEmpty()
|| endKey.isEmpty()
|| Key.toRawKey(startKey).compareTo(Key.toRawKey(endKey)) < 0) {
TiRegion currentRegion = clientBuilder.getRegionManager().getRegionByKey(startKey, backOffer); TiRegion currentRegion = clientBuilder.getRegionManager().getRegionByKey(startKey, backOffer);
regions.add(currentRegion); regions.add(currentRegion);
startKey = currentRegion.getEndKey(); startKey = currentRegion.getEndKey();

View File

@ -26,6 +26,7 @@ import org.tikv.common.exception.KeyException;
import org.tikv.common.region.RegionManager; import org.tikv.common.region.RegionManager;
import org.tikv.common.region.RegionStoreClient; import org.tikv.common.region.RegionStoreClient;
import org.tikv.common.region.TiRegion; import org.tikv.common.region.TiRegion;
import org.tikv.common.region.TiStore;
import org.tikv.common.util.BackOffer; import org.tikv.common.util.BackOffer;
import org.tikv.common.util.ChannelFactory; import org.tikv.common.util.ChannelFactory;
import org.tikv.kvproto.Kvrpcpb; import org.tikv.kvproto.Kvrpcpb;
@ -66,22 +67,23 @@ public interface AbstractLockResolverClient {
} }
static AbstractLockResolverClient getInstance( static AbstractLockResolverClient getInstance(
String storeVersion,
TiConfiguration conf, TiConfiguration conf,
TiRegion region, TiRegion region,
TiStore store,
TikvGrpc.TikvBlockingStub blockingStub, TikvGrpc.TikvBlockingStub blockingStub,
TikvGrpc.TikvStub asyncStub, TikvGrpc.TikvStub asyncStub,
ChannelFactory channelFactory, ChannelFactory channelFactory,
RegionManager regionManager, RegionManager regionManager,
PDClient pdClient, PDClient pdClient,
RegionStoreClient.RegionStoreClientBuilder clientBuilder) { RegionStoreClient.RegionStoreClientBuilder clientBuilder) {
if (StoreVersion.compareTo(storeVersion, Version.RESOLVE_LOCK_V3) < 0) { if (StoreVersion.compareTo(store.getStore().getVersion(), Version.RESOLVE_LOCK_V3) < 0) {
return new LockResolverClientV2( return new LockResolverClientV2(
conf, region, blockingStub, asyncStub, channelFactory, regionManager); conf, region, store, blockingStub, asyncStub, channelFactory, regionManager);
} else if (StoreVersion.compareTo(storeVersion, Version.RESOLVE_LOCK_V4) < 0) { } else if (StoreVersion.compareTo(store.getStore().getVersion(), Version.RESOLVE_LOCK_V4) < 0) {
return new LockResolverClientV3( return new LockResolverClientV3(
conf, conf,
region, region,
store,
blockingStub, blockingStub,
asyncStub, asyncStub,
channelFactory, channelFactory,
@ -92,6 +94,7 @@ public interface AbstractLockResolverClient {
return new LockResolverClientV4( return new LockResolverClientV4(
conf, conf,
region, region,
store,
blockingStub, blockingStub,
asyncStub, asyncStub,
channelFactory, channelFactory,

View File

@ -1,62 +0,0 @@
/*
* Copyright 2017 PingCAP, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.tikv.txn;
import com.google.protobuf.ByteString;
import java.util.ArrayList;
import java.util.List;
import org.tikv.common.region.TiRegion;
import org.tikv.kvproto.Metapb;
public class BatchKeys {
private final TiRegion region;
private final Metapb.Store store;
private List<ByteString> keys;
private final int sizeInBytes;
public BatchKeys(
TiRegion region, Metapb.Store store, List<ByteString> keysInput, int sizeInBytes) {
this.region = region;
this.store = store;
this.keys = new ArrayList<>();
this.keys.addAll(keysInput);
this.sizeInBytes = sizeInBytes;
}
public List<ByteString> getKeys() {
return keys;
}
public void setKeys(List<ByteString> keys) {
this.keys = keys;
}
public TiRegion getRegion() {
return region;
}
public Metapb.Store getStore() {
return store;
}
public int getSizeInBytes() {
return sizeInBytes;
}
public float getSizeInKB() {
return ((float) sizeInBytes) / 1024;
}
}

View File

@ -1,52 +0,0 @@
/*
* Copyright 2019 The TiKV Project Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.tikv.txn;
public class ClientRPCResult {
private boolean success;
private boolean retry;
private Exception exception;
public ClientRPCResult(boolean success, boolean retry, Exception exception) {
this.success = success;
this.retry = retry;
this.exception = exception;
}
public boolean isSuccess() {
return success;
}
public void setSuccess(boolean success) {
this.success = success;
}
public boolean isRetry() {
return retry;
}
public void setRetry(boolean retry) {
this.retry = retry;
}
public Exception getException() {
return exception;
}
public void setException(Exception exception) {
this.exception = exception;
}
}

View File

@ -1,41 +0,0 @@
/*
* Copyright 2017 PingCAP, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.tikv.txn;
import com.google.protobuf.ByteString;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.tikv.common.region.TiRegion;
import org.tikv.common.util.Pair;
import org.tikv.kvproto.Metapb;
public class GroupKeyResult {
private Map<Pair<TiRegion, Metapb.Store>, List<ByteString>> groupsResult;
public GroupKeyResult() {
this.groupsResult = new HashMap<>();
}
public Map<Pair<TiRegion, Metapb.Store>, List<ByteString>> getGroupsResult() {
return groupsResult;
}
public void setGroupsResult(Map<Pair<TiRegion, Metapb.Store>, List<ByteString>> groupsResult) {
this.groupsResult = groupsResult;
}
}

View File

@ -42,6 +42,7 @@ import org.tikv.common.region.AbstractRegionStoreClient;
import org.tikv.common.region.RegionManager; import org.tikv.common.region.RegionManager;
import org.tikv.common.region.TiRegion; import org.tikv.common.region.TiRegion;
import org.tikv.common.region.TiRegion.RegionVerID; import org.tikv.common.region.TiRegion.RegionVerID;
import org.tikv.common.region.TiStore;
import org.tikv.common.util.BackOffer; import org.tikv.common.util.BackOffer;
import org.tikv.common.util.ChannelFactory; import org.tikv.common.util.ChannelFactory;
import org.tikv.common.util.TsoUtils; import org.tikv.common.util.TsoUtils;
@ -74,11 +75,12 @@ public class LockResolverClientV2 extends AbstractRegionStoreClient
public LockResolverClientV2( public LockResolverClientV2(
TiConfiguration conf, TiConfiguration conf,
TiRegion region, TiRegion region,
TiStore store,
TikvBlockingStub blockingStub, TikvBlockingStub blockingStub,
TikvStub asyncStub, TikvStub asyncStub,
ChannelFactory channelFactory, ChannelFactory channelFactory,
RegionManager regionManager) { RegionManager regionManager) {
super(conf, region, channelFactory, blockingStub, asyncStub, regionManager); super(conf, region, store, channelFactory, blockingStub, asyncStub, regionManager);
resolved = new HashMap<>(); resolved = new HashMap<>();
recentResolved = new LinkedList<>(); recentResolved = new LinkedList<>();
readWriteLock = new ReentrantReadWriteLock(); readWriteLock = new ReentrantReadWriteLock();
@ -125,7 +127,7 @@ public class LockResolverClientV2 extends AbstractRegionStoreClient
Supplier<CleanupRequest> factory = Supplier<CleanupRequest> factory =
() -> () ->
CleanupRequest.newBuilder() CleanupRequest.newBuilder()
.setContext(region.getContext()) .setContext(region.getLeaderContext())
.setKey(primary) .setKey(primary)
.setStartVersion(txnID) .setStartVersion(txnID)
.build(); .build();
@ -232,7 +234,7 @@ public class LockResolverClientV2 extends AbstractRegionStoreClient
factory = factory =
() -> () ->
ResolveLockRequest.newBuilder() ResolveLockRequest.newBuilder()
.setContext(region.getContext()) .setContext(region.getLeaderContext())
.setStartVersion(lock.getTxnID()) .setStartVersion(lock.getTxnID())
.setCommitVersion(txnStatus) .setCommitVersion(txnStatus)
.build(); .build();
@ -240,7 +242,7 @@ public class LockResolverClientV2 extends AbstractRegionStoreClient
factory = factory =
() -> () ->
ResolveLockRequest.newBuilder() ResolveLockRequest.newBuilder()
.setContext(region.getContext()) .setContext(region.getLeaderContext())
.setStartVersion(lock.getTxnID()) .setStartVersion(lock.getTxnID())
.build(); .build();
} }

View File

@ -39,10 +39,7 @@ import org.tikv.common.exception.KeyException;
import org.tikv.common.exception.RegionException; import org.tikv.common.exception.RegionException;
import org.tikv.common.exception.TiClientInternalException; import org.tikv.common.exception.TiClientInternalException;
import org.tikv.common.operation.KVErrorHandler; import org.tikv.common.operation.KVErrorHandler;
import org.tikv.common.region.AbstractRegionStoreClient; import org.tikv.common.region.*;
import org.tikv.common.region.RegionManager;
import org.tikv.common.region.RegionStoreClient;
import org.tikv.common.region.TiRegion;
import org.tikv.common.region.TiRegion.RegionVerID; import org.tikv.common.region.TiRegion.RegionVerID;
import org.tikv.common.util.BackOffer; import org.tikv.common.util.BackOffer;
import org.tikv.common.util.ChannelFactory; import org.tikv.common.util.ChannelFactory;
@ -79,13 +76,14 @@ public class LockResolverClientV3 extends AbstractRegionStoreClient
public LockResolverClientV3( public LockResolverClientV3(
TiConfiguration conf, TiConfiguration conf,
TiRegion region, TiRegion region,
TiStore store,
TikvBlockingStub blockingStub, TikvBlockingStub blockingStub,
TikvStub asyncStub, TikvStub asyncStub,
ChannelFactory channelFactory, ChannelFactory channelFactory,
RegionManager regionManager, RegionManager regionManager,
PDClient pdClient, PDClient pdClient,
RegionStoreClient.RegionStoreClientBuilder clientBuilder) { RegionStoreClient.RegionStoreClientBuilder clientBuilder) {
super(conf, region, channelFactory, blockingStub, asyncStub, regionManager); super(conf, region, store, channelFactory, blockingStub, asyncStub, regionManager);
resolved = new HashMap<>(); resolved = new HashMap<>();
recentResolved = new LinkedList<>(); recentResolved = new LinkedList<>();
readWriteLock = new ReentrantReadWriteLock(); readWriteLock = new ReentrantReadWriteLock();
@ -151,7 +149,7 @@ public class LockResolverClientV3 extends AbstractRegionStoreClient
Kvrpcpb.ResolveLockRequest.Builder builder = Kvrpcpb.ResolveLockRequest.Builder builder =
Kvrpcpb.ResolveLockRequest.newBuilder() Kvrpcpb.ResolveLockRequest.newBuilder()
.setContext(region.getContext()) .setContext(region.getLeaderContext())
.setStartVersion(lock.getTxnID()); .setStartVersion(lock.getTxnID());
if (txnStatus.isCommitted()) { if (txnStatus.isCommitted()) {
@ -230,7 +228,7 @@ public class LockResolverClientV3 extends AbstractRegionStoreClient
() -> { () -> {
TiRegion primaryKeyRegion = regionManager.getRegionByKey(primary); TiRegion primaryKeyRegion = regionManager.getRegionByKey(primary);
return CleanupRequest.newBuilder() return CleanupRequest.newBuilder()
.setContext(primaryKeyRegion.getContext()) .setContext(primaryKeyRegion.getLeaderContext())
.setKey(primary) .setKey(primary)
.setStartVersion(txnID) .setStartVersion(txnID)
.setCurrentTs(currentTS) .setCurrentTs(currentTS)

View File

@ -39,10 +39,7 @@ import org.tikv.common.exception.KeyException;
import org.tikv.common.exception.RegionException; import org.tikv.common.exception.RegionException;
import org.tikv.common.exception.TiClientInternalException; import org.tikv.common.exception.TiClientInternalException;
import org.tikv.common.operation.KVErrorHandler; import org.tikv.common.operation.KVErrorHandler;
import org.tikv.common.region.AbstractRegionStoreClient; import org.tikv.common.region.*;
import org.tikv.common.region.RegionManager;
import org.tikv.common.region.RegionStoreClient;
import org.tikv.common.region.TiRegion;
import org.tikv.common.region.TiRegion.RegionVerID; import org.tikv.common.region.TiRegion.RegionVerID;
import org.tikv.common.util.BackOffer; import org.tikv.common.util.BackOffer;
import org.tikv.common.util.ChannelFactory; import org.tikv.common.util.ChannelFactory;
@ -79,13 +76,14 @@ public class LockResolverClientV4 extends AbstractRegionStoreClient
public LockResolverClientV4( public LockResolverClientV4(
TiConfiguration conf, TiConfiguration conf,
TiRegion region, TiRegion region,
TiStore store,
TikvBlockingStub blockingStub, TikvBlockingStub blockingStub,
TikvStub asyncStub, TikvStub asyncStub,
ChannelFactory channelFactory, ChannelFactory channelFactory,
RegionManager regionManager, RegionManager regionManager,
PDClient pdClient, PDClient pdClient,
RegionStoreClient.RegionStoreClientBuilder clientBuilder) { RegionStoreClient.RegionStoreClientBuilder clientBuilder) {
super(conf, region, channelFactory, blockingStub, asyncStub, regionManager); super(conf, region, store, channelFactory, blockingStub, asyncStub, regionManager);
resolved = new HashMap<>(); resolved = new HashMap<>();
recentResolved = new LinkedList<>(); recentResolved = new LinkedList<>();
readWriteLock = new ReentrantReadWriteLock(); readWriteLock = new ReentrantReadWriteLock();
@ -169,7 +167,7 @@ public class LockResolverClientV4 extends AbstractRegionStoreClient
Supplier<Kvrpcpb.PessimisticRollbackRequest> factory = Supplier<Kvrpcpb.PessimisticRollbackRequest> factory =
() -> () ->
Kvrpcpb.PessimisticRollbackRequest.newBuilder() Kvrpcpb.PessimisticRollbackRequest.newBuilder()
.setContext(region.getContext()) .setContext(region.getLeaderContext())
.setStartVersion(lock.getTxnID()) .setStartVersion(lock.getTxnID())
.setForUpdateTs(forUpdateTS) .setForUpdateTs(forUpdateTS)
.addKeys(lock.getKey()) .addKeys(lock.getKey())
@ -287,7 +285,7 @@ public class LockResolverClientV4 extends AbstractRegionStoreClient
() -> { () -> {
TiRegion primaryKeyRegion = regionManager.getRegionByKey(primary); TiRegion primaryKeyRegion = regionManager.getRegionByKey(primary);
return Kvrpcpb.CheckTxnStatusRequest.newBuilder() return Kvrpcpb.CheckTxnStatusRequest.newBuilder()
.setContext(primaryKeyRegion.getContext()) .setContext(primaryKeyRegion.getLeaderContext())
.setPrimaryKey(primary) .setPrimaryKey(primary)
.setLockTs(txnID) .setLockTs(txnID)
.setCallerStartTs(callerStartTS) .setCallerStartTs(callerStartTS)
@ -364,7 +362,7 @@ public class LockResolverClientV4 extends AbstractRegionStoreClient
Kvrpcpb.ResolveLockRequest.Builder builder = Kvrpcpb.ResolveLockRequest.Builder builder =
Kvrpcpb.ResolveLockRequest.newBuilder() Kvrpcpb.ResolveLockRequest.newBuilder()
.setContext(region.getContext()) .setContext(region.getLeaderContext())
.setStartVersion(lock.getTxnID()); .setStartVersion(lock.getTxnID());
if (txnStatus.isCommitted()) { if (txnStatus.isCommitted()) {

View File

@ -30,11 +30,11 @@ import org.tikv.common.exception.TiBatchWriteException;
import org.tikv.common.meta.TiTimestamp; import org.tikv.common.meta.TiTimestamp;
import org.tikv.common.region.RegionManager; import org.tikv.common.region.RegionManager;
import org.tikv.common.region.TiRegion; import org.tikv.common.region.TiRegion;
import org.tikv.common.region.TiStore;
import org.tikv.common.util.BackOffFunction; import org.tikv.common.util.BackOffFunction;
import org.tikv.common.util.BackOffer; import org.tikv.common.util.BackOffer;
import org.tikv.common.util.ConcreteBackOffer; import org.tikv.common.util.ConcreteBackOffer;
import org.tikv.common.util.Pair; import org.tikv.common.util.Pair;
import org.tikv.kvproto.Metapb;
import org.tikv.txn.type.ClientRPCResult; import org.tikv.txn.type.ClientRPCResult;
/** /**
@ -105,9 +105,9 @@ public class TTLManager {
} }
private void sendTxnHeartBeat(BackOffer bo, long ttl) { private void sendTxnHeartBeat(BackOffer bo, long ttl) {
Pair<TiRegion, Metapb.Store> pair = regionManager.getRegionStorePairByKey(primaryLock); Pair<TiRegion, TiStore> pair = regionManager.getRegionStorePairByKey(primaryLock);
TiRegion tiRegion = pair.first; TiRegion tiRegion = pair.first;
Metapb.Store store = pair.second; TiStore store = pair.second;
ClientRPCResult result = kvClient.txnHeartBeat(bo, primaryLock, startTS, ttl, tiRegion, store); ClientRPCResult result = kvClient.txnHeartBeat(bo, primaryLock, startTS, ttl, tiRegion, store);
@ -121,7 +121,7 @@ public class TTLManager {
new GrpcException( new GrpcException(
String.format("sendTxnHeartBeat failed, regionId=%s", tiRegion.getId()), String.format("sendTxnHeartBeat failed, regionId=%s", tiRegion.getId()),
result.getException())); result.getException()));
this.regionManager.invalidateStore(store.getId()); this.regionManager.invalidateStore(store.getStore().getId());
this.regionManager.invalidateRegion(tiRegion); this.regionManager.invalidateRegion(tiRegion);
// re-split keys and commit again. // re-split keys and commit again.
sendTxnHeartBeat(bo, ttl); sendTxnHeartBeat(bo, ttl);

View File

@ -38,13 +38,13 @@ import org.tikv.common.exception.GrpcException;
import org.tikv.common.exception.TiBatchWriteException; import org.tikv.common.exception.TiBatchWriteException;
import org.tikv.common.region.RegionManager; import org.tikv.common.region.RegionManager;
import org.tikv.common.region.TiRegion; import org.tikv.common.region.TiRegion;
import org.tikv.common.region.TiStore;
import org.tikv.common.util.BackOffFunction; import org.tikv.common.util.BackOffFunction;
import org.tikv.common.util.BackOffer; import org.tikv.common.util.BackOffer;
import org.tikv.common.util.ConcreteBackOffer; import org.tikv.common.util.ConcreteBackOffer;
import org.tikv.common.util.Pair; import org.tikv.common.util.Pair;
import org.tikv.kvproto.Kvrpcpb; import org.tikv.kvproto.Kvrpcpb;
import org.tikv.kvproto.Kvrpcpb.Op; import org.tikv.kvproto.Kvrpcpb.Op;
import org.tikv.kvproto.Metapb;
import org.tikv.txn.type.BatchKeys; import org.tikv.txn.type.BatchKeys;
import org.tikv.txn.type.ClientRPCResult; import org.tikv.txn.type.ClientRPCResult;
import org.tikv.txn.type.GroupKeyResult; import org.tikv.txn.type.GroupKeyResult;
@ -146,9 +146,9 @@ public class TwoPhaseCommitter {
private void doPrewritePrimaryKeyWithRetry(BackOffer backOffer, ByteString key, ByteString value) private void doPrewritePrimaryKeyWithRetry(BackOffer backOffer, ByteString key, ByteString value)
throws TiBatchWriteException { throws TiBatchWriteException {
Pair<TiRegion, Metapb.Store> pair = this.regionManager.getRegionStorePairByKey(key, backOffer); Pair<TiRegion, TiStore> pair = this.regionManager.getRegionStorePairByKey(key, backOffer);
TiRegion tiRegion = pair.first; TiRegion tiRegion = pair.first;
Metapb.Store store = pair.second; TiStore store = pair.second;
Kvrpcpb.Mutation mutation; Kvrpcpb.Mutation mutation;
if (!value.isEmpty()) { if (!value.isEmpty()) {
@ -201,9 +201,9 @@ public class TwoPhaseCommitter {
private void doCommitPrimaryKeyWithRetry(BackOffer backOffer, ByteString key, long commitTs) private void doCommitPrimaryKeyWithRetry(BackOffer backOffer, ByteString key, long commitTs)
throws TiBatchWriteException { throws TiBatchWriteException {
Pair<TiRegion, Metapb.Store> pair = this.regionManager.getRegionStorePairByKey(key, backOffer); Pair<TiRegion, TiStore> pair = this.regionManager.getRegionStorePairByKey(key, backOffer);
TiRegion tiRegion = pair.first; TiRegion tiRegion = pair.first;
Metapb.Store store = pair.second; TiStore store = pair.second;
ByteString[] keys = new ByteString[] {key}; ByteString[] keys = new ByteString[] {key};
// send rpc request to tikv server // send rpc request to tikv server
@ -335,11 +335,11 @@ public class TwoPhaseCommitter {
// groups keys by region // groups keys by region
GroupKeyResult groupResult = this.groupKeysByRegion(keys, size, backOffer); GroupKeyResult groupResult = this.groupKeysByRegion(keys, size, backOffer);
List<BatchKeys> batchKeyList = new LinkedList<>(); List<BatchKeys> batchKeyList = new LinkedList<>();
Map<Pair<TiRegion, Metapb.Store>, List<ByteString>> groupKeyMap = groupResult.getGroupsResult(); Map<Pair<TiRegion, TiStore>, List<ByteString>> groupKeyMap = groupResult.getGroupsResult();
for (Map.Entry<Pair<TiRegion, Metapb.Store>, List<ByteString>> entry : groupKeyMap.entrySet()) { for (Map.Entry<Pair<TiRegion, TiStore>, List<ByteString>> entry : groupKeyMap.entrySet()) {
TiRegion tiRegion = entry.getKey().first; TiRegion tiRegion = entry.getKey().first;
Metapb.Store store = entry.getKey().second; TiStore store = entry.getKey().second;
this.appendBatchBySize(batchKeyList, tiRegion, store, entry.getValue(), true, mutations); this.appendBatchBySize(batchKeyList, tiRegion, store, entry.getValue(), true, mutations);
} }
@ -450,7 +450,7 @@ public class TwoPhaseCommitter {
private void appendBatchBySize( private void appendBatchBySize(
List<BatchKeys> batchKeyList, List<BatchKeys> batchKeyList,
TiRegion tiRegion, TiRegion tiRegion,
Metapb.Store store, TiStore store,
List<ByteString> keys, List<ByteString> keys,
boolean sizeIncludeValue, boolean sizeIncludeValue,
Map<ByteString, Kvrpcpb.Mutation> mutations) { Map<ByteString, Kvrpcpb.Mutation> mutations) {
@ -571,11 +571,11 @@ public class TwoPhaseCommitter {
// groups keys by region // groups keys by region
GroupKeyResult groupResult = this.groupKeysByRegion(keys, size, backOffer); GroupKeyResult groupResult = this.groupKeysByRegion(keys, size, backOffer);
List<BatchKeys> batchKeyList = new ArrayList<>(); List<BatchKeys> batchKeyList = new ArrayList<>();
Map<Pair<TiRegion, Metapb.Store>, List<ByteString>> groupKeyMap = groupResult.getGroupsResult(); Map<Pair<TiRegion, TiStore>, List<ByteString>> groupKeyMap = groupResult.getGroupsResult();
for (Map.Entry<Pair<TiRegion, Metapb.Store>, List<ByteString>> entry : groupKeyMap.entrySet()) { for (Map.Entry<Pair<TiRegion, TiStore>, List<ByteString>> entry : groupKeyMap.entrySet()) {
TiRegion tiRegion = entry.getKey().first; TiRegion tiRegion = entry.getKey().first;
Metapb.Store store = entry.getKey().second; TiStore store = entry.getKey().second;
this.appendBatchBySize(batchKeyList, tiRegion, store, entry.getValue(), false, null); this.appendBatchBySize(batchKeyList, tiRegion, store, entry.getValue(), false, null);
} }
@ -615,13 +615,12 @@ public class TwoPhaseCommitter {
private GroupKeyResult groupKeysByRegion(ByteString[] keys, int size, BackOffer backOffer) private GroupKeyResult groupKeysByRegion(ByteString[] keys, int size, BackOffer backOffer)
throws TiBatchWriteException { throws TiBatchWriteException {
Map<Pair<TiRegion, Metapb.Store>, List<ByteString>> groups = new HashMap<>(); Map<Pair<TiRegion, TiStore>, List<ByteString>> groups = new HashMap<>();
int index = 0; int index = 0;
try { try {
for (; index < size; index++) { for (; index < size; index++) {
ByteString key = keys[index]; ByteString key = keys[index];
Pair<TiRegion, Metapb.Store> pair = Pair<TiRegion, TiStore> pair = this.regionManager.getRegionStorePairByKey(key, backOffer);
this.regionManager.getRegionStorePairByKey(key, backOffer);
if (pair != null) { if (pair != null) {
groups.computeIfAbsent(pair, e -> new ArrayList<>()).add(key); groups.computeIfAbsent(pair, e -> new ArrayList<>()).add(key);
} }

View File

@ -33,11 +33,11 @@ import org.tikv.common.meta.TiTimestamp;
import org.tikv.common.region.RegionManager; import org.tikv.common.region.RegionManager;
import org.tikv.common.region.RegionStoreClient; import org.tikv.common.region.RegionStoreClient;
import org.tikv.common.region.TiRegion; import org.tikv.common.region.TiRegion;
import org.tikv.common.region.TiStore;
import org.tikv.common.util.BackOffFunction; import org.tikv.common.util.BackOffFunction;
import org.tikv.common.util.BackOffer; import org.tikv.common.util.BackOffer;
import org.tikv.common.util.ConcreteBackOffer; import org.tikv.common.util.ConcreteBackOffer;
import org.tikv.kvproto.Kvrpcpb; import org.tikv.kvproto.Kvrpcpb;
import org.tikv.kvproto.Metapb;
import org.tikv.txn.type.ClientRPCResult; import org.tikv.txn.type.ClientRPCResult;
/** KV client of transaction APIs for GET/PUT/DELETE/SCAN */ /** KV client of transaction APIs for GET/PUT/DELETE/SCAN */
@ -94,7 +94,7 @@ public class TxnKVClient implements AutoCloseable {
long lockTTL, long lockTTL,
long startTs, long startTs,
TiRegion tiRegion, TiRegion tiRegion,
Metapb.Store store) { TiStore store) {
ClientRPCResult result = new ClientRPCResult(true, false, null); ClientRPCResult result = new ClientRPCResult(true, false, null);
// send request // send request
RegionStoreClient client = clientBuilder.build(tiRegion, store); RegionStoreClient client = clientBuilder.build(tiRegion, store);
@ -116,7 +116,7 @@ public class TxnKVClient implements AutoCloseable {
long startTs, long startTs,
long ttl, long ttl,
TiRegion tiRegion, TiRegion tiRegion,
Metapb.Store store) { TiStore store) {
ClientRPCResult result = new ClientRPCResult(true, false, null); ClientRPCResult result = new ClientRPCResult(true, false, null);
// send request // send request
RegionStoreClient client = clientBuilder.build(tiRegion, store); RegionStoreClient client = clientBuilder.build(tiRegion, store);
@ -148,7 +148,7 @@ public class TxnKVClient implements AutoCloseable {
long startTs, long startTs,
long commitTs, long commitTs,
TiRegion tiRegion, TiRegion tiRegion,
Metapb.Store store) { TiStore store) {
ClientRPCResult result = new ClientRPCResult(true, false, null); ClientRPCResult result = new ClientRPCResult(true, false, null);
// send request // send request
RegionStoreClient client = clientBuilder.build(tiRegion, store); RegionStoreClient client = clientBuilder.build(tiRegion, store);

View File

@ -19,16 +19,15 @@ import com.google.protobuf.ByteString;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.tikv.common.region.TiRegion; import org.tikv.common.region.TiRegion;
import org.tikv.kvproto.Metapb; import org.tikv.common.region.TiStore;
public class BatchKeys { public class BatchKeys {
private final TiRegion region; private final TiRegion region;
private final Metapb.Store store; private final TiStore store;
private List<ByteString> keys; private List<ByteString> keys;
private final int sizeInBytes; private final int sizeInBytes;
public BatchKeys( public BatchKeys(TiRegion region, TiStore store, List<ByteString> keysInput, int sizeInBytes) {
TiRegion region, Metapb.Store store, List<ByteString> keysInput, int sizeInBytes) {
this.region = region; this.region = region;
this.store = store; this.store = store;
this.keys = new ArrayList<>(); this.keys = new ArrayList<>();
@ -48,7 +47,7 @@ public class BatchKeys {
return region; return region;
} }
public Metapb.Store getStore() { public TiStore getStore() {
return store; return store;
} }

View File

@ -20,22 +20,22 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.tikv.common.region.TiRegion; import org.tikv.common.region.TiRegion;
import org.tikv.common.region.TiStore;
import org.tikv.common.util.Pair; import org.tikv.common.util.Pair;
import org.tikv.kvproto.Metapb;
public class GroupKeyResult { public class GroupKeyResult {
private Map<Pair<TiRegion, Metapb.Store>, List<ByteString>> groupsResult; private Map<Pair<TiRegion, TiStore>, List<ByteString>> groupsResult;
public GroupKeyResult() { public GroupKeyResult() {
this.groupsResult = new HashMap<>(); this.groupsResult = new HashMap<>();
} }
public Map<Pair<TiRegion, Metapb.Store>, List<ByteString>> getGroupsResult() { public Map<Pair<TiRegion, TiStore>, List<ByteString>> getGroupsResult() {
return groupsResult; return groupsResult;
} }
public void setGroupsResult(Map<Pair<TiRegion, Metapb.Store>, List<ByteString>> groupsResult) { public void setGroupsResult(Map<Pair<TiRegion, TiStore>, List<ByteString>> groupsResult) {
this.groupsResult = groupsResult; this.groupsResult = groupsResult;
} }
} }

View File

@ -1,24 +0,0 @@
package(default_visibility = ["//visibility:public"])
load(":rule.bzl", "junit_suite_test")
junit_suite_test(
name = "tikv-client-java-test",
srcs = glob(
["**/*.java"],
),
deps = [
"//src/main/java/com/pingcap/tikv:tikv-java-client-lib",
"//:java",
"//:java_compile_imports",
"@com_fasterxml_jackson_core_jackson_annotations//jar",
"@com_fasterxml_jackson_core_jackson_core//jar",
"@com_fasterxml_jackson_core_jackson_databind//jar",
"@org_pubref_rules_protobuf//java:grpc_compiletime_deps",
"@org_pubref_rules_protobuf//java:netty_runtime_deps",
"@net_sf_trove4j_trove4j//jar",
"@junit_junit//jar",
"@joda_time//jar",
],
)

View File

@ -5,6 +5,7 @@ import java.io.IOException;
import org.junit.Before; import org.junit.Before;
import org.tikv.common.TiConfiguration.KVMode; import org.tikv.common.TiConfiguration.KVMode;
import org.tikv.common.region.TiRegion; import org.tikv.common.region.TiRegion;
import org.tikv.common.replica.ReplicaSelector;
import org.tikv.kvproto.Metapb; import org.tikv.kvproto.Metapb;
import org.tikv.kvproto.Pdpb; import org.tikv.kvproto.Pdpb;
@ -31,9 +32,11 @@ public class MockServerTest extends PDMockServerTest {
new TiRegion( new TiRegion(
r, r,
r.getPeers(0), r.getPeers(0),
null,
session.getConf().getIsolationLevel(), session.getConf().getIsolationLevel(),
session.getConf().getCommandPriority(), session.getConf().getCommandPriority(),
KVMode.TXN); KVMode.TXN,
ReplicaSelector.LEADER);
pdServer.addGetRegionResp(Pdpb.GetRegionResponse.newBuilder().setRegion(r).build()); pdServer.addGetRegionResp(Pdpb.GetRegionResponse.newBuilder().setRegion(r).build());
server = new KVMockServer(); server = new KVMockServer();
port = server.start(region); port = server.start(region);

View File

@ -18,7 +18,6 @@ package org.tikv.common;
import static org.junit.Assert.*; import static org.junit.Assert.*;
import static org.tikv.common.GrpcUtils.encodeKey; import static org.tikv.common.GrpcUtils.encodeKey;
import com.google.common.collect.ImmutableList;
import com.google.protobuf.ByteString; import com.google.protobuf.ByteString;
import java.util.concurrent.*; import java.util.concurrent.*;
import org.junit.Test; import org.junit.Test;
@ -37,7 +36,7 @@ public class PDClientTest extends PDMockServerTest {
@Test @Test
public void testCreate() throws Exception { public void testCreate() throws Exception {
try (PDClient client = session.getPDClient()) { try (PDClient client = session.getPDClient()) {
assertEquals(client.getLeaderWrapper().getLeaderInfo(), LOCAL_ADDR + ":" + pdServer.port); assertEquals(client.getPdClientWrapper().getLeaderInfo(), LOCAL_ADDR + ":" + pdServer.port);
assertEquals(client.getHeader().getClusterId(), CLUSTER_ID); assertEquals(client.getHeader().getClusterId(), CLUSTER_ID);
} }
} }
@ -45,17 +44,18 @@ public class PDClientTest extends PDMockServerTest {
@Test @Test
public void testSwitchLeader() throws Exception { public void testSwitchLeader() throws Exception {
try (PDClient client = session.getPDClient()) { try (PDClient client = session.getPDClient()) {
client.switchLeader(ImmutableList.of("http://" + LOCAL_ADDR + ":" + (pdServer.port + 1))); client.trySwitchLeader("http://" + LOCAL_ADDR + ":" + (pdServer.port + 1));
assertEquals( assertEquals(
client.getLeaderWrapper().getLeaderInfo(), LOCAL_ADDR + ":" + (pdServer.port + 1)); "http://" + LOCAL_ADDR + ":" + (pdServer.port + 1),
client.getPdClientWrapper().getLeaderInfo());
} }
tearDown(); tearDown();
setUp(LOCAL_ADDR_IPV6); setUp(LOCAL_ADDR_IPV6);
try (PDClient client = session.getPDClient()) { try (PDClient client = session.getPDClient()) {
client.switchLeader( client.trySwitchLeader("http://" + LOCAL_ADDR_IPV6 + ":" + (pdServer.port + 2));
ImmutableList.of("http://" + LOCAL_ADDR_IPV6 + ":" + (pdServer.port + 2)));
assertEquals( assertEquals(
client.getLeaderWrapper().getLeaderInfo(), LOCAL_ADDR_IPV6 + ":" + (pdServer.port + 2)); "http://" + LOCAL_ADDR_IPV6 + ":" + (pdServer.port + 2),
client.getPdClientWrapper().getLeaderInfo());
} }
} }
@ -95,33 +95,6 @@ public class PDClientTest extends PDMockServerTest {
} }
} }
@Test
public void testGetRegionByKeyAsync() throws Exception {
byte[] startKey = new byte[] {1, 0, 2, 4};
byte[] endKey = new byte[] {1, 0, 2, 5};
int confVer = 1026;
int ver = 1027;
pdServer.addGetRegionResp(
GrpcUtils.makeGetRegionResponse(
pdServer.getClusterId(),
GrpcUtils.makeRegion(
1,
encodeKey(startKey),
encodeKey(endKey),
GrpcUtils.makeRegionEpoch(confVer, ver),
GrpcUtils.makePeer(1, 10),
GrpcUtils.makePeer(2, 20))));
try (PDClient client = session.getPDClient()) {
TiRegion r = client.getRegionByKeyAsync(defaultBackOff(), ByteString.EMPTY).get();
assertEquals(r.getStartKey(), ByteString.copyFrom(startKey));
assertEquals(r.getEndKey(), ByteString.copyFrom(endKey));
assertEquals(r.getRegionEpoch().getConfVer(), confVer);
assertEquals(r.getRegionEpoch().getVersion(), ver);
assertEquals(r.getLeader().getId(), 1);
assertEquals(r.getLeader().getStoreId(), 10);
}
}
@Test @Test
public void testGetRegionById() throws Exception { public void testGetRegionById() throws Exception {
byte[] startKey = new byte[] {1, 0, 2, 4}; byte[] startKey = new byte[] {1, 0, 2, 4};
@ -150,33 +123,6 @@ public class PDClientTest extends PDMockServerTest {
} }
} }
@Test
public void testGetRegionByIdAsync() throws Exception {
byte[] startKey = new byte[] {1, 0, 2, 4};
byte[] endKey = new byte[] {1, 0, 2, 5};
int confVer = 1026;
int ver = 1027;
pdServer.addGetRegionByIDResp(
GrpcUtils.makeGetRegionResponse(
pdServer.getClusterId(),
GrpcUtils.makeRegion(
1,
encodeKey(startKey),
encodeKey(endKey),
GrpcUtils.makeRegionEpoch(confVer, ver),
GrpcUtils.makePeer(1, 10),
GrpcUtils.makePeer(2, 20))));
try (PDClient client = session.getPDClient()) {
TiRegion r = client.getRegionByIDAsync(defaultBackOff(), 0).get();
assertEquals(r.getStartKey(), ByteString.copyFrom(startKey));
assertEquals(r.getEndKey(), ByteString.copyFrom(endKey));
assertEquals(r.getRegionEpoch().getConfVer(), confVer);
assertEquals(r.getRegionEpoch().getVersion(), ver);
assertEquals(r.getLeader().getId(), 1);
assertEquals(r.getLeader().getStoreId(), 10);
}
}
@Test @Test
public void testGetStore() throws Exception { public void testGetStore() throws Exception {
long storeId = 1; long storeId = 1;
@ -208,38 +154,6 @@ public class PDClientTest extends PDMockServerTest {
} }
} }
@Test
public void testGetStoreAsync() throws Exception {
long storeId = 1;
String testAddress = "testAddress";
pdServer.addGetStoreResp(
GrpcUtils.makeGetStoreResponse(
pdServer.getClusterId(),
GrpcUtils.makeStore(
storeId,
testAddress,
Metapb.StoreState.Up,
GrpcUtils.makeStoreLabel("k1", "v1"),
GrpcUtils.makeStoreLabel("k2", "v2"))));
try (PDClient client = session.getPDClient()) {
Store r = client.getStoreAsync(defaultBackOff(), 0).get();
assertEquals(r.getId(), storeId);
assertEquals(r.getAddress(), testAddress);
assertEquals(r.getState(), Metapb.StoreState.Up);
assertEquals(r.getLabels(0).getKey(), "k1");
assertEquals(r.getLabels(1).getKey(), "k2");
assertEquals(r.getLabels(0).getValue(), "v1");
assertEquals(r.getLabels(1).getValue(), "v2");
pdServer.addGetStoreResp(
GrpcUtils.makeGetStoreResponse(
pdServer.getClusterId(),
GrpcUtils.makeStore(storeId, testAddress, Metapb.StoreState.Tombstone)));
assertEquals(
StoreState.Tombstone, client.getStoreAsync(defaultBackOff(), 0).get().getState());
}
}
private BackOffer defaultBackOff() { private BackOffer defaultBackOff() {
return ConcreteBackOffer.newCustomBackOff(1000); return ConcreteBackOffer.newCustomBackOff(1000);
} }

View File

@ -43,7 +43,7 @@ public class PDMockServer extends PDGrpc.PDImplBase {
@Override @Override
public void getMembers(GetMembersRequest request, StreamObserver<GetMembersResponse> resp) { public void getMembers(GetMembersRequest request, StreamObserver<GetMembersResponse> resp) {
try { try {
resp.onNext(getMembersResp.removeFirst().get()); resp.onNext(getMembersResp.getFirst().get());
resp.onCompleted(); resp.onCompleted();
} catch (Exception e) { } catch (Exception e) {
resp.onError(Status.INTERNAL.asRuntimeException()); resp.onError(Status.INTERNAL.asRuntimeException());

View File

@ -26,10 +26,10 @@ import org.junit.Test;
import org.tikv.common.key.Key; import org.tikv.common.key.Key;
import org.tikv.common.region.RegionManager; import org.tikv.common.region.RegionManager;
import org.tikv.common.region.TiRegion; import org.tikv.common.region.TiRegion;
import org.tikv.common.region.TiStore;
import org.tikv.common.util.KeyRangeUtils; import org.tikv.common.util.KeyRangeUtils;
import org.tikv.common.util.Pair; import org.tikv.common.util.Pair;
import org.tikv.kvproto.Metapb; import org.tikv.kvproto.Metapb;
import org.tikv.kvproto.Metapb.Store;
import org.tikv.kvproto.Metapb.StoreState; import org.tikv.kvproto.Metapb.StoreState;
public class RegionManagerTest extends PDMockServerTest { public class RegionManagerTest extends PDMockServerTest {
@ -115,7 +115,7 @@ public class RegionManagerTest extends PDMockServerTest {
Metapb.StoreState.Up, Metapb.StoreState.Up,
GrpcUtils.makeStoreLabel("k1", "v1"), GrpcUtils.makeStoreLabel("k1", "v1"),
GrpcUtils.makeStoreLabel("k2", "v2")))); GrpcUtils.makeStoreLabel("k2", "v2"))));
Pair<TiRegion, Store> pair = mgr.getRegionStorePairByKey(searchKey); Pair<TiRegion, TiStore> pair = mgr.getRegionStorePairByKey(searchKey);
assertEquals(pair.first.getId(), regionId); assertEquals(pair.first.getId(), regionId);
assertEquals(pair.first.getId(), storeId); assertEquals(pair.first.getId(), storeId);
} }
@ -133,8 +133,8 @@ public class RegionManagerTest extends PDMockServerTest {
Metapb.StoreState.Up, Metapb.StoreState.Up,
GrpcUtils.makeStoreLabel("k1", "v1"), GrpcUtils.makeStoreLabel("k1", "v1"),
GrpcUtils.makeStoreLabel("k2", "v2")))); GrpcUtils.makeStoreLabel("k2", "v2"))));
Store store = mgr.getStoreById(storeId); TiStore store = mgr.getStoreById(storeId);
assertEquals(store.getId(), storeId); assertEquals(store.getStore().getId(), storeId);
pdServer.addGetStoreResp( pdServer.addGetStoreResp(
GrpcUtils.makeGetStoreResponse( GrpcUtils.makeGetStoreResponse(

View File

@ -24,6 +24,7 @@ import org.junit.Test;
import org.tikv.common.region.RegionManager; import org.tikv.common.region.RegionManager;
import org.tikv.common.region.RegionStoreClient; import org.tikv.common.region.RegionStoreClient;
import org.tikv.common.region.RegionStoreClient.RegionStoreClientBuilder; import org.tikv.common.region.RegionStoreClient.RegionStoreClientBuilder;
import org.tikv.common.region.TiStore;
import org.tikv.common.util.BackOffer; import org.tikv.common.util.BackOffer;
import org.tikv.common.util.ConcreteBackOffer; import org.tikv.common.util.ConcreteBackOffer;
import org.tikv.kvproto.Kvrpcpb; import org.tikv.kvproto.Kvrpcpb;
@ -40,13 +41,14 @@ public class RegionStoreClientTest extends MockServerTest {
} }
private RegionStoreClient createClient(String version) { private RegionStoreClient createClient(String version) {
Metapb.Store store = Metapb.Store meta =
Metapb.Store.newBuilder() Metapb.Store.newBuilder()
.setAddress(LOCAL_ADDR + ":" + port) .setAddress(LOCAL_ADDR + ":" + port)
.setId(1) .setId(1)
.setState(Metapb.StoreState.Up) .setState(Metapb.StoreState.Up)
.setVersion(version) .setVersion(version)
.build(); .build();
TiStore store = new TiStore(meta);
RegionStoreClientBuilder builder = RegionStoreClientBuilder builder =
new RegionStoreClientBuilder( new RegionStoreClientBuilder(

View File

@ -1,5 +1,7 @@
package org.tikv.raw; package org.tikv.raw;
import static org.junit.Assert.*;
import com.google.protobuf.ByteString; import com.google.protobuf.ByteString;
import java.io.IOException; import java.io.IOException;
import java.util.*; import java.util.*;
@ -8,6 +10,7 @@ import java.util.stream.Collectors;
import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.RandomStringUtils;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test; import org.junit.Test;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -91,7 +94,8 @@ public class RawKVClientTest {
} }
} }
@Test // tikv-4.0 does not support atomic api
@Ignore
public void atomicAPITest() { public void atomicAPITest() {
if (!initialized) return; if (!initialized) return;
long ttl = 10; long ttl = 10;
@ -100,19 +104,20 @@ public class RawKVClientTest {
ByteString value2 = ByteString.copyFromUtf8("value2"); ByteString value2 = ByteString.copyFromUtf8("value2");
client.delete(key); client.delete(key);
ByteString res1 = client.putIfAbsent(key, value, ttl); ByteString res1 = client.putIfAbsent(key, value, ttl);
assert res1.isEmpty(); assertTrue(res1.isEmpty());
ByteString res2 = client.putIfAbsent(key, value2, ttl); ByteString res2 = client.putIfAbsent(key, value2, ttl);
assert res2.equals(value); assertEquals(value, res2);
try { try {
Thread.sleep(ttl * 1000); Thread.sleep(ttl * 1000);
} catch (InterruptedException e) { } catch (InterruptedException e) {
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();
} }
ByteString res3 = client.putIfAbsent(key, value, ttl); ByteString res3 = client.putIfAbsent(key, value, ttl);
assert res3.isEmpty(); assertTrue(res3.isEmpty());
} }
@Test // tikv-4.0 doest not support ttl
@Ignore
public void getKeyTTLTest() { public void getKeyTTLTest() {
if (!initialized) return; if (!initialized) return;
long ttl = 10; long ttl = 10;
@ -254,30 +259,47 @@ public class RawKVClientTest {
public void simpleTest() { public void simpleTest() {
if (!initialized) return; if (!initialized) return;
ByteString key = rawKey("key"); ByteString key = rawKey("key");
ByteString key0 = rawKey("key0");
ByteString key1 = rawKey("key1"); ByteString key1 = rawKey("key1");
ByteString key2 = rawKey("key2"); ByteString key2 = rawKey("key2");
ByteString key3 = rawKey("key3"); ByteString key3 = rawKey("key3");
ByteString value = rawValue("value");
ByteString value1 = rawValue("value1"); ByteString value1 = rawValue("value1");
ByteString value2 = rawValue("value2"); ByteString value2 = rawValue("value2");
ByteString value3 = rawValue("value3");
Kvrpcpb.KvPair kv = Kvrpcpb.KvPair.newBuilder().setKey(key).setValue(value).build();
Kvrpcpb.KvPair kv1 = Kvrpcpb.KvPair.newBuilder().setKey(key1).setValue(value1).build(); Kvrpcpb.KvPair kv1 = Kvrpcpb.KvPair.newBuilder().setKey(key1).setValue(value1).build();
Kvrpcpb.KvPair kv2 = Kvrpcpb.KvPair.newBuilder().setKey(key2).setValue(value2).build(); Kvrpcpb.KvPair kv2 = Kvrpcpb.KvPair.newBuilder().setKey(key2).setValue(value2).build();
Kvrpcpb.KvPair kv3 = Kvrpcpb.KvPair.newBuilder().setKey(key3).setValue(value3).build();
try { try {
checkEmpty(key1); checkDeleteRange(ByteString.EMPTY, ByteString.EMPTY);
checkEmpty(key2); checkEmpty(kv);
checkPut(key1, value1); checkEmpty(kv1);
checkPut(key2, value2); checkEmpty(kv2);
List<Kvrpcpb.KvPair> result = new ArrayList<>(); checkEmpty(kv3);
List<Kvrpcpb.KvPair> result2 = new ArrayList<>(); checkPut(kv);
result.add(kv1); checkPut(kv1);
result.add(kv2); checkPut(kv2);
checkScan(key, key3, result, limit); checkPut(kv3);
checkScan(key1, key3, result, limit); // <key, value>, <key1,value1>, <key2,value2>, <key3,value3>
checkScan(key, key1, new ArrayList<>(), limit); // (-, +)
result2.add(kv1); checkScan(ByteString.EMPTY, ByteString.EMPTY, Arrays.asList(kv, kv1, kv2, kv3), limit);
checkScan(key, key2, result2, limit); // (-, key3)
checkScan(ByteString.EMPTY, key3, Arrays.asList(kv, kv1, kv2), limit);
// [key1, +)
checkScan(key1, ByteString.EMPTY, Arrays.asList(kv1, kv2, kv3), limit);
// [key, key3)
checkScan(key, key3, Arrays.asList(kv, kv1, kv2), limit);
// [key1, key3)
checkScan(key1, key3, Arrays.asList(kv1, kv2), limit);
// [key0, key1)
checkScan(key0, key1, new ArrayList<>(), limit);
// [key, key2)
checkScan(key, key2, Arrays.asList(kv, kv1), limit);
checkDelete(key1); checkDelete(key1);
checkDelete(key2); checkDelete(key2);
checkDeleteRange(ByteString.EMPTY, ByteString.EMPTY);
} catch (final TiKVException e) { } catch (final TiKVException e) {
logger.warn("Test fails with Exception: " + e); logger.warn("Test fails with Exception: " + e);
} }
@ -509,7 +531,7 @@ public class RawKVClientTest {
} else { } else {
int i = 0; int i = 0;
for (Map.Entry<ByteString, ByteString> pair : data.entrySet()) { for (Map.Entry<ByteString, ByteString> pair : data.entrySet()) {
assert client.get(pair.getKey()).equals(pair.getValue()); assertEquals(pair.getValue(), client.get(pair.getKey()));
i++; i++;
if (i >= getCases) { if (i >= getCases) {
break; break;
@ -756,27 +778,31 @@ public class RawKVClientTest {
private void checkBatchGet(List<ByteString> keys) { private void checkBatchGet(List<ByteString> keys) {
List<Kvrpcpb.KvPair> result = client.batchGet(keys); List<Kvrpcpb.KvPair> result = client.batchGet(keys);
for (Kvrpcpb.KvPair kvPair : result) { for (Kvrpcpb.KvPair kvPair : result) {
assert data.containsKey(kvPair.getKey()); assertTrue(data.containsKey(kvPair.getKey()));
assert kvPair.getValue().equals(data.get(kvPair.getKey())); assertEquals(data.get(kvPair.getKey()), kvPair.getValue());
} }
} }
private void checkPut(Kvrpcpb.KvPair kv) {
checkPut(kv.getKey(), kv.getValue());
}
private void checkPut(ByteString key, ByteString value) { private void checkPut(ByteString key, ByteString value) {
client.put(key, value); client.put(key, value);
assert client.get(key).equals(value); assertEquals(value, client.get(key));
} }
private void checkBatchPut(Map<ByteString, ByteString> kvPairs) { private void checkBatchPut(Map<ByteString, ByteString> kvPairs) {
client.batchPut(kvPairs); client.batchPut(kvPairs);
for (Map.Entry<ByteString, ByteString> kvPair : kvPairs.entrySet()) { for (Map.Entry<ByteString, ByteString> kvPair : kvPairs.entrySet()) {
assert client.get(kvPair.getKey()).equals(kvPair.getValue()); assertEquals(kvPair.getValue(), client.get(kvPair.getKey()));
} }
} }
private void checkScan( private void checkScan(
ByteString startKey, ByteString endKey, List<Kvrpcpb.KvPair> ans, int limit) { ByteString startKey, ByteString endKey, List<Kvrpcpb.KvPair> expected, int limit) {
List<Kvrpcpb.KvPair> result = client.scan(startKey, endKey, limit); List<Kvrpcpb.KvPair> result = client.scan(startKey, endKey, limit);
assert result.equals(ans); assertEquals(expected, result);
} }
private void checkScan( private void checkScan(
@ -812,7 +838,7 @@ public class RawKVClientTest {
.setValue(kvPair.getValue()) .setValue(kvPair.getValue())
.build()) .build())
.collect(Collectors.toList()); .collect(Collectors.toList());
assert result.get(i).equals(partialResult); assertEquals(partialResult, result.get(i));
i++; i++;
} }
} }
@ -827,31 +853,35 @@ public class RawKVClientTest {
logger.info("delete range complete"); logger.info("delete range complete");
List<Kvrpcpb.KvPair> result = client.scan(startKey, endKey); List<Kvrpcpb.KvPair> result = client.scan(startKey, endKey);
logger.info("checking scan complete. number of remaining keys in range: " + result.size()); logger.info("checking scan complete. number of remaining keys in range: " + result.size());
assert result.isEmpty(); assertTrue(result.isEmpty());
} }
private void checkPutTTL(ByteString key, ByteString value, long ttl) { private void checkPutTTL(ByteString key, ByteString value, long ttl) {
client.put(key, value, ttl); client.put(key, value, ttl);
assert client.get(key).equals(value); assertEquals(value, client.get(key));
} }
private void checkGetKeyTTL(ByteString key, long ttl) { private void checkGetKeyTTL(ByteString key, long ttl) {
Long t = client.getKeyTTL(key); Long t = client.getKeyTTL(key);
assert t != null; assertNotNull(t);
assert t <= ttl && t > 0; assertTrue(t <= ttl && t > 0);
} }
private void checkGetTTLTimeOut(ByteString key) { private void checkGetTTLTimeOut(ByteString key) {
assert client.get(key).isEmpty(); assertTrue(client.get(key).isEmpty());
} }
private void checkGetKeyTTLTimeOut(ByteString key) { private void checkGetKeyTTLTimeOut(ByteString key) {
Long t = client.getKeyTTL(key); Long t = client.getKeyTTL(key);
assert t == null; assertNull(t);
}
private void checkEmpty(Kvrpcpb.KvPair kv) {
checkEmpty(kv.getKey());
} }
private void checkEmpty(ByteString key) { private void checkEmpty(ByteString key) {
assert client.get(key).isEmpty(); assertTrue(client.get(key).isEmpty());
} }
private static ByteString rawKey(String key) { private static ByteString rawKey(String key) {

View File

@ -1,40 +0,0 @@
def junit_suite_test(name, srcs, deps, size="small", resources=[], classpath_resources=[], jvm_flags=[], tags=[], data=[]):
tests = []
package = PACKAGE_NAME.replace("src/test/java/", "").replace("/", ".")
for src in srcs:
if src.endswith("Test.java"):
if "/" in src:
src = package + "." + src.replace("/", ".")
tests += [src.replace(".java", ".class")]
native.genrule(
name = name + "-AllTests-gen",
outs = ["AllTests.java"],
cmd = """
cat <<EOF >> $@
package %s;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
@RunWith(Suite.class)
@Suite.SuiteClasses({%s})
public class AllTests {}
EOF
""" % (package, ",".join(tests))
)
native.java_test(
name = name,
srcs = srcs + ["AllTests.java"],
test_class = package + ".AllTests",
resources = resources,
classpath_resources = classpath_resources,
data = data,
size = size,
tags = tags,
jvm_flags = jvm_flags,
deps = deps + [
],
)

View File

@ -0,0 +1,84 @@
package org.tikv.txn;
import com.google.protobuf.ByteString;
import java.util.ArrayList;
import java.util.List;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.tikv.common.TiConfiguration;
import org.tikv.common.TiSession;
import org.tikv.common.replica.ReplicaSelector;
import org.tikv.kvproto.Metapb;
public class ReplicaReadTest extends TXNTest {
private TiSession session;
private String key;
private String value;
@Test
public void leaderReadTest() {
doTest(TiConfiguration.ReplicaRead.LEADER);
}
// ci only has one TiKV instance
@Ignore
public void followerReadTest() {
doTest(TiConfiguration.ReplicaRead.FOLLOWER);
}
@Test
public void leadAndFollowerReadTest() {
doTest(TiConfiguration.ReplicaRead.LEADER_AND_FOLLOWER);
}
@Test
public void replicaSelectorTest() {
TiConfiguration conf = TiConfiguration.createDefault();
conf.setReplicaSelector(
new ReplicaSelector() {
@Override
public List<Metapb.Peer> select(
Metapb.Peer leader, List<Metapb.Peer> followers, List<Metapb.Peer> learners) {
List<Metapb.Peer> list = new ArrayList<>();
list.addAll(followers);
list.addAll(learners);
list.add(leader);
return list;
}
});
session = TiSession.create(conf);
putKV(key, value);
ByteString v = session.createSnapshot().get(ByteString.copyFromUtf8(key));
Assert.assertEquals(value, v.toStringUtf8());
}
private void doTest(TiConfiguration.ReplicaRead replicaRead) {
TiConfiguration conf = TiConfiguration.createDefault();
conf.setReplicaRead(replicaRead);
session = TiSession.create(conf);
putKV(key, value);
ByteString v = session.createSnapshot().get(ByteString.copyFromUtf8(key));
Assert.assertEquals(value, v.toStringUtf8());
}
@Before
public void setUp() {
super.setUp();
key = genRandomKey(64);
value = "v0";
}
@After
public void tearDown() throws Exception {
if (session != null) {
session.close();
}
super.tearDown();
}
}

View File

@ -0,0 +1,131 @@
package org.tikv.txn;
import static junit.framework.TestCase.assertTrue;
import static junit.framework.TestCase.fail;
import com.google.protobuf.ByteString;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.Collectors;
import org.junit.After;
import org.junit.Before;
import org.tikv.common.TiConfiguration;
import org.tikv.common.TiSession;
import org.tikv.common.exception.RegionException;
import org.tikv.common.region.RegionStoreClient;
import org.tikv.common.region.TiRegion;
import org.tikv.common.util.BackOffFunction;
import org.tikv.common.util.BackOffer;
import org.tikv.common.util.ConcreteBackOffer;
import org.tikv.kvproto.Kvrpcpb;
public class TXNTest {
static final int DEFAULT_TTL = 10;
private TiSession session;
RegionStoreClient.RegionStoreClientBuilder builder;
@Before
public void setUp() {
TiConfiguration conf = TiConfiguration.createDefault();
try {
session = TiSession.create(conf);
this.builder = session.getRegionStoreClientBuilder();
} catch (Exception e) {
fail("TiDB cluster may not be present");
}
}
@After
public void tearDown() throws Exception {
if (session != null) {
session.close();
}
}
void putKV(String key, String value) {
long startTS = session.getTimestamp().getVersion();
long commitTS = session.getTimestamp().getVersion();
putKV(key, value, startTS, commitTS);
}
void putKV(String key, String value, long startTS, long commitTS) {
Kvrpcpb.Mutation m =
Kvrpcpb.Mutation.newBuilder()
.setKey(ByteString.copyFromUtf8(key))
.setOp(Kvrpcpb.Op.Put)
.setValue(ByteString.copyFromUtf8(value))
.build();
boolean res = prewriteString(Collections.singletonList(m), startTS, key, DEFAULT_TTL);
assertTrue(res);
res = commitString(Collections.singletonList(key), startTS, commitTS);
assertTrue(res);
}
boolean prewriteString(List<Kvrpcpb.Mutation> mutations, long startTS, String primary, long ttl) {
return prewrite(mutations, startTS, ByteString.copyFromUtf8(primary), ttl);
}
boolean prewrite(List<Kvrpcpb.Mutation> mutations, long startTS, ByteString primary, long ttl) {
if (mutations.size() == 0) return true;
BackOffer backOffer = ConcreteBackOffer.newCustomBackOff(1000);
for (Kvrpcpb.Mutation m : mutations) {
while (true) {
try {
TiRegion region = session.getRegionManager().getRegionByKey(m.getKey());
RegionStoreClient client = builder.build(region);
client.prewrite(backOffer, primary, Collections.singletonList(m), startTS, ttl, false);
break;
} catch (RegionException e) {
backOffer.doBackOff(BackOffFunction.BackOffFuncType.BoRegionMiss, e);
}
}
}
return true;
}
boolean commitString(List<String> keys, long startTS, long commitTS) {
return commit(
keys.stream().map(ByteString::copyFromUtf8).collect(Collectors.toList()),
startTS,
commitTS);
}
boolean commit(List<ByteString> keys, long startTS, long commitTS) {
if (keys.size() == 0) return true;
BackOffer backOffer = ConcreteBackOffer.newCustomBackOff(1000);
for (ByteString byteStringK : keys) {
while (true) {
try {
TiRegion tiRegion = session.getRegionManager().getRegionByKey(byteStringK);
RegionStoreClient client = builder.build(tiRegion);
client.commit(backOffer, Collections.singletonList(byteStringK), startTS, commitTS);
break;
} catch (RegionException e) {
backOffer.doBackOff(BackOffFunction.BackOffFuncType.BoRegionMiss, e);
}
}
}
return true;
}
String genRandomKey(int strLength) {
Random rnd = ThreadLocalRandom.current();
String prefix = rnd.nextInt(2) % 2 == 0 ? "a-test-" : "z-test-";
StringBuilder ret = new StringBuilder(prefix);
for (int i = 0; i < strLength; i++) {
boolean isChar = (rnd.nextInt(2) % 2 == 0);
if (isChar) {
int choice = rnd.nextInt(2) % 2 == 0 ? 65 : 97;
ret.append((char) (choice + rnd.nextInt(26)));
} else {
ret.append(rnd.nextInt(10));
}
}
return ret.toString();
}
}