1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.hadoop.hbase.client;
21
22 import java.io.Closeable;
23 import java.io.IOException;
24 import java.lang.reflect.Proxy;
25 import java.lang.reflect.UndeclaredThrowableException;
26 import java.net.InetSocketAddress;
27 import java.util.ArrayList;
28 import java.util.Collections;
29 import java.util.HashMap;
30 import java.util.HashSet;
31 import java.util.LinkedHashMap;
32 import java.util.List;
33 import java.util.Map;
34 import java.util.Map.Entry;
35 import java.util.NavigableMap;
36 import java.util.Set;
37 import java.util.TreeMap;
38 import java.util.concurrent.Callable;
39 import java.util.concurrent.ConcurrentHashMap;
40 import java.util.concurrent.CopyOnWriteArraySet;
41 import java.util.concurrent.ExecutionException;
42 import java.util.concurrent.ExecutorService;
43 import java.util.concurrent.Future;
44 import java.util.concurrent.SynchronousQueue;
45 import java.util.concurrent.ThreadPoolExecutor;
46 import java.util.concurrent.TimeUnit;
47 import java.util.concurrent.atomic.AtomicBoolean;
48 import java.util.concurrent.atomic.AtomicInteger;
49
50 import org.apache.commons.logging.Log;
51 import org.apache.commons.logging.LogFactory;
52 import org.apache.hadoop.conf.Configuration;
53 import org.apache.hadoop.hbase.DoNotRetryIOException;
54 import org.apache.hadoop.hbase.HBaseConfiguration;
55 import org.apache.hadoop.hbase.HConstants;
56 import org.apache.hadoop.hbase.HRegionInfo;
57 import org.apache.hadoop.hbase.HRegionLocation;
58 import org.apache.hadoop.hbase.HServerAddress;
59 import org.apache.hadoop.hbase.HTableDescriptor;
60 import org.apache.hadoop.hbase.KeyValue;
61 import org.apache.hadoop.hbase.MasterAddressTracker;
62 import org.apache.hadoop.hbase.MasterNotRunningException;
63 import org.apache.hadoop.hbase.RemoteExceptionHandler;
64 import org.apache.hadoop.hbase.ServerName;
65 import org.apache.hadoop.hbase.TableNotFoundException;
66 import org.apache.hadoop.hbase.ZooKeeperConnectionException;
67 import org.apache.hadoop.hbase.client.MetaScanner.MetaScannerVisitor;
68 import org.apache.hadoop.hbase.client.MetaScanner.MetaScannerVisitorBase;
69 import org.apache.hadoop.hbase.client.coprocessor.Batch;
70 import org.apache.hadoop.hbase.ipc.CoprocessorProtocol;
71 import org.apache.hadoop.hbase.ipc.ExecRPCInvoker;
72 import org.apache.hadoop.hbase.ipc.HBaseRPC;
73 import org.apache.hadoop.hbase.ipc.HMasterInterface;
74 import org.apache.hadoop.hbase.ipc.HRegionInterface;
75 import org.apache.hadoop.hbase.ipc.RpcEngine;
76 import org.apache.hadoop.hbase.util.Addressing;
77 import org.apache.hadoop.hbase.util.Bytes;
78 import org.apache.hadoop.hbase.util.Pair;
79 import org.apache.hadoop.hbase.util.SoftValueSortedMap;
80 import org.apache.hadoop.hbase.util.Threads;
81 import org.apache.hadoop.hbase.util.Writables;
82 import org.apache.hadoop.hbase.zookeeper.ClusterId;
83 import org.apache.hadoop.hbase.zookeeper.RootRegionTracker;
84 import org.apache.hadoop.hbase.zookeeper.ZKTableReadOnly;
85 import org.apache.hadoop.hbase.zookeeper.ZKUtil;
86 import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
87 import org.apache.hadoop.ipc.RemoteException;
88 import org.apache.zookeeper.KeeperException;
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151 @SuppressWarnings("serial")
152 public class HConnectionManager {
153
154
155
156 static final Map<HConnectionKey, HConnectionImplementation> HBASE_INSTANCES;
157
158 public static final int MAX_CACHED_HBASE_INSTANCES;
159
160 private static Log LOG = LogFactory.getLog(HConnectionManager.class);
161
162 static {
163
164
165
166
167 MAX_CACHED_HBASE_INSTANCES = HBaseConfiguration.create().getInt(
168 HConstants.ZOOKEEPER_MAX_CLIENT_CNXNS,
169 HConstants.DEFAULT_ZOOKEPER_MAX_CLIENT_CNXNS) + 1;
170 HBASE_INSTANCES = new LinkedHashMap<HConnectionKey, HConnectionImplementation>(
171 (int) (MAX_CACHED_HBASE_INSTANCES / 0.75F) + 1, 0.75F, true) {
172 @Override
173 protected boolean removeEldestEntry(
174 Map.Entry<HConnectionKey, HConnectionImplementation> eldest) {
175 return size() > MAX_CACHED_HBASE_INSTANCES;
176 }
177 };
178 }
179
180
181
182
183 protected HConnectionManager() {
184 super();
185 }
186
187
188
189
190
191
192
193
194
195
196 public static HConnection getConnection(Configuration conf)
197 throws ZooKeeperConnectionException {
198 HConnectionKey connectionKey = new HConnectionKey(conf);
199 synchronized (HBASE_INSTANCES) {
200 HConnectionImplementation connection = HBASE_INSTANCES.get(connectionKey);
201 if (connection == null) {
202 connection = new HConnectionImplementation(conf, true, null);
203 HBASE_INSTANCES.put(connectionKey, connection);
204 } else if (connection.isClosed()) {
205 HConnectionManager.deleteConnection(connectionKey, true);
206 connection = new HConnectionImplementation(conf, true, null);
207 HBASE_INSTANCES.put(connectionKey, connection);
208 }
209 connection.incCount();
210 return connection;
211 }
212 }
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234 public static HConnection createConnection(Configuration conf)
235 throws ZooKeeperConnectionException {
236 return new HConnectionImplementation(conf, false, null);
237 }
238
239 public static HConnection createConnection(Configuration conf, ExecutorService pool)
240 throws IOException {
241 return new HConnectionImplementation(conf, false, pool);
242 }
243
244
245
246
247
248
249
250
251
252
253
254
255
256 @Deprecated
257 public static void deleteConnection(Configuration conf, boolean stopProxy) {
258 deleteConnection(conf);
259 }
260
261
262
263
264
265
266
267
268
269
270 @Deprecated
271 public static void deleteConnection(Configuration conf) {
272 deleteConnection(new HConnectionKey(conf), false);
273 }
274
275
276
277
278
279
280
281
282 public static void deleteStaleConnection(HConnection connection) {
283 deleteConnection(connection, true);
284 }
285
286
287
288
289
290
291 @Deprecated
292 public static void deleteAllConnections(boolean stopProxy) {
293 deleteAllConnections();
294 }
295
296
297
298
299
300 @Deprecated
301 public static void deleteAllConnections() {
302 synchronized (HBASE_INSTANCES) {
303 Set<HConnectionKey> connectionKeys = new HashSet<HConnectionKey>();
304 connectionKeys.addAll(HBASE_INSTANCES.keySet());
305 for (HConnectionKey connectionKey : connectionKeys) {
306 deleteConnection(connectionKey, false);
307 }
308 HBASE_INSTANCES.clear();
309 }
310 }
311
312 @Deprecated
313 private static void deleteConnection(HConnection connection, boolean staleConnection) {
314 synchronized (HBASE_INSTANCES) {
315 for (Entry<HConnectionKey, HConnectionImplementation> connectionEntry : HBASE_INSTANCES
316 .entrySet()) {
317 if (connectionEntry.getValue() == connection) {
318 deleteConnection(connectionEntry.getKey(), staleConnection);
319 break;
320 }
321 }
322 }
323 }
324
325 @Deprecated
326 private static void deleteConnection(HConnectionKey connectionKey,
327 boolean staleConnection) {
328 synchronized (HBASE_INSTANCES) {
329 HConnectionImplementation connection = HBASE_INSTANCES
330 .get(connectionKey);
331 if (connection != null) {
332 connection.decCount();
333 if (connection.isZeroReference() || staleConnection) {
334 HBASE_INSTANCES.remove(connectionKey);
335 connection.internalClose();
336 }
337 }else {
338 LOG.error("Connection not found in the list, can't delete it "+
339 "(connection key="+connectionKey+"). May be the key was modified?");
340 }
341 }
342 }
343
344
345
346
347
348
349
350 static int getCachedRegionCount(Configuration conf,
351 final byte[] tableName)
352 throws IOException {
353 return execute(new HConnectable<Integer>(conf) {
354 @Override
355 public Integer connect(HConnection connection) {
356 return ((HConnectionImplementation) connection)
357 .getNumberOfCachedRegionLocations(tableName);
358 }
359 });
360 }
361
362
363
364
365
366
367
368 static boolean isRegionCached(Configuration conf,
369 final byte[] tableName, final byte[] row) throws IOException {
370 return execute(new HConnectable<Boolean>(conf) {
371 @Override
372 public Boolean connect(HConnection connection) {
373 return ((HConnectionImplementation) connection).isRegionCached(tableName, row);
374 }
375 });
376 }
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392 public static abstract class HConnectable<T> {
393 public Configuration conf;
394
395 public HConnectable(Configuration conf) {
396 this.conf = conf;
397 }
398
399 public abstract T connect(HConnection connection) throws IOException;
400 }
401
402
403
404
405
406
407
408
409
410
411
412 public static <T> T execute(HConnectable<T> connectable) throws IOException {
413 if (connectable == null || connectable.conf == null) {
414 return null;
415 }
416 Configuration conf = connectable.conf;
417 HConnection connection = HConnectionManager.getConnection(conf);
418 boolean connectSucceeded = false;
419 try {
420 T returnValue = connectable.connect(connection);
421 connectSucceeded = true;
422 return returnValue;
423 } finally {
424 try {
425 connection.close();
426 } catch (Exception e) {
427 if (connectSucceeded) {
428 throw new IOException("The connection to " + connection
429 + " could not be deleted.", e);
430 }
431 }
432 }
433 }
434
435
436
437
438
439
440
441
442
443
444 public static class HConnectionKey {
445 public static String[] CONNECTION_PROPERTIES = new String[] {
446 HConstants.ZOOKEEPER_QUORUM, HConstants.ZOOKEEPER_ZNODE_PARENT,
447 HConstants.ZOOKEEPER_CLIENT_PORT,
448 HConstants.ZOOKEEPER_RECOVERABLE_WAITTIME,
449 HConstants.HBASE_CLIENT_PAUSE, HConstants.HBASE_CLIENT_RETRIES_NUMBER,
450 HConstants.HBASE_CLIENT_RPC_MAXATTEMPTS,
451 HConstants.HBASE_RPC_TIMEOUT_KEY,
452 HConstants.HBASE_CLIENT_PREFETCH_LIMIT,
453 HConstants.HBASE_META_SCANNER_CACHING,
454 HConstants.HBASE_CLIENT_INSTANCE_ID };
455
456 private Map<String, String> properties;
457 private String username;
458
459 public HConnectionKey(Configuration conf) {
460 Map<String, String> m = new HashMap<String, String>();
461 if (conf != null) {
462 for (String property : CONNECTION_PROPERTIES) {
463 String value = conf.get(property);
464 if (value != null) {
465 m.put(property, value);
466 }
467 }
468 }
469 this.properties = Collections.unmodifiableMap(m);
470
471 try {
472 UserProvider provider = UserProvider.instantiate(conf);
473 username = provider.getCurrentUserName();
474 } catch (IOException ioe) {
475 LOG.warn("Error obtaining current user, skipping username in HConnectionKey",
476 ioe);
477 }
478 }
479
480 @Override
481 public int hashCode() {
482 final int prime = 31;
483 int result = 1;
484 if (username != null) {
485 result = username.hashCode();
486 }
487 for (String property : CONNECTION_PROPERTIES) {
488 String value = properties.get(property);
489 if (value != null) {
490 result = prime * result + value.hashCode();
491 }
492 }
493
494 return result;
495 }
496
497 @Override
498 public boolean equals(Object obj) {
499 if (this == obj)
500 return true;
501 if (obj == null)
502 return false;
503 if (getClass() != obj.getClass())
504 return false;
505 HConnectionKey that = (HConnectionKey) obj;
506 if (this.username != null && !this.username.equals(that.username)) {
507 return false;
508 } else if (this.username == null && that.username != null) {
509 return false;
510 }
511 if (this.properties == null) {
512 if (that.properties != null) {
513 return false;
514 }
515 } else {
516 if (that.properties == null) {
517 return false;
518 }
519 for (String property : CONNECTION_PROPERTIES) {
520 String thisValue = this.properties.get(property);
521 String thatValue = that.properties.get(property);
522 if (thisValue == thatValue) {
523 continue;
524 }
525 if (thisValue == null || !thisValue.equals(thatValue)) {
526 return false;
527 }
528 }
529 }
530 return true;
531 }
532
533 @Override
534 public String toString() {
535 return "HConnectionKey{" +
536 "properties=" + properties +
537 ", username='" + username + '\'' +
538 '}';
539 }
540 }
541
542
543 static class HConnectionImplementation implements HConnection, Closeable {
544 static final Log LOG = LogFactory.getLog(HConnectionImplementation.class);
545 private final Class<? extends HRegionInterface> serverInterfaceClass;
546 private final long pause;
547 private final int numRetries;
548 private final int maxRPCAttempts;
549 private final int rpcTimeout;
550 private final int prefetchRegionLimit;
551
552 private final Object masterLock = new Object();
553 private volatile boolean closed;
554 private volatile boolean aborted;
555 private volatile boolean resetting;
556 private volatile HMasterInterface master;
557
558 private volatile ZooKeeperWatcher zooKeeper;
559
560 private volatile MasterAddressTracker masterAddressTracker;
561 private volatile RootRegionTracker rootRegionTracker;
562 private volatile ClusterId clusterId;
563
564 private final Object metaRegionLock = new Object();
565
566 private final Object userRegionLock = new Object();
567
568 private final Object resetLock = new Object();
569
570
571
572 private volatile ExecutorService batchPool = null;
573 private volatile boolean cleanupPool = false;
574
575 private final Configuration conf;
576
577 private RpcEngine rpcEngine;
578
579
580
581 private final Map<String, HRegionInterface> servers =
582 new ConcurrentHashMap<String, HRegionInterface>();
583 private final ConcurrentHashMap<String, String> connectionLock =
584 new ConcurrentHashMap<String, String>();
585
586
587
588
589
590 private final Map<Integer, SoftValueSortedMap<byte [], HRegionLocation>>
591 cachedRegionLocations =
592 new HashMap<Integer, SoftValueSortedMap<byte [], HRegionLocation>>();
593
594
595
596
597
598 private final Set<String> cachedServers =
599 new HashSet<String>();
600
601
602
603 private final Set<Integer> regionCachePrefetchDisabledTables =
604 new CopyOnWriteArraySet<Integer>();
605
606 private int refCount;
607
608
609 private final boolean managed;
610
611
612
613
614 @SuppressWarnings("unchecked")
615 public HConnectionImplementation(Configuration conf, boolean managed, ExecutorService pool)
616 throws ZooKeeperConnectionException {
617 this.conf = conf;
618 this.batchPool = pool;
619 this.managed = managed;
620 String serverClassName = conf.get(HConstants.REGION_SERVER_CLASS,
621 HConstants.DEFAULT_REGION_SERVER_CLASS);
622 this.closed = false;
623 try {
624 this.serverInterfaceClass =
625 (Class<? extends HRegionInterface>) Class.forName(serverClassName);
626 } catch (ClassNotFoundException e) {
627 throw new UnsupportedOperationException(
628 "Unable to find region server interface " + serverClassName, e);
629 }
630 this.pause = conf.getLong(HConstants.HBASE_CLIENT_PAUSE,
631 HConstants.DEFAULT_HBASE_CLIENT_PAUSE);
632 this.numRetries = conf.getInt(HConstants.HBASE_CLIENT_RETRIES_NUMBER,
633 HConstants.DEFAULT_HBASE_CLIENT_RETRIES_NUMBER);
634 this.maxRPCAttempts = conf.getInt(
635 HConstants.HBASE_CLIENT_RPC_MAXATTEMPTS,
636 HConstants.DEFAULT_HBASE_CLIENT_RPC_MAXATTEMPTS);
637 this.rpcTimeout = conf.getInt(
638 HConstants.HBASE_RPC_TIMEOUT_KEY,
639 HConstants.DEFAULT_HBASE_RPC_TIMEOUT);
640 this.prefetchRegionLimit = conf.getInt(
641 HConstants.HBASE_CLIENT_PREFETCH_LIMIT,
642 HConstants.DEFAULT_HBASE_CLIENT_PREFETCH_LIMIT);
643
644 this.master = null;
645 this.resetting = false;
646 }
647
648 @Override
649 public HTableInterface getTable(String tableName) throws IOException {
650 return getTable(Bytes.toBytes(tableName));
651 }
652
653 @Override
654 public HTableInterface getTable(byte[] tableName) throws IOException {
655 return getTable(tableName, getBatchPool());
656 }
657
658 @Override
659 public HTableInterface getTable(String tableName, ExecutorService pool) throws IOException {
660 return getTable(Bytes.toBytes(tableName), pool);
661 }
662
663 @Override
664 public HTableInterface getTable(byte[] tableName, ExecutorService pool) throws IOException {
665 if (managed) {
666 throw new IOException("The connection has to be unmanaged.");
667 }
668 return new HTable(tableName, this, pool);
669 }
670
671 private ExecutorService getBatchPool() {
672 if (batchPool == null) {
673
674 synchronized (this) {
675 if (batchPool == null) {
676 int maxThreads = conf.getInt("hbase.hconnection.threads.max", Integer.MAX_VALUE);
677 if (maxThreads == 0) {
678 maxThreads = Runtime.getRuntime().availableProcessors();
679 }
680 long keepAliveTime = conf.getLong("hbase.hconnection.threads.keepalivetime", 60);
681 this.batchPool = new ThreadPoolExecutor(Runtime.getRuntime().availableProcessors(),
682 maxThreads, keepAliveTime, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(),
683 Threads.newDaemonThreadFactory("hbase-connection-shared-executor"));
684 ((ThreadPoolExecutor) this.batchPool).allowCoreThreadTimeOut(true);
685 }
686 this.cleanupPool = true;
687 }
688 }
689 return this.batchPool;
690 }
691
692 protected ExecutorService getCurrentBatchPool() {
693 return batchPool;
694 }
695
696 private void shutdownBatchPool() {
697 if (this.cleanupPool && this.batchPool != null && !this.batchPool.isShutdown()) {
698 this.batchPool.shutdown();
699 try {
700 if (!this.batchPool.awaitTermination(10, TimeUnit.SECONDS)) {
701 this.batchPool.shutdownNow();
702 }
703 } catch (InterruptedException e) {
704 this.batchPool.shutdownNow();
705 }
706 }
707 }
708
709 private synchronized void ensureZookeeperTrackers()
710 throws ZooKeeperConnectionException {
711
712 if (zooKeeper == null) {
713 zooKeeper = getZooKeeperWatcher();
714 }
715 if (clusterId == null) {
716 clusterId = new ClusterId(zooKeeper, this);
717 if (clusterId.hasId()) {
718 conf.set(HConstants.CLUSTER_ID, clusterId.getId());
719 }
720 }
721 if (masterAddressTracker == null) {
722 masterAddressTracker = new MasterAddressTracker(zooKeeper, this);
723 masterAddressTracker.start();
724 }
725 if (rootRegionTracker == null) {
726 rootRegionTracker = new RootRegionTracker(zooKeeper, this);
727 rootRegionTracker.start();
728 }
729
730 if (rpcEngine == null) {
731 this.rpcEngine = HBaseRPC.getProtocolEngine(conf);
732 }
733 }
734
735 private synchronized void resetZooKeeperTrackers() {
736 if (masterAddressTracker != null) {
737 masterAddressTracker.stop();
738 masterAddressTracker = null;
739 }
740 if (rootRegionTracker != null) {
741 rootRegionTracker.stop();
742 rootRegionTracker = null;
743 }
744 clusterId = null;
745 if (zooKeeper != null) {
746 zooKeeper.close();
747 zooKeeper = null;
748 }
749 }
750
751 public Configuration getConfiguration() {
752 return this.conf;
753 }
754
755
756
757
758
759 private boolean shouldRetryGetMaster(int tries, Exception e) {
760 if (tries == numRetries - 1) {
761
762 LOG.info("getMaster attempt " + tries + " of " + numRetries +
763 " failed; no more retrying.", e);
764 return false;
765 }
766 LOG.info("getMaster attempt " + tries + " of " + numRetries +
767 " failed; retrying after sleep of " +
768 ConnectionUtils.getPauseTime(this.pause, tries), e);
769 return true;
770 }
771
772 public HMasterInterface getMaster()
773 throws MasterNotRunningException, ZooKeeperConnectionException {
774
775
776
777 try {
778 if (master != null && master.isMasterRunning()) {
779 return master;
780 }
781 } catch (UndeclaredThrowableException ute) {
782
783 LOG.info("Exception contacting master. Retrying...", ute.getCause());
784 }
785
786 ensureZookeeperTrackers();
787 checkIfBaseNodeAvailable();
788 ServerName sn = null;
789 synchronized (this.masterLock) {
790 try {
791 if (master != null && master.isMasterRunning()) {
792 return master;
793 }
794 } catch (UndeclaredThrowableException ute) {
795
796 LOG.info("Exception contacting master. Retrying...", ute.getCause());
797 }
798 this.master = null;
799
800 for (int tries = 0;
801 !this.closed && this.master == null && tries < numRetries;
802 tries++) {
803
804 try {
805 sn = masterAddressTracker.getMasterAddress();
806 if (sn == null) {
807 LOG.info("ZooKeeper available but no active master location found");
808 throw new MasterNotRunningException();
809 }
810
811 InetSocketAddress isa =
812 new InetSocketAddress(sn.getHostname(), sn.getPort());
813 HMasterInterface tryMaster = rpcEngine.getProxy(
814 HMasterInterface.class, HMasterInterface.VERSION, isa, this.conf,
815 this.rpcTimeout);
816
817 if (tryMaster.isMasterRunning()) {
818 this.master = tryMaster;
819 this.masterLock.notifyAll();
820 break;
821 }
822
823 } catch (IOException e) {
824 if (!shouldRetryGetMaster(tries, e)) break;
825 } catch (UndeclaredThrowableException ute) {
826 if (!shouldRetryGetMaster(tries, ute)) break;
827 }
828
829
830 try {
831 this.masterLock.wait(ConnectionUtils.getPauseTime(this.pause, tries));
832 } catch (InterruptedException e) {
833 Thread.currentThread().interrupt();
834 throw new RuntimeException("Thread was interrupted while trying to connect to master.");
835 }
836 }
837
838 if (this.master == null) {
839 if (sn == null) {
840 throw new MasterNotRunningException();
841 }
842 throw new MasterNotRunningException(sn.toString());
843 }
844 return this.master;
845 }
846 }
847
848 private void checkIfBaseNodeAvailable() throws MasterNotRunningException {
849 if (false == masterAddressTracker.checkIfBaseNodeAvailable()) {
850 String errorMsg = "Check the value configured in 'zookeeper.znode.parent'. "
851 + "There could be a mismatch with the one configured in the master.";
852 LOG.error(errorMsg);
853 throw new MasterNotRunningException(errorMsg);
854 }
855 }
856
857 public boolean isMasterRunning()
858 throws MasterNotRunningException, ZooKeeperConnectionException {
859 if (this.master == null) {
860 getMaster();
861 }
862 boolean isRunning = master.isMasterRunning();
863 if(isRunning) {
864 return true;
865 }
866 throw new MasterNotRunningException();
867 }
868
869 public HRegionLocation getRegionLocation(final byte [] name,
870 final byte [] row, boolean reload)
871 throws IOException {
872 return reload? relocateRegion(name, row): locateRegion(name, row);
873 }
874
875 public boolean isTableEnabled(byte[] tableName) throws IOException {
876 return testTableOnlineState(tableName, true);
877 }
878
879 public boolean isTableDisabled(byte[] tableName) throws IOException {
880 return testTableOnlineState(tableName, false);
881 }
882
883 public boolean isTableAvailable(final byte[] tableName) throws IOException {
884 final AtomicBoolean available = new AtomicBoolean(true);
885 final AtomicInteger regionCount = new AtomicInteger(0);
886 MetaScannerVisitor visitor = new MetaScannerVisitorBase() {
887 @Override
888 public boolean processRow(Result row) throws IOException {
889 byte[] value = row.getValue(HConstants.CATALOG_FAMILY,
890 HConstants.REGIONINFO_QUALIFIER);
891 HRegionInfo info = Writables.getHRegionInfoOrNull(value);
892 if (info != null && !info.isSplitParent()) {
893 if (Bytes.equals(tableName, info.getTableName())) {
894 value = row.getValue(HConstants.CATALOG_FAMILY,
895 HConstants.SERVER_QUALIFIER);
896 if (value == null) {
897 available.set(false);
898 return false;
899 }
900 regionCount.incrementAndGet();
901 }
902 }
903 return true;
904 }
905 };
906 MetaScanner.metaScan(conf, this, visitor, null);
907 return available.get() && (regionCount.get() > 0);
908 }
909
910
911
912
913 private boolean testTableOnlineState(byte [] tableName, boolean online)
914 throws IOException {
915 if (Bytes.equals(tableName, HConstants.ROOT_TABLE_NAME)) {
916
917 return online;
918 }
919 ZooKeeperWatcher zkw = getZooKeeperWatcher();
920 String tableNameStr = Bytes.toString(tableName);
921 try {
922 if (online) {
923 return ZKTableReadOnly.isEnabledTable(zkw, tableNameStr);
924 }
925 return ZKTableReadOnly.isDisabledTable(zkw, tableNameStr);
926 } catch (KeeperException e) {
927 throw new IOException("Enable/Disable failed", e);
928 }
929 }
930
931 @Override
932 public HRegionLocation locateRegion(final byte[] regionName) throws IOException {
933 return locateRegion(HRegionInfo.getTableName(regionName),
934 HRegionInfo.getStartKey(regionName), false, true);
935 }
936
937 @Override
938 public List<HRegionLocation> locateRegions(final byte[] tableName)
939 throws IOException {
940 return locateRegions(tableName, false, true);
941 }
942
943 @Override
944 public List<HRegionLocation> locateRegions(final byte[] tableName, final boolean useCache,
945 final boolean offlined) throws IOException {
946 NavigableMap<HRegionInfo, ServerName> regions = MetaScanner.allTableRegions(conf, this,
947 tableName, offlined);
948 final List<HRegionLocation> locations = new ArrayList<HRegionLocation>();
949 for (HRegionInfo regionInfo : regions.keySet()) {
950 locations.add(locateRegion(tableName, regionInfo.getStartKey(), useCache, true));
951 }
952 return locations;
953 }
954
955 public HRegionLocation locateRegion(final byte [] tableName,
956 final byte [] row)
957 throws IOException{
958 return locateRegion(tableName, row, true, true);
959 }
960
961 public HRegionLocation relocateRegion(final byte [] tableName,
962 final byte [] row)
963 throws IOException{
964
965
966
967
968 if (isTableDisabled(tableName)) {
969 throw new DoNotRetryIOException(Bytes.toString(tableName) + " is disabled.");
970 }
971
972 return locateRegion(tableName, row, false, true);
973 }
974
975 private HRegionLocation locateRegion(final byte [] tableName,
976 final byte [] row, boolean useCache, boolean retry)
977 throws IOException {
978 if (this.closed) throw new IOException(toString() + " closed");
979 if (tableName == null || tableName.length == 0) {
980 throw new IllegalArgumentException(
981 "table name cannot be null or zero length");
982 }
983 ensureZookeeperTrackers();
984 if (Bytes.equals(tableName, HConstants.ROOT_TABLE_NAME)) {
985 try {
986 ServerName servername = this.rootRegionTracker.waitRootRegionLocation(this.rpcTimeout);
987 LOG.debug("Looked up root region location, connection=" + this +
988 "; serverName=" + ((servername == null)? "": servername.toString()));
989 if (servername == null) return null;
990 return new HRegionLocation(HRegionInfo.ROOT_REGIONINFO,
991 servername.getHostname(), servername.getPort());
992 } catch (InterruptedException e) {
993 Thread.currentThread().interrupt();
994 return null;
995 }
996 } else if (Bytes.equals(tableName, HConstants.META_TABLE_NAME)) {
997 return locateRegionInMeta(HConstants.ROOT_TABLE_NAME, tableName, row,
998 useCache, metaRegionLock, retry);
999 } else {
1000
1001 return locateRegionInMeta(HConstants.META_TABLE_NAME, tableName, row,
1002 useCache, userRegionLock, retry);
1003 }
1004 }
1005
1006
1007
1008
1009
1010
1011 private void prefetchRegionCache(final byte[] tableName,
1012 final byte[] row) {
1013
1014
1015 MetaScannerVisitor visitor = new MetaScannerVisitorBase() {
1016 public boolean processRow(Result result) throws IOException {
1017 try {
1018 byte[] value = result.getValue(HConstants.CATALOG_FAMILY,
1019 HConstants.REGIONINFO_QUALIFIER);
1020 HRegionInfo regionInfo = null;
1021
1022 if (value != null) {
1023
1024 regionInfo = Writables.getHRegionInfo(value);
1025
1026
1027 if (!Bytes.equals(regionInfo.getTableName(),
1028 tableName)) {
1029 return false;
1030 }
1031 if (regionInfo.isOffline()) {
1032
1033 return true;
1034 }
1035 value = result.getValue(HConstants.CATALOG_FAMILY,
1036 HConstants.SERVER_QUALIFIER);
1037 if (value == null) {
1038 return true;
1039 }
1040 final String hostAndPort = Bytes.toString(value);
1041 String hostname = Addressing.parseHostname(hostAndPort);
1042 int port = Addressing.parsePort(hostAndPort);
1043 value = result.getValue(HConstants.CATALOG_FAMILY,
1044 HConstants.STARTCODE_QUALIFIER);
1045
1046 HRegionLocation loc =
1047 new HRegionLocation(regionInfo, hostname, port);
1048
1049 cacheLocation(tableName, loc);
1050 }
1051 return true;
1052 } catch (RuntimeException e) {
1053 throw new IOException(e);
1054 }
1055 }
1056 };
1057 try {
1058
1059 MetaScanner.metaScan(conf, this, visitor, tableName, row,
1060 this.prefetchRegionLimit, HConstants.META_TABLE_NAME);
1061 } catch (IOException e) {
1062 LOG.warn("Encountered problems when prefetch META table: ", e);
1063 }
1064 }
1065
1066
1067
1068
1069
1070 private HRegionLocation locateRegionInMeta(final byte [] parentTable,
1071 final byte [] tableName, final byte [] row, boolean useCache,
1072 Object regionLockObject, boolean retry)
1073 throws IOException {
1074 HRegionLocation location;
1075
1076
1077 if (useCache) {
1078 location = getCachedLocation(tableName, row);
1079 if (location != null) {
1080 return location;
1081 }
1082 }
1083
1084 int localNumRetries = retry ? numRetries : 1;
1085
1086
1087
1088 byte [] metaKey = HRegionInfo.createRegionName(tableName, row,
1089 HConstants.NINES, false);
1090 for (int tries = 0; true; tries++) {
1091 if (tries >= localNumRetries) {
1092 throw new NoServerForRegionException("Unable to find region for "
1093 + Bytes.toStringBinary(row) + " after " + numRetries + " tries.");
1094 }
1095
1096 HRegionLocation metaLocation = null;
1097 try {
1098
1099 metaLocation = locateRegion(parentTable, metaKey, true, false);
1100
1101 if (metaLocation == null) continue;
1102 HRegionInterface server =
1103 getHRegionConnection(metaLocation.getHostname(), metaLocation.getPort());
1104
1105 Result regionInfoRow = null;
1106 if (useCache) {
1107 if (Bytes.equals(parentTable, HConstants.META_TABLE_NAME)
1108 && (getRegionCachePrefetch(tableName))) {
1109
1110
1111
1112 synchronized (regionLockObject) {
1113
1114
1115 location = getCachedLocation(tableName, row);
1116 if (location != null) {
1117 return location;
1118 }
1119
1120
1121 prefetchRegionCache(tableName, row);
1122 }
1123 }
1124 location = getCachedLocation(tableName, row);
1125 if (location != null) {
1126 return location;
1127 }
1128 } else {
1129
1130
1131 deleteCachedLocation(tableName, row);
1132 }
1133
1134
1135 regionInfoRow = server.getClosestRowBefore(
1136 metaLocation.getRegionInfo().getRegionName(), metaKey,
1137 HConstants.CATALOG_FAMILY);
1138 if (regionInfoRow == null) {
1139 throw new TableNotFoundException(Bytes.toString(tableName));
1140 }
1141 byte [] value = regionInfoRow.getValue(HConstants.CATALOG_FAMILY,
1142 HConstants.REGIONINFO_QUALIFIER);
1143 if (value == null || value.length == 0) {
1144 throw new IOException("HRegionInfo was null or empty in " +
1145 Bytes.toString(parentTable) + ", row=" + regionInfoRow);
1146 }
1147
1148 HRegionInfo regionInfo = (HRegionInfo) Writables.getWritable(
1149 value, new HRegionInfo());
1150
1151 if (!Bytes.equals(regionInfo.getTableName(), tableName)) {
1152 throw new TableNotFoundException(
1153 "Table '" + Bytes.toString(tableName) + "' was not found, got: " +
1154 Bytes.toString(regionInfo.getTableName()) + ".");
1155 }
1156 if (regionInfo.isSplit()) {
1157 throw new RegionOfflineException("the only available region for" +
1158 " the required row is a split parent," +
1159 " the daughters should be online soon: " +
1160 regionInfo.getRegionNameAsString());
1161 }
1162 if (regionInfo.isOffline()) {
1163 throw new RegionOfflineException("the region is offline, could" +
1164 " be caused by a disable table call: " +
1165 regionInfo.getRegionNameAsString());
1166 }
1167
1168 value = regionInfoRow.getValue(HConstants.CATALOG_FAMILY,
1169 HConstants.SERVER_QUALIFIER);
1170 String hostAndPort = "";
1171 if (value != null) {
1172 hostAndPort = Bytes.toString(value);
1173 }
1174 if (hostAndPort.equals("")) {
1175 throw new NoServerForRegionException("No server address listed " +
1176 "in " + Bytes.toString(parentTable) + " for region " +
1177 regionInfo.getRegionNameAsString() + " containing row " +
1178 Bytes.toStringBinary(row));
1179 }
1180
1181
1182 String hostname = Addressing.parseHostname(hostAndPort);
1183 int port = Addressing.parsePort(hostAndPort);
1184 location = new HRegionLocation(regionInfo, hostname, port);
1185 cacheLocation(tableName, location);
1186 return location;
1187 } catch (TableNotFoundException e) {
1188
1189
1190
1191 throw e;
1192 } catch (IOException e) {
1193 if (e instanceof RemoteException) {
1194 e = RemoteExceptionHandler.decodeRemoteException((RemoteException) e);
1195 }
1196 if (tries < numRetries - 1) {
1197 if (LOG.isDebugEnabled()) {
1198 LOG.debug("locateRegionInMeta parentTable=" +
1199 Bytes.toString(parentTable) + ", metaLocation=" +
1200 ((metaLocation == null)? "null": "{" + metaLocation + "}") +
1201 ", attempt=" + tries + " of " +
1202 this.numRetries + " failed; retrying after sleep of " +
1203 ConnectionUtils.getPauseTime(this.pause, tries) + " because: " + e.getMessage());
1204 }
1205 } else {
1206 throw e;
1207 }
1208
1209 if(!(e instanceof RegionOfflineException ||
1210 e instanceof NoServerForRegionException)) {
1211 relocateRegion(parentTable, metaKey);
1212 }
1213 }
1214 try{
1215 Thread.sleep(ConnectionUtils.getPauseTime(this.pause, tries));
1216 } catch (InterruptedException e) {
1217 Thread.currentThread().interrupt();
1218 throw new IOException("Giving up trying to location region in " +
1219 "meta: thread is interrupted.");
1220 }
1221 }
1222 }
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235 HRegionLocation getCachedLocation(final byte [] tableName,
1236 final byte [] row) {
1237 SoftValueSortedMap<byte [], HRegionLocation> tableLocations =
1238 getTableLocations(tableName);
1239
1240
1241
1242 if (tableLocations.isEmpty()) {
1243 return null;
1244 }
1245
1246 HRegionLocation possibleRegion = tableLocations.get(row);
1247 if (possibleRegion != null) {
1248 return possibleRegion;
1249 }
1250
1251 possibleRegion = tableLocations.lowerValueByKey(row);
1252 if (possibleRegion == null) {
1253 return null;
1254 }
1255
1256
1257
1258
1259
1260
1261 byte[] endKey = possibleRegion.getRegionInfo().getEndKey();
1262 if (Bytes.equals(endKey, HConstants.EMPTY_END_ROW) ||
1263 KeyValue.getRowComparator(tableName).compareRows(
1264 endKey, 0, endKey.length, row, 0, row.length) > 0) {
1265 return possibleRegion;
1266 }
1267
1268
1269 return null;
1270 }
1271
1272
1273
1274
1275
1276
1277 void deleteCachedLocation(final byte [] tableName, final byte [] row) {
1278 synchronized (this.cachedRegionLocations) {
1279 Map<byte[], HRegionLocation> tableLocations = getTableLocations(tableName);
1280 if (!tableLocations.isEmpty()) {
1281
1282
1283 HRegionLocation rl = getCachedLocation(tableName, row);
1284 if (rl != null) {
1285 tableLocations.remove(rl.getRegionInfo().getStartKey());
1286 if (LOG.isDebugEnabled()) {
1287 LOG.debug("Removed " +
1288 rl.getRegionInfo().getRegionNameAsString() +
1289 " for tableName=" + Bytes.toString(tableName) +
1290 " from cache " + "because of " + Bytes.toStringBinary(row));
1291 }
1292 }
1293 }
1294 }
1295 }
1296
1297 @Override
1298 public void deleteCachedRegionLocation(final HRegionLocation location) {
1299 if (location == null) {
1300 return;
1301 }
1302 synchronized (this.cachedRegionLocations) {
1303 byte[] tableName = location.getRegionInfo().getTableName();
1304 Map<byte[], HRegionLocation> tableLocations = getTableLocations(tableName);
1305 if (!tableLocations.isEmpty()) {
1306
1307 HRegionLocation removedLocation =
1308 tableLocations.remove(location.getRegionInfo().getStartKey());
1309 if (LOG.isDebugEnabled() && removedLocation != null) {
1310 LOG.debug("Removed " +
1311 location.getRegionInfo().getRegionNameAsString() +
1312 " for tableName=" + Bytes.toString(tableName) +
1313 " from cache");
1314 }
1315 }
1316 }
1317 }
1318
1319 @Override
1320 public void clearCaches(String sn) {
1321 clearCachedLocationForServer(sn);
1322 }
1323
1324
1325
1326
1327
1328
1329
1330 private void clearCachedLocationForServer(final String server) {
1331 boolean deletedSomething = false;
1332 synchronized (this.cachedRegionLocations) {
1333 if (!cachedServers.contains(server)) {
1334 return;
1335 }
1336 for (Map<byte[], HRegionLocation> tableLocations :
1337 cachedRegionLocations.values()) {
1338 for (Entry<byte[], HRegionLocation> e : tableLocations.entrySet()) {
1339 HRegionLocation value = e.getValue();
1340 if (value != null
1341 && value.getHostnamePort().equals(server)) {
1342 tableLocations.remove(e.getKey());
1343 deletedSomething = true;
1344 }
1345 }
1346 }
1347 cachedServers.remove(server);
1348 }
1349 if (deletedSomething && LOG.isDebugEnabled()) {
1350 LOG.debug("Removed all cached region locations that map to " + server);
1351 }
1352 }
1353
1354
1355
1356
1357
1358 private SoftValueSortedMap<byte [], HRegionLocation> getTableLocations(
1359 final byte [] tableName) {
1360
1361 Integer key = Bytes.mapKey(tableName);
1362 SoftValueSortedMap<byte [], HRegionLocation> result;
1363 synchronized (this.cachedRegionLocations) {
1364 result = this.cachedRegionLocations.get(key);
1365
1366 if (result == null) {
1367 result = new SoftValueSortedMap<byte [], HRegionLocation>(
1368 Bytes.BYTES_COMPARATOR);
1369 this.cachedRegionLocations.put(key, result);
1370 }
1371 }
1372 return result;
1373 }
1374
1375 @Override
1376 public void clearRegionCache() {
1377 synchronized(this.cachedRegionLocations) {
1378 this.cachedRegionLocations.clear();
1379 this.cachedServers.clear();
1380 }
1381 }
1382
1383 @Override
1384 public void clearRegionCache(final byte [] tableName) {
1385 synchronized (this.cachedRegionLocations) {
1386 this.cachedRegionLocations.remove(Bytes.mapKey(tableName));
1387 }
1388 }
1389
1390
1391
1392
1393 private void cacheLocation(final byte [] tableName,
1394 final HRegionLocation location) {
1395 byte [] startKey = location.getRegionInfo().getStartKey();
1396 Map<byte [], HRegionLocation> tableLocations =
1397 getTableLocations(tableName);
1398 boolean hasNewCache = false;
1399 synchronized (this.cachedRegionLocations) {
1400 cachedServers.add(location.getHostnamePort());
1401 hasNewCache = (tableLocations.put(startKey, location) == null);
1402 }
1403 if (hasNewCache) {
1404 LOG.debug("Cached location for " +
1405 location.getRegionInfo().getRegionNameAsString() +
1406 " is " + location.getHostnamePort());
1407 }
1408 }
1409
1410 public HRegionInterface getHRegionConnection(HServerAddress hsa)
1411 throws IOException {
1412 return getHRegionConnection(hsa, false);
1413 }
1414
1415 @Override
1416 public HRegionInterface getHRegionConnection(final String hostname,
1417 final int port)
1418 throws IOException {
1419 return getHRegionConnection(hostname, port, false);
1420 }
1421
1422 public HRegionInterface getHRegionConnection(HServerAddress hsa,
1423 boolean master)
1424 throws IOException {
1425 return getHRegionConnection(null, -1, hsa.getInetSocketAddress(), master);
1426 }
1427
1428 @Override
1429 public HRegionInterface getHRegionConnection(final String hostname,
1430 final int port, final boolean master)
1431 throws IOException {
1432 return getHRegionConnection(hostname, port, null, master);
1433 }
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445 HRegionInterface getHRegionConnection(final String hostname, final int port,
1446 final InetSocketAddress isa, final boolean master)
1447 throws IOException {
1448 if (master) getMaster();
1449 HRegionInterface server;
1450 String rsName = null;
1451 if (isa != null) {
1452 rsName = Addressing.createHostAndPortStr(isa.getHostName(),
1453 isa.getPort());
1454 } else {
1455 rsName = Addressing.createHostAndPortStr(hostname, port);
1456 }
1457 ensureZookeeperTrackers();
1458
1459 server = this.servers.get(rsName);
1460 if (server == null) {
1461
1462 this.connectionLock.putIfAbsent(rsName, rsName);
1463
1464 synchronized (this.connectionLock.get(rsName)) {
1465
1466 server = this.servers.get(rsName);
1467 if (server == null) {
1468 try {
1469
1470 InetSocketAddress address = isa != null? isa:
1471 new InetSocketAddress(hostname, port);
1472
1473 server = HBaseRPC.waitForProxy(this.rpcEngine,
1474 serverInterfaceClass, HRegionInterface.VERSION,
1475 address, this.conf,
1476 this.maxRPCAttempts, this.rpcTimeout, this.rpcTimeout);
1477 this.servers.put(Addressing.createHostAndPortStr(
1478 address.getHostName(), address.getPort()), server);
1479 } catch (RemoteException e) {
1480 LOG.warn("RemoteException connecting to RS", e);
1481
1482 throw e.unwrapRemoteException();
1483 }
1484 }
1485 }
1486 }
1487 return server;
1488 }
1489
1490
1491
1492
1493
1494
1495
1496
1497 @Deprecated
1498 public synchronized ZooKeeperWatcher getZooKeeperWatcher()
1499 throws ZooKeeperConnectionException {
1500 if(zooKeeper == null) {
1501 try {
1502 if (this.closed) {
1503 throw new IOException(toString() + " closed");
1504 }
1505 this.zooKeeper = new ZooKeeperWatcher(conf, "hconnection", this);
1506 } catch(ZooKeeperConnectionException zce) {
1507 throw zce;
1508 } catch (IOException e) {
1509 throw new ZooKeeperConnectionException("An error is preventing" +
1510 " HBase from connecting to ZooKeeper", e);
1511 }
1512 }
1513 return zooKeeper;
1514 }
1515
1516 public <T> T getRegionServerWithRetries(ServerCallable<T> callable)
1517 throws IOException, RuntimeException {
1518 return callable.withRetries();
1519 }
1520
1521 public <T> T getRegionServerWithoutRetries(ServerCallable<T> callable)
1522 throws IOException, RuntimeException {
1523 return callable.withoutRetries();
1524 }
1525
1526 private <R> Callable<MultiResponse> createCallable(final HRegionLocation loc,
1527 final MultiAction<R> multi, final byte [] tableName) {
1528
1529
1530
1531 final HConnection connection = this;
1532 return new Callable<MultiResponse>() {
1533 public MultiResponse call() throws IOException {
1534 ServerCallable<MultiResponse> callable =
1535 new ServerCallable<MultiResponse>(connection, tableName, null) {
1536 public MultiResponse call() throws IOException {
1537 return server.multi(multi);
1538 }
1539 @Override
1540 public void connect(boolean reload) throws IOException {
1541 server = connection.getHRegionConnection(loc.getHostname(), loc.getPort());
1542 }
1543 };
1544 return callable.withoutRetries();
1545 }
1546 };
1547 }
1548
1549 public void processBatch(List<? extends Row> list,
1550 final byte[] tableName,
1551 ExecutorService pool,
1552 Object[] results) throws IOException, InterruptedException {
1553
1554
1555
1556 if (results.length != list.size()) {
1557 throw new IllegalArgumentException("argument results must be the same size as argument list");
1558 }
1559
1560 processBatchCallback(list, tableName, pool, results, null);
1561 }
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585 public <T extends CoprocessorProtocol,R> void processExecs(
1586 final Class<T> protocol,
1587 List<byte[]> rows,
1588 final byte[] tableName,
1589 ExecutorService pool,
1590 final Batch.Call<T,R> callable,
1591 final Batch.Callback<R> callback)
1592 throws IOException, Throwable {
1593
1594 Map<byte[],Future<R>> futures =
1595 new TreeMap<byte[],Future<R>>(Bytes.BYTES_COMPARATOR);
1596 for (final byte[] r : rows) {
1597 final ExecRPCInvoker invoker =
1598 new ExecRPCInvoker(conf, this, protocol, tableName, r);
1599 Future<R> future = pool.submit(
1600 new Callable<R>() {
1601 public R call() throws Exception {
1602 T instance = (T)Proxy.newProxyInstance(conf.getClassLoader(),
1603 new Class[]{protocol},
1604 invoker);
1605 R result = callable.call(instance);
1606 byte[] region = invoker.getRegionName();
1607 if (callback != null) {
1608 callback.update(region, r, result);
1609 }
1610 return result;
1611 }
1612 });
1613 futures.put(r, future);
1614 }
1615 for (Map.Entry<byte[],Future<R>> e : futures.entrySet()) {
1616 try {
1617 e.getValue().get();
1618 } catch (ExecutionException ee) {
1619 LOG.warn("Error executing for row "+Bytes.toStringBinary(e.getKey()), ee);
1620 throw ee.getCause();
1621 } catch (InterruptedException ie) {
1622 Thread.currentThread().interrupt();
1623 throw new IOException("Interrupted executing for row " +
1624 Bytes.toStringBinary(e.getKey()), ie);
1625 }
1626 }
1627 }
1628
1629
1630
1631
1632
1633 public <R> void processBatchCallback(
1634 List<? extends Row> list,
1635 byte[] tableName,
1636 ExecutorService pool,
1637 Object[] results,
1638 Batch.Callback<R> callback)
1639 throws IOException, InterruptedException {
1640
1641
1642
1643 if (results.length != list.size()) {
1644 throw new IllegalArgumentException(
1645 "argument results must be the same size as argument list");
1646 }
1647 if (list.isEmpty()) {
1648 return;
1649 }
1650
1651
1652
1653
1654
1655 HRegionLocation [] lastServers = new HRegionLocation[results.length];
1656 List<Row> workingList = new ArrayList<Row>(list);
1657 boolean retry = true;
1658
1659 int actionCount = 0;
1660
1661 for (int tries = 0; tries < numRetries && retry; ++tries) {
1662
1663
1664 if (tries >= 1) {
1665 long sleepTime = ConnectionUtils.getPauseTime(this.pause, tries);
1666 LOG.debug("Retry " +tries+ ", sleep for " +sleepTime+ "ms!");
1667 Thread.sleep(sleepTime);
1668 }
1669
1670 Map<HRegionLocation, MultiAction<R>> actionsByServer =
1671 new HashMap<HRegionLocation, MultiAction<R>>();
1672 for (int i = 0; i < workingList.size(); i++) {
1673 Row row = workingList.get(i);
1674 if (row != null) {
1675 HRegionLocation loc = locateRegion(tableName, row.getRow());
1676 byte[] regionName = loc.getRegionInfo().getRegionName();
1677
1678 MultiAction<R> actions = actionsByServer.get(loc);
1679 if (actions == null) {
1680 actions = new MultiAction<R>();
1681 actionsByServer.put(loc, actions);
1682 }
1683
1684 Action<R> action = new Action<R>(row, i);
1685 lastServers[i] = loc;
1686 actions.add(regionName, action);
1687 }
1688 }
1689
1690
1691
1692 Map<HRegionLocation, Future<MultiResponse>> futures =
1693 new HashMap<HRegionLocation, Future<MultiResponse>>(
1694 actionsByServer.size());
1695
1696 for (Entry<HRegionLocation, MultiAction<R>> e: actionsByServer.entrySet()) {
1697 futures.put(e.getKey(), pool.submit(createCallable(e.getKey(), e.getValue(), tableName)));
1698 }
1699
1700
1701
1702 for (Entry<HRegionLocation, Future<MultiResponse>> responsePerServer
1703 : futures.entrySet()) {
1704 HRegionLocation loc = responsePerServer.getKey();
1705
1706 try {
1707 Future<MultiResponse> future = responsePerServer.getValue();
1708 MultiResponse resp = future.get();
1709
1710 if (resp == null) {
1711
1712 LOG.debug("Failed all for server: " + loc.getHostnamePort() +
1713 ", removing from cache");
1714 continue;
1715 }
1716
1717 for (Entry<byte[], List<Pair<Integer,Object>>> e : resp.getResults().entrySet()) {
1718 byte[] regionName = e.getKey();
1719 List<Pair<Integer, Object>> regionResults = e.getValue();
1720 for (Pair<Integer, Object> regionResult : regionResults) {
1721 if (regionResult == null) {
1722
1723 LOG.debug("Failures for region: " +
1724 Bytes.toStringBinary(regionName) +
1725 ", removing from cache");
1726 } else {
1727
1728 results[regionResult.getFirst()] = regionResult.getSecond();
1729 if (callback != null && !(regionResult.getSecond() instanceof Throwable)) {
1730 callback.update(e.getKey(),
1731 list.get(regionResult.getFirst()).getRow(),
1732 (R)regionResult.getSecond());
1733 }
1734 }
1735 }
1736 }
1737 } catch (ExecutionException e) {
1738 LOG.warn("Failed all from " + loc, e);
1739 }
1740 }
1741
1742
1743
1744
1745
1746 retry = false;
1747 workingList.clear();
1748 actionCount = 0;
1749 for (int i = 0; i < results.length; i++) {
1750
1751
1752 if (results[i] == null ||
1753 (results[i] instanceof Throwable &&
1754 !(results[i] instanceof DoNotRetryIOException))) {
1755
1756 retry = true;
1757 actionCount++;
1758 Row row = list.get(i);
1759 workingList.add(row);
1760 deleteCachedLocation(tableName, row.getRow());
1761 } else {
1762 if (results[i] != null && results[i] instanceof Throwable) {
1763 actionCount++;
1764 }
1765
1766 workingList.add(null);
1767 }
1768 }
1769 }
1770
1771 List<Throwable> exceptions = new ArrayList<Throwable>(actionCount);
1772 List<Row> actions = new ArrayList<Row>(actionCount);
1773 List<String> addresses = new ArrayList<String>(actionCount);
1774
1775 for (int i = 0 ; i < results.length; i++) {
1776 if (results[i] == null || results[i] instanceof Throwable) {
1777 exceptions.add((Throwable)results[i]);
1778 actions.add(list.get(i));
1779 addresses.add(lastServers[i].getHostnamePort());
1780 }
1781 }
1782
1783 if (!exceptions.isEmpty()) {
1784 throw new RetriesExhaustedWithDetailsException(exceptions,
1785 actions,
1786 addresses);
1787 }
1788 }
1789
1790
1791
1792
1793
1794 int getNumberOfCachedRegionLocations(final byte[] tableName) {
1795 Integer key = Bytes.mapKey(tableName);
1796 synchronized (this.cachedRegionLocations) {
1797 Map<byte[], HRegionLocation> tableLocs =
1798 this.cachedRegionLocations.get(key);
1799
1800 if (tableLocs == null) {
1801 return 0;
1802 }
1803 return tableLocs.values().size();
1804 }
1805 }
1806
1807
1808
1809
1810
1811
1812
1813
1814 boolean isRegionCached(final byte[] tableName, final byte[] row) {
1815 HRegionLocation location = getCachedLocation(tableName, row);
1816 return location != null;
1817 }
1818
1819 public void setRegionCachePrefetch(final byte[] tableName,
1820 final boolean enable) {
1821 if (!enable) {
1822 regionCachePrefetchDisabledTables.add(Bytes.mapKey(tableName));
1823 }
1824 else {
1825 regionCachePrefetchDisabledTables.remove(Bytes.mapKey(tableName));
1826 }
1827 }
1828
1829 public boolean getRegionCachePrefetch(final byte[] tableName) {
1830 return !regionCachePrefetchDisabledTables.contains(Bytes.mapKey(tableName));
1831 }
1832
1833 @Override
1834 public void prewarmRegionCache(byte[] tableName,
1835 Map<HRegionInfo, HServerAddress> regions) {
1836 for (Map.Entry<HRegionInfo, HServerAddress> e : regions.entrySet()) {
1837 HServerAddress hsa = e.getValue();
1838 if (hsa == null || hsa.getInetSocketAddress() == null) continue;
1839 cacheLocation(tableName,
1840 new HRegionLocation(e.getKey(), hsa.getHostname(), hsa.getPort()));
1841 }
1842 }
1843
1844 @Override
1845 public void abort(final String msg, Throwable t) {
1846 if (t instanceof KeeperException) {
1847 LOG.info("This client just lost it's session with ZooKeeper, will"
1848 + " automatically reconnect when needed.");
1849 if (t instanceof KeeperException.SessionExpiredException) {
1850 LOG.info("ZK session expired. This disconnect could have been" +
1851 " caused by a network partition or a long-running GC pause," +
1852 " either way it's recommended that you verify your environment.");
1853 synchronized (resetLock) {
1854 if (resetting) return;
1855 this.resetting = true;
1856 }
1857 resetZooKeeperTrackers();
1858 this.resetting = false;
1859 }
1860 return;
1861 }
1862 if (t != null) LOG.fatal(msg, t);
1863 else LOG.fatal(msg);
1864 this.aborted = true;
1865 close();
1866 }
1867
1868 @Override
1869 public boolean isClosed() {
1870 return this.closed;
1871 }
1872
1873 @Override
1874 public boolean isAborted(){
1875 return this.aborted;
1876 }
1877
1878 public int getCurrentNrHRS() throws IOException {
1879 try {
1880 ZooKeeperWatcher zkw = getZooKeeperWatcher();
1881
1882
1883 return ZKUtil.getNumberOfChildren(zkw,
1884 zkw.rsZNode);
1885 } catch (KeeperException ke) {
1886 throw new IOException("Unexpected ZooKeeper exception", ke);
1887 }
1888 }
1889
1890
1891
1892
1893 void incCount() {
1894 ++refCount;
1895 }
1896
1897
1898
1899
1900 void decCount() {
1901 if (refCount > 0) {
1902 --refCount;
1903 }
1904 }
1905
1906
1907
1908
1909
1910
1911 boolean isZeroReference() {
1912 return refCount == 0;
1913 }
1914
1915 void internalClose() {
1916 if (this.closed) {
1917 return;
1918 }
1919 shutdownBatchPool();
1920 master = null;
1921
1922 this.servers.clear();
1923 if (this.rpcEngine != null) {
1924 this.rpcEngine.close();
1925 }
1926
1927 synchronized (this) {
1928 if (this.zooKeeper != null) {
1929 LOG.info("Closed zookeeper sessionid=0x" +
1930 Long.toHexString(this.zooKeeper.getRecoverableZooKeeper().getSessionId()));
1931 this.zooKeeper.close();
1932 this.zooKeeper = null;
1933 }
1934 this.closed = true;
1935 }
1936 }
1937
1938 public void close() {
1939 if (managed) {
1940 if (aborted) {
1941 HConnectionManager.deleteStaleConnection(this);
1942 } else {
1943 HConnectionManager.deleteConnection(this, false);
1944 }
1945 } else {
1946 internalClose();
1947 }
1948 if (LOG.isTraceEnabled()) LOG.debug("" + this.zooKeeper + " closed.");
1949 }
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962 @Override
1963 protected void finalize() throws Throwable {
1964
1965 refCount = 1;
1966 close();
1967 LOG.debug("The connection to " + this.zooKeeper
1968 + " was closed by the finalize method.");
1969 }
1970
1971 public HTableDescriptor[] listTables() throws IOException {
1972 HTableDescriptor[] htd = getMaster().getHTableDescriptors();
1973 return htd;
1974 }
1975
1976 public HTableDescriptor[] getHTableDescriptors(List<String> tableNames) throws IOException {
1977 if (tableNames == null || tableNames.isEmpty()) return new HTableDescriptor[0];
1978 if (tableNames == null || tableNames.size() == 0) return null;
1979 return getMaster().getHTableDescriptors(tableNames);
1980 }
1981
1982 @Override
1983 public String[] getTableNames() throws IOException {
1984 return getMaster().getTableNames();
1985 }
1986
1987 public HTableDescriptor getHTableDescriptor(final byte[] tableName)
1988 throws IOException {
1989 if (tableName == null || tableName.length == 0) return null;
1990 if (Bytes.equals(tableName, HConstants.ROOT_TABLE_NAME)) {
1991 return new UnmodifyableHTableDescriptor(HTableDescriptor.ROOT_TABLEDESC);
1992 }
1993 if (Bytes.equals(tableName, HConstants.META_TABLE_NAME)) {
1994 return HTableDescriptor.META_TABLEDESC;
1995 }
1996 List<String> tableNameList = new ArrayList<String>(1);
1997 tableNameList.add(Bytes.toString(tableName));
1998 HTableDescriptor[] htds = getHTableDescriptors(tableNameList);
1999 if (htds != null && htds.length > 0) {
2000 return htds[0];
2001 }
2002 throw new TableNotFoundException(Bytes.toString(tableName));
2003 }
2004 }
2005
2006
2007
2008
2009
2010
2011
2012
2013 public static void setServerSideHConnectionRetries(final Configuration c,
2014 final Log log) {
2015 int hcRetries = c.getInt(HConstants.HBASE_CLIENT_RETRIES_NUMBER,
2016 HConstants.DEFAULT_HBASE_CLIENT_RETRIES_NUMBER);
2017
2018
2019 int serversideMultiplier =
2020 c.getInt("hbase.client.serverside.retries.multiplier", 10);
2021 int retries = hcRetries * serversideMultiplier;
2022 c.setInt(HConstants.HBASE_CLIENT_RETRIES_NUMBER, retries);
2023 log.debug("Set serverside HConnection retries=" + retries);
2024 }
2025 }