2121import edu .umd .cs .findbugs .annotations .Nullable ;
2222import java .io .EOFException ;
2323import java .io .IOException ;
24+ import java .io .InterruptedIOException ;
2425import java .util .Arrays ;
2526import java .util .Comparator ;
2627import java .util .List ;
2728import java .util .Map ;
2829import java .util .Optional ;
2930import java .util .TreeMap ;
3031import java .util .concurrent .ConcurrentHashMap ;
32+ import java .util .concurrent .ConcurrentSkipListMap ;
33+ import java .util .concurrent .CountDownLatch ;
34+ import java .util .concurrent .LinkedBlockingQueue ;
35+ import java .util .concurrent .ThreadPoolExecutor ;
36+ import java .util .concurrent .TimeUnit ;
37+ import java .util .concurrent .atomic .AtomicBoolean ;
3138import org .apache .commons .lang3 .NotImplementedException ;
3239import org .apache .hadoop .conf .Configuration ;
3340import org .apache .hadoop .fs .FSDataInputStream ;
5562import org .slf4j .LoggerFactory ;
5663
5764import org .apache .hbase .thirdparty .com .google .common .primitives .Ints ;
65+ import org .apache .hbase .thirdparty .com .google .common .util .concurrent .ThreadFactoryBuilder ;
5866
5967/**
6068 * Implementation of {@link TableDescriptors} that reads descriptors from the passed filesystem. It
@@ -79,6 +87,8 @@ public class FSTableDescriptors implements TableDescriptors {
7987 private final boolean fsreadonly ;
8088 private final boolean usecache ;
8189 private volatile boolean fsvisited ;
90+ private boolean tableDescriptorParallelLoadEnable = false ;
91+ private ThreadPoolExecutor executor ;
8292
8393 long cachehits = 0 ;
8494 long invocations = 0 ;
@@ -108,10 +118,23 @@ public FSTableDescriptors(final FileSystem fs, final Path rootdir) {
108118
109119 public FSTableDescriptors (final FileSystem fs , final Path rootdir , final boolean fsreadonly ,
110120 final boolean usecache ) {
121+ this (fs , rootdir , fsreadonly , usecache , 0 );
122+ }
123+
124+ public FSTableDescriptors (final FileSystem fs , final Path rootdir , final boolean fsreadonly ,
125+ final boolean usecache , final int tableDescriptorParallelLoadThreads ) {
111126 this .fs = fs ;
112127 this .rootdir = rootdir ;
113128 this .fsreadonly = fsreadonly ;
114129 this .usecache = usecache ;
130+ if (tableDescriptorParallelLoadThreads > 0 ) {
131+ tableDescriptorParallelLoadEnable = true ;
132+ executor = new ThreadPoolExecutor (tableDescriptorParallelLoadThreads ,
133+ tableDescriptorParallelLoadThreads , 1 , TimeUnit .SECONDS , new LinkedBlockingQueue <>(),
134+ new ThreadFactoryBuilder ().setNameFormat ("FSTableDescriptorLoad-pool-%d" ).setDaemon (true )
135+ .setUncaughtExceptionHandler (Threads .LOGGING_EXCEPTION_HANDLER ).build ());
136+ executor .allowCoreThreadTimeOut (true );
137+ }
115138 }
116139
117140 public static void tryUpdateMetaTableDescriptor (Configuration conf ) throws IOException {
@@ -235,27 +258,56 @@ public TableDescriptor get(TableName tableName) {
235258 */
236259 @ Override
237260 public Map <String , TableDescriptor > getAll () throws IOException {
238- Map <String , TableDescriptor > tds = new TreeMap <>();
261+ Map <String , TableDescriptor > tds = new ConcurrentSkipListMap <>();
239262 if (fsvisited ) {
240263 for (Map .Entry <TableName , TableDescriptor > entry : this .cache .entrySet ()) {
241264 tds .put (entry .getKey ().getNameWithNamespaceInclAsString (), entry .getValue ());
242265 }
243266 } else {
244- LOG .trace ("Fetching table descriptors from the filesystem." );
245- boolean allvisited = usecache ;
246- for (Path d : FSUtils .getTableDirs (fs , rootdir )) {
247- TableDescriptor htd = get (CommonFSUtils .getTableName (d ));
248- if (htd == null ) {
249- allvisited = false ;
250- } else {
251- tds .put (htd .getTableName ().getNameWithNamespaceInclAsString (), htd );
267+ LOG .info ("Fetching table descriptors from the filesystem." );
268+ final long startTime = EnvironmentEdgeManager .currentTime ();
269+ AtomicBoolean allvisited = new AtomicBoolean (usecache );
270+ List <Path > tableDirs = FSUtils .getTableDirs (fs , rootdir );
271+ if (!tableDescriptorParallelLoadEnable ) {
272+ for (Path dir : tableDirs ) {
273+ internalGet (dir , tds , allvisited );
274+ }
275+ } else {
276+ CountDownLatch latch = new CountDownLatch (tableDirs .size ());
277+ for (Path dir : tableDirs ) {
278+ executor .submit (new Runnable () {
279+ @ Override
280+ public void run () {
281+ try {
282+ internalGet (dir , tds , allvisited );
283+ } finally {
284+ latch .countDown ();
285+ }
286+ }
287+ });
288+ }
289+ try {
290+ latch .await ();
291+ } catch (InterruptedException ie ) {
292+ throw (InterruptedIOException ) new InterruptedIOException ().initCause (ie );
252293 }
253294 }
254- fsvisited = allvisited ;
295+ fsvisited = allvisited .get ();
296+ LOG .info ("Fetched table descriptors(size=" + tds .size () + ") cost "
297+ + (EnvironmentEdgeManager .currentTime () - startTime ) + "ms." );
255298 }
256299 return tds ;
257300 }
258301
302+ private void internalGet (Path dir , Map <String , TableDescriptor > tds , AtomicBoolean allvisited ) {
303+ TableDescriptor htd = get (CommonFSUtils .getTableName (dir ));
304+ if (htd == null ) {
305+ allvisited .set (false );
306+ } else {
307+ tds .put (htd .getTableName ().getNameWithNamespaceInclAsString (), htd );
308+ }
309+ }
310+
259311 /**
260312 * Find descriptors by namespace.
261313 * @see #get(org.apache.hadoop.hbase.TableName)
@@ -379,6 +431,14 @@ private static String formatTableInfoSequenceId(final int number) {
379431 return Bytes .toString (b );
380432 }
381433
434+ @ Override
435+ public void close () throws IOException {
436+ // Close the executor when parallel loading enabled.
437+ if (tableDescriptorParallelLoadEnable ) {
438+ this .executor .shutdown ();
439+ }
440+ }
441+
382442 static final class SequenceIdAndFileLength {
383443
384444 final int sequenceId ;
0 commit comments