HBASE-26481 Consider rolling upgrading from old region replication framework (#3880)
[hbase.git] / hbase-client / src / main / java / org / apache / hadoop / hbase / ipc / HBaseRpcControllerImpl.java
blob7dde67c38e1cff45d402f2eea04bbbbfe473af69
1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
18 package org.apache.hadoop.hbase.ipc;
20 import org.apache.hadoop.hbase.client.RegionInfo;
21 import org.apache.hbase.thirdparty.com.google.protobuf.RpcCallback;
23 import java.io.IOException;
24 import java.util.ArrayList;
25 import java.util.List;
27 import org.apache.hadoop.hbase.CellScannable;
28 import org.apache.hadoop.hbase.CellScanner;
29 import org.apache.hadoop.hbase.CellUtil;
30 import org.apache.hadoop.hbase.HConstants;
31 import org.apache.hadoop.hbase.TableName;
32 import org.apache.yetus.audience.InterfaceAudience;
34 /**
35 * Get instances via {@link RpcControllerFactory} on client-side.
36 * @see RpcControllerFactory
38 @InterfaceAudience.Private
39 public class HBaseRpcControllerImpl implements HBaseRpcController {
40 /**
41 * The time, in ms before the call should expire.
43 private Integer callTimeout;
45 private boolean done = false;
47 private boolean cancelled = false;
49 private final List<RpcCallback<Object>> cancellationCbs = new ArrayList<>();
51 private IOException exception;
53 /**
54 * Rpc target Region's RegionInfo we are going against. May be null.
55 * @see #hasRegionInfo()
57 private RegionInfo regionInfo;
59 /**
60 * Priority to set on this request. Set it here in controller so available composing the request.
61 * This is the ordained way of setting priorities going forward. We will be undoing the old
62 * annotation-based mechanism.
64 private int priority = HConstants.PRIORITY_UNSET;
66 /**
67 * They are optionally set on construction, cleared after we make the call, and then optionally
68 * set on response with the result. We use this lowest common denominator access to Cells because
69 * sometimes the scanner is backed by a List of Cells and other times, it is backed by an encoded
70 * block that implements CellScanner.
72 private CellScanner cellScanner;
74 public HBaseRpcControllerImpl() {
75 this(null, (CellScanner) null);
78 /**
79 * Used server-side. Clients should go via {@link RpcControllerFactory}
81 public HBaseRpcControllerImpl(final CellScanner cellScanner) {
82 this(null, cellScanner);
85 HBaseRpcControllerImpl(RegionInfo regionInfo, final CellScanner cellScanner) {
86 this.cellScanner = cellScanner;
87 this.regionInfo = regionInfo;
90 HBaseRpcControllerImpl(RegionInfo regionInfo, final List<CellScannable> cellIterables) {
91 this.cellScanner = cellIterables == null ? null : CellUtil.createCellScanner(cellIterables);
92 this.regionInfo = null;
95 @Override
96 public boolean hasRegionInfo() {
97 return this.regionInfo != null;
100 @Override
101 public RegionInfo getRegionInfo() {
102 return this.regionInfo;
106 * @return One-shot cell scanner (you cannot back it up and restart)
108 @Override
109 public CellScanner cellScanner() {
110 return cellScanner;
113 @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "IS2_INCONSISTENT_SYNC",
114 justification = "The only possible race method is startCancel")
115 @Override
116 public void setCellScanner(final CellScanner cellScanner) {
117 this.cellScanner = cellScanner;
120 @Override
121 public void setPriority(int priority) {
122 this.priority = Math.max(this.priority, priority);
126 @Override
127 public void setPriority(final TableName tn) {
128 setPriority(
129 tn != null && tn.isSystemTable() ? HConstants.SYSTEMTABLE_QOS : HConstants.NORMAL_QOS);
132 @Override
133 public int getPriority() {
134 return priority < 0 ? HConstants.NORMAL_QOS : priority;
137 @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "IS2_INCONSISTENT_SYNC",
138 justification = "The only possible race method is startCancel")
139 @Override
140 public void reset() {
141 priority = 0;
142 cellScanner = null;
143 exception = null;
144 callTimeout = null;
145 regionInfo = null;
146 // In the implementations of some callable with replicas, rpc calls are executed in a executor
147 // and we could cancel the operation from outside which means there could be a race between
148 // reset and startCancel. Although I think the race should be handled by the callable since the
149 // reset may clear the cancel state...
150 synchronized (this) {
151 done = false;
152 cancelled = false;
153 cancellationCbs.clear();
157 @Override
158 public int getCallTimeout() {
159 return callTimeout != null? callTimeout: 0;
162 @Override
163 public void setCallTimeout(int callTimeout) {
164 this.callTimeout = callTimeout;
167 @Override
168 public boolean hasCallTimeout() {
169 return callTimeout != null;
172 @Override
173 public synchronized String errorText() {
174 if (!done || exception == null) {
175 return null;
177 return exception.getMessage();
180 @Override
181 public synchronized boolean failed() {
182 return done && this.exception != null;
185 @Override
186 public synchronized boolean isCanceled() {
187 return cancelled;
190 @Override
191 public void notifyOnCancel(RpcCallback<Object> callback) {
192 synchronized (this) {
193 if (done) {
194 return;
196 if (!cancelled) {
197 cancellationCbs.add(callback);
198 return;
201 // run it directly as we have already been cancelled.
202 callback.run(null);
205 @Override
206 public synchronized void setFailed(String reason) {
207 if (done) {
208 return;
210 done = true;
211 exception = new IOException(reason);
214 @Override
215 public synchronized void setFailed(IOException e) {
216 if (done) {
217 return;
219 done = true;
220 exception = e;
223 @Override
224 public synchronized IOException getFailed() {
225 return done ? exception : null;
228 @Override
229 public synchronized void setDone(CellScanner cellScanner) {
230 if (done) {
231 return;
233 done = true;
234 this.cellScanner = cellScanner;
237 @Override
238 public void startCancel() {
239 // As said above in the comment of reset, the cancellationCbs maybe cleared by reset, so we need
240 // to copy it.
241 List<RpcCallback<Object>> cbs;
242 synchronized (this) {
243 if (done) {
244 return;
246 done = true;
247 cancelled = true;
248 cbs = new ArrayList<>(cancellationCbs);
250 for (RpcCallback<?> cb : cbs) {
251 cb.run(null);
255 @Override
256 public synchronized void notifyOnCancel(RpcCallback<Object> callback, CancellationCallback action)
257 throws IOException {
258 if (cancelled) {
259 action.run(true);
260 } else {
261 cancellationCbs.add(callback);
262 action.run(false);