static void execute(EventLoop eventLoop, Runnable action) {
    if (eventLoop.inEventLoop()) {
      // this is used to prevent stack overflow, you can see the same trick in netty's LocalChannel
      // implementation.
      MutableInt depth = DEPTH.get();
      if (depth.intValue() < MAX_DEPTH) {
        depth.increment();
        try {
          action.run();
        } finally {
          depth.decrement();
        }
      } else {
        eventLoop.execute(action);
      }
    } else {
      eventLoop.execute(action);
    }
  }
Takes an Exception, the address, and if pertinent, the RegionInfo for the Region we were trying
to connect to and returns an IOException with the input exception as the cause. The new
exception provides the stack trace of the place where the exception is thrown and some extra
diagnostics information.
<p/>
Notice that we will try our best to keep the original exception type when creating a new
exception, especially for the 'connection' exceptions, as it is used to determine whether this
is a network issue or the remote side tells us clearly what is wrong, which is important
deciding whether to retry. If it is not possible to create a new exception with the same type,
for example, the {@code error} is not an {@link IOException}, an {@link IOException} will be
created.
@param addr  target address
@param error the relevant exception
@return an exception to throw
@see ClientExceptionsUtil#isConnectionException(Throwable)
hbase-client/src/main/java/org/apache/hadoop/hbase/ipc/IPCUtil.java