All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.julienviet.pgclient.impl.PgPoolImpl Maven / Gradle / Ivy

There is a newer version: 0.6.0
Show newest version
/*
 * Copyright (C) 2017 Julien Viet
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package com.julienviet.pgclient.impl;

import com.julienviet.pgclient.*;
import io.vertx.core.AsyncResult;
import io.vertx.core.Context;
import io.vertx.core.Future;
import io.vertx.core.Handler;
import io.vertx.core.Vertx;

/**
 * Todo :
 *
 * - handle timeout when acquiring a connection
 * - for per statement pooling, have several physical connection and use the less busy one to avoid head of line blocking effect
 *
 * @author Julien Viet
 * @author Emad Alblueshi
 */
public class PgPoolImpl extends PgClientBase implements PgPool {

  private final Context context;
  private final PgConnectionFactory factory;
  private final ConnectionPool pool;
  private final boolean closeVertx;

  public PgPoolImpl(Vertx vertx, boolean closeVertx, PgPoolOptions options) {
    int maxSize = options.getMaxSize();
    if (maxSize < 1) {
      throw new IllegalArgumentException("Pool max size must be > 0");
    }
    this.context = vertx.getOrCreateContext();
    this.factory = new PgConnectionFactory(context, Vertx.currentContext() != null, options);
    this.pool = new ConnectionPool(factory::connect, maxSize);
    this.closeVertx = closeVertx;
  }

  @Override
  public void getConnection(Handler> handler) {
    Context current = Vertx.currentContext();
    if (current == context) {
      pool.acquire(new ConnectionWaiter(handler));
    } else {
      context.runOnContext(v -> getConnection(handler));
    }
  }

  @Override
  protected void schedule(CommandBase cmd) {
    Context current = Vertx.currentContext();
    if (current == context) {
      pool.acquire(new CommandWaiter() {
        @Override
        protected void onSuccess(Connection conn) {
          // Work around stack over flow
          context.runOnContext(v -> {
            conn.schedule(cmd);
            conn.close(this);
          });
        }
        @Override
        protected void onFailure(Throwable cause) {
          cmd.fail(cause);
        }
      });
    } else {
      context.runOnContext(v -> schedule(cmd));
    }
  }

  private abstract class CommandWaiter implements Connection.Holder, Handler> {

    private Connection conn;

    protected abstract void onSuccess(Connection conn);

    protected abstract void onFailure(Throwable cause);

    @Override
    public void handleNotification(int processId, String channel, String payload) {
      // What should we do ?
    }

    @Override
    public void handle(AsyncResult ar) {
      if (ar.succeeded()) {
        Connection conn = ar.result();
        this.conn = conn;
        conn.init(this);
        onSuccess(conn);
      } else {
        onFailure(ar.cause());
      }
    }

    @Override
    public void handleClosed() {
    }

    @Override
    public void handleException(Throwable err) {
    }

    @Override
    public Connection connection() {
      return conn;
    }
  }

  private class ConnectionWaiter implements Handler> {

    private final Handler> handler;

    private ConnectionWaiter(Handler> handler) {
      this.handler = handler;
    }

    @Override
    public void handle(AsyncResult ar) {
      if (ar.succeeded()) {
        Connection conn = ar.result();
        PgConnectionImpl holder = new PgConnectionImpl(context, conn);
        conn.init(holder);
        handler.handle(Future.succeededFuture(holder));
      } else {
        handler.handle(Future.failedFuture(ar.cause()));
      }
    }
  }

  @Override
  public void close() {
    pool.close();
    factory.close();
    if (closeVertx) {
      context.owner().close();
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy