diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterFileSystem.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterFileSystem.java index 9ec49c2..7c45d32 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterFileSystem.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterFileSystem.java @@ -101,6 +101,13 @@ public class MasterFileSystem { } }; + final static PathFilter SYS_FILTER = new PathFilter() { + @Override + public boolean accept(Path p) { + return DefaultWALProvider.isSystemFile(p); + } + }; + final static PathFilter NON_META_FILTER = new PathFilter() { @Override public boolean accept(Path p) { @@ -315,6 +322,26 @@ public class MasterFileSystem { splitLog(serverNames, META_FILTER); } + /** + * Specialized method to handle the splitting for system WAL + * @param serverName + * @throws IOException + */ + public void splitSystemLog(final ServerName serverName) throws IOException { + Set serverNames = new HashSet(); + serverNames.add(serverName); + splitSystemLog(serverNames); + } + + /** + * Specialized method to handle the splitting for System WAL + * @param serverNames + * @throws IOException + */ + public void splitSystemLog(final Set serverNames) throws IOException { + splitLog(serverNames, SYS_FILTER); + } + @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="UL_UNRELEASED_LOCK", justification= "We only release this lock when we set it. Updates to code that uses it should verify use " + "of the guard boolean.") diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java index 8a5e423..4b9d8f2 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java @@ -79,6 +79,7 @@ import org.apache.hadoop.hbase.ZNodeClearer; import org.apache.hadoop.hbase.classification.InterfaceAudience; import org.apache.hadoop.hbase.client.ClusterConnection; import org.apache.hadoop.hbase.client.ConnectionUtils; +import org.apache.hadoop.hbase.client.RegionReplicaUtil; import org.apache.hadoop.hbase.client.RpcRetryingCallerFactory; import org.apache.hadoop.hbase.conf.ConfigurationManager; import org.apache.hadoop.hbase.coordination.BaseCoordinatedStateManager; @@ -363,6 +364,8 @@ public class HRegionServer extends HasThread implements final LogRoller walRoller; // Lazily initialized if this RegionServer hosts a meta table. final AtomicReference metawalRoller = new AtomicReference(); + // Lazily initialized if this RegionServer hosts a system table. + final AtomicReference sysWalRoller = new AtomicReference(); // flag set after we're done setting up server threads final AtomicBoolean online = new AtomicBoolean(false); @@ -1673,6 +1676,28 @@ public class HRegionServer extends HasThread implements return roller; } + /* + * This is similar to ensureMetaWALRoller(). It handles WAL roller for system tables + */ + protected LogRoller ensureSystemWALRoller() { + // Using a tmp log roller to ensure metaLogRoller is alive once it is not null + LogRoller roller = sysWalRoller.get(); + if (null == roller) { + LogRoller tmpLogRoller = new LogRoller(this, this); + String n = Thread.currentThread().getName(); + Threads.setDaemonThreadRunning(tmpLogRoller.getThread(), + n + "-SystemLogRoller", uncaughtExceptionHandler); + if (sysWalRoller.compareAndSet(null, tmpLogRoller)) { + roller = tmpLogRoller; + } else { + // Another thread won starting the roller + Threads.shutdown(tmpLogRoller.getThread()); + roller = sysWalRoller.get(); + } + } + return roller; + } + public MetricsRegionServer getRegionServerMetrics() { return this.metricsRegionServer; } @@ -1847,11 +1872,16 @@ public class HRegionServer extends HasThread implements public WAL getWAL(HRegionInfo regionInfo) throws IOException { WAL wal; LogRoller roller = walRoller; - //_ROOT_ and hbase:meta regions have separate WAL. + // hbase:meta regions have separate WAL. if (regionInfo != null && regionInfo.isMetaTable() && - regionInfo.getReplicaId() == HRegionInfo.DEFAULT_REPLICA_ID) { + RegionReplicaUtil.isDefaultReplica(regionInfo)) { roller = ensureMetaWALRoller(); wal = walFactory.getMetaWAL(regionInfo.getEncodedNameAsBytes()); + } else if (regionInfo != null && regionInfo.isSystemTable() && + RegionReplicaUtil.isDefaultReplica(regionInfo)) { + roller = ensureSystemWALRoller(); + wal = walFactory.getSystemWAL(regionInfo.getEncodedNameAsBytes(), + regionInfo.getTable().getNamespace()); } else if (regionInfo == null) { wal = walFactory.getWAL(UNSPECIFIED_REGION, null); } else { diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/util/MetaUtils.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/util/MetaUtils.java index 309bd4a..d024e29 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/util/MetaUtils.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/util/MetaUtils.java @@ -96,8 +96,9 @@ public class MetaUtils { } final byte[] region = info.getEncodedNameAsBytes(); final byte[] namespace = info.getTable().getNamespace(); - return info.isMetaRegion() ? walFactory.getMetaWAL(region) : walFactory.getWAL(region, - namespace); + if (info.isMetaRegion()) return walFactory.getMetaWAL(region); + if (info.isSystemTable()) return walFactory.getSystemWAL(region,info.getTable().getNamespace()); + return walFactory.getWAL(region, namespace); } /** diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/wal/DefaultWALProvider.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/wal/DefaultWALProvider.java index 027e7a2..62bbaf4 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/wal/DefaultWALProvider.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/wal/DefaultWALProvider.java @@ -149,6 +149,8 @@ public class DefaultWALProvider implements WALProvider { /** The hbase:meta region's WAL filename extension */ @VisibleForTesting public static final String META_WAL_PROVIDER_ID = ".meta"; + @VisibleForTesting + public static final String SYS_WAL_PROVIDER_ID = ".sys"; static final String DEFAULT_PROVIDER_ID = "default"; // Implementation details that currently leak in tests or elsewhere follow @@ -361,6 +363,17 @@ public class DefaultWALProvider implements WALProvider { return false; } + public static boolean isSystemFile(Path p) { + return isSystemFile(p.getName()); + } + + public static boolean isSystemFile(String p) { + if (p != null && p.endsWith(SYS_WAL_PROVIDER_ID)) { + return true; + } + return false; + } + /** * public because of FSHLog. Should be package-private */ diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/wal/WALFactory.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/wal/WALFactory.java index 0317b66..05e60d6 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/wal/WALFactory.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/wal/WALFactory.java @@ -89,12 +89,18 @@ public class WALFactory { static final String META_WAL_PROVIDER = "hbase.wal.meta_provider"; static final String DEFAULT_META_WAL_PROVIDER = Providers.defaultProvider.name(); + static final String SYS_WAL_PROVIDER = "hbase.wal.sys_provider"; + static final String DEFAULT_SYS_WAL_PROVIDER = Providers.defaultProvider.name(); + final String factoryId; final WALProvider provider; // The meta updates are written to a different wal. If this // regionserver holds meta regions, then this ref will be non-null. // lazily intialized; most RegionServers don't deal with META final AtomicReference metaProvider = new AtomicReference(); + // The updates to system tables are written to a different wal. + // lazily intialized + final AtomicReference sysProvider = new AtomicReference(); /** * Configuration-specified WAL Reader used when a custom reader is requested @@ -194,6 +200,10 @@ public class WALFactory { if (null != metaProvider) { metaProvider.close(); } + final WALProvider sysProvider = this.sysProvider.get(); + if (null != sysProvider) { + sysProvider.close(); + } // close is called on a WALFactory with null provider in the case of contention handling // within the getInstance method. if (null != provider) { @@ -216,6 +226,14 @@ public class WALFactory { exception = ioe; } } + final WALProvider sysProvider = this.sysProvider.get(); + if (null != sysProvider) { + try { + sysProvider.shutdown(); + } catch(IOException ioe) { + exception = ioe; + } + } provider.shutdown(); if (null != exception) { throw exception; @@ -250,6 +268,26 @@ public class WALFactory { return metaProvider.getWAL(identifier, null); } + /** + * @param identifier may not be null, contents will not be altered + */ + public WAL getSystemWAL(final byte[] identifier, final byte[] namespace) throws IOException { + WALProvider sysProvider = this.sysProvider.get(); + if (null == sysProvider) { + final WALProvider temp = getProvider(SYS_WAL_PROVIDER, DEFAULT_SYS_WAL_PROVIDER, + Collections.singletonList(new MetricsWAL()), + DefaultWALProvider.SYS_WAL_PROVIDER_ID); + if (this.sysProvider.compareAndSet(null, temp)) { + sysProvider = temp; + } else { + // reference must now be to a provider created in another thread. + temp.close(); + sysProvider = this.sysProvider.get(); + } + } + return sysProvider.getWAL(identifier, namespace); + } + public Reader createReader(final FileSystem fs, final Path path) throws IOException { return createReader(fs, path, (CancelableProgressable)null); }