001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase.util; 019 020import static org.apache.hadoop.hbase.util.RecoverLeaseFSUtils.LEASE_RECOVERABLE_CLASS_NAME; 021import static org.junit.jupiter.api.Assertions.assertFalse; 022import static org.junit.jupiter.api.Assertions.assertTrue; 023import static org.mockito.Mockito.mock; 024import static org.mockito.Mockito.times; 025import static org.mockito.Mockito.verify; 026import static org.mockito.Mockito.when; 027 028import java.io.IOException; 029import org.apache.hadoop.conf.Configuration; 030import org.apache.hadoop.fs.FileSystem; 031import org.apache.hadoop.fs.LocalFileSystem; 032import org.apache.hadoop.fs.Path; 033import org.apache.hadoop.hbase.HBaseCommonTestingUtil; 034import org.apache.hadoop.hbase.testclassification.MediumTests; 035import org.apache.hadoop.hbase.testclassification.MiscTests; 036import org.apache.hadoop.hdfs.DistributedFileSystem; 037import org.junit.jupiter.api.BeforeAll; 038import org.junit.jupiter.api.Tag; 039import org.junit.jupiter.api.Test; 040 041/** 042 * Test our recoverLease loop against mocked up filesystem. 043 */ 044@Tag(MiscTests.TAG) 045@Tag(MediumTests.TAG) 046public class TestRecoverLeaseFSUtils { 047 048 private static final HBaseCommonTestingUtil HTU = new HBaseCommonTestingUtil(); 049 050 private static Path FILE; 051 052 @BeforeAll 053 public static void setUp() { 054 Configuration conf = HTU.getConfiguration(); 055 conf.setInt("hbase.lease.recovery.first.pause", 10); 056 conf.setInt("hbase.lease.recovery.pause", 10); 057 FILE = new Path(HTU.getDataTestDir(), "file.txt"); 058 } 059 060 /** 061 * Test recover lease eventually succeeding. 062 */ 063 @Test 064 public void testRecoverLease() throws IOException { 065 long startTime = EnvironmentEdgeManager.currentTime(); 066 HTU.getConfiguration().setInt("hbase.lease.recovery.dfs.timeout", 1000); 067 CancelableProgressable reporter = mock(CancelableProgressable.class); 068 when(reporter.progress()).thenReturn(true); 069 DistributedFileSystem dfs = mock(DistributedFileSystem.class); 070 // Fail four times and pass on the fifth. 071 when(dfs.recoverLease(FILE)).thenReturn(false).thenReturn(false).thenReturn(false) 072 .thenReturn(false).thenReturn(true); 073 RecoverLeaseFSUtils.recoverFileLease(dfs, FILE, HTU.getConfiguration(), reporter); 074 verify(dfs, times(5)).recoverLease(FILE); 075 // Make sure we waited at least hbase.lease.recovery.dfs.timeout * 3 (the first two 076 // invocations will happen pretty fast... the we fall into the longer wait loop). 077 assertTrue((EnvironmentEdgeManager.currentTime() - startTime) 078 > (3 * HTU.getConfiguration().getInt("hbase.lease.recovery.dfs.timeout", 61000))); 079 } 080 081 private interface FakeLeaseRecoverable { 082 083 boolean recoverLease(Path p) throws IOException; 084 } 085 086 private static abstract class RecoverableFileSystem extends FileSystem 087 implements FakeLeaseRecoverable { 088 @Override 089 public boolean recoverLease(Path p) throws IOException { 090 return true; 091 } 092 } 093 094 /** 095 * Test that we can use reflection to access LeaseRecoverable methods. 096 */ 097 @Test 098 public void testLeaseRecoverable() throws IOException { 099 try { 100 // set LeaseRecoverable to FakeLeaseRecoverable for testing 101 RecoverLeaseFSUtils.initializeRecoverLeaseMethod(FakeLeaseRecoverable.class.getName()); 102 RecoverableFileSystem mockFS = mock(RecoverableFileSystem.class); 103 when(mockFS.recoverLease(FILE)).thenReturn(true); 104 RecoverLeaseFSUtils.recoverFileLease(mockFS, FILE, HTU.getConfiguration()); 105 verify(mockFS, times(1)).recoverLease(FILE); 106 107 assertTrue(RecoverLeaseFSUtils.isLeaseRecoverable(mock(RecoverableFileSystem.class))); 108 } finally { 109 RecoverLeaseFSUtils.initializeRecoverLeaseMethod(LEASE_RECOVERABLE_CLASS_NAME); 110 } 111 } 112 113 /** 114 * Test that isFileClosed makes us recover lease faster. 115 */ 116 @Test 117 public void testIsFileClosed() throws IOException { 118 // Make this time long so it is plain we broke out because of the isFileClosed invocation. 119 HTU.getConfiguration().setInt("hbase.lease.recovery.dfs.timeout", 100000); 120 CancelableProgressable reporter = mock(CancelableProgressable.class); 121 when(reporter.progress()).thenReturn(true); 122 IsFileClosedDistributedFileSystem dfs = mock(IsFileClosedDistributedFileSystem.class); 123 // Now make it so we fail the first two times -- the two fast invocations, then we fall into 124 // the long loop during which we will call isFileClosed.... the next invocation should 125 // therefore return true if we are to break the loop. 126 when(dfs.recoverLease(FILE)).thenReturn(false).thenReturn(false).thenReturn(true); 127 when(dfs.isFileClosed(FILE)).thenReturn(true); 128 RecoverLeaseFSUtils.recoverFileLease(dfs, FILE, HTU.getConfiguration(), reporter); 129 verify(dfs, times(2)).recoverLease(FILE); 130 verify(dfs, times(1)).isFileClosed(FILE); 131 } 132 133 @Test 134 public void testIsLeaseRecoverable() { 135 assertTrue(RecoverLeaseFSUtils.isLeaseRecoverable(new DistributedFileSystem())); 136 assertFalse(RecoverLeaseFSUtils.isLeaseRecoverable(new LocalFileSystem())); 137 } 138 139 /** 140 * Version of DFS that has HDFS-4525 in it. 141 */ 142 private static class IsFileClosedDistributedFileSystem extends DistributedFileSystem { 143 /** 144 * Close status of a file. Copied over from HDFS-4525 145 * @return true if file is already closed 146 **/ 147 @Override 148 public boolean isFileClosed(Path f) throws IOException { 149 return false; 150 } 151 } 152}