mirror of https://github.com/tikv/client-java.git
				
				
				
			add slow log (#328)
This commit is contained in:
		
							parent
							
								
									1e74211269
								
							
						
					
					
						commit
						a881a6585b
					
				|  | @ -90,7 +90,8 @@ public abstract class AbstractGRPCClient< | |||
|                   return ClientCalls.blockingUnaryCall( | ||||
|                       stub.getChannel(), method, stub.getCallOptions(), requestFactory.get()); | ||||
|                 }, | ||||
|                 method.getFullMethodName()); | ||||
|                 method.getFullMethodName(), | ||||
|                 backOffer); | ||||
| 
 | ||||
|     if (logger.isTraceEnabled()) { | ||||
|       logger.trace(String.format("leaving %s...", method.getFullMethodName())); | ||||
|  | @ -118,7 +119,8 @@ public abstract class AbstractGRPCClient< | |||
|                   responseObserver); | ||||
|               return null; | ||||
|             }, | ||||
|             method.getFullMethodName()); | ||||
|             method.getFullMethodName(), | ||||
|             backOffer); | ||||
|     logger.debug(String.format("leaving %s...", method.getFullMethodName())); | ||||
|   } | ||||
| 
 | ||||
|  | @ -139,7 +141,8 @@ public abstract class AbstractGRPCClient< | |||
|                   return asyncBidiStreamingCall( | ||||
|                       stub.getChannel().newCall(method, stub.getCallOptions()), responseObserver); | ||||
|                 }, | ||||
|                 method.getFullMethodName()); | ||||
|                 method.getFullMethodName(), | ||||
|                 backOffer); | ||||
|     logger.debug(String.format("leaving %s...", method.getFullMethodName())); | ||||
|     return observer; | ||||
|   } | ||||
|  | @ -162,7 +165,8 @@ public abstract class AbstractGRPCClient< | |||
|                       blockingServerStreamingCall( | ||||
|                           stub.getChannel(), method, stub.getCallOptions(), requestFactory.get())); | ||||
|                 }, | ||||
|                 method.getFullMethodName()); | ||||
|                 method.getFullMethodName(), | ||||
|                 backOffer); | ||||
|     logger.debug(String.format("leaving %s...", method.getFullMethodName())); | ||||
|     return response; | ||||
|   } | ||||
|  |  | |||
|  | @ -67,6 +67,13 @@ public class ConfigUtils { | |||
|   public static final String TIKV_RAWKV_SCAN_TIMEOUT_IN_MS = "tikv.rawkv.scan_timeout_in_ms"; | ||||
|   public static final String TIKV_RAWKV_CLEAN_TIMEOUT_IN_MS = "tikv.rawkv.clean_timeout_in_ms"; | ||||
|   public static final String TIKV_BO_REGION_MISS_BASE_IN_MS = "tikv.bo_region_miss_base_in_ms"; | ||||
|   public static final String TIKV_RAWKV_READ_SLOWLOG_IN_MS = "tikv.rawkv.read_slowlog_in_ms"; | ||||
|   public static final String TIKV_RAWKV_WRITE_SLOWLOG_IN_MS = "tikv.rawkv.write_slowlog_in_ms"; | ||||
|   public static final String TIKV_RAWKV_BATCH_READ_SLOWLOG_IN_MS = | ||||
|       "tikv.rawkv.batch_read_slowlog_in_ms"; | ||||
|   public static final String TIKV_RAWKV_BATCH_WRITE_SLOWLOG_IN_MS = | ||||
|       "tikv.rawkv.batch_write_slowlog_in_ms"; | ||||
|   public static final String TIKV_RAWKV_SCAN_SLOWLOG_IN_MS = "tikv.rawkv.scan_slowlog_in_ms"; | ||||
| 
 | ||||
|   public static final String DEF_PD_ADDRESSES = "127.0.0.1:2379"; | ||||
|   public static final String DEF_TIMEOUT = "200ms"; | ||||
|  | @ -110,6 +117,7 @@ public class ConfigUtils { | |||
|   public static final int DEF_TIKV_RAWKV_CLEAN_TIMEOUT_IN_MS = 600000; | ||||
| 
 | ||||
|   public static final int DEF_TIKV_BO_REGION_MISS_BASE_IN_MS = 20; | ||||
|   public static final String DEF_TIKV_RAWKV_SCAN_SLOWLOG_IN_MS = "5000"; | ||||
| 
 | ||||
|   public static final String NORMAL_COMMAND_PRIORITY = "NORMAL"; | ||||
|   public static final String LOW_COMMAND_PRIORITY = "LOW"; | ||||
|  |  | |||
|  | @ -119,6 +119,7 @@ public class TiConfiguration implements Serializable { | |||
|     setIfMissing(TIKV_RAWKV_SCAN_TIMEOUT_IN_MS, DEF_TIKV_RAWKV_SCAN_TIMEOUT_IN_MS); | ||||
|     setIfMissing(TIKV_RAWKV_CLEAN_TIMEOUT_IN_MS, DEF_TIKV_RAWKV_CLEAN_TIMEOUT_IN_MS); | ||||
|     setIfMissing(TIKV_BO_REGION_MISS_BASE_IN_MS, DEF_TIKV_BO_REGION_MISS_BASE_IN_MS); | ||||
|     setIfMissing(TIKV_RAWKV_SCAN_SLOWLOG_IN_MS, DEF_TIKV_RAWKV_SCAN_SLOWLOG_IN_MS); | ||||
|   } | ||||
| 
 | ||||
|   public static void listAll() { | ||||
|  | @ -169,6 +170,10 @@ public class TiConfiguration implements Serializable { | |||
|     return Integer.parseInt(get(key)); | ||||
|   } | ||||
| 
 | ||||
|   public static Optional<Integer> getIntOption(String key) { | ||||
|     return getOption(key).map(Integer::parseInt); | ||||
|   } | ||||
| 
 | ||||
|   private static int getInt(String key, int defaultValue) { | ||||
|     try { | ||||
|       return getOption(key).map(Integer::parseInt).orElse(defaultValue); | ||||
|  | @ -315,6 +320,13 @@ public class TiConfiguration implements Serializable { | |||
|   private int rawKVBatchWriteTimeoutInMS = getInt(TIKV_RAWKV_BATCH_WRITE_TIMEOUT_IN_MS); | ||||
|   private int rawKVScanTimeoutInMS = getInt(TIKV_RAWKV_SCAN_TIMEOUT_IN_MS); | ||||
|   private int rawKVCleanTimeoutInMS = getInt(TIKV_RAWKV_CLEAN_TIMEOUT_IN_MS); | ||||
|   private Optional<Integer> rawKVReadSlowLogInMS = getIntOption(TIKV_RAWKV_READ_SLOWLOG_IN_MS); | ||||
|   private Optional<Integer> rawKVWriteSlowLogInMS = getIntOption(TIKV_RAWKV_WRITE_SLOWLOG_IN_MS); | ||||
|   private Optional<Integer> rawKVBatchReadSlowLogInMS = | ||||
|       getIntOption(TIKV_RAWKV_BATCH_READ_SLOWLOG_IN_MS); | ||||
|   private Optional<Integer> rawKVBatchWriteSlowLogInMS = | ||||
|       getIntOption(TIKV_RAWKV_BATCH_WRITE_SLOWLOG_IN_MS); | ||||
|   private int rawKVScanSlowLogInMS = getInt(TIKV_RAWKV_SCAN_SLOWLOG_IN_MS); | ||||
| 
 | ||||
|   public enum KVMode { | ||||
|     TXN, | ||||
|  | @ -677,4 +689,44 @@ public class TiConfiguration implements Serializable { | |||
|   public void setRawKVCleanTimeoutInMS(int rawKVCleanTimeoutInMS) { | ||||
|     this.rawKVCleanTimeoutInMS = rawKVCleanTimeoutInMS; | ||||
|   } | ||||
| 
 | ||||
|   public Integer getRawKVReadSlowLogInMS() { | ||||
|     return rawKVReadSlowLogInMS.orElse((int) (getTimeout() * 2)); | ||||
|   } | ||||
| 
 | ||||
|   public void setRawKVReadSlowLogInMS(Integer rawKVReadSlowLogInMS) { | ||||
|     this.rawKVReadSlowLogInMS = Optional.of(rawKVReadSlowLogInMS); | ||||
|   } | ||||
| 
 | ||||
|   public Integer getRawKVWriteSlowLogInMS() { | ||||
|     return rawKVWriteSlowLogInMS.orElse((int) (getTimeout() * 2)); | ||||
|   } | ||||
| 
 | ||||
|   public void setRawKVWriteSlowLogInMS(Integer rawKVWriteSlowLogInMS) { | ||||
|     this.rawKVWriteSlowLogInMS = Optional.of(rawKVWriteSlowLogInMS); | ||||
|   } | ||||
| 
 | ||||
|   public Integer getRawKVBatchReadSlowLogInMS() { | ||||
|     return rawKVBatchReadSlowLogInMS.orElse((int) (getTimeout() * 2)); | ||||
|   } | ||||
| 
 | ||||
|   public void setRawKVBatchReadSlowLogInMS(Integer rawKVBatchReadSlowLogInMS) { | ||||
|     this.rawKVBatchReadSlowLogInMS = Optional.of(rawKVBatchReadSlowLogInMS); | ||||
|   } | ||||
| 
 | ||||
|   public Integer getRawKVBatchWriteSlowLogInMS() { | ||||
|     return rawKVBatchWriteSlowLogInMS.orElse((int) (getTimeout() * 2)); | ||||
|   } | ||||
| 
 | ||||
|   public void setRawKVBatchWriteSlowLogInMS(Integer rawKVBatchWriteSlowLogInMS) { | ||||
|     this.rawKVBatchWriteSlowLogInMS = Optional.of(rawKVBatchWriteSlowLogInMS); | ||||
|   } | ||||
| 
 | ||||
|   public int getRawKVScanSlowLogInMS() { | ||||
|     return rawKVScanSlowLogInMS; | ||||
|   } | ||||
| 
 | ||||
|   public void setRawKVScanSlowLogInMS(int rawKVScanSlowLogInMS) { | ||||
|     this.rawKVScanSlowLogInMS = rawKVScanSlowLogInMS; | ||||
|   } | ||||
| } | ||||
|  |  | |||
|  | @ -0,0 +1,26 @@ | |||
| /* | ||||
|  * | ||||
|  * 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.log; | ||||
| 
 | ||||
| public interface SlowLog { | ||||
|   void addProperty(String key, String value); | ||||
| 
 | ||||
|   SlowLogSpan start(String name); | ||||
| 
 | ||||
|   void log(); | ||||
| } | ||||
|  | @ -0,0 +1,35 @@ | |||
| /* | ||||
|  * | ||||
|  * 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.log; | ||||
| 
 | ||||
| public class SlowLogEmptyImpl implements SlowLog { | ||||
|   public static final SlowLogEmptyImpl INSTANCE = new SlowLogEmptyImpl(); | ||||
| 
 | ||||
|   private SlowLogEmptyImpl() {} | ||||
| 
 | ||||
|   @Override | ||||
|   public void addProperty(String key, String value) {} | ||||
| 
 | ||||
|   @Override | ||||
|   public SlowLogSpan start(String name) { | ||||
|     return SlowLogSpanEmptyImpl.INSTANCE; | ||||
|   } | ||||
| 
 | ||||
|   @Override | ||||
|   public void log() {} | ||||
| } | ||||
|  | @ -0,0 +1,93 @@ | |||
| /* | ||||
|  * | ||||
|  * 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.log; | ||||
| 
 | ||||
| import com.google.gson.JsonArray; | ||||
| import com.google.gson.JsonObject; | ||||
| import java.text.SimpleDateFormat; | ||||
| import java.util.ArrayList; | ||||
| import java.util.HashMap; | ||||
| import java.util.List; | ||||
| import java.util.Map; | ||||
| import org.slf4j.Logger; | ||||
| import org.slf4j.LoggerFactory; | ||||
| 
 | ||||
| public class SlowLogImpl implements SlowLog { | ||||
|   private static final Logger logger = LoggerFactory.getLogger(SlowLogImpl.class); | ||||
| 
 | ||||
|   private static final int MAX_SPAN_SIZE = 1024; | ||||
| 
 | ||||
|   public static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("HH:mm:ss.SSS"); | ||||
| 
 | ||||
|   private final List<SlowLogSpan> slowLogSpans = new ArrayList<>(); | ||||
| 
 | ||||
|   private final long startMS; | ||||
|   private final long slowThresholdMS; | ||||
| 
 | ||||
|   /** Key-Value pairs which will be logged, e.g. function name, key, region, etc. */ | ||||
|   private final Map<String, String> properties; | ||||
| 
 | ||||
|   public SlowLogImpl(long slowThresholdMS, Map<String, String> properties) { | ||||
|     this.startMS = System.currentTimeMillis(); | ||||
|     this.slowThresholdMS = slowThresholdMS; | ||||
|     this.properties = new HashMap<>(properties); | ||||
|   } | ||||
| 
 | ||||
|   @Override | ||||
|   public void addProperty(String key, String value) { | ||||
|     this.properties.put(key, value); | ||||
|   } | ||||
| 
 | ||||
|   @Override | ||||
|   public synchronized SlowLogSpan start(String name) { | ||||
|     SlowLogSpan slowLogSpan = new SlowLogSpanImpl(name); | ||||
|     if (slowLogSpans.size() < MAX_SPAN_SIZE) { | ||||
|       slowLogSpans.add(slowLogSpan); | ||||
|     } | ||||
|     slowLogSpan.start(); | ||||
|     return slowLogSpan; | ||||
|   } | ||||
| 
 | ||||
|   @Override | ||||
|   public void log() { | ||||
|     long currentMS = System.currentTimeMillis(); | ||||
|     if (slowThresholdMS >= 0 && currentMS - startMS > slowThresholdMS) { | ||||
|       logger.warn("SlowLog:" + getSlowLogString(currentMS)); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   private String getSlowLogString(long currentMS) { | ||||
|     JsonObject jsonObject = new JsonObject(); | ||||
| 
 | ||||
|     jsonObject.addProperty("start", DATE_FORMAT.format(startMS)); | ||||
|     jsonObject.addProperty("end", DATE_FORMAT.format(currentMS)); | ||||
|     jsonObject.addProperty("duration", (currentMS - startMS) + "ms"); | ||||
| 
 | ||||
|     for (Map.Entry<String, String> entry : properties.entrySet()) { | ||||
|       jsonObject.addProperty(entry.getKey(), entry.getValue()); | ||||
|     } | ||||
| 
 | ||||
|     JsonArray jsonArray = new JsonArray(); | ||||
|     for (SlowLogSpan slowLogSpan : slowLogSpans) { | ||||
|       jsonArray.add(slowLogSpan.toJsonElement()); | ||||
|     } | ||||
|     jsonObject.add("spans", jsonArray); | ||||
| 
 | ||||
|     return jsonObject.toString(); | ||||
|   } | ||||
| } | ||||
|  | @ -0,0 +1,28 @@ | |||
| /* | ||||
|  * | ||||
|  * 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.log; | ||||
| 
 | ||||
| import com.google.gson.JsonElement; | ||||
| 
 | ||||
| public interface SlowLogSpan { | ||||
|   void start(); | ||||
| 
 | ||||
|   void end(); | ||||
| 
 | ||||
|   JsonElement toJsonElement(); | ||||
| } | ||||
|  | @ -0,0 +1,39 @@ | |||
| /* | ||||
|  * | ||||
|  * 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.log; | ||||
| 
 | ||||
| import com.google.gson.JsonElement; | ||||
| import com.google.gson.JsonObject; | ||||
| 
 | ||||
| public class SlowLogSpanEmptyImpl implements SlowLogSpan { | ||||
| 
 | ||||
|   public static final SlowLogSpanEmptyImpl INSTANCE = new SlowLogSpanEmptyImpl(); | ||||
| 
 | ||||
|   private SlowLogSpanEmptyImpl() {} | ||||
| 
 | ||||
|   @Override | ||||
|   public void start() {} | ||||
| 
 | ||||
|   @Override | ||||
|   public void end() {} | ||||
| 
 | ||||
|   @Override | ||||
|   public JsonElement toJsonElement() { | ||||
|     return new JsonObject(); | ||||
|   } | ||||
| } | ||||
|  | @ -0,0 +1,77 @@ | |||
| /* | ||||
|  * | ||||
|  * 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.log; | ||||
| 
 | ||||
| import static org.tikv.common.log.SlowLogImpl.DATE_FORMAT; | ||||
| 
 | ||||
| import com.google.gson.JsonElement; | ||||
| import com.google.gson.JsonObject; | ||||
| 
 | ||||
| public class SlowLogSpanImpl implements SlowLogSpan { | ||||
|   private final String name; | ||||
|   private long startMS; | ||||
|   private long endMS; | ||||
| 
 | ||||
|   public SlowLogSpanImpl(String name) { | ||||
|     this.name = name; | ||||
|     this.startMS = 0; | ||||
|     this.endMS = 0; | ||||
|   } | ||||
| 
 | ||||
|   @Override | ||||
|   public void start() { | ||||
|     this.startMS = System.currentTimeMillis(); | ||||
|   } | ||||
| 
 | ||||
|   @Override | ||||
|   public void end() { | ||||
|     this.endMS = System.currentTimeMillis(); | ||||
|   } | ||||
| 
 | ||||
|   @Override | ||||
|   public JsonElement toJsonElement() { | ||||
|     JsonObject jsonObject = new JsonObject(); | ||||
|     jsonObject.addProperty("name", name); | ||||
|     jsonObject.addProperty("start", getStartString()); | ||||
|     jsonObject.addProperty("end", getEndString()); | ||||
|     jsonObject.addProperty("duration", getDurationString()); | ||||
| 
 | ||||
|     return jsonObject; | ||||
|   } | ||||
| 
 | ||||
|   private String getStartString() { | ||||
|     if (startMS == 0) { | ||||
|       return "N/A"; | ||||
|     } | ||||
|     return DATE_FORMAT.format(startMS); | ||||
|   } | ||||
| 
 | ||||
|   private String getEndString() { | ||||
|     if (endMS == 0) { | ||||
|       return "N/A"; | ||||
|     } | ||||
|     return DATE_FORMAT.format(endMS); | ||||
|   } | ||||
| 
 | ||||
|   private String getDurationString() { | ||||
|     if (startMS == 0 || endMS == 0) { | ||||
|       return "N/A"; | ||||
|     } | ||||
|     return (endMS - startMS) + "ms"; | ||||
|   } | ||||
| } | ||||
|  | @ -217,7 +217,7 @@ public class RegionErrorHandler<RespT> implements ErrorHandler<RespT> { | |||
| 
 | ||||
|   @Override | ||||
|   public boolean handleRequestError(BackOffer backOffer, Exception e) { | ||||
|     if (recv.onStoreUnreachable()) { | ||||
|     if (recv.onStoreUnreachable(backOffer.getSlowLog())) { | ||||
|       if (!backOffer.canRetryAfterSleep(BackOffFunction.BackOffFuncType.BoTiKVRPC)) { | ||||
|         regionManager.onRequestFail(recv.getRegion()); | ||||
|         throw new GrpcException("retry is exhausted.", e); | ||||
|  |  | |||
|  | @ -21,6 +21,7 @@ import io.prometheus.client.Counter; | |||
| import io.prometheus.client.Histogram; | ||||
| import java.util.concurrent.Callable; | ||||
| import org.tikv.common.exception.GrpcException; | ||||
| import org.tikv.common.log.SlowLogSpan; | ||||
| import org.tikv.common.operation.ErrorHandler; | ||||
| import org.tikv.common.util.BackOffer; | ||||
| import org.tikv.common.util.ConcreteBackOffer; | ||||
|  | @ -67,8 +68,10 @@ public abstract class RetryPolicy<RespT> { | |||
|     } | ||||
|   } | ||||
| 
 | ||||
|   public RespT callWithRetry(Callable<RespT> proc, String methodName) { | ||||
|   public RespT callWithRetry(Callable<RespT> proc, String methodName, BackOffer backOffer) { | ||||
|     Histogram.Timer callWithRetryTimer = CALL_WITH_RETRY_DURATION.labels(methodName).startTimer(); | ||||
|     SlowLogSpan callWithRetrySlowLogSpan = | ||||
|         backOffer.getSlowLog().start("callWithRetry " + methodName); | ||||
|     try { | ||||
|       while (true) { | ||||
|         RespT result = null; | ||||
|  | @ -76,9 +79,11 @@ public abstract class RetryPolicy<RespT> { | |||
|           // add single request duration histogram | ||||
|           Histogram.Timer requestTimer = | ||||
|               GRPC_SINGLE_REQUEST_LATENCY.labels(methodName).startTimer(); | ||||
|           SlowLogSpan slowLogSpan = backOffer.getSlowLog().start("gRPC " + methodName); | ||||
|           try { | ||||
|             result = proc.call(); | ||||
|           } finally { | ||||
|             slowLogSpan.end(); | ||||
|             requestTimer.observeDuration(); | ||||
|           } | ||||
|         } catch (Exception e) { | ||||
|  | @ -105,6 +110,7 @@ public abstract class RetryPolicy<RespT> { | |||
|       } | ||||
|     } finally { | ||||
|       callWithRetryTimer.observeDuration(); | ||||
|       callWithRetrySlowLogSpan.end(); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|  |  | |||
|  | @ -35,6 +35,9 @@ import org.slf4j.LoggerFactory; | |||
| import org.tikv.common.AbstractGRPCClient; | ||||
| import org.tikv.common.TiConfiguration; | ||||
| import org.tikv.common.exception.GrpcException; | ||||
| import org.tikv.common.log.SlowLog; | ||||
| import org.tikv.common.log.SlowLogEmptyImpl; | ||||
| import org.tikv.common.log.SlowLogSpan; | ||||
| import org.tikv.common.util.ChannelFactory; | ||||
| import org.tikv.common.util.Pair; | ||||
| import org.tikv.kvproto.Kvrpcpb; | ||||
|  | @ -80,7 +83,9 @@ public abstract class AbstractRegionStoreClient | |||
|     if (this.store.getProxyStore() != null) { | ||||
|       this.timeout = conf.getForwardTimeout(); | ||||
|     } else if (!this.store.isReachable()) { | ||||
|       onStoreUnreachable(); | ||||
|       // cannot get Deadline or SlowLog instance here | ||||
|       // use SlowLogEmptyImpl instead to skip slow log record | ||||
|       onStoreUnreachable(SlowLogEmptyImpl.INSTANCE); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|  | @ -130,7 +135,7 @@ public abstract class AbstractRegionStoreClient | |||
|   } | ||||
| 
 | ||||
|   @Override | ||||
|   public boolean onStoreUnreachable() { | ||||
|   public boolean onStoreUnreachable(SlowLog slowLog) { | ||||
|     if (!store.isValid()) { | ||||
|       logger.warn(String.format("store [%d] has been invalid", store.getId())); | ||||
|       store = regionManager.getStoreById(store.getId()); | ||||
|  | @ -148,13 +153,13 @@ public abstract class AbstractRegionStoreClient | |||
|     } | ||||
| 
 | ||||
|     // seek an available leader store to send request | ||||
|     Boolean result = seekLeaderStore(); | ||||
|     Boolean result = seekLeaderStore(slowLog); | ||||
|     if (result != null) { | ||||
|       return result; | ||||
|     } | ||||
|     if (conf.getEnableGrpcForward()) { | ||||
|       // seek an available proxy store to forward request | ||||
|       return seekProxyStore(); | ||||
|       return seekProxyStore(slowLog); | ||||
|     } | ||||
|     return false; | ||||
|   } | ||||
|  | @ -187,8 +192,9 @@ public abstract class AbstractRegionStoreClient | |||
|     } | ||||
|   } | ||||
| 
 | ||||
|   private Boolean seekLeaderStore() { | ||||
|   private Boolean seekLeaderStore(SlowLog slowLog) { | ||||
|     Histogram.Timer switchLeaderDurationTimer = SEEK_LEADER_STORE_DURATION.startTimer(); | ||||
|     SlowLogSpan slowLogSpan = slowLog.start("seekLeaderStore"); | ||||
|     try { | ||||
|       List<Metapb.Peer> peers = region.getFollowerList(); | ||||
|       if (peers.isEmpty()) { | ||||
|  | @ -237,11 +243,13 @@ public abstract class AbstractRegionStoreClient | |||
|       } | ||||
|     } finally { | ||||
|       switchLeaderDurationTimer.observeDuration(); | ||||
|       slowLogSpan.end(); | ||||
|     } | ||||
|     return null; | ||||
|   } | ||||
| 
 | ||||
|   private boolean seekProxyStore() { | ||||
|   private boolean seekProxyStore(SlowLog slowLog) { | ||||
|     SlowLogSpan slowLogSpan = slowLog.start("seekProxyStore"); | ||||
|     Histogram.Timer grpcForwardDurationTimer = SEEK_PROXY_STORE_DURATION.startTimer(); | ||||
|     try { | ||||
|       logger.info(String.format("try grpc forward: region[%d]", region.getId())); | ||||
|  | @ -259,6 +267,7 @@ public abstract class AbstractRegionStoreClient | |||
|       return true; | ||||
|     } finally { | ||||
|       grpcForwardDurationTimer.observeDuration(); | ||||
|       slowLogSpan.end(); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|  |  | |||
|  | @ -17,11 +17,13 @@ | |||
| 
 | ||||
| package org.tikv.common.region; | ||||
| 
 | ||||
| import org.tikv.common.log.SlowLog; | ||||
| 
 | ||||
| public interface RegionErrorReceiver { | ||||
|   boolean onNotLeader(TiRegion region); | ||||
| 
 | ||||
|   /// return whether we need to retry this request. | ||||
|   boolean onStoreUnreachable(); | ||||
|   boolean onStoreUnreachable(SlowLog slowLog); | ||||
| 
 | ||||
|   TiRegion getRegion(); | ||||
| } | ||||
|  |  | |||
|  | @ -17,6 +17,8 @@ | |||
| 
 | ||||
| package org.tikv.common.util; | ||||
| 
 | ||||
| import org.tikv.common.log.SlowLog; | ||||
| 
 | ||||
| public interface BackOffer { | ||||
|   // Back off types. | ||||
|   int seconds = 1000; | ||||
|  | @ -58,4 +60,6 @@ public interface BackOffer { | |||
|     // DecorrJitter increases the maximum jitter based on the last random value. | ||||
|     DecorrJitter | ||||
|   } | ||||
| 
 | ||||
|   SlowLog getSlowLog(); | ||||
| } | ||||
|  |  | |||
|  | @ -29,6 +29,9 @@ import org.slf4j.Logger; | |||
| import org.slf4j.LoggerFactory; | ||||
| import org.tikv.common.TiConfiguration; | ||||
| import org.tikv.common.exception.GrpcException; | ||||
| import org.tikv.common.log.SlowLog; | ||||
| import org.tikv.common.log.SlowLogEmptyImpl; | ||||
| import org.tikv.common.log.SlowLogSpan; | ||||
| 
 | ||||
| public class ConcreteBackOffer implements BackOffer { | ||||
|   private static final Logger logger = LoggerFactory.getLogger(ConcreteBackOffer.class); | ||||
|  | @ -37,6 +40,7 @@ public class ConcreteBackOffer implements BackOffer { | |||
|   private final List<Exception> errors; | ||||
|   private int totalSleep; | ||||
|   private final long deadline; | ||||
|   private final SlowLog slowLog; | ||||
| 
 | ||||
|   public static final Histogram BACKOFF_DURATION = | ||||
|       Histogram.build() | ||||
|  | @ -45,7 +49,7 @@ public class ConcreteBackOffer implements BackOffer { | |||
|           .labelNames("type") | ||||
|           .register(); | ||||
| 
 | ||||
|   private ConcreteBackOffer(int maxSleep, long deadline) { | ||||
|   private ConcreteBackOffer(int maxSleep, long deadline, SlowLog slowLog) { | ||||
|     Preconditions.checkArgument( | ||||
|         maxSleep == 0 || deadline == 0, "Max sleep time should be 0 or Deadline should be 0."); | ||||
|     Preconditions.checkArgument(maxSleep >= 0, "Max sleep time cannot be less than 0."); | ||||
|  | @ -54,6 +58,7 @@ public class ConcreteBackOffer implements BackOffer { | |||
|     this.errors = new ArrayList<>(); | ||||
|     this.backOffFunctionMap = new HashMap<>(); | ||||
|     this.deadline = deadline; | ||||
|     this.slowLog = slowLog; | ||||
|   } | ||||
| 
 | ||||
|   private ConcreteBackOffer(ConcreteBackOffer source) { | ||||
|  | @ -62,39 +67,40 @@ public class ConcreteBackOffer implements BackOffer { | |||
|     this.errors = source.errors; | ||||
|     this.backOffFunctionMap = source.backOffFunctionMap; | ||||
|     this.deadline = source.deadline; | ||||
|     this.slowLog = source.slowLog; | ||||
|   } | ||||
| 
 | ||||
|   public static ConcreteBackOffer newDeadlineBackOff(int timeoutInMs) { | ||||
|   public static ConcreteBackOffer newDeadlineBackOff(int timeoutInMs, SlowLog slowLog) { | ||||
|     long deadline = System.currentTimeMillis() + timeoutInMs; | ||||
|     return new ConcreteBackOffer(0, deadline); | ||||
|     return new ConcreteBackOffer(0, deadline, slowLog); | ||||
|   } | ||||
| 
 | ||||
|   public static ConcreteBackOffer newCustomBackOff(int maxSleep) { | ||||
|     return new ConcreteBackOffer(maxSleep, 0); | ||||
|     return new ConcreteBackOffer(maxSleep, 0, SlowLogEmptyImpl.INSTANCE); | ||||
|   } | ||||
| 
 | ||||
|   public static ConcreteBackOffer newScannerNextMaxBackOff() { | ||||
|     return new ConcreteBackOffer(SCANNER_NEXT_MAX_BACKOFF, 0); | ||||
|     return new ConcreteBackOffer(SCANNER_NEXT_MAX_BACKOFF, 0, SlowLogEmptyImpl.INSTANCE); | ||||
|   } | ||||
| 
 | ||||
|   public static ConcreteBackOffer newBatchGetMaxBackOff() { | ||||
|     return new ConcreteBackOffer(BATCH_GET_MAX_BACKOFF, 0); | ||||
|     return new ConcreteBackOffer(BATCH_GET_MAX_BACKOFF, 0, SlowLogEmptyImpl.INSTANCE); | ||||
|   } | ||||
| 
 | ||||
|   public static ConcreteBackOffer newCopNextMaxBackOff() { | ||||
|     return new ConcreteBackOffer(COP_NEXT_MAX_BACKOFF, 0); | ||||
|     return new ConcreteBackOffer(COP_NEXT_MAX_BACKOFF, 0, SlowLogEmptyImpl.INSTANCE); | ||||
|   } | ||||
| 
 | ||||
|   public static ConcreteBackOffer newGetBackOff() { | ||||
|     return new ConcreteBackOffer(GET_MAX_BACKOFF, 0); | ||||
|     return new ConcreteBackOffer(GET_MAX_BACKOFF, 0, SlowLogEmptyImpl.INSTANCE); | ||||
|   } | ||||
| 
 | ||||
|   public static ConcreteBackOffer newRawKVBackOff() { | ||||
|     return new ConcreteBackOffer(RAWKV_MAX_BACKOFF, 0); | ||||
|     return new ConcreteBackOffer(RAWKV_MAX_BACKOFF, 0, SlowLogEmptyImpl.INSTANCE); | ||||
|   } | ||||
| 
 | ||||
|   public static ConcreteBackOffer newTsoBackOff() { | ||||
|     return new ConcreteBackOffer(TSO_MAX_BACKOFF, 0); | ||||
|     return new ConcreteBackOffer(TSO_MAX_BACKOFF, 0, SlowLogEmptyImpl.INSTANCE); | ||||
|   } | ||||
| 
 | ||||
|   public static ConcreteBackOffer create(BackOffer source) { | ||||
|  | @ -151,6 +157,7 @@ public class ConcreteBackOffer implements BackOffer { | |||
|   } | ||||
| 
 | ||||
|   public boolean canRetryAfterSleep(BackOffFunction.BackOffFuncType funcType, long maxSleepMs) { | ||||
|     SlowLogSpan slowLogSpan = getSlowLog().start("backoff " + funcType.name()); | ||||
|     Histogram.Timer backOffTimer = BACKOFF_DURATION.labels(funcType.name()).startTimer(); | ||||
|     BackOffFunction backOffFunction = | ||||
|         backOffFunctionMap.computeIfAbsent(funcType, this::createBackOffFunc); | ||||
|  | @ -171,8 +178,10 @@ public class ConcreteBackOffer implements BackOffer { | |||
|       Thread.sleep(sleep); | ||||
|     } catch (InterruptedException e) { | ||||
|       throw new GrpcException(e); | ||||
|     } finally { | ||||
|       slowLogSpan.end(); | ||||
|       backOffTimer.observeDuration(); | ||||
|     } | ||||
|     backOffTimer.observeDuration(); | ||||
|     if (maxSleep > 0 && totalSleep >= maxSleep) { | ||||
|       logger.warn(String.format("BackOffer.maxSleep %dms is exceeded, errors:", maxSleep)); | ||||
|       return false; | ||||
|  | @ -206,4 +215,9 @@ public class ConcreteBackOffer implements BackOffer { | |||
|     // Use the last backoff type to generate an exception | ||||
|     throw new GrpcException("retry is exhausted.", err); | ||||
|   } | ||||
| 
 | ||||
|   @Override | ||||
|   public SlowLog getSlowLog() { | ||||
|     return slowLog; | ||||
|   } | ||||
| } | ||||
|  |  | |||
|  | @ -27,8 +27,12 @@ import org.slf4j.Logger; | |||
| import org.slf4j.LoggerFactory; | ||||
| import org.tikv.common.TiConfiguration; | ||||
| import org.tikv.common.TiSession; | ||||
| import org.tikv.common.codec.KeyUtils; | ||||
| import org.tikv.common.exception.TiKVException; | ||||
| import org.tikv.common.key.Key; | ||||
| import org.tikv.common.log.SlowLog; | ||||
| import org.tikv.common.log.SlowLogEmptyImpl; | ||||
| import org.tikv.common.log.SlowLogImpl; | ||||
| import org.tikv.common.operation.iterator.RawScanIterator; | ||||
| import org.tikv.common.region.RegionStoreClient; | ||||
| import org.tikv.common.region.RegionStoreClient.RegionStoreClientBuilder; | ||||
|  | @ -129,10 +133,21 @@ public class RawKVClient implements AutoCloseable { | |||
|   private void put(ByteString key, ByteString value, long ttl, boolean atomic) { | ||||
|     String label = "client_raw_put"; | ||||
|     Histogram.Timer requestTimer = RAW_REQUEST_LATENCY.labels(label).startTimer(); | ||||
|     SlowLog slowLog = | ||||
|         new SlowLogImpl( | ||||
|             conf.getRawKVWriteSlowLogInMS(), | ||||
|             new HashMap<String, String>(2) { | ||||
|               { | ||||
|                 put("func", "put"); | ||||
|                 put("key", KeyUtils.formatBytesUTF8(key)); | ||||
|               } | ||||
|             }); | ||||
|     ConcreteBackOffer backOffer = | ||||
|         ConcreteBackOffer.newDeadlineBackOff(conf.getRawKVWriteTimeoutInMS(), slowLog); | ||||
|     try { | ||||
|       BackOffer backOffer = ConcreteBackOffer.newDeadlineBackOff(conf.getRawKVWriteTimeoutInMS()); | ||||
|       while (true) { | ||||
|         RegionStoreClient client = clientBuilder.build(key, backOffer); | ||||
|         slowLog.addProperty("region", client.getRegion().toString()); | ||||
|         try { | ||||
|           client.rawPut(backOffer, key, value, ttl, atomic); | ||||
|           RAW_REQUEST_SUCCESS.labels(label).inc(); | ||||
|  | @ -147,6 +162,7 @@ public class RawKVClient implements AutoCloseable { | |||
|       throw e; | ||||
|     } finally { | ||||
|       requestTimer.observeDuration(); | ||||
|       slowLog.log(); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|  | @ -174,10 +190,21 @@ public class RawKVClient implements AutoCloseable { | |||
|   public ByteString putIfAbsent(ByteString key, ByteString value, long ttl) { | ||||
|     String label = "client_raw_put_if_absent"; | ||||
|     Histogram.Timer requestTimer = RAW_REQUEST_LATENCY.labels(label).startTimer(); | ||||
|     SlowLog slowLog = | ||||
|         new SlowLogImpl( | ||||
|             conf.getRawKVWriteSlowLogInMS(), | ||||
|             new HashMap<String, String>(2) { | ||||
|               { | ||||
|                 put("func", "putIfAbsent"); | ||||
|                 put("key", KeyUtils.formatBytesUTF8(key)); | ||||
|               } | ||||
|             }); | ||||
|     ConcreteBackOffer backOffer = | ||||
|         ConcreteBackOffer.newDeadlineBackOff(conf.getRawKVWriteTimeoutInMS(), slowLog); | ||||
|     try { | ||||
|       BackOffer backOffer = ConcreteBackOffer.newDeadlineBackOff(conf.getRawKVWriteTimeoutInMS()); | ||||
|       while (true) { | ||||
|         RegionStoreClient client = clientBuilder.build(key, backOffer); | ||||
|         slowLog.addProperty("region", client.getRegion().toString()); | ||||
|         try { | ||||
|           ByteString result = client.rawPutIfAbsent(backOffer, key, value, ttl); | ||||
|           RAW_REQUEST_SUCCESS.labels(label).inc(); | ||||
|  | @ -192,6 +219,7 @@ public class RawKVClient implements AutoCloseable { | |||
|       throw e; | ||||
|     } finally { | ||||
|       requestTimer.observeDuration(); | ||||
|       slowLog.log(); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|  | @ -236,9 +264,18 @@ public class RawKVClient implements AutoCloseable { | |||
|   private void batchPut(Map<ByteString, ByteString> kvPairs, long ttl, boolean atomic) { | ||||
|     String label = "client_raw_batch_put"; | ||||
|     Histogram.Timer requestTimer = RAW_REQUEST_LATENCY.labels(label).startTimer(); | ||||
|     SlowLog slowLog = | ||||
|         new SlowLogImpl( | ||||
|             conf.getRawKVBatchWriteSlowLogInMS(), | ||||
|             new HashMap<String, String>(2) { | ||||
|               { | ||||
|                 put("func", "batchPut"); | ||||
|                 put("keySize", String.valueOf(kvPairs.size())); | ||||
|               } | ||||
|             }); | ||||
|     ConcreteBackOffer backOffer = | ||||
|         ConcreteBackOffer.newDeadlineBackOff(conf.getRawKVBatchWriteTimeoutInMS(), slowLog); | ||||
|     try { | ||||
|       BackOffer backOffer = | ||||
|           ConcreteBackOffer.newDeadlineBackOff(conf.getRawKVBatchWriteTimeoutInMS()); | ||||
|       long deadline = System.currentTimeMillis() + conf.getRawKVBatchWriteTimeoutInMS(); | ||||
|       doSendBatchPut(backOffer, kvPairs, ttl, atomic, deadline); | ||||
|       RAW_REQUEST_SUCCESS.labels(label).inc(); | ||||
|  | @ -247,6 +284,7 @@ public class RawKVClient implements AutoCloseable { | |||
|       throw e; | ||||
|     } finally { | ||||
|       requestTimer.observeDuration(); | ||||
|       slowLog.log(); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|  | @ -259,10 +297,22 @@ public class RawKVClient implements AutoCloseable { | |||
|   public ByteString get(ByteString key) { | ||||
|     String label = "client_raw_get"; | ||||
|     Histogram.Timer requestTimer = RAW_REQUEST_LATENCY.labels(label).startTimer(); | ||||
|     SlowLog slowLog = | ||||
|         new SlowLogImpl( | ||||
|             conf.getRawKVReadSlowLogInMS(), | ||||
|             new HashMap<String, String>(2) { | ||||
|               { | ||||
|                 put("func", "get"); | ||||
|                 put("key", KeyUtils.formatBytesUTF8(key)); | ||||
|               } | ||||
|             }); | ||||
| 
 | ||||
|     ConcreteBackOffer backOffer = | ||||
|         ConcreteBackOffer.newDeadlineBackOff(conf.getRawKVReadTimeoutInMS(), slowLog); | ||||
|     try { | ||||
|       BackOffer backOffer = ConcreteBackOffer.newDeadlineBackOff(conf.getRawKVReadTimeoutInMS()); | ||||
|       while (true) { | ||||
|         RegionStoreClient client = clientBuilder.build(key, backOffer); | ||||
|         slowLog.addProperty("region", client.getRegion().toString()); | ||||
|         try { | ||||
|           ByteString result = client.rawGet(backOffer, key); | ||||
|           RAW_REQUEST_SUCCESS.labels(label).inc(); | ||||
|  | @ -277,6 +327,7 @@ public class RawKVClient implements AutoCloseable { | |||
|       throw e; | ||||
|     } finally { | ||||
|       requestTimer.observeDuration(); | ||||
|       slowLog.log(); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|  | @ -289,9 +340,18 @@ public class RawKVClient implements AutoCloseable { | |||
|   public List<KvPair> batchGet(List<ByteString> keys) { | ||||
|     String label = "client_raw_batch_get"; | ||||
|     Histogram.Timer requestTimer = RAW_REQUEST_LATENCY.labels(label).startTimer(); | ||||
|     SlowLog slowLog = | ||||
|         new SlowLogImpl( | ||||
|             conf.getRawKVBatchReadSlowLogInMS(), | ||||
|             new HashMap<String, String>(2) { | ||||
|               { | ||||
|                 put("func", "batchGet"); | ||||
|                 put("keySize", String.valueOf(keys.size())); | ||||
|               } | ||||
|             }); | ||||
|     ConcreteBackOffer backOffer = | ||||
|         ConcreteBackOffer.newDeadlineBackOff(conf.getRawKVBatchReadTimeoutInMS(), slowLog); | ||||
|     try { | ||||
|       BackOffer backOffer = | ||||
|           ConcreteBackOffer.newDeadlineBackOff(conf.getRawKVBatchReadTimeoutInMS()); | ||||
|       long deadline = System.currentTimeMillis() + conf.getRawKVBatchReadTimeoutInMS(); | ||||
|       List<KvPair> result = doSendBatchGet(backOffer, keys, deadline); | ||||
|       RAW_REQUEST_SUCCESS.labels(label).inc(); | ||||
|  | @ -301,6 +361,7 @@ public class RawKVClient implements AutoCloseable { | |||
|       throw e; | ||||
|     } finally { | ||||
|       requestTimer.observeDuration(); | ||||
|       slowLog.log(); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|  | @ -325,9 +386,18 @@ public class RawKVClient implements AutoCloseable { | |||
|   private void batchDelete(List<ByteString> keys, boolean atomic) { | ||||
|     String label = "client_raw_batch_delete"; | ||||
|     Histogram.Timer requestTimer = RAW_REQUEST_LATENCY.labels(label).startTimer(); | ||||
|     SlowLog slowLog = | ||||
|         new SlowLogImpl( | ||||
|             conf.getRawKVBatchWriteSlowLogInMS(), | ||||
|             new HashMap<String, String>(2) { | ||||
|               { | ||||
|                 put("func", "batchDelete"); | ||||
|                 put("keySize", String.valueOf(keys.size())); | ||||
|               } | ||||
|             }); | ||||
|     ConcreteBackOffer backOffer = | ||||
|         ConcreteBackOffer.newDeadlineBackOff(conf.getRawKVBatchWriteTimeoutInMS(), slowLog); | ||||
|     try { | ||||
|       BackOffer backOffer = | ||||
|           ConcreteBackOffer.newDeadlineBackOff(conf.getRawKVBatchWriteTimeoutInMS()); | ||||
|       long deadline = System.currentTimeMillis() + conf.getRawKVBatchWriteTimeoutInMS(); | ||||
|       doSendBatchDelete(backOffer, keys, atomic, deadline); | ||||
|       RAW_REQUEST_SUCCESS.labels(label).inc(); | ||||
|  | @ -337,6 +407,7 @@ public class RawKVClient implements AutoCloseable { | |||
|       throw e; | ||||
|     } finally { | ||||
|       requestTimer.observeDuration(); | ||||
|       slowLog.log(); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|  | @ -350,10 +421,21 @@ public class RawKVClient implements AutoCloseable { | |||
|   public Long getKeyTTL(ByteString key) { | ||||
|     String label = "client_raw_get_key_ttl"; | ||||
|     Histogram.Timer requestTimer = RAW_REQUEST_LATENCY.labels(label).startTimer(); | ||||
|     SlowLog slowLog = | ||||
|         new SlowLogImpl( | ||||
|             conf.getRawKVReadSlowLogInMS(), | ||||
|             new HashMap<String, String>(2) { | ||||
|               { | ||||
|                 put("func", "getKeyTTL"); | ||||
|                 put("key", KeyUtils.formatBytesUTF8(key)); | ||||
|               } | ||||
|             }); | ||||
|     ConcreteBackOffer backOffer = | ||||
|         ConcreteBackOffer.newDeadlineBackOff(conf.getRawKVReadTimeoutInMS(), slowLog); | ||||
|     try { | ||||
|       BackOffer backOffer = ConcreteBackOffer.newDeadlineBackOff(conf.getRawKVReadTimeoutInMS()); | ||||
|       while (true) { | ||||
|         RegionStoreClient client = clientBuilder.build(key, backOffer); | ||||
|         slowLog.addProperty("region", client.getRegion().toString()); | ||||
|         try { | ||||
|           Long result = client.rawGetKeyTTL(backOffer, key); | ||||
|           RAW_REQUEST_SUCCESS.labels(label).inc(); | ||||
|  | @ -368,6 +450,7 @@ public class RawKVClient implements AutoCloseable { | |||
|       throw e; | ||||
|     } finally { | ||||
|       requestTimer.observeDuration(); | ||||
|       slowLog.log(); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|  | @ -445,8 +528,21 @@ public class RawKVClient implements AutoCloseable { | |||
|   public List<KvPair> scan(ByteString startKey, ByteString endKey, int limit, boolean keyOnly) { | ||||
|     String label = "client_raw_scan"; | ||||
|     Histogram.Timer requestTimer = RAW_REQUEST_LATENCY.labels(label).startTimer(); | ||||
|     SlowLog slowLog = | ||||
|         new SlowLogImpl( | ||||
|             conf.getRawKVScanSlowLogInMS(), | ||||
|             new HashMap<String, String>(5) { | ||||
|               { | ||||
|                 put("func", "scan"); | ||||
|                 put("startKey", KeyUtils.formatBytesUTF8(startKey)); | ||||
|                 put("endKey", KeyUtils.formatBytesUTF8(endKey)); | ||||
|                 put("limit", String.valueOf(limit)); | ||||
|                 put("keyOnly", String.valueOf(keyOnly)); | ||||
|               } | ||||
|             }); | ||||
|     ConcreteBackOffer backOffer = | ||||
|         ConcreteBackOffer.newDeadlineBackOff(conf.getRawKVScanTimeoutInMS(), slowLog); | ||||
|     try { | ||||
|       BackOffer backOffer = ConcreteBackOffer.newDeadlineBackOff(conf.getRawKVScanTimeoutInMS()); | ||||
|       Iterator<KvPair> iterator = | ||||
|           rawScanIterator(conf, clientBuilder, startKey, endKey, limit, keyOnly, backOffer); | ||||
|       List<KvPair> result = new ArrayList<>(); | ||||
|  | @ -458,6 +554,7 @@ public class RawKVClient implements AutoCloseable { | |||
|       throw e; | ||||
|     } finally { | ||||
|       requestTimer.observeDuration(); | ||||
|       slowLog.log(); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|  | @ -506,18 +603,37 @@ public class RawKVClient implements AutoCloseable { | |||
|   public List<KvPair> scan(ByteString startKey, ByteString endKey, boolean keyOnly) { | ||||
|     String label = "client_raw_scan_without_limit"; | ||||
|     Histogram.Timer requestTimer = RAW_REQUEST_LATENCY.labels(label).startTimer(); | ||||
|     SlowLog slowLog = | ||||
|         new SlowLogImpl( | ||||
|             conf.getRawKVScanSlowLogInMS(), | ||||
|             new HashMap<String, String>(4) { | ||||
|               { | ||||
|                 put("func", "scan"); | ||||
|                 put("startKey", KeyUtils.formatBytesUTF8(startKey)); | ||||
|                 put("endKey", KeyUtils.formatBytesUTF8(endKey)); | ||||
|                 put("keyOnly", String.valueOf(keyOnly)); | ||||
|               } | ||||
|             }); | ||||
|     ConcreteBackOffer backOffer = | ||||
|         ConcreteBackOffer.newDeadlineBackOff(conf.getRawKVScanTimeoutInMS(), slowLog); | ||||
|     try { | ||||
|       BackOffer backOffer = ConcreteBackOffer.newDeadlineBackOff(conf.getRawKVScanTimeoutInMS()); | ||||
|       ByteString newStartKey = startKey; | ||||
|       List<KvPair> result = new ArrayList<>(); | ||||
|       while (true) { | ||||
|         Iterator<KvPair> iterator = | ||||
|             rawScanIterator( | ||||
|                 conf, clientBuilder, startKey, endKey, conf.getScanBatchSize(), keyOnly, backOffer); | ||||
|                 conf, | ||||
|                 clientBuilder, | ||||
|                 newStartKey, | ||||
|                 endKey, | ||||
|                 conf.getScanBatchSize(), | ||||
|                 keyOnly, | ||||
|                 backOffer); | ||||
|         if (!iterator.hasNext()) { | ||||
|           break; | ||||
|         } | ||||
|         iterator.forEachRemaining(result::add); | ||||
|         startKey = Key.toRawKey(result.get(result.size() - 1).getKey()).next().toByteString(); | ||||
|         newStartKey = Key.toRawKey(result.get(result.size() - 1).getKey()).next().toByteString(); | ||||
|       } | ||||
|       RAW_REQUEST_SUCCESS.labels(label).inc(); | ||||
|       return result; | ||||
|  | @ -526,6 +642,7 @@ public class RawKVClient implements AutoCloseable { | |||
|       throw e; | ||||
|     } finally { | ||||
|       requestTimer.observeDuration(); | ||||
|       slowLog.log(); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|  | @ -578,10 +695,22 @@ public class RawKVClient implements AutoCloseable { | |||
|   private void delete(ByteString key, boolean atomic) { | ||||
|     String label = "client_raw_delete"; | ||||
|     Histogram.Timer requestTimer = RAW_REQUEST_LATENCY.labels(label).startTimer(); | ||||
|     SlowLog slowLog = | ||||
|         new SlowLogImpl( | ||||
|             conf.getRawKVWriteSlowLogInMS(), | ||||
|             new HashMap<String, String>(3) { | ||||
|               { | ||||
|                 put("func", "delete"); | ||||
|                 put("key", KeyUtils.formatBytesUTF8(key)); | ||||
|                 put("atomic", String.valueOf(atomic)); | ||||
|               } | ||||
|             }); | ||||
|     ConcreteBackOffer backOffer = | ||||
|         ConcreteBackOffer.newDeadlineBackOff(conf.getRawKVWriteTimeoutInMS(), slowLog); | ||||
|     try { | ||||
|       BackOffer backOffer = ConcreteBackOffer.newDeadlineBackOff(conf.getRawKVWriteTimeoutInMS()); | ||||
|       while (true) { | ||||
|         RegionStoreClient client = clientBuilder.build(key, backOffer); | ||||
|         slowLog.addProperty("region", client.getRegion().toString()); | ||||
|         try { | ||||
|           client.rawDelete(backOffer, key, atomic); | ||||
|           RAW_REQUEST_SUCCESS.labels(label).inc(); | ||||
|  | @ -596,6 +725,7 @@ public class RawKVClient implements AutoCloseable { | |||
|       throw e; | ||||
|     } finally { | ||||
|       requestTimer.observeDuration(); | ||||
|       slowLog.log(); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|  | @ -611,8 +741,10 @@ public class RawKVClient implements AutoCloseable { | |||
|   public synchronized void deleteRange(ByteString startKey, ByteString endKey) { | ||||
|     String label = "client_raw_delete_range"; | ||||
|     Histogram.Timer requestTimer = RAW_REQUEST_LATENCY.labels(label).startTimer(); | ||||
|     ConcreteBackOffer backOffer = | ||||
|         ConcreteBackOffer.newDeadlineBackOff( | ||||
|             conf.getRawKVCleanTimeoutInMS(), SlowLogEmptyImpl.INSTANCE); | ||||
|     try { | ||||
|       BackOffer backOffer = ConcreteBackOffer.newDeadlineBackOff(conf.getRawKVCleanTimeoutInMS()); | ||||
|       long deadline = System.currentTimeMillis() + conf.getRawKVCleanTimeoutInMS(); | ||||
|       doSendDeleteRange(backOffer, startKey, endKey, deadline); | ||||
|       RAW_REQUEST_SUCCESS.labels(label).inc(); | ||||
|  |  | |||
|  | @ -19,6 +19,7 @@ import org.tikv.common.TiSession; | |||
| import org.tikv.common.codec.KeyUtils; | ||||
| import org.tikv.common.exception.TiKVException; | ||||
| import org.tikv.common.key.Key; | ||||
| import org.tikv.common.log.SlowLogEmptyImpl; | ||||
| import org.tikv.common.util.BackOffFunction; | ||||
| import org.tikv.common.util.BackOffer; | ||||
| import org.tikv.common.util.ConcreteBackOffer; | ||||
|  | @ -187,7 +188,7 @@ public class RawKVClientTest { | |||
|   public void testDeadlineBackOff() { | ||||
|     int timeout = 2000; | ||||
|     int sleep = 150; | ||||
|     BackOffer backOffer = ConcreteBackOffer.newDeadlineBackOff(timeout); | ||||
|     BackOffer backOffer = ConcreteBackOffer.newDeadlineBackOff(timeout, SlowLogEmptyImpl.INSTANCE); | ||||
|     long s = System.currentTimeMillis(); | ||||
|     try { | ||||
|       while (true) { | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue