Documentation
¶
Overview ¶
Package chconn owns the process's ClickHouse connections: one pool per distinct address, database, user, password and tls tuple (ClickHouse authenticates per connection, so different credentials never share one), shared by the tenants whose settings name it and reconciled after every settings reload under the boot config's connection ceiling. Manager implements driver.Conn by delegating every call to the connection current at that instant, so a consumer resolves its tenant's Manager per call and never learns a resize happened; the HTTP-side consumers (ingest INSERTs, the raw-SQL proxy) read their tenant's Target per request and take their client from an HTTPClients.
Index ¶
- func ExceptionCode(err error) (int32, bool)
- func HTTPStatus(err error) (int, bool)
- func Splittable(err error) bool
- func TableScoped(err error) bool
- type Class
- type HTTPClients
- type HTTPError
- type Identity
- type Manager
- func (m *Manager) AsyncInsert(ctx context.Context, query string, wait bool, args ...any) error
- func (m *Manager) Close() error
- func (m *Manager) Contributors() []string
- func (m *Manager) Exec(ctx context.Context, query string, args ...any) error
- func (m *Manager) Identity() Identity
- func (m *Manager) InsertFormat(ctx context.Context, format, query string, data io.Reader) error
- func (m *Manager) Ping(ctx context.Context) error
- func (m *Manager) PrepareBatch(ctx context.Context, query string, opts ...driver.PrepareBatchOption) (driver.Batch, error)
- func (m *Manager) Query(ctx context.Context, query string, args ...any) (driver.Rows, error)
- func (m *Manager) QueryFormat(ctx context.Context, format, query string, args ...any) (io.ReadCloser, error)
- func (m *Manager) QueryRow(ctx context.Context, query string, args ...any) driver.Row
- func (m *Manager) Release(grace time.Duration)
- func (m *Manager) Resize(s Sizes, grace time.Duration) error
- func (m *Manager) Select(ctx context.Context, dest any, query string, args ...any) error
- func (m *Manager) ServerVersion() (*driver.ServerVersion, error)
- func (m *Manager) Sizes() Sizes
- func (m *Manager) Stats() driver.Stats
- func (m *Manager) TLSConfig() *tls.Config
- type Member
- type Params
- type Pools
- type Sizes
- type TLS
- type Target
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ExceptionCode ¶
ExceptionCode is the ClickHouse exception code err carries, if any.
func HTTPStatus ¶
HTTPStatus is the status of the non-2xx HTTP answer err carries, if any.
func Splittable ¶
Splittable reports whether err is a retried failure that a smaller request may avoid — so a caller holding a batch should split it before backing off.
func TableScoped ¶
TableScoped reports whether err is a retried failure of the one table the request wrote to, not of the server or the identity — so a caller backing off can hold back that table alone.
Types ¶
type Class ¶
type Class int
Class is what a failed ClickHouse request says about the request itself: whether sending it again, unchanged, can succeed. The ingest worker retries every class but Rejected and dead-letters only Rejected; the query handlers map the same classes onto HTTP statuses (api/ch_errors.go).
const ( // Unknown is a failure with no verdict: ClickHouse sent no exception // code, and the error is not one the way to ClickHouse is known to // produce. Nothing says the request was judged. Unknown Class = iota // request now — refused or dropped connections, timeouts, overload, // read-only tables, lost replicas or Keeper. The request was not judged; // the same request can succeed later. Unavailable // Denied means ClickHouse refused the credentials or grants the request // ran under: the connection's configuration, not the request's content. Denied // Rejected means ClickHouse judged the request and refused it — a value // it cannot parse, a type mismatch, a table or column it does not have, // bad SQL. Sent again unchanged, it fails the same way. Rejected )
func ClassOfCode ¶
ClassOfCode classes a ClickHouse exception code. A code on neither list is Rejected: an exception code means the server was up and read the request, and most of ClickHouse's several hundred codes are about what it read. The availability codes are the enumerated exception, not the other way round.
type HTTPClients ¶
type HTTPClients struct {
// contains filtered or unexported fields
}
HTTPClients hands an HTTP-interface consumer the client for a target: one per TLS config, made by the consumer's own factory (the worker's tuned transport, the proxy's redirect policy) and kept for the process lifetime. A config is built each time a pool opens on a tls block, so the set grows with the pools ever opened on one — a block whose pool closed and reopened adds another — not with requests; a client whose pool is gone keeps only its transport, whose idle connections time out on their own.
The factory gets a copy of the config, never the target's own: net/http appends its HTTP/2 protocols to TLSClientConfig.NextProtos in place when a transport first dials, which would race the driver's handshakes on the shared config and offer HTTP protocols on the native hop. The target's pointer stays the cache key.
func NewHTTPClients ¶
func NewHTTPClients(build func(*tls.Config) *http.Client) *HTTPClients
NewHTTPClients returns a cache whose clients build makes from a target's TLS config, nil meaning net/http's defaults.
type HTTPError ¶
type HTTPError struct {
StatusCode int
// Code is the ClickHouse exception code, 0 when the response carried
// none (usually a proxy's answer, not ClickHouse's).
Code int32
Body string
}
HTTPError is a non-2xx answer from the ClickHouse HTTP interface. Its message keeps the body verbatim — the dead-letter headers carry it.
func NewHTTPError ¶
NewHTTPError reads a non-2xx ClickHouse HTTP response into an HTTPError, taking the exception code from the X-ClickHouse-Exception-Code header, or failing that from the body's "Code: NNN." prefix. The caller closes the body.
type Identity ¶
Identity is the tuple that decides which pool a tenant shares. Comparable as it stands — the TLS block is a value of strings and bools — so it is the map key as well.
type Manager ¶
type Manager struct {
// contains filtered or unexported fields
}
Manager is a driver.Conn over one tuple's pool, whose backing connection is swapped by Resize.
func Open ¶
Open builds the pool for id at sizes s. Like clickhouse.Open it does not dial — boot tolerates an unreachable ClickHouse (schema discovery degrades and retries) — so only a malformed option or a certificate file that cannot be read or parsed errors here.
func (*Manager) AsyncInsert ¶
func (*Manager) Close ¶
Close closes the current connection now. Replaced and released connections close on their own grace timers.
func (*Manager) Contributors ¶
func (*Manager) InsertFormat ¶
func (*Manager) PrepareBatch ¶
func (*Manager) QueryFormat ¶
func (*Manager) Release ¶
Release closes the pool after grace, for a tuple no tenant names any more: a consumer that resolved this Manager just before the reload's swap finishes its query on it.
func (*Manager) Resize ¶
Resize swaps in a connection sized s when s differs from the current size — the tls block is the tuple's and never changes under a Manager, so no file is re-read. The replaced connection is closed after grace, so the queries in flight on it finish; grace is the longest query timeout among the tenants sharing the pool.
func (*Manager) ServerVersion ¶
func (m *Manager) ServerVersion() (*driver.ServerVersion, error)
type Member ¶
Member is one tenant's ask of the pools: the tuple it shares, and its own sizes, deadline and HTTP wiring.
type Params ¶
type Params struct {
Addr string
HTTPPort int
HTTPScheme string
Database string
Username string
Password string
QueryTimeout time.Duration
TLS TLS
// Headers go on every HTTP-interface request; read-only once handed in.
Headers map[string]string
MaxOpenConns int
MaxIdleConns int
}
Params is what one tenant asks of its connection: the settings directory's clickhouse block, password included. The Identity picks the pool; the rest is the tenant's own — the HTTP-interface wiring and headers, the query deadline, and the pool sizes the shared pool is at least as large as.
type Pools ¶
type Pools struct {
// contains filtered or unexported fields
}
Pools holds one Manager per tuple the served tenants name, reconciled after every settings reload: a new tuple opens a pool (no dial), a tenant whose tuple changed is repointed, a tuple no tenant names any more is released after its grace, and a pool shared by several tenants is sized to their largest ask. The ceiling — the boot config's clickhouse.max_total_conns, 0 for none — bounds the sum of the open pools' MaxOpenConns: at boot it refuses to open, and at a reload a resize above it is refused with the pool kept at its size, and a tuple that cannot be opened leaves its tenants where they were, on their previous pool, or with none when they had none. Both are logged by the caller and retried by the next reload. Resolution is per tenant: For, Target, SharingTables.
func NewPools ¶
NewPools opens the pools want names, under ceiling. Any refusal — a certificate file that cannot be read, options the driver refuses, or pools that would add up to more than the ceiling, named with the sum — refuses boot: nothing is left open.
func (*Pools) For ¶
For returns the pool of tenant id, or nil when the tenant is on none: it is not served, or its tuple could not be opened.
func (*Pools) Ping ¶
Ping pings every open pool at once and returns nil at the first answer, or every pool's error joined when none answers — including when none is open. At once, not in turn: the driver waits up to its dial timeout on a host that does not answer, longer than a readiness probe's, so one such pool must not hide the ones that do answer.
func (*Pools) Reconcile ¶
Reconcile sets the pools to what want names (the served tenants, in id order), and returns the tenants whose cache is stale, for the caller to orphan, with every refusal joined: the ones it admitted that were not on a pool before — new, or back after a rejection or removal, so out of the fan-out (SharingTables) while away — and the ones it moved to another address or database, whose cached results were read from other tables. A move that keeps the address and database (a username or tls change) reads the same tables and is not stale. The walk keeps the ceiling at every step: tenants no longer wanted leave first, then each wanted tenant is placed in turn, and a refused placement — the ceiling, or a pool that cannot be opened — is undone before the next, so a refused move leaves the tenant on the pool it had, with the Params it had. What was refused is placed once more at the end, since a shrink or a move placed after it may have freed the budget it needed; only what the second pass refuses is reported.
func (*Pools) SharingTables ¶
SharingTables returns the tenants reading the same tables as tenant id — the same address and database, whatever their user or tls — id included, in id order; nil when id is on no pool.
type TLS ¶
type TLS struct {
Enabled bool
CAFile string
CertFile string
KeyFile string
InsecureSkipVerify bool
ServerName string
}
TLS is the settings directory's clickhouse.tls block. Enabled switches the native protocol to TLS; the material applies to whichever hop uses TLS — native when Enabled, HTTP when http_scheme is https.
type Target ¶
type Target struct {
// URL is the HTTP base, e.g. http://host:8123.
URL string
Username string
Password string
Database string
// TLS configures an https URL; nil means net/http's defaults. The
// pointer is the tuple's, so it changes only when the tenant moves to a
// tuple with another tls block, which is what HTTPClients keys on.
TLS *tls.Config
// Headers go on every request ahead of the consumer's own; read-only.
Headers map[string]string
}
Target is what the HTTP-interface consumers need per request.