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; 022import org.apache.hadoop.hbase.DoNotRetryIOException; 023import org.apache.hadoop.hbase.TableName; 024import org.apache.hadoop.hbase.master.MasterServices; 025import org.apache.hadoop.hbase.procedure2.Procedure; 026import org.apache.hadoop.hbase.procedure2.ProcedureException; 027import org.apache.hadoop.hbase.procedure2.ProcedureExecutor; 028import org.apache.hadoop.hbase.security.User; 029import org.apache.hadoop.hbase.util.NonceKey; 030import org.apache.hadoop.security.UserGroupInformation; 031import org.apache.yetus.audience.InterfaceAudience; 032import org.apache.yetus.audience.InterfaceStability; 033 034import org.apache.hadoop.hbase.shaded.protobuf.generated.RPCProtos.UserInformation; 035 036@InterfaceAudience.Private 037@InterfaceStability.Evolving 038public final class MasterProcedureUtil { 039 040 private MasterProcedureUtil() { 041 } 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 submitting procs with 067 * nonce. See submitProcedure() for an example. 068 */ 069 public static abstract class NonceProcedureRunnable { 070 private final MasterServices master; 071 private final NonceKey nonceKey; 072 private Long procId; 073 074 public NonceProcedureRunnable(final MasterServices master, final long nonceGroup, 075 final long nonce) { 076 this.master = master; 077 this.nonceKey = getProcedureExecutor().createNonceKey(nonceGroup, nonce); 078 } 079 080 protected NonceKey getNonceKey() { 081 return nonceKey; 082 } 083 084 protected MasterServices getMaster() { 085 return master; 086 } 087 088 protected ProcedureExecutor<MasterProcedureEnv> getProcedureExecutor() { 089 return master.getMasterProcedureExecutor(); 090 } 091 092 protected long getProcId() { 093 return procId != null ? procId.longValue() : -1; 094 } 095 096 protected long setProcId(final long procId) { 097 this.procId = procId; 098 return procId; 099 } 100 101 protected abstract void run() throws IOException; 102 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. Internally the 114 * NonceProcedureRunnable.run() will be called only if no one else registered the nonce. any 115 * Exception thrown by the run() method will be collected/handled and rethrown. <code> 116 * long procId = MasterProcedureUtil.submitProcedure( 117 * new NonceProcedureRunnable(procExec, nonceGroup, nonce) { 118 * {@literal @}Override 119 * public void run() { 120 * cpHost.preOperation(); 121 * submitProcedure(new MyProc()); 122 * cpHost.postOperation(); 123 * } 124 * }); 125 * </code> 126 */ 127 public static long submitProcedure(final NonceProcedureRunnable runnable) throws IOException { 128 final ProcedureExecutor<MasterProcedureEnv> procExec = runnable.getProcedureExecutor(); 129 final long procId = procExec.registerNonce(runnable.getNonceKey()); 130 if (procId >= 0) return procId; // someone already registered the nonce 131 try { 132 runnable.run(); 133 } catch (IOException e) { 134 procExec.setFailureResultForNonce(runnable.getNonceKey(), runnable.getDescription(), 135 procExec.getEnvironment().getRequestUser(), e); 136 throw e; 137 } finally { 138 procExec.unregisterNonceIfProcedureWasNotSubmitted(runnable.getNonceKey()); 139 } 140 return runnable.getProcId(); 141 } 142 143 /** 144 * Pattern used to validate a Procedure WAL file name see 145 * {@link #validateProcedureWALFilename(String)} for description. 146 * @deprecated Since 2.3.0, will be removed in 4.0.0. We do not use this style of procedure wal 147 * file name any more. 148 */ 149 @Deprecated 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. We need to throw DNRIOE 185 * to clients if a failed Procedure else they will keep trying. The default 186 * proc.getException().unwrapRemoteException doesn't have access to DNRIOE from the procedure2 187 * 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) 193 ? new DoNotRetryIOException(e) 194 : proc.getException().unwrapRemoteIOException(); 195 } 196}