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 */ 150 private static final Pattern pattern = Pattern.compile(".*pv2-\\d{20}.log"); 151 152 /** 153 * A Procedure WAL file name is of the format: pv-<wal-id>.log where wal-id is 20 digits. 154 * @param filename name of the file to validate 155 * @return <tt>true</tt> if the filename matches a Procedure WAL, <tt>false</tt> otherwise 156 */ 157 public static boolean validateProcedureWALFilename(String filename) { 158 return pattern.matcher(filename).matches(); 159 } 160 161 /** 162 * Return the priority for the given table. Now meta table is 3, other system tables are 2, and 163 * user tables are 1. 164 */ 165 public static int getTablePriority(TableName tableName) { 166 if (TableName.isMetaTableName(tableName)) { 167 return 3; 168 } else if (tableName.isSystemTable()) { 169 return 2; 170 } else { 171 return 1; 172 } 173 } 174 175 /** 176 * Return the priority for the given procedure. For now we only have two priorities, 100 for 177 * server carrying meta, and 1 for others. 178 */ 179 public static int getServerPriority(ServerProcedureInterface proc) { 180 return proc.hasMetaTableRegion() ? 100 : 1; 181 } 182 183 /** 184 * This is a version of unwrapRemoteIOException that can do DoNotRetryIOE. 185 * We need to throw DNRIOE to clients if a failed Procedure else they will 186 * keep trying. The default proc.getException().unwrapRemoteException 187 * doesn't have access to DNRIOE from the procedure2 module. 188 */ 189 public static IOException unwrapRemoteIOException(Procedure proc) { 190 Exception e = proc.getException().unwrapRemoteException(); 191 // Do not retry ProcedureExceptions! 192 return (e instanceof ProcedureException)? new DoNotRetryIOException(e): 193 proc.getException().unwrapRemoteIOException(); 194 } 195}