private FunctionInfo getFunctionInfoFromMetastoreNoLock(String functionName, HiveConf conf) {
    try {
      String[] parts = FunctionUtils.getQualifiedFunctionNameParts(functionName);
      Function func = Hive.get(conf).getFunction(parts[0].toLowerCase(), parts[1]);
      if (func == null) {
        return null;
      }
      // Found UDF in metastore - now add it to the function registry.
      FunctionInfo fi = registerPermanentFunction(functionName, func.getClassName(), true,
          FunctionUtils.toFunctionResource(func.getResourceUris()));
      if (fi == null) {
        LOG.error(func.getClassName() + " is not a valid UDF class and was not registered");
        return null;
      }
      return fi;
    } catch (Throwable e) {
      LOG.info("Unable to look up " + functionName + " in metastore", e);
    }
    return null;
  }
This is called outside of the lock. Some of the methods that are called transitively by
this (e.g. addFunction) will take the lock again and then release it, which is ok.
ql/src/java/org/apache/hadoop/hive/ql/exec/Registry.java