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.wal;
019
020import java.io.Closeable;
021import java.io.IOException;
022import java.util.concurrent.atomic.AtomicReference;
023import org.apache.hadoop.conf.Configuration;
024import org.apache.hadoop.hbase.Abortable;
025import org.apache.hadoop.hbase.regionserver.wal.MetricsWAL;
026import org.apache.hadoop.hbase.wal.WALFactory.Providers;
027import org.apache.yetus.audience.InterfaceAudience;
028
029/**
030 * A lazy initialized WAL provider for holding the WALProvider for some special tables, such as
031 * hbase:meta, hbase:replication, etc.
032 */
033@InterfaceAudience.Private
034class LazyInitializedWALProvider implements Closeable {
035
036  private final WALFactory factory;
037
038  private final String providerId;
039
040  private final String providerConfigName;
041
042  private final Abortable abortable;
043
044  private final AtomicReference<WALProvider> holder = new AtomicReference<>();
045
046  LazyInitializedWALProvider(WALFactory factory, String providerId, String providerConfigName,
047    Abortable abortable) {
048    this.factory = factory;
049    this.providerId = providerId;
050    this.providerConfigName = providerConfigName;
051    this.abortable = abortable;
052  }
053
054  WALProvider getProvider() throws IOException {
055    Configuration conf = factory.getConf();
056    for (;;) {
057      WALProvider provider = this.holder.get();
058      if (provider != null) {
059        return provider;
060      }
061      Class<? extends WALProvider> clz = null;
062      if (conf.get(providerConfigName) == null) {
063        try {
064          clz = conf.getClass(WALFactory.WAL_PROVIDER, Providers.defaultProvider.clazz,
065            WALProvider.class);
066        } catch (Throwable t) {
067          // the WAL provider should be an enum. Proceed
068        }
069      }
070      if (clz == null) {
071        clz = factory.getProviderClass(providerConfigName,
072          conf.get(WALFactory.WAL_PROVIDER, WALFactory.DEFAULT_WAL_PROVIDER));
073      }
074      provider = WALFactory.createProvider(clz);
075      provider.init(factory, conf, providerId, this.abortable);
076      provider.addWALActionsListener(new MetricsWAL());
077      if (this.holder.compareAndSet(null, provider)) {
078        return provider;
079      } else {
080        // someone is ahead of us, close and try again.
081        provider.close();
082      }
083    }
084  }
085
086  /**
087   * Get the provider if it already initialized, otherwise just return {@code null} instead of
088   * creating it.
089   */
090  WALProvider getProviderNoCreate() {
091    return holder.get();
092  }
093
094  @Override
095  public void close() throws IOException {
096    WALProvider provider = this.holder.get();
097    if (provider != null) {
098      provider.close();
099    }
100  }
101
102  void shutdown() throws IOException {
103    WALProvider provider = this.holder.get();
104    if (provider != null) {
105      provider.shutdown();
106    }
107  }
108}