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 43ae2f8..4fab3ff 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 2ce2193..e8420b2 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 @@ -80,6 +80,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; @@ -364,6 +365,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); @@ -1677,6 +1680,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; } @@ -1851,11 +1876,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..fd23a16 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 @@ -126,14 +126,25 @@ public class DefaultWALProvider implements WALProvider { if (log == null) { log = new FSHLog(FileSystem.get(conf), FSUtils.getRootDir(conf), getWALDirectoryName(factory.factoryId), HConstants.HREGION_OLDLOGDIR_NAME, conf, - listeners, true, logPrefix, - META_WAL_PROVIDER_ID.equals(providerId) ? META_WAL_PROVIDER_ID : null); + listeners, true, logPrefix, getLogSuffix()); } } } return log; } + private String getLogSuffix() { + String suffix; + if (META_WAL_PROVIDER_ID.equals(providerId)) { + suffix = META_WAL_PROVIDER_ID; + } else if (SYS_WAL_PROVIDER_ID.equals(providerId)) { + suffix = SYS_WAL_PROVIDER_ID; + } else { + suffix = null; + } + return suffix; + } + @Override public void close() throws IOException { if (log != null) log.close(); @@ -149,6 +160,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 @@ -213,14 +226,16 @@ public class DefaultWALProvider implements WALProvider { throw new IllegalArgumentException("The WAL path couldn't be null"); } final String[] walPathStrs = walName.toString().split("\\" + WAL_FILE_NAME_DELIMITER); - return Long.parseLong(walPathStrs[walPathStrs.length - (isMetaFile(walName) ? 2:1)]); + return Long.parseLong(walPathStrs[walPathStrs.length - + (isMetaFile(walName)||isSystemFile(walName) ? 2:1)]); } /** * Pattern used to validate a WAL file name * see {@link #validateWALFilename(String)} for description. */ - private static final Pattern pattern = Pattern.compile(".*\\.\\d*("+META_WAL_PROVIDER_ID+")*"); + private static final Pattern pattern = Pattern.compile(".*\\.\\d*(["+ + META_WAL_PROVIDER_ID + "|" + SYS_WAL_PROVIDER_ID + "])*"); /** * A WAL file name is of the format: @@ -361,6 +376,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 */ @@ -387,7 +413,14 @@ public class DefaultWALProvider implements WALProvider { * @return prefix of the log */ public static String getWALPrefixFromWALName(String name) { - int endIndex = name.replaceAll(META_WAL_PROVIDER_ID, "").lastIndexOf("."); + int endIndex; + if (isMetaFile(name)) { + endIndex = name.substring(0, name.lastIndexOf(META_WAL_PROVIDER_ID)).lastIndexOf("."); + } else if (isSystemFile(name)) { + endIndex = name.substring(0, name.lastIndexOf(SYS_WAL_PROVIDER_ID)).lastIndexOf("."); + } else { + endIndex = name.lastIndexOf("."); + } return name.substring(0, endIndex); } diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/wal/RegionGroupingProvider.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/wal/RegionGroupingProvider.java index 2885428..b10bfe3 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/wal/RegionGroupingProvider.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/wal/RegionGroupingProvider.java @@ -19,6 +19,7 @@ package org.apache.hadoop.hbase.wal; import static org.apache.hadoop.hbase.wal.DefaultWALProvider.META_WAL_PROVIDER_ID; +import static org.apache.hadoop.hbase.wal.DefaultWALProvider.SYS_WAL_PROVIDER_ID; import static org.apache.hadoop.hbase.wal.DefaultWALProvider.WAL_FILE_NAME_DELIMITER; import java.io.IOException; @@ -123,6 +124,7 @@ class RegionGroupingProvider implements WALProvider { public static final String REGION_GROUPING_STRATEGY = "hbase.wal.regiongrouping.strategy"; public static final String DEFAULT_REGION_GROUPING_STRATEGY = Strategies.defaultStrategy.name(); + public static final String IDENTITY_REGION_GROUPING_STRATEGY = Strategies.identity.name(); private static final String META_WAL_GROUP_NAME = "meta"; @@ -157,7 +159,9 @@ class RegionGroupingProvider implements WALProvider { } } this.providerId = sb.toString(); - this.strategy = getStrategy(conf, REGION_GROUPING_STRATEGY, DEFAULT_REGION_GROUPING_STRATEGY); + this.strategy = getStrategy(conf, REGION_GROUPING_STRATEGY, + DefaultWALProvider.SYS_WAL_PROVIDER_ID.equals(providerId) ? + IDENTITY_REGION_GROUPING_STRATEGY : DEFAULT_REGION_GROUPING_STRATEGY); this.conf = conf; } @@ -166,11 +170,12 @@ class RegionGroupingProvider implements WALProvider { */ FSHLog populateCache(String groupName) throws IOException { boolean isMeta = META_WAL_PROVIDER_ID.equals(providerId); + boolean isSystem = SYS_WAL_PROVIDER_ID.equals(providerId); String hlogPrefix; List listeners; - if (isMeta) { + if (isMeta || isSystem) { hlogPrefix = this.providerId; - // don't watch log roll for meta + // don't watch log roll for meta / system tables listeners = Collections. singletonList(new MetricsWAL()); } else { hlogPrefix = groupName; @@ -178,7 +183,8 @@ class RegionGroupingProvider implements WALProvider { } FSHLog log = new FSHLog(FileSystem.get(conf), FSUtils.getRootDir(conf), DefaultWALProvider.getWALDirectoryName(providerId), HConstants.HREGION_OLDLOGDIR_NAME, - conf, listeners, true, hlogPrefix, isMeta ? META_WAL_PROVIDER_ID : null); + conf, listeners, true, hlogPrefix, isMeta ? META_WAL_PROVIDER_ID : + isSystem ? SYS_WAL_PROVIDER_ID : null); cached.put(groupName, log); logs.add(log); return log; 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); }