View Javadoc
1   /*
2    * Copyright 2020 TiKV Project Authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   *
16   */
17  
18  package org.tikv.txn;
19  
20  import java.util.List;
21  import org.tikv.common.PDClient;
22  import org.tikv.common.StoreVersion;
23  import org.tikv.common.TiConfiguration;
24  import org.tikv.common.Version;
25  import org.tikv.common.apiversion.RequestKeyCodec;
26  import org.tikv.common.exception.KeyException;
27  import org.tikv.common.region.RegionManager;
28  import org.tikv.common.region.RegionStoreClient;
29  import org.tikv.common.region.TiRegion;
30  import org.tikv.common.region.TiStore;
31  import org.tikv.common.util.BackOffer;
32  import org.tikv.common.util.ChannelFactory;
33  import org.tikv.kvproto.Kvrpcpb;
34  import org.tikv.kvproto.TikvGrpc;
35  
36  public interface AbstractLockResolverClient {
37    /** ResolvedCacheSize is max number of cached txn status. */
38    long RESOLVED_TXN_CACHE_SIZE = 2048;
39  
40    /** transaction involves keys exceed this threshold can be treated as `big transaction`. */
41    long BIG_TXN_THRESHOLD = 16;
42  
43    static Lock extractLockFromKeyErr(Kvrpcpb.KeyError keyError, RequestKeyCodec codec) {
44      if (keyError.hasLocked()) {
45        return new Lock(keyError.getLocked(), codec);
46      }
47  
48      if (keyError.hasConflict()) {
49        Kvrpcpb.WriteConflict conflict = keyError.getConflict();
50        throw new KeyException(
51            String.format(
52                "scan meet key conflict on primary key %s at commit ts %s",
53                codec.decodeKey(conflict.getPrimary()), conflict.getConflictTs()));
54      }
55  
56      if (!keyError.getRetryable().isEmpty()) {
57        throw new KeyException(
58            String.format("tikv restart txn %s", keyError.getRetryableBytes().toStringUtf8()));
59      }
60  
61      if (!keyError.getAbort().isEmpty()) {
62        throw new KeyException(
63            String.format("tikv abort txn %s", keyError.getAbortBytes().toStringUtf8()));
64      }
65  
66      throw new KeyException(
67          String.format("unexpected key error meets and it is %s", keyError.toString()));
68    }
69  
70    static AbstractLockResolverClient getInstance(
71        TiConfiguration conf,
72        TiRegion region,
73        TiStore store,
74        TikvGrpc.TikvBlockingStub blockingStub,
75        TikvGrpc.TikvFutureStub asyncStub,
76        ChannelFactory channelFactory,
77        RegionManager regionManager,
78        PDClient pdClient,
79        RegionStoreClient.RegionStoreClientBuilder clientBuilder) {
80      if (StoreVersion.compareTo(store.getStore().getVersion(), Version.RESOLVE_LOCK_V3) < 0) {
81        return new LockResolverClientV2(
82            conf, region, store, blockingStub, asyncStub, channelFactory, regionManager);
83      } else if (StoreVersion.compareTo(store.getStore().getVersion(), Version.RESOLVE_LOCK_V4) < 0) {
84        return new LockResolverClientV3(
85            conf,
86            region,
87            store,
88            blockingStub,
89            asyncStub,
90            channelFactory,
91            regionManager,
92            pdClient,
93            clientBuilder);
94      } else {
95        return new LockResolverClientV4(
96            conf,
97            region,
98            store,
99            blockingStub,
100           asyncStub,
101           channelFactory,
102           regionManager,
103           pdClient,
104           clientBuilder);
105     }
106   }
107 
108   String getVersion();
109 
110   /**
111    * ResolveLocks tries to resolve Locks. The resolving process is in 3 steps: 1) Use the `lockTTL`
112    * to pick up all expired locks. Only locks that are old enough are considered orphan locks and
113    * will be handled later. If all locks are expired then all locks will be resolved so true will be
114    * returned, otherwise caller should sleep a while before retry. 2) For each lock, query the
115    * primary key to get txn(which left the lock)'s commit status. 3) Send `ResolveLock` cmd to the
116    * lock's region to resolve all locks belong to the same transaction.
117    *
118    * @param bo
119    * @param callerStartTS
120    * @param locks
121    * @param forWrite
122    * @return msBeforeTxnExpired: 0 means all locks are resolved
123    */
124   ResolveLockResult resolveLocks(
125       BackOffer bo, long callerStartTS, List<Lock> locks, boolean forWrite);
126 }