# gizdb:pg/cluster

gizdb cluster: many databases behind one port. Each database is a directory under the root, served by a gizdb process of its own that starts at its first connection and stops once it has had none for --idle: an idle database costs no memory, and one database's process cannot reach another's files. The router reads a client's startup message for the database it names and relays the connection to that database's process, which authenticates it as it would alone. On connections to the cluster's own database, postgres, the router answers CREATE, DROP and ALTER DATABASE and `SELECT datname FROM pg_database` itself, once that process has accepted the client; every other statement goes on to the process.

Each database's limits live in <root>/<name>.conf (key=value lines, written by CREATE and ALTER DATABASE) and reach its process as flags when it next starts: connection_limit (--max-connections), statement_timeout (--statement-timeout), quota (--quota), memory (GIZLANG_MEMORY_LIMIT); and the host settings, which only the host sets (hostSetting): the server paths archive (--archive) and backups (--backups), and password, the database's own login (else the cluster's). The cluster password then reaches only the cluster's own database. A process gets its listener from the router (--port handed) and the cluster password in its environment, and exits when the router's end of its stdin closes.

```gizlang
import * as Cluster from "gizdb:pg/cluster";
```

## Types

### `ClusterOptions`

```gizlang
type ClusterOptions = { host: string; port: i64; root: string; program: string; password: string; idleMs: i64; socket: string; tlsCert: string; tlsKey: string; }
```

`host` "" leaves TCP off; `socket`: a directory where the cluster also listens at
`.s.PGSQL.<port>`, as gizdb --socket. `program`: the gizdb binary each database's process runs. `idleMs`: how long a process
without connections lives. `password`: every process's own password (its superuser's).

- `host`: `string`
- `port`: `i64`
- `root`: `string`
- `program`: `string`
- `password`: `string`
- `idleMs`: `i64`
- `socket`: `string`
- `tlsCert`: `string` — PEM files (the chain and its key): the router ends TLS itself and refuses a client in the clear. They are read
again each hour, so a renewed certificate serves within that.
- `tlsKey`: `string`

## Functions

### `serveClusterUntilStopped`

```gizlang
function serveClusterUntilStopped(sys: System, options: ClusterOptions, bound: Task.Cell<i64>): Result<i64, string>
```

serveCluster that also ends on TERM or INT, as gizdb cluster runs.

Effects: fail, read, write, console, io.

### `serveCluster`

```gizlang
function serveCluster(sys: System, options: ClusterOptions, bound: Task.Cell<i64>): Result<i64, string>
```

Runs the cluster until its listener fails; `bound` gets the port (-1 when startup failed).

Effects: fail, read, write, console, io.

### `bytesOf`

```gizlang
function bytesOf(v: string): Option<i64>
```

512, 64K, 10G: a number of bytes.

Effects: fail.

### `hostSetting`

```gizlang
function hostSetting(sys: System, root: string, name: string, key: string, value: string): Result<bool, string>
```

Sets KEY (one of HOST_SETTINGS: a server path, or the password of the database's process) of database NAME under
the cluster root ROOT to VALUE, for the next start of its process. It is the host's way, through the folder; false
when it was already so.

Effects: fail, read, write, console, io.

### `databasePassword`

```gizlang
function databasePassword(sys: System, root: string, name: string): Result<string, string>
```

The password of database NAME under the cluster root ROOT (its host setting), made the first time: the login that
reaches that database alone.

Effects: fail, read, write, console, io.

