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.master.procedure; 019 020import java.io.IOException; 021import java.util.regex.Pattern; 022 023import org.apache.hadoop.hbase.DoNotRetryIOException; 024import org.apache.hadoop.hbase.TableName; 025import org.apache.hadoop.hbase.master.MasterServices; 026import org.apache.hadoop.hbase.procedure2.Procedure; 027import org.apache.hadoop.hbase.procedure2.ProcedureException; 028import org.apache.hadoop.hbase.procedure2.ProcedureExecutor; 029import org.apache.hadoop.hbase.security.User; 030import org.apache.hadoop.hbase.util.NonceKey; 031import org.apache.hadoop.security.UserGroupInformation; 032import org.apache.yetus.audience.InterfaceAudience; 033import org.apache.yetus.audience.InterfaceStability; 034 035import org.apache.hadoop.hbase.shaded.protobuf.generated.RPCProtos.UserInformation; 036 037@InterfaceAudience.Private 038@InterfaceStability.Evolving 039public final class MasterProcedureUtil { 040 041 private MasterProcedureUtil() {} 042 043 public static UserInformation toProtoUserInfo(User user) { 044 UserInformation.Builder userInfoPB = UserInformation.newBuilder(); 045 userInfoPB.setEffectiveUser(user.getName()); 046 if (user.getUGI().getRealUser() != null) { 047 userInfoPB.setRealUser(user.getUGI().getRealUser().getUserName()); 048 } 049 return userInfoPB.build(); 050 } 051 052 public static User toUserInfo(UserInformation userInfoProto) { 053 if (userInfoProto.hasEffectiveUser()) { 054 String effectiveUser = userInfoProto.getEffectiveUser(); 055 if (userInfoProto.hasRealUser()) { 056 String realUser = userInfoProto.getRealUser(); 057 UserGroupInformation realUserUgi = UserGroupInformation.createRemoteUser(realUser); 058 return User.create(UserGroupInformation.createProxyUser(effectiveUser, realUserUgi)); 059 } 060 return User.create(UserGroupInformation.createRemoteUser(effectiveUser)); 061 } 062 return null; 063 } 064 065 /** 066 * Helper Runnable used in conjunction with submitProcedure() to deal with 067 * submitting procs with nonce. 068 * See submitProcedure() for an example. 069 */ 070 public static abstract class NonceProcedureRunnable { 071 private final MasterServices master; 072 private final NonceKey nonceKey; 073 private Long procId; 074 075 public NonceProcedureRunnable(final MasterServices master, 076 final long nonceGroup, final long nonce) { 077 this.master = master; 078 this.nonceKey = getProcedureExecutor().createNonceKey(nonceGroup, nonce); 079 } 080 081 protected NonceKey getNonceKey() { 082 return nonceKey; 083 } 084 085 protected MasterServices getMaster() { 086 return master; 087 } 088 089 protected ProcedureExecutor<MasterProcedureEnv> getProcedureExecutor() { 090 return master.getMasterProcedureExecutor(); 091 } 092 093 protected long getProcId() { 094 return procId != null ? procId.longValue() : -1; 095 } 096 097 protected long setProcId(final long procId) { 098 this.procId = procId; 099 return procId; 100 } 101 102 protected abstract void run() throws IOException; 103 protected abstract String getDescription(); 104 105 protected long submitProcedure(final Procedure<MasterProcedureEnv> proc) { 106 assert procId == null : "submitProcedure() was already called, running procId=" + procId; 107 procId = getProcedureExecutor().submitProcedure(proc, nonceKey); 108 return procId; 109 } 110 } 111 112 /** 113 * Helper used to deal with submitting procs with nonce. 114 * Internally the NonceProcedureRunnable.run() will be called only if no one else 115 * registered the nonce. any Exception thrown by the run() method will be 116 * collected/handled and rethrown. 117 * <code> 118 * long procId = MasterProcedureUtil.submitProcedure( 119 * new NonceProcedureRunnable(procExec, nonceGroup, nonce) { 120 * {@literal @}Override 121 * public void run() { 122 * cpHost.preOperation(); 123 * submitProcedure(new MyProc()); 124 * cpHost.postOperation(); 125 * } 126 * }); 127 * </code> 128 */ 129 public static long submitProcedure(final NonceProcedureRunnable runnable) throws IOException { 130 final ProcedureExecutor<MasterProcedureEnv> procExec = runnable.getProcedureExecutor(); 131 final long procId = procExec.registerNonce(runnable.getNonceKey()); 132 if (procId >= 0) return procId; // someone already registered the nonce 133 try { 134 runnable.run(); 135 } catch (IOException e) { 136 procExec.setFailureResultForNonce(runnable.getNonceKey(), 137 runnable.getDescription(), 138 procExec.getEnvironment().getRequestUser(), e); 139 throw e; 140 } finally { 141 procExec.unregisterNonceIfProcedureWasNotSubmitted(runnable.getNonceKey()); 142 } 143 return runnable.getProcId(); 144 } 145 146 /** 147 * Pattern used to validate a Procedure WAL file name see 148 * {@link #validateProcedureWALFilename(String)} for description. 149 * @deprecated Since 2.3.0, will be removed in 4.0.0. We do not use this style of procedure wal 150 * file name any more. 151 */ 152 @Deprecated 153 private static final Pattern PATTERN = Pattern.compile(".*pv2-\\d{20}.log"); 154 155 /** 156 * A Procedure WAL file name is of the format: pv-<wal-id>.log where wal-id is 20 digits. 157 * @param filename name of the file to validate 158 * @return <tt>true</tt> if the filename matches a Procedure WAL, <tt>false</tt> otherwise 159 */ 160 public static boolean validateProcedureWALFilename(String filename) { 161 return PATTERN.matcher(filename).matches(); 162 } 163 164 /** 165 * Return the priority for the given table. Now meta table is 3, other system tables are 2, and 166 * user tables are 1. 167 */ 168 public static int getTablePriority(TableName tableName) { 169 if (TableName.isMetaTableName(tableName)) { 170 return 3; 171 } else if (tableName.isSystemTable()) { 172 return 2; 173 } else { 174 return 1; 175 } 176 } 177 178 /** 179 * Return the priority for the given procedure. For now we only have two priorities, 100 for 180 * server carrying meta, and 1 for others. 181 */ 182 public static int getServerPriority(ServerProcedureInterface proc) { 183 return proc.hasMetaTableRegion() ? 100 : 1; 184 } 185 186 /** 187 * This is a version of unwrapRemoteIOException that can do DoNotRetryIOE. 188 * We need to throw DNRIOE to clients if a failed Procedure else they will 189 * keep trying. The default proc.getException().unwrapRemoteException 190 * doesn't have access to DNRIOE from the procedure2 module. 191 */ 192 public static IOException unwrapRemoteIOException(Procedure proc) { 193 Exception e = proc.getException().unwrapRemoteException(); 194 // Do not retry ProcedureExceptions! 195 return (e instanceof ProcedureException)? new DoNotRetryIOException(e): 196 proc.getException().unwrapRemoteIOException(); 197 } 198}