Excellent open-source code analysis (two) HikariPool (a) acquaintance

Java Geeks | Author /   Kengran leaf
This is a Java geeks of 50 original articles

1. What is HikariPool

HikariPool is an open source database connection pool management tool, with excellent performance known.

2. What can be learned from the HikariPool

1.HikariPool use a lot of concurrency and thread management tools, you can learn from their usage.

2. There are a lot of performance improvements usage, we can learn from.

3. uses some Java features, making the code look more friendly, simple, for example:
the definition of 1) int of

// 以下这个定义是合法的,可用_来表示千分位,方便识别具体值是多少,而不用一个个的数
int i = 10_000;
复制代码

2) to simplify the class defined by the interior Lambda, e.g. HikariPool.java the following code:

         closeConnectionExecutor.execute(() -> {
            quietlyCloseConnection(connection, closureReason);
            if (poolState == POOL_NORMAL) {
               fillPool();
            }
         });
复制代码

Lambda expressions was not written as follows:

         closeConnectionExecutor.execute(new Runnable() {
            @Override
            public void run() {
               quietlyCloseConnection(connection, closureReason);
               if (poolState == POOL_NORMAL) {
                  fillPool();
               }
            }
         });
复制代码

Because only a method Runnable, so by

() -> {
复制代码

Alternatively the following code, such code more concise:

new Runnable() {
            @Override
            public void run() {
            }
复制代码

3, Hatsu识 HikariPool

HikariPool code logic is more complex at first glance, start here how to get the database connection began to realize it. Obtaining a connection interfaces associated classes as follows:

3.1, HikariPool

HikariPool connection pool management class, responsible for managing the database connection.

3.2 ConcurrentBag

ConcurrentBag is a package of concurrency management tool, responsible for managing the pooling of resources, not just the database connection, other pooled resources can be managed by it.

3.2.1, the class definition

// 通过泛型要求其包含的池化资源必须实现IConcurrentBagEntry接口
public class ConcurrentBag<T extends IConcurrentBagEntry> implements AutoCloseable
复制代码

3.2.2, pooling resources Interface

   // 池化资源接口
   public interface IConcurrentBagEntry
   {
      // 池化资源的状态定义
      int STATE_NOT_IN_USE = 0;
      int STATE_IN_USE = 1;
      int STATE_REMOVED = -1;
      int STATE_RESERVED = -2;

      // 通过CAS操作而非锁来提高并发效率
      boolean compareAndSet(int expectState, int newState);
      void setState(int newState);
      int getState();
   }
复制代码

3.2.3, obtain PoolEntry

public T borrow(long timeout, final TimeUnit timeUnit) throws InterruptedException
复制代码

ConcurrentBag code is more, in more detail later in the presentation.

3.3, Pool Entry

PoolEntry is the entry class pooled resources to achieve the IConcurrentBagEntry interface, while holding one-Connection, Connection for easy management. Its code that creates a connection broker is as follows:

   Connection createProxyConnection(final ProxyLeakTask leakTask, final long now)
   {
      return ProxyFactory.getProxyConnection(this, connection, openStatements, leakTask, now, isReadOnly, isAutoCommit);
   }
复制代码

3.4、ProxyFactory

ProxyFactory used to obtain a database connection.

3.4.1, get connected

   static ProxyConnection getProxyConnection(final PoolEntry poolEntry, final Connection connection, final FastList<Statement> openStatements, final ProxyLeakTask leakTask, final long now, final boolean isReadOnly, final boolean isAutoCommit)
   {
      // Body is replaced (injected) by JavassistProxyFactory
      throw new IllegalStateException("You need to run the CLI build and you need target/classes in your classpath to run.");
   }
复制代码

Internal 1. This method throws an exception, the actual method of experience is JavassistProxyFactory replaced.

2. Here, rather than return ProxyConnection Connection will be more flexible, easy to implement database monitoring. About Database Monitoring Reference: the Java call key chain tracking technology (four) SQL Monitoring

3.4.2、JavassistProxyFactory.java

A method for replacing ProxyFactory body type.

   private static void modifyProxyFactory() throws NotFoundException, CannotCompileException, IOException {
      System.out.println("Generating method bodies for com.zaxxer.hikari.proxy.ProxyFactory");

      String packageName = ProxyConnection.class.getPackage().getName();
      CtClass proxyCt = classPool.getCtClass("com.zaxxer.hikari.pool.ProxyFactory");
      for (CtMethod method : proxyCt.getMethods()) {
         switch (method.getName()) {
           // 这里对getProxyConnection方法体内容做了替换
            case "getProxyConnection":
               method.setBody("{return new " + packageName + ".HikariProxyConnection($$);}");
               break;
            case "getProxyStatement":
               method.setBody("{return new " + packageName + ".HikariProxyStatement($$);}");
               break;
            case "getProxyPreparedStatement":
               method.setBody("{return new " + packageName + ".HikariProxyPreparedStatement($$);}");
               break;
            case "getProxyCallableStatement":
               method.setBody("{return new " + packageName + ".HikariProxyCallableStatement($$);}");
               break;
            case "getProxyResultSet":
               method.setBody("{return new " + packageName + ".HikariProxyResultSet($$);}");
               break;
            case "getProxyDatabaseMetaData":
               method.setBody("{return new " + packageName + ".HikariProxyDatabaseMetaData($$);}");
               break;
            default:
               // unhandled method
               break;
         }
      }
      // 替换后的class直接放到classes目录下    
      proxyCt.writeFile(genDirectory + "target/classes");
   }
复制代码

3.5、ProxyConnection

ProxyConnection is a connection broker, hold Connection.

3.6、ProxyLeakTask

ProxyLeakTask for monitoring database connections for leaks, monitoring ideas:

1. When you create a connection ScheduledExecutorService delay the execution ProxyLeakTask, this time delay execution for leakDetectionThreshold configuration, if from the beginning to create a proxy connection over leakDetectionThreshold not close the connection proxy, ProxyLeakTask will be executed once the execution is a connection proxy may leaked.

2. If, within the time leakDetectionThreshold Connection Broker is closed, ProxyLeakTask will be cancel, so it will not be executed.

class ProxyLeakTask implements Runnable
{
   private static final Logger LOGGER = LoggerFactory.getLogger(ProxyLeakTask.class);
   static final ProxyLeakTask NO_LEAK;

   // 用于延迟调度ProxyLeakTask
   private ScheduledFuture<?> scheduledFuture;
   private String connectionName;
   private Exception exception;
   private String threadName;
   private boolean isLeaked;

   static
   {
      // 不需要监控连接泄露的ProxyLeakTask的实现类
      NO_LEAK = new ProxyLeakTask() {
         @Override
         void schedule(ScheduledExecutorService executorService, long leakDetectionThreshold) {}

         @Override
         public void run() {}  // 默认啥都不做

         @Override
         public void cancel() {} // 默认啥都不做
      };
   }

   ProxyLeakTask(final PoolEntry poolEntry)
   {
      this.exception = new Exception("Apparent connection leak detected");
      this.threadName = Thread.currentThread().getName();
      this.connectionName = poolEntry.connection.toString();
   }

   private ProxyLeakTask()
   {
   }

   void schedule(ScheduledExecutorService executorService, long leakDetectionThreshold)
   {
      // 通过超过leakDetectionThreshold时间后,延迟调用ProxyLeakTask,来报告泄漏信息
      scheduledFuture = executorService.schedule(this, leakDetectionThreshold, TimeUnit.MILLISECONDS);
   }

   /** {@inheritDoc} */
   @Override
   // 一旦被执行,说明获取连接到关闭超过了leakDetectionThreshold时间
   public void run()
   {
      isLeaked = true;

      final StackTraceElement[] stackTrace = exception.getStackTrace();
      final StackTraceElement[] trace = new StackTraceElement[stackTrace.length - 5];
      System.arraycopy(stackTrace, 5, trace, 0, trace.length);

      exception.setStackTrace(trace);
      // 下面是监控到连接泄漏的处理,这里只是记录到日志中,如果通过一个接口处理,并可以让使用者动态实现会更灵活
      LOGGER.warn("Connection leak detection triggered for {} on thread {}, stack trace follows", connectionName, threadName, exception);
   }

   void cancel()
   {
      scheduledFuture.cancel(false);
      if (isLeaked) {  // 检查到泄漏后连接被关闭,则给一个提示信息
         LOGGER.info("Previously reported leaked connection {} on thread {} was returned to the pool (unleaked)", connectionName, threadName);
      }
   }
}
复制代码

3.7、ProxyLeakTaskFactory

ProxyLeakTaskFactory is a factory class for creating ProxyLeakTask, reason why there is this factory class, because there are different ProxyLeakTask achieved. You can decide whether you want to monitor the connection leak depending on the configuration.

   ProxyLeakTask schedule(final PoolEntry poolEntry)
   {
      // 根据配置来创建不同的代理泄露监控类
      return (leakDetectionThreshold == 0) ? ProxyLeakTask.NO_LEAK : scheduleNewTask(poolEntry);
   }
复制代码

Above, a preliminary understanding of HikariPool, followed by further in more detail.

4, HiKaripool source address

1. Cloud code image
2.github warehouse

end.


Related reading:
the Java call key chain tracking technology (four) SQL Monitoring
excellent open-source code analysis (a) Google guava of EventBus


Java Geek site: javageektour.com/

Guess you like

Origin juejin.im/post/5e80b68ce51d45470c12a249