diff --git a/README.md b/README.md index a44ac99d89cc41ff1d3a5c924505501a6fe716e2..11605e13f02459d19412d1a3e461ce96e80976ca 100644 --- a/README.md +++ b/README.md @@ -16,19 +16,19 @@ i'll lyk when its done PostgreSQL pooler (like PgBouncer) with sharding, load balancing and failover support. ## Features -| **Feature** | **Status** | **Comments** | -|--------------------------------|-----------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------| -| Transaction pooling | :white_check_mark: | Identical to PgBouncer. | -| Session pooling | :white_check_mark: | Identical to PgBouncer. | -| `COPY` support | :white_check_mark: | Both `COPY TO` and `COPY FROM` are supported. | -| Query cancellation | :white_check_mark: | Supported both in transaction and session pooling modes. | -| Load balancing of read queries | :white_check_mark: | Using random between replicas. Primary is included when `primary_reads_enabled` is enabled (default). | -| Sharding | :white_check_mark: | Transactions are sharded using `SET SHARD TO` and `SET SHARDING KEY TO` syntax extensions; see examples below. | -| Failover | :white_check_mark: | Replicas are tested with a health check. If a health check fails, remaining replicas are attempted; see below for algorithm description and examples. | -| Statistics | :white_check_mark: | Statistics available in the admin database (`pgcat` and `pgbouncer`) with `SHOW STATS`, `SHOW POOLS` and others. | -| Live configuration reloading | :white_check_mark: | Reload supported settings with a `SIGHUP` to the process, e.g. `kill -s SIGHUP $(pgrep pgcat)` or `RELOAD` query issued to the admin database. | -| Client authentication | :white_check_mark: :wrench: | MD5 password authentication is supported, SCRAM is on the roadmap; one user is used to connect to Postgres with both SCRAM and MD5 supported. | -| Admin database | :white_check_mark: | The admin database, similar to PgBouncer's, allows to query for statistics and reload the configuration. | +| **Feature** | **Status** | Gat Status | **Comments** | +|--------------------------------|-----------------------------|--------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------| +| Transaction pooling | :white_check_mark: | :white_check_mark: | Identical to PgBouncer. | +| Session pooling | :white_check_mark: | :white_check_mark: | Identical to PgBouncer. | +| `COPY` support | :white_check_mark: | :white_check_mark: | Both `COPY TO` and `COPY FROM` are supported. | +| Query cancellation | :white_check_mark: | no | Supported both in transaction and session pooling modes. | +| Load balancing of read queries | :white_check_mark: | no | Using random between replicas. Primary is included when `primary_reads_enabled` is enabled (default). | +| Sharding | :white_check_mark: | no | Transactions are sharded using `SET SHARD TO` and `SET SHARDING KEY TO` syntax extensions; see examples below. | +| Failover | :white_check_mark: | no | Replicas are tested with a health check. If a health check fails, remaining replicas are attempted; see below for algorithm description and examples. | +| Statistics | :white_check_mark: | no | Statistics available in the admin database (`pgcat` and `pgbouncer`) with `SHOW STATS`, `SHOW POOLS` and others. | +| Live configuration reloading | :white_check_mark: | kind of | Reload supported settings with a `SIGHUP` to the process, e.g. `kill -s SIGHUP $(pgrep pgcat)` or `RELOAD` query issued to the admin database. | +| Client authentication | :white_check_mark: :wrench: | same as them | MD5 password authentication is supported, SCRAM is on the roadmap; one user is used to connect to Postgres with both SCRAM and MD5 supported. | +| Admin database | :white_check_mark: | no | The admin database, similar to PgBouncer's, allows to query for statistics and reload the configuration. | ## Deployment diff --git a/lib/gat/gatling/conn_pool/conn_pool.go b/lib/gat/gatling/conn_pool/conn_pool.go index d4b6b74306a7c932502592dc7258359438a2dc54..39207d30ea492f10bd2d751a3d5f6e6510bcc1da 100644 --- a/lib/gat/gatling/conn_pool/conn_pool.go +++ b/lib/gat/gatling/conn_pool/conn_pool.go @@ -15,21 +15,14 @@ import ( "gfx.cafe/gfx/pggat/lib/gat/protocol" ) -type request[T any] struct { - client gat.Client - payload T - ctx context.Context - done context.CancelFunc -} - -type servers struct { +type connections struct { primary *server.Server replica *server.Server mu sync.Mutex } -func (s *servers) choose(role config.ServerRole) *server.Server { +func (s *connections) choose(role config.ServerRole) *server.Server { switch role { case config.SERVERROLE_PRIMARY: return s.primary @@ -45,8 +38,8 @@ func (s *servers) choose(role config.ServerRole) *server.Server { } type shard struct { - conf *config.Shard - servers []*servers + conf *config.Shard + conns []*connections mu sync.Mutex } @@ -95,8 +88,8 @@ func (c *ConnectionPool) EnsureConfig(conf *config.Pool) { } sc := s if !reflect.DeepEqual(c.shards[i].conf, &sc) { - // disconnect all connections, switch to new conf - c.shards[i].servers = nil + // disconnect all conns, switch to new conf + c.shards[i].conns = nil c.shards[i].conf = sc } } @@ -114,8 +107,8 @@ func (c *ConnectionPool) chooseShard() *shard { return &c.shards[rand.Intn(len(c.shards))] } -// chooseServer locks and returns a server for you to use -func (c *ConnectionPool) chooseServer() *servers { +// chooseConnections locks and returns connections for you to use +func (c *ConnectionPool) chooseConnections() *connections { s := c.chooseShard() if s == nil { log.Println("no available shard for query :(") @@ -125,14 +118,14 @@ func (c *ConnectionPool) chooseServer() *servers { s.mu.Lock() defer s.mu.Unlock() // TODO ideally this would choose the server based on load, capabilities, etc. for now we just trylock - for _, srv := range s.servers { + for _, srv := range s.conns { if srv.mu.TryLock() { return srv } } - // there are no servers available in the pool, let's make a new connection - // connect to primary server - srvs := &servers{} + // there are no conns available in the shard, let's make a new connection + // connect to servers in shard config + srvs := &connections{} for _, srvConf := range s.conf.Servers { srv, err := server.Dial( context.Background(), @@ -155,7 +148,7 @@ func (c *ConnectionPool) chooseServer() *servers { return nil } srvs.mu.Lock() - s.servers = append(s.servers, srvs) + s.conns = append(s.conns, srvs) return srvs } @@ -164,7 +157,7 @@ func (c *ConnectionPool) GetUser() *config.User { } func (c *ConnectionPool) GetServerInfo() []*protocol.ParameterStatus { - srv := c.chooseServer() + srv := c.chooseConnections() if srv == nil { return nil } diff --git a/lib/gat/gatling/conn_pool/worker.go b/lib/gat/gatling/conn_pool/worker.go index e3d0ea6096af4d5e61fbc971816687ae5b021719..0f7dd0a17220888e0b2b53949327847942a837e9 100644 --- a/lib/gat/gatling/conn_pool/worker.go +++ b/lib/gat/gatling/conn_pool/worker.go @@ -60,7 +60,7 @@ func (w *worker) HandleQuery(ctx context.Context, c gat.Client, query string) er func (w *worker) z_actually_do_fn(ctx context.Context, client gat.Client, payload *protocol.FunctionCall) error { c := w.w - srv := c.chooseServer() + srv := c.chooseConnections() if srv == nil { return fmt.Errorf("fn('%+v') fail: no server", payload) } @@ -79,7 +79,7 @@ func (w *worker) z_actually_do_fn(ctx context.Context, client gat.Client, payloa func (w *worker) z_actually_do_query(ctx context.Context, client gat.Client, payload string) error { c := w.w // chose a server - srv := c.chooseServer() + srv := c.chooseConnections() if srv == nil { return fmt.Errorf("call to query '%s' failed", payload) }