2323import org .apache .hadoop .hbase .*;
2424
2525import org .apache .hadoop .hbase .exceptions .ClientExceptionsUtil ;
26+ import org .apache .hadoop .hbase .exceptions .LockTimeoutException ;
2627import org .apache .hadoop .hbase .exceptions .RegionOpeningException ;
2728import org .apache .hadoop .hbase .protobuf .generated .ClientProtos ;
2829import org .apache .hadoop .hbase .protobuf .generated .ClientProtos .GetResponse ;
4243import java .io .IOException ;
4344import java .util .ArrayList ;
4445import java .util .List ;
46+ import org .slf4j .Logger ;
47+ import org .slf4j .LoggerFactory ;
4548
4649import static junit .framework .Assert .assertEquals ;
4750import static org .junit .Assert .assertNotNull ;
@@ -57,6 +60,7 @@ public class TestMetaCache {
5760 private static final byte [] QUALIFIER = Bytes .toBytes ("qual" );
5861
5962 private static HRegionServer badRS ;
63+ private static final Logger LOG = LoggerFactory .getLogger (TestMetaCache .class );
6064
6165 /**
6266 * @throws java.lang.Exception
@@ -356,4 +360,77 @@ public void throwOnScan(FakeRSRpcServices rpcServices, ClientProtos.ScanRequest
356360 throws ServiceException {
357361 }
358362 }
359- }
363+
364+ @ Test
365+ public void testUserRegionLockThrowsException () throws IOException , InterruptedException {
366+ ((FakeRSRpcServices )badRS .getRSRpcServices ()).setExceptionInjector (new LockSleepInjector ());
367+ Configuration conf = new Configuration (TEST_UTIL .getConfiguration ());
368+ conf .setInt (HConstants .HBASE_CLIENT_RETRIES_NUMBER , 1 );
369+ conf .setLong (HConstants .HBASE_CLIENT_META_OPERATION_TIMEOUT , 2000 );
370+ conf .setLong (HConstants .HBASE_CLIENT_SCANNER_TIMEOUT_PERIOD , 2000 );
371+
372+ try (ConnectionManager .HConnectionImplementation conn =
373+ (ConnectionManager .HConnectionImplementation ) ConnectionFactory .createConnection (conf )) {
374+ ClientThread client1 = new ClientThread (conn );
375+ ClientThread client2 = new ClientThread (conn );
376+ client1 .start ();
377+ client2 .start ();
378+ client1 .join ();
379+ client2 .join ();
380+ // One thread will get the lock but will sleep in LockExceptionInjector#throwOnScan and
381+ // eventually fail since the sleep time is more than hbase client scanner timeout period.
382+ // Other thread will wait to acquire userRegionLock.
383+ // Have no idea which thread will be scheduled first. So need to check both threads.
384+
385+ // Both the threads will throw exception. One thread will throw exception since after
386+ // acquiring user region lock, it is sleeping for 5 seconds when the scanner time out period
387+ // is 2 seconds.
388+ // Other thread will throw exception since it was not able to get hold of user region lock
389+ // within meta operation timeout period.
390+ assertNotNull (client1 .getException ());
391+ assertNotNull (client2 .getException ());
392+
393+ assertTrue (client1 .getException () instanceof LockTimeoutException
394+ ^ client2 .getException () instanceof LockTimeoutException );
395+ }
396+ }
397+
398+ private final class ClientThread extends Thread {
399+ private Exception exception ;
400+ private ConnectionManager .HConnectionImplementation connection ;
401+
402+ private ClientThread (ConnectionManager .HConnectionImplementation connection ) {
403+ this .connection = connection ;
404+ }
405+ @ Override
406+ public void run () {
407+ byte [] currentKey = HConstants .EMPTY_START_ROW ;
408+ try {
409+ connection .getRegionLocation (TABLE_NAME , currentKey , true );
410+ } catch (IOException e ) {
411+ LOG .error ("Thread id: " + this .getId () + " exception: " , e );
412+ this .exception = e ;
413+ }
414+ }
415+ public Exception getException () {
416+ return exception ;
417+ }
418+ }
419+
420+ public static class LockSleepInjector extends ExceptionInjector {
421+ @ Override
422+ public void throwOnScan (FakeRSRpcServices rpcServices , ClientProtos .ScanRequest request ) {
423+ try {
424+ Thread .sleep (5000 );
425+ } catch (InterruptedException e ) {
426+ LOG .info ("Interrupted exception" , e );
427+ }
428+ }
429+
430+ @ Override
431+ public void throwOnGet (FakeRSRpcServices rpcServices , ClientProtos .GetRequest request ) { }
432+
433+ @ Override
434+ public void throwOnMutate (FakeRSRpcServices rpcServices , ClientProtos .MutateRequest request ) { }
435+ }
436+ }
0 commit comments