KDB knowledge

Protection - timeouts, limits, safe updates, read-only

Stop slow statements (timeout and cancel), limit the memory of one query and the statements of one user, refuse UPDATE or DELETE without WHERE, and make a database read-only.

These settings keep one bad query, one busy user or one typing mistake from hurting the server. They cost almost nothing: a running query looks at one flag every 16,384 rows, never at every row.

ProtectionTurn it onDefault of kdb serve
statement timeout--statement-timeout 30s, SET statement_timeout = '5s', ALTER USER u SET statement_timeout = '2s'60 s
cancel a running statementPostgres cancel (pgx context, psql Ctrl+C), DELETE /exec/<id>, closing the HTTP connectionon
memory of one query--max-result-memory 1GB, --max-groups 50000001 GB, 5,000,000 groups
memory of the whole server--memory-limit 3GB (memory limit)85% of a container's limit, else of the machine's memory
statements per user--max-queries-per-user 3232
requests per second--rate-limit-ip 50, --rate-limit-user 20 (rate limits)no limit
safe updates--safe-updates, SET safe_updates = onoff
read-only--read-only, ALTER DATABASE x SET READ ONLYoff

kdb sql, kdb shell and programs that use the KDB library have no limits unless they set DatabaseOptions.

SET statement_timeout

Syntax:

kdb serve --statement-timeout 60s          (0 = no limit)
SET statement_timeout = '5s' | 5000 | 0 | DEFAULT
HTTP header:  X-KDB-Statement-Timeout: 5s

A statement (one request, or one Postgres query message) that runs longer is stopped. Nothing of a stopped change is written: an UPDATE stopped halfway changes no row.

ValueMeaning
'5s', '500ms', '2min', 5000the time; a plain number is milliseconds (like PostgreSQL)
0no limit (only admins; others keep the server's limit)
DEFAULTthe server's --statement-timeout again

Example: A time for the rest of this session (sample data: sample)

SET statement_timeout = '5s';
SELECT count(*) FROM ochl_day;

Result:

SET statement_timeout = '5s'

statement_timeout is 5 s for this session

SELECT count(*) FROM ochl_day

count(*) (LONG)
57

(1 row)

Cancel a running statement

Syntax:

PostgreSQL:  CancelRequest (pgx: cancel the context; psql: Ctrl+C)
HTTP:        POST /exec with X-KDB-Request-Id: <id>, then DELETE /exec/<id>
HTTP:        close the connection (the browser or program gave up)
SQL:         SELECT pg_cancel_backend(pid)   (pid from pg_stat_activity; pg_terminate_backend also closes it)

Stops a statement that is running now.

DELETE /exec/<id>

Syntax:

DELETE /exec/<id>

Stops the /exec request that was sent with the header X-KDB-Request-Id: <id>. The id is chosen by the program (for example a random text).

HTTP: Nothing with this id is running

DELETE /exec/report-17

Response:

HTTP 404 (application/json)

{"error": "no running request has the id 'report-17' (it may have finished)"}

Memory limits

Syntax:

kdb serve --max-result-memory 1GB --max-groups 5000000        (0 = no limit)

Stops a query that would keep too much in memory: the rows of the result, rows waiting for ORDER BY, DISTINCT or window functions, and the groups of GROUP BY, SAMPLE BY and LATEST ON.

--max-queries-per-user

Syntax:

kdb serve --max-queries-per-user 32        (0 = no limit)

How many statements one user may run at the same time, over HTTP and the Postgres port together.

--rate-limit-ip and --rate-limit-user

Syntax:

kdb serve --rate-limit-ip 50 --rate-limit-user 20       (requests per second, 0 = no limit)
kdb.conf:  "rate_limit_ip": 50, "rate_limit_user": 20
env:       KDB_RATE_LIMIT_IP=50  KDB_RATE_LIMIT_USER=20

How many requests one client address, and one user, may send per second. Both are off unless set.

Counts as one requestWhere
one HTTP request to /exec, /exp, /write, /imp, /cursor, /api/... and POST /api/loginHTTP port
one Query message, or one Execute of a prepared statementPostgreSQL port

SET safe_updates

Syntax:

kdb serve --safe-updates
SET safe_updates = on | off
HTTP header:  X-KDB-Safe-Updates: on | off

Refuses UPDATE and DELETE without WHERE, the classic mistake that changes every row.

Example: UPDATE without WHERE is refused (sample data: sample; shows an error)

SET safe_updates = on;
UPDATE securities SET name = 'oops';

Result:

safe updates are on for this session

Error: safe updates are on: an UPDATE without WHERE would change every row of 'securities'. Add a WHERE (WHERE true changes every row on purpose), or turn safe updates off for this session: SET safe_updates = off

ALTER DATABASE ... SET READ ONLY

Syntax:

ALTER DATABASE <name> SET READ ONLY
ALTER DATABASE <name> SET READ WRITE
kdb serve --read-only

A read-only database takes no changes: INSERT, UPDATE, DELETE, DDL, CALL, the line protocol. SELECT, backups and checks work.

Example: Read-only, then writable again (shows an error)

ALTER DATABASE demo SET READ ONLY;
SELECT count(*) FROM securities;
INSERT INTO brokers VALUES (99, 'New broker');

Result:

database 'demo' is read-only now: only reads are allowed

Error: the database is read-only (ALTER DATABASE demo SET READ ONLY; undo with SET READ WRITE): only reads are allowed

Stopping the server without cutting requests off

Syntax:

kdb serve --drain-timeout 30s          (0 = do not wait; env KDB_DRAIN_TIMEOUT; 5s in the Docker image)

When the server is asked to stop (Ctrl+C, SIGTERM, docker stop), it does not drop what is running:

RequestWhat happens
already runningfinishes and gets its real answer, for up to --drain-timeout; then its connection closes
arrives during the stopHTTP 503 with Retry-After: 2; nothing of it is run
still running after --drain-timeoutcancelled like a statement timeout; nothing half-done is written