Java geek

1. What is HikariPool

HikariPool is an open source database connection pool management tool known for its excellent performance.

2. What can we learn from HikariPool

HikariPool uses a number of concurrency and thread management tools. Learn how to use them.

2. There are many ways to improve performance.

3. Use some Java features to make code look more friendly and concise, such as: 1)int definition

// The following definition is legal, using _ to represent the thousandths, so that it is easy to identify specific values rather than individual numbers
int i = 10 _000;
Copy the code

2) Use Lambda to simplify the definition of inner classes, such as hikariPool.java:

         closeConnectionExecutor.execute(() -> {
            quietlyCloseConnection(connection, closureReason);
            if(poolState == POOL_NORMAL) { fillPool(); }});Copy the code

Instead of a Lambda expression, we could write it as follows:

         closeConnectionExecutor.execute(new Runnable() {
            @Override
            public void run() {
               quietlyCloseConnection(connection, closureReason);
               if(poolState == POOL_NORMAL) { fillPool(); }}});Copy the code

Because Runnable has only one method, it passes

() - > {Copy the code

Replace the following code to make the code more concise:

new Runnable() {
            @Override
            public void run(a) {}Copy the code

3. First acquaintance with HikariPool

The HikariPool code is logically complex at first glance, so let’s start with how to get a database connection. The class interface associated with getting the connection is as follows:

3.1, HikariPool

HikariPool is a connection pool management class that manages database connections.

3.2, load-balanced across

ConcurrentBag is an encapsulated concurrency management tool that manages pooled resources, not just database connections, but other pooled resources.

3.2.1. Class Definition

// Pooled resources must implement the IConcurrentBagEntry interface through generics
public class ConcurrentBag<T extends IConcurrentBagEntry> implements AutoCloseable
Copy the code

3.2.2 Pooling Resource Interfaces

   // Pool resource interfaces
   public interface IConcurrentBagEntry
   {
      // State definition of pooled resources
      int STATE_NOT_IN_USE = 0;
      int STATE_IN_USE = 1;
      int STATE_REMOVED = -1;
      int STATE_RESERVED = -2;

      // Increase concurrency efficiency through CAS operations instead of locks
      boolean compareAndSet(int expectState, int newState);
      void setState(int newState);
      int getState(a);
   }
Copy the code

3.2.3 Get PoolEntry

public T borrow(long timeout, final TimeUnit timeUnit) throws InterruptedException
Copy the code

ConcurrentBag has a lot of code and will be covered in more detail later.

3.3, PoolEntry

PoolEntry is an entry class for pooled resources. It implements the IConcurrentBagEntry interface and holds Connection one-to-one to facilitate Connection management. The code to create the connection proxy is as follows:

   Connection createProxyConnection(final ProxyLeakTask leakTask, final long now)
   {
      return ProxyFactory.getProxyConnection(this, connection, openStatements, leakTask, now, isReadOnly, isAutoCommit);
   }
Copy the code

3.4, ProxyFactory

ProxyFactory is used to get database connections.

3.4.1. Get the connection

   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.");
   }
Copy the code

1. This method throws an exception internally. The actual method will be replaced by JavassistProxyFactory.

2. It is more flexible to return ProxyConnection instead of Connection to facilitate database monitoring. About database monitoring reference: Java call chain tracking key technology (four) SQL monitoring

3.4.2, JavassistProxyFactory. Java

The method body used to replace the ProxyFactory class.

   private static void modifyProxyFactory(a) 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()) {
           // This replaces the body of the getProxyConnection method
            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; }}// Put the replaced classes directly into the classes directory
      proxyCt.writeFile(genDirectory + "target/classes");
   }
Copy the code

3.5, ProxyConnection

ProxyConnection is a Connection proxy that holds a Connection.

3.6, ProxyLeakTask

ProxyLeakTask Is used to monitor whether the database connection is leaky.

1. When creating a connection, use ScheduledExecutorService to delay the execution of ProxyLeakTask. The delay is the configured leakDetectionThreshold. If the connection agent is not shut down from the time it is created until the leakDetectionThreshold is exceeded, ProxyLeakTask will be executed, which means that the connection agent may have leaked.

2. If the Connection agent is closed within the leakDetectionThreshold time, ProxyLeakTask will be cancelled and will not be executed.

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

   // Used to delay scheduling ProxyLeakTask
   privateScheduledFuture<? > scheduledFuture;private String connectionName;
   private Exception exception;
   private String threadName;
   private boolean isLeaked;

   static
   {
      // There is no need to monitor the implementation class of ProxyLeakTask for connection leaks
      NO_LEAK = new ProxyLeakTask() {
         @Override
         void schedule(ScheduledExecutorService executorService, long leakDetectionThreshold) {}

         @Override
         public void run(a) {}  // Do nothing by default

         @Override
         public void cancel(a) {} // Do nothing by default
      };
   }

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

   private ProxyLeakTask(a)
   {}void schedule(ScheduledExecutorService executorService, long leakDetectionThreshold)
   {
      // Delay the call to ProxyLeakTask after the leakDetectionThreshold has been passed to report the leak information
      scheduledFuture = executorService.schedule(this, leakDetectionThreshold, TimeUnit.MILLISECONDS);
   }

   / * * {@inheritDoc} * /
   @Override
   // If executed, the leakDetectionThreshold time for obtaining the connection to close has exceeded
   public void run(a)
   {
      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);
      // The following is the process that monitors connection leaks. Here, it is only recorded in the log. It is more flexible if it is handled through an interface and can be implemented dynamically by the user
      LOGGER.warn("Connection leak detection triggered for {} on thread {}, stack trace follows", connectionName, threadName, exception);
   }

   void cancel(a)
   {
      scheduledFuture.cancel(false);
      if (isLeaked) {  // If the connection is closed after a leak is detected, a message will be given
         LOGGER.info("Previously reported leaked connection {} on thread {} was returned to the pool (unleaked)", connectionName, threadName); }}}Copy the code

3.7, ProxyLeakTaskFactory

ProxyLeakTaskFactory is a factory class that is used to create ProxyLeakTask. This factory class is available because there are different proxyLeakTaskTask implementations. You can determine whether you want to monitor connection leaks based on your configuration.

   ProxyLeakTask schedule(final PoolEntry poolEntry)
   {
      // Create different proxy leak monitoring classes according to the configuration
      return (leakDetectionThreshold == 0)? ProxyLeakTask.NO_LEAK : scheduleNewTask(poolEntry); }Copy the code

The above is a preliminary understanding of HikariPool, which will be further introduced in more detail later.

4, HiKaripool source address

1. Code cloud image 2. Github repository

end.


<– Thanks for the triple punch, left likes and followings.


Related reading: HikariPool source code (two) design ideas for reference HikariPool source code (three) resource pool dynamic scaling HikariPool source code (four) resource state HikariPool source code (five) thread and related tools EventBus JAVA call chain tracking key technology (four) SQL monitoring


Java geek site: javageektour.com/