xp-framework/rfc

Connection pool

thekid opened this issue · 1 comments

Scope of Change

This RFC suggests creating a connection pool around the rdbms library.

Rationale

Handle disconnects from database servers and concurrency in long-running processes like xp web.

Functionality

Low-level

$pool= new Connections($dsn, 10);

// Acquiring a connection will return any unused connection
// It will also ensure the connection is still valid before issuing queries
$conn= $pool->acquire();

// The interface is compatible to rdbms.DBConnection, e.g.:
$records= $conn->select('...');
$results= $conn->query('...');
$affected= $conn->update('...');

// Mark for reuse
$conn->release();

To not forget to mark a connection for reuse, a with() method is supplied. It will release the connection whether an exception is raised or not.

$identity= $pool->with(function($conn) {
  $conn->update('...');
  $conn->insert('...');
  return $conn->identity();
});

There are also shortcuts to rdbms.DBConnection-style methods, which will acquire a connection, execute a single query on it and release the connection once the query has completed.

$records= $pool->select('...');
$results= $pool->query('...');
$affected= $pool->update('...');

Migration scenario

class Feedbacks {
  private $conn;

  public function __construct(DBConnection $conn) {
    $this->conn= $conn;
  }

  public function from(int $senderId): Sequence {
    return Sequence::of($this->conn->query(
      'select * from feedback where sender_id= %d',
      $senderId
    ));
  }

  public function create(int $senderId, int $recipientId, string $text): int {
    $this->conn->insert('into feedback ...', $senderId, $recipientId, $text);
    return $this->conn->identity();
  }
}
class Feedbacks {
  private $pool;

  public function __construct(Connections $pool) {
    $this->pool= $pool;
  }

  public function from(int $senderId): Sequence {
    return Sequence::of($this->pool->query(
      'select * from feedback where sender_id= %d',
      $senderId
    ));
  }

  public function create(int $senderId, int $recipientId, string $text): int {
    return $this->pool->with(function($conn) use($senderId, $recipientId, $text) {
      $conn->insert('into feedback ...', $senderId, $recipientId, $text);
      return $conn->identity();
    });
  }
}

Security considerations

Speed impact

Dependencies

Related documents

Would this work across fork'ed children?