CUBRID System Parameters — Tunable Registry, Conf/Env/URL Parsing, and Per-Session Scoping
Contents:
- Theoretical Background
- Common DBMS Design
- CUBRID’s Approach
- Source Walkthrough
- Cross-check Notes
- Open Questions
- Sources
Theoretical Background
Section titled “Theoretical Background”A relational DBMS has hundreds of knobs. Buffer-pool size, log-buffer size, lock-timeout, isolation-level default, error-log severity, checkpoint cadence, character set, time-zone — every subsystem brings its own pile. The configuration subsystem is the place where those knobs are named, typed, given defaults, overridden from external sources, and served back to the rest of the engine on demand. It is one of the few modules that nearly every other module calls into, which means it has to be cheap, predictable, and type-safe in a way that is unusual for engine internals.
Three properties shape every implementation:
- A central registry. Every parameter has a name, a type, a default, optional bounds, and a set of behavioural flags (is it client-side, server-side, both? can the user change it on-line? does it need a restart? is it deprecated?). The registry is the one place that knows the answer for every parameter, and the one place that needs to be touched when a parameter is added.
- Multiple sources, ordered by priority. A typical engine reads
defaults from the registry, then from a configuration file, then
from process environment, then from connection-time arguments,
then from runtime SQL (
SETstatements). Each later source overrides earlier ones. The ordering matters because users expect the most-specific source — the one they explicitly typed in theSETstatement — to win. - Per-server vs. per-session scope. Some parameters are
global: they describe the physical state of the server (buffer
pool, log buffer, port number, max-clients) and can change only
when the server restarts or via a privileged DBA. Others are
session-scoped: they describe how the current client wants its
queries to behave (isolation level, time-zone, optimizer
reservations, error-log severity for this session) and a single
client’s
SET SYSTEM PARAMETERSshould only affect that client’s own session. The configuration subsystem is responsible for knowing which is which and for routing reads/writes appropriately.
The textbook treatment is thin — Database Internals (Petrov)
skips it; the Postgres GUC paper “PostgreSQL’s Configuration
Engine” by Tom Lane is the closest canonical reference, and its
insight is that the parameter list is itself a type-checked
symbol table that the rest of the engine compiles against.
Operating-system literature has the same pattern under “kernel
tunables” (sysctl in Linux, MIB in BSD): both are read by
hundreds of callers on hot paths and both end up using the same
idiom of an enum-keyed table of typed slots with inline accessors.
The implementation degrees of freedom are: the type system
(CUBRID adds BIGINT for >2 GiB byte counts, KEYWORD for named
enum values, and INTEGER_LIST to int/float/bool/string);
default-vs-current (CUBRID stores both per slot so the dump
routine can flag drift with one comparison); conf-file sectioning
(CUBRID picks INI-style sectioning so one file handles both
process-level and per-database overrides); and per-session storage
(CUBRID keeps a sparse array indexed by a precomputed
“session-eligible” subset, prm_Def_session_idx[]).
Common DBMS Design
Section titled “Common DBMS Design”Every relational engine has converged on roughly the same architecture for parameters; the differences are mostly in the ergonomics of the user-facing surface.
Postgres GUC (Grand Unified Configuration). Per-type subclasses
(config_int, config_real, config_string, config_bool,
config_enum) over struct config_generic, with separate arrays
walked at startup (ConfigureNamesInt[], etc.). Each GUC carries a
context enum (PGC_INTERNAL, PGC_POSTMASTER, PGC_SIGHUP,
PGC_SUSET, PGC_USERSET, PGC_BACKEND) that decides who can
change it and when. Reads go through GetConfigOption() or direct
pointer access for hot paths. The pg_settings catalog view is a
thin wrapper over the GUC table.
MySQL system variables. Registry of sys_var objects
registered via Sys_var_init(). Reads use THD::sys_var_value()
for session and a global lock for global. The SESSION / GLOBAL
split is explicit in SET GLOBAL, SET SESSION, SHOW VARIABLES.
Conf file is my.cnf with [server] / [client] / [mysqld]
sections.
Oracle SPFILE/PFILE. Parameters live in either a binary
SPFILE (persisted) or text PFILE (init.ora). The
ALTER SYSTEM SET ... SCOPE = MEMORY|SPFILE|BOTH syntax decides
in-memory vs. persistent. Catalog views: v$parameter,
v$spparameter.
SQLite. Pragmas only — PRAGMA name = value. Some
per-connection (journal_mode, synchronous), some per-database
(page_size, set at create time only). No configuration file.
CUBRID is closest to MySQL in user-facing shape (SQL
SET SYSTEM PARAMETERS '...', INI-style cubrid.conf, GLOBAL /
SESSION distinction implicit in flags) but closer to Postgres in
implementation (a single prm_Def[] array of typed slots accessed
through inline getters, with a per-parameter flag word encoding
context/scope/persistence rules).
Theory ↔ CUBRID mapping
Section titled “Theory ↔ CUBRID mapping”| Theoretical concept | CUBRID name |
|---|---|
| Parameter ID enum | enum param_id / PARAM_ID (system_parameter.h) |
| Per-parameter slot | struct sysprm_param / SYSPRM_PARAM (system_parameter.h) |
| Registry array | prm_Def[] (system_parameter.c) |
| Type tag | SYSPRM_DATATYPE (int/float/bool/keyword/bigint/string/intlist) |
| Static (compile-time) flag word | SYSPRM_PARAM::static_flag (PRM_FOR_CLIENT, PRM_FOR_SERVER, …) |
| Dynamic (runtime) flag word | SYSPRM_PARAM::dynamic_flag (PRM_SET, PRM_ALLOCATED, …) |
| Tagged value | SYSPRM_PARAM_VALUE { is_null, v } over SYSPRM_VALUE union |
| Default-vs-current | default_value and value fields side-by-side |
| Bounds | lower_limit, upper_limit |
| Forced override | force_value (string) + prm_set_force |
| Unit translator | set_dup / get_dup callbacks |
| Conf-file loader | sysprm_load_and_init → prm_read_and_parse_ini_file |
| Section dispatcher | prm_load_by_section |
| Env override | prm_check_environment (uppercases name → envvar_get) |
| Cross-parameter tuning | prm_tune_parameters (post-load) |
| Compound parameter | PRM_COMPOUND flag + prm_set_compound (e.g. compat_mode) |
| Aliased parameter pair | PARAM_VALUE_SHARE[] table + sysprm_find_shared_system_parameter |
| Session-scoped subset | PRM_FOR_SESSION flag + prm_Def_session_idx[] |
| Per-session value array | SESSION_PARAM array on SESSION_STATE::session_parameters |
| Per-session getter detour | prm_get_value / PRM_SERVER_SESSION macro |
| Runtime change list | SYSPRM_ASSIGN_VALUE linked list |
| User SQL → registry | db_set_system_parameters → sysprm_validate_change_parameters |
| Server-side parameter change | xsysprm_change_server_parameters (x = server stub) |
| Server-forced refresh on connect | PRM_FORCE_SERVER + xsysprm_get_force_server_parameters |
| Reload | sysprm_reload_and_init (only PRM_RELOADABLE parameters) |
| Final teardown | sysprm_final |
CUBRID’s Approach
Section titled “CUBRID’s Approach”The configuration subsystem is built on five moving parts: the parameter table that names every tunable, the resolution pipeline that pulls values from defaults, the conf file, the environment, and runtime SQL, the per-session detour that lets a session override a subset of parameters without affecting other sessions, the propagation channel that synchronises values between client and server when scopes overlap, and the dump/print machinery that serialises the table for diagnostics. We walk them in that order.
Overall structure
Section titled “Overall structure”flowchart LR
subgraph SRC["External sources"]
DEF["Compile-time<br/>defaults<br/>(prm_Def[].default_value)"]
CONF["cubrid.conf<br/>(INI sections)"]
HACONF["cubrid_ha.conf<br/>(HA-only)"]
ENV["Environment<br/>variables<br/>UPPERCASED name"]
URL["URL / connect<br/>params (cci/jdbc)"]
SQL["SET SYSTEM<br/>PARAMETERS '...'"]
end
subgraph LOAD["Resolution (system_parameter.c)"]
SLI["sysprm_load_and_init<br/>→ _internal"]
PRP["prm_read_and_parse_ini_file"]
PLBS["prm_load_by_section"]
PCE["prm_check_environment"]
PTP["prm_tune_parameters"]
end
subgraph TBL["Registry"]
PRM["prm_Def[] array<br/>indexed by PARAM_ID"]
IDX["prm_Def_session_idx[]<br/>sparse session map"]
SHARE["PARAM_VALUE_SHARE[]<br/>aliased pairs"]
end
subgraph SCOPE["Per-process state"]
GLOBAL["Per-server values<br/>(prm_Def[].value)"]
SESS["Per-session values<br/>(SESSION_PARAM array<br/>on SESSION_STATE)"]
end
subgraph READ["Read API"]
GETI["prm_get_integer_value (inline)"]
GETB["prm_get_bool_value (inline)"]
GETS["prm_get_string_value (inline)"]
GETV["prm_get_value (per-session detour)"]
end
DEF --> SLI
CONF --> PRP
HACONF --> PRP
PRP --> PLBS
PLBS --> SLI
ENV --> PCE
PCE --> SLI
SLI --> PTP
PTP --> PRM
PRM --> IDX
PRM --> SHARE
PRM --> GLOBAL
URL --> SQL
SQL --> SESS
SQL --> GLOBAL
GLOBAL --> GETI
GLOBAL --> GETB
GLOBAL --> GETS
SESS --> GETV
GETI --> GETV
GETB --> GETV
GETS --> GETV
The parameter table
Section titled “The parameter table”Every tunable in CUBRID is one entry in the prm_Def[] array
(system_parameter.c:1010). The struct shape is fixed by
SYSPRM_PARAM in the header:
// sysprm_param — system_parameter.hstruct sysprm_param{ PARAM_ID id; // enum tag const char *name; // string the parser expects unsigned int static_flag; // compile-time scope/role flags SYSPRM_DATATYPE datatype; // int/float/bool/keyword/bigint/string/intlist unsigned int dynamic_flag; // runtime: SET / ALLOCATED / ... const SYSPRM_PARAM_VALUE default_value; // compile-time default SYSPRM_PARAM_VALUE value; // current value (mutated) const SYSPRM_PARAM_VALUE upper_limit; // optional bound const SYSPRM_PARAM_VALUE lower_limit; // optional bound char *force_value; // string forced from runtime API DUP_PRM_FUNC set_dup; // input -> storage unit DUP_PRM_FUNC get_dup; // storage -> display unit};Three points are worth lingering on.
The ID enum is the canonical anchor. PARAM_ID (header:97) is
declared in the same order as prm_Def[] is initialised, and the
debug-build sanity check sysprm_check_id_order (the immediately-
invoked lambda at system_parameter.c:5965) asserts that
GET_PRM(i)->id == i for every slot. That invariant lets every
caller dereference prm_Def[id] in O(1) without ever calling
prm_find for a by-name lookup. The macro GET_PRM(id)
(header:679) is just (&prm_Def[(id)]).
The static flag word is the policy field. A handful of bits
encode every policy decision the engine ever makes about a
parameter: PRM_USER_CHANGE (allow runtime SET), PRM_FOR_CLIENT
/ PRM_FOR_SERVER (which side hosts a copy), PRM_HIDDEN
(suppress from dumps), PRM_RELOADABLE (sysprm_reload_and_init
may reset), PRM_COMPOUND (setting it cascades to others),
PRM_TEST_CHANGE (only changeable while test_mode=on),
PRM_FOR_HA (read from cubrid_ha.conf), PRM_FOR_SESSION
(session-scoped), PRM_FORCE_SERVER (client must pull from
server on connect), PRM_FOR_QRY_STRING (include in plan-cache
key), PRM_CLIENT_SESSION (client/server session, do not affect
server), PRM_SIZE_UNIT / PRM_TIME_UNIT / PRM_DIFFER_UNIT
(unit handling), PRM_FOR_HA_CONTEXT (replicate via HA log
applier), PRM_GET_SERVER (dual-scope, read from server),
PRM_FOR_PL_CONTEXT (forward to PL/SP context),
PRM_DEPRECATED, PRM_OBSOLETED.
A typical table entry encodes its full policy in a few ORed flags.
For data_buffer_size, the row sets static_flag = PRM_FOR_SERVER | PRM_SIZE_UNIT | PRM_DIFFER_UNIT | PRM_RELOADABLE, type
PRM_INTEGER, default and “current” both {.i = 32768} (pages),
no upper limit, lower limit 1024 pages, and set_dup /
get_dup callbacks prm_size_to_io_pages / prm_io_pages_to_size.
The flags say “server-only, accepts a K/M/G suffix on input,
displays back in human-readable units, may be reloaded; the
storage unit is pages but the user-facing unit is bytes”. The
set_dup / get_dup pair is how that unit translation is plumbed
in.
The default-and-current pair is duplicated for a reason. Storing
both default_value and value per slot looks wasteful, but it
lets sysprm_dump_parameters (5847) flag every non-default
value with a single comparison, and it lets
prm_set_default_internal (9489) restore a parameter to its
compile-time baseline with one structure assignment
(prm->value = prm->default_value;) for the scalar types.
The resolution pipeline
Section titled “The resolution pipeline”The whole loader is bottle-necked through one private function,
sysprm_load_and_init_internal (system_parameter.c:6015), which is
called by three public entry points: sysprm_load_and_init for the
server side, sysprm_load_and_init_client for the CS/SA client, and
sysprm_reload_and_init (with the reload=true flag) for runtime
re-reads.
sequenceDiagram
participant Caller as boot_restart_server / boot_cl
participant SLI as sysprm_load_and_init_internal
participant Reset as PRM_RELOADABLE reset loop
participant File as prm_read_and_parse_ini_file
participant Sec as prm_load_by_section
participant DefLoop as missing-default loop
participant Env as prm_check_environment
participant Tune as prm_tune_parameters
participant Force as force_value loop
Caller->>SLI: db_name, conf_file, load_flags
Note right of SLI: if reload, reset all PRM_RELOADABLE
SLI->>Reset: for each prm if PRM_RELOADABLE: prm_set_default
SLI->>File: ${CUBRID}/conf/cubrid.conf or $CONF_FILE
File->>Sec: section "common" (ignore_section=true)
File->>Sec: section "@<dbname>"
File->>Sec: section "service" (only on first pass)
Note right of File: if HA mode on: also load cubrid_ha.conf
File->>Sec: section "%<host>|*", "%<host>|<user>"
SLI->>DefLoop: for each prm without PRM_SET: prm_set_default
SLI->>Env: for each prm: envvar_get(UPPERCASE name)
SLI->>Tune: cross-parameter consistency adjustments
SLI->>Force: for each prm with force_value: prm_set
SLI-->>Caller: NO_ERROR
The loader has three layered concerns: which file to read, which sections of that file apply, and what to do when a key has no value yet.
Which file. The default is ${CUBRID}/conf/cubrid.conf,
resolved by envvar_confdir_file against the install layout. The
environment variable CONF_FILE overrides the path; the optional
HA_CONF_FILE chooses a separate file for HA-only parameters when
ha_mode != off. The argument conf_file to
sysprm_load_and_init exists for callers that want to inject a
specific path; in practice it is always passed NULL and the
internal asserts that.
Which sections. The conf file is INI-formatted, parsed by the
ini_parser library, and walked once per section by
prm_load_by_section (system_parameter.c:6350). The sections that
apply, in order, are:
[common]— every database, every host. Read first so per- database overrides win.[@<dbname>]— settings specific to one database (only ifdb_name != NULL, which is the server’s normal case).[standalone]— only consulted inSA_MODE(csql -S, utilities).[service]— service-launcher settings (service,serverkeys used by thecubridshell wrapper). Theignore_section=falseflag here is what tells the loader to keep theservice::prefix in the parameter name; that is why two of the parameter defines in the registry have the explicit prefix"service::service"and"service::server".[%<host>|*]and[%<host>|<user>]— per-host or per-host- per-user overrides, only consulted when HA is enabled and the host name resolves.
prm_load_by_section does not blindly call prm_set on every key
— it first filters by mode and flags. Under CS_MODE a
server-only parameter (no PRM_FOR_CLIENT) is silently skipped;
under SERVER_MODE the inverse is true. Reloads skip parameters
without PRM_RELOADABLE. Without SYSPRM_IGNORE_HA in the
load-flags, only PRM_FOR_HA parameters are considered (this is
how cubrid_ha.conf is layered onto cubrid.conf from a single
loader path). PRM_OBSOLETED is silently skipped, PRM_DEPRECATED
warns but proceeds. The pattern is the static flags decide
whether the value is even considered; the same conf file is read
by both binaries and only the relevant subset applies to each.
Default-fill and environment. After all sections have been
applied, every parameter that was not touched is filled from its
compile-time default by the loop at system_parameter.c:6144. The
environment pass prm_check_environment (7091) walks the table,
upper-cases each parameter name, and asks envvar_get whether
the corresponding env variable is exported; if so, the value is
fed through prm_set. The order is “default → conf file →
environment → runtime force”; each later phase calls prm_set
with set_flag=true, setting PRM_SET in the dynamic flag word
so the next phase can do “set if not yet set” decisions
correctly.
Cross-parameter tuning. prm_tune_parameters
(system_parameter.c:9865) is the post-load fixup pass. It
materialises invariants that depend on multiple parameters jointly:
clamp max_clients to min(CSS_MAX_CLIENT_COUNT, css_get_max_socket_fds()), override task_worker if the user left
the default and the host has a known core count, force HA-related
parameters into self-consistent shapes (ha_server_state defaults
to STANDBY when ha_mode != off, ACTIVE otherwise), set
ha_node_list to <host>@<host> when the user did not provide one,
and so on. This is where the configuration subsystem does its
reluctant role of engine policy — most of the function is “if the
user did not say otherwise, here is what the system thinks is
sensible”.
Forced overrides. The very last thing the loader does is loop
over the table and, for any slot with a non-NULL force_value
string, call prm_set with set_flag=false to replay it. The
force_value field is populated only by prm_set_force
(9471), exposed as the public sysprm_set_force API. It is
used by callers that need a value to survive a subsequent
reload — notably the boot module when it injects URL-style
param=val overrides early during client attach. Because
set_flag=false, the dynamic flag PRM_SET is not raised, so the
dump routine still considers the slot “default” for diagnostic
purposes.
The per-session detour
Section titled “The per-session detour”The hardest design choice in the configuration subsystem is what
happens when the same parameter is settable both globally and per
session. CUBRID’s answer is: it is a flag on the parameter
(PRM_FOR_SESSION), and the read path takes a detour for those
parameters only.
The mechanics rest on three pieces of state.
The session index. A flat int[], sized once to DIM (prm_Def), that maps each PARAM_ID to its position in the
per-session value array, or -1 for parameters that are not
session-scoped:
// prm_Def_session_idx fill — system_parameter.cSYSPRM_INDIRECT_POS prm_Def_session_idx[DIM (prm_Def)];static int num_session_parameters = 0;
if (num_session_parameters == 0) { for (i = 0; i < MAX_SYSTEM_PARAMS; i++) prm_Def_session_idx[i] = (PRM_IS_FOR_SESSION (GET_PRM (i))) ? num_session_parameters++ : -1;}The hash-on-demand approach was rejected because the read path is
too hot — prm_get_*_value is called on every page touch, every
lock acquisition, every plan generation, and the per-session detour
must compile to pointer arithmetic + one indirect array load, not
a hash lookup.
The per-session value array. SESSION_PARAM is a small
struct-of-typed-values (prm_id, flag, datatype, value),
one entry per session-eligible parameter. The session module (see
cubrid-server-session.md) hangs an array of NUM_SESSION_PRM of
these on SESSION_STATE::session_parameters at first attach.
sysprm_session_init_session_parameters (11447) is the
attach-time reconciler: if the session-state already has its
parameter array (a reconnect), keep the server-side values and
discard the values just unpacked from the client packet; if not (a
fresh client), use the client’s values and call
update_session_state_from_sys_params so derived caches like the
session timezone region pick them up. This is the mechanism that
lets a TCP-level reconnect recover the per-session settings the
client had set before disconnecting.
The detour in the read path. The inline getter
prm_get_integer_value (header:834-846) and its siblings check
the PRM_SERVER_SESSION macro (header:681-683) and, only on
SERVER_MODE and only when the parameter is actually session-
scoped, dereference through the current thread’s session via
prm_get_value (10486). The macro itself is
#define SERVER_SESSION_MASK ((PRM_FOR_SESSION | PRM_FOR_SERVER) | PRM_CLIENT_SESSION)#define SERVER_SESSION_CHCK ((PRM_FOR_SESSION | PRM_FOR_SERVER) & ~PRM_CLIENT_SESSION)#define PRM_SERVER_SESSION(id) \ (((GET_PRM (id))->static_flag & SERVER_SESSION_MASK) == SERVER_SESSION_CHCK)— the one place the “is this parameter both session-scoped and
server-side, but not client-only-session” question is encoded.
The branch is predicted heavily toward “no detour”; the slow path
itself is a BO_IS_SERVER_RESTARTED guard plus one
session_get_session_parameter lookup in the per-session array,
falling back to the global value if the session does not yet have
its array attached.
flowchart TD
CALL["prm_get_integer_value(prm_id)"]
CHECK{"PRM_SERVER_SESSION(prm_id)<br/>and SERVER_MODE<br/>and server-restarted"}
GLOBAL["return prm_Def[prm_id].value.v.i"]
SESS["session_get_session_parameter(thread, prm_id)"]
SHASH{"found in<br/>session_parameters[]"}
GLOBAL2["return prm_Def[prm_id].value.v.i"]
SESSV["return SESSION_PARAM.value.i"]
CALL --> CHECK
CHECK -- no --> GLOBAL
CHECK -- yes --> SESS
SESS --> SHASH
SHASH -- no --> GLOBAL2
SHASH -- yes --> SESSV
Cross-parameter aliasing
Section titled “Cross-parameter aliasing”A handful of parameters are dual names for the same underlying
storage. The classic example is sort_buffer_size (in bytes) and
sort_buffer_pages (in IO pages) — there is one storage location
(integer page count) but two ways for the user to set it. CUBRID’s
solution is the PARAM_VALUE_SHARE[] table
(system_parameter.c:5341):
static const int *PARAM_VALUE_SHARE[] = { /* {count, PRM_ID_a, PRM_ID_b, ...} */ (int[]) {2, PRM_ID_SR_NBUFFERS, PRM_ID_SORT_BUFFER_SIZE}, (int[]) {2, PRM_ID_PB_NBUFFERS, PRM_ID_PAGE_BUFFER_SIZE}, (int[]) {2, PRM_ID_BT_OID_NBUFFERS,PRM_ID_BT_OID_BUFFER_SIZE}, (int[]) {2, PRM_ID_LK_TIMEOUT_SECS,PRM_ID_LK_TIMEOUT}, (int[]) {2, PRM_ID_LOG_NBUFFERS, PRM_ID_LOG_BUFFER_SIZE}, /* ... */ (int[]) {2, PRM_ID_JAVA_STORED_PROCEDURE, PRM_ID_STORED_PROCEDURE}, /* ... */ NULL,};Each row’s first element is the count of aliased ids; the rest are
the ids themselves, which the comment says must be in ascending
order and consecutive. When sysprm_set_value (9335) sets a
value on one of those parameters, it consults
sysprm_find_shared_system_parameter and replays the same set on
every other id in the row through sysprm_set_value_internal. The
unit translation per parameter (the set_dup / get_dup
callbacks declared in the registry entry for the bytes-flavoured
twin) takes care of the actual pages-↔-bytes conversion; the share
table is just the membership relation.
The PRM_COMPOUND flag is a different mechanism. A compound
parameter sets several others as a side-effect, but the relationship
is “one input keyword chooses N output values” rather than “one
storage location with N names”. The only example today is
compat_mode: when set, prm_compound_has_changed (9448) calls
prm_set_compound (10310) with compat_mode_values, a 2-D
array indexed by the compat target (CUBRID/MySQL/Oracle) and the
parameter to update — oracle_style_outerjoin, ansi_quotes,
pipes_as_concat, etc., land on different defaults depending on
which target the user chose.
Propagation to and from the server
Section titled “Propagation to and from the server”A CUBRID install has at least two processes that must see consistent
parameter values: the client (cubridcs library, linked into the
JDBC/CCI driver, or cubridsa for SA mode) and the server
(cub_server). Each maintains its own prm_Def[] table, but they
must agree on values for parameters tagged PRM_FOR_CLIENT | PRM_FOR_SERVER. The propagation rules are encoded in three flags:
PRM_FOR_CLIENTonly — the parameter exists on the client and is invisible to the server. Pure client-side parameters (e.g. CSQL behaviours).PRM_FOR_SERVERonly — vice versa. Most physical-resource parameters (buffer sizes, log sizes, port).- Both flags set — the parameter exists on both sides; the rules
for which side wins, and when, depend on
PRM_FORCE_SERVERandPRM_GET_SERVER.
Client-initiated changes. The user-facing path is
SET SYSTEM PARAMETERS '<name>=<value>;...', which lands in
db_set_system_parameters (db_admin.c:2879). The pattern is
“validate → maybe RPC → apply locally”:
sysprm_validate_change_parameters (7196) parses the
name=value;name=value payload through sysprm_generate_new_value
and returns a SYSPRM_ASSIGN_VALUE linked list plus a status code
(PRM_ERR_NO_ERROR if every parameter is client-only,
PRM_ERR_NOT_FOR_CLIENT if at least one needs the server,
PRM_ERR_NOT_FOR_CLIENT_NO_AUTH if DBA privilege is required).
When the server is needed, db_set_system_parameters calls
sysprm_change_server_parameters (the client-side RPC stub) which
arrives at xsysprm_change_server_parameters (8124); this is a
thin wrapper around sysprm_change_parameter_values with
check=true so the server can reject parameters that were marked
client-only. Whether the RPC fired or not, the client also calls
sysprm_change_parameter_values locally.
The reciprocal direction is db_get_system_parameters →
sysprm_obtain_parameters (7983) →
sysprm_obtain_server_parameters for parameters whose value lives
on the server.
Server-forced refresh. The flag PRM_FORCE_SERVER declares
“this parameter’s authoritative value lives on the server, and
every fresh client must pull it on connect”.
sysprm_tune_client_parameters (10266) is the client-side hook
called right after boot_register_client: it asks the server
through sysprm_get_force_server_parameters, packs the response
into a SYSPRM_ASSIGN_VALUE list, and applies it locally with
sysprm_change_parameter_values (..., check=false, ...). The
server side is xsysprm_get_force_server_parameters (8165),
which walks the table and packs every parameter flagged
PRM_FORCE_SERVER into the response. Typical examples are
intl_collation, server_timezone, and block_ddl_statement —
values the client must inherit because otherwise SQL semantics
would diverge.
sequenceDiagram participant Client participant Server participant ClientPRM as Client prm_Def[] participant ServerPRM as Server prm_Def[] Note over Client,Server: At register time Client->>Server: xboot_register_client (session_params packed) Server->>ServerPRM: sysprm_session_init_session_parameters Server-->>Client: BOOT_SERVER_CREDENTIAL + session_id Client->>Server: sysprm_get_force_server_parameters Server->>ServerPRM: walk PRM_FORCE_SERVER Server-->>Client: SYSPRM_ASSIGN_VALUE list Client->>ClientPRM: sysprm_change_parameter_values Note over Client,Server: At runtime SET SYSTEM PARAMETERS Client->>ClientPRM: sysprm_validate_change_parameters Client->>Server: sysprm_change_server_parameters (if PRM_FOR_SERVER) Server->>ServerPRM: sysprm_change_parameter_values Client->>ClientPRM: sysprm_change_parameter_values (if PRM_FOR_CLIENT)
URL parameters, reload, and teardown
Section titled “URL parameters, reload, and teardown”The CCI/JDBC drivers accept connection URLs of the shape
cubrid:host:port:db:user:password:?param=val&.... The URL
fragment is reformatted into name=val;name=val form, passed to
db_set_system_parameters early during the DB-Connect callback,
and from there everything is identical to a runtime SQL SET. For
URL parameters that must survive a subsequent reload (e.g.
lock_timeout chosen by URL must not be overwritten by
cubrid.conf), the driver uses prm_set_force: each value is
stashed in the slot’s force_value field and reapplied at the
tail of every sysprm_load_and_init_internal call.
sysprm_reload_and_init is the on-the-fly re-read path: it calls
_internal with reload=true, which (a) before reading the conf
file resets every PRM_RELOADABLE parameter to its default and
(b) inside prm_load_by_section skips any parameter that lacks
PRM_RELOADABLE. Heavy physical parameters
(PRM_ID_PAGE_BUFFER_SIZE, PRM_ID_LOG_NBUFFERS,
PRM_ID_CSS_MAX_CLIENTS) are not reloadable — they participate in
one-shot allocation. sysprm_final (9783) is the symmetric
teardown that walks the table, frees any value flagged
PRM_ALLOCATED, resets dynamic_flag = 0, and clears the
prm_file_has_been_loaded set.
Dump for diagnostics
Section titled “Dump for diagnostics”sysprm_dump_parameters (5847) is the introspection routine.
Its caller passes a marker character (' ', 'C', 'S'),
include/exclude flag masks, and AND-vs-OR semantics for those
masks. The new-style output is [<marker><differs>] name=value (default) so a reader sees drifts at a glance; the old style
prints just name=value. The flagged-on-difference comparison
reads prm->value and prm->default_value straight from the slot
— no re-formatting, no I/O — which is the reason the table holds
both. xsysprm_dump_server_parameters is the server-side wrapper
that pre-fills the marker to 'S'.
Source Walkthrough
Section titled “Source Walkthrough”The configuration subsystem is one C file plus its public header.
Below the symbols are grouped by role; the position-hint table at
the end pairs each symbol with its line number as of updated:.
Header — types and policy. system_parameter.h exposes the
id enum PARAM_ID, the type tag SYSPRM_DATATYPE, the variant
union SYSPRM_VALUE and its tagged wrapper SYSPRM_PARAM_VALUE,
the slot struct SYSPRM_PARAM, the session-scoped value type
SESSION_PARAM, the change-list type SYSPRM_ASSIGN_VALUE, the
static and dynamic flag definitions, the accessor macros
(GET_PRM, PRM_GET_INT/BOOL/...), the policy macro
PRM_SERVER_SESSION, and the STATIC_INLINE getters
prm_get_integer_value / ..._bool_value / ..._float_value /
..._string_value / ..._integer_list_value / ..._bigint_value.
Windows builds provide the getters out-of-line.
Registry data (system_parameter.c). One
#define PRM_NAME_<ID> per parameter (120-797), then
SYSPRM_PARAM prm_Def[] (1010-5331), the precomputed session
index prm_Def_session_idx[], the size cache MAX_SYSTEM_PARAMS,
the alias table PARAM_VALUE_SHARE[], the per-CS_MODE cache
cached_session_parameters, and the keyword tables
(boolean_words, er_log_level_words, isolation_level_words,
ha_mode_words, compat_words, etc.).
Loader. Three public entry points
(sysprm_load_and_init / ..._client / _reload_and_init) all
funnel through sysprm_load_and_init_internal. Section-by-section
work is prm_read_and_parse_ini_file → prm_load_by_section →
prm_section_cmp + prm_find. Post-load passes are
prm_check_environment (env override), prm_tune_parameters
(cross-parameter consistency), and the forced-value replay loop.
init_server_timezone_parameter is the timezone-specific
late-init step.
Write paths. prm_set parses a string into a typed value
(sysprm_generate_new_value) and applies it via sysprm_set_value,
which calls sysprm_set_value_internal for the actual mutation,
consults sysprm_find_shared_system_parameter to propagate to
aliased ids, and (for PRM_COMPOUND) calls
prm_compound_has_changed → prm_set_compound to cascade
further sets. prm_set_default resets to baseline. prm_set_force
stashes a string in force_value for replay. The typed public
setters prm_set_integer_value / ..._bool / ..._float /
..._string / ..._integer_list / ..._bigint are the
direct-write API.
Read paths. prm_get_value returns a pointer to the active
SYSPRM_VALUE, taking the per-session detour when needed. The
inline getters in the header are the hot path. prm_get_name,
prm_get_master_port_id, prm_get_commit_on_shutdown are typed
convenience wrappers.
SQL/URL and propagation. sysprm_validate_change_parameters
parses name=val;... into a SYSPRM_ASSIGN_VALUE list with
policy checks. sysprm_make_default_values reformats names →
name=default; strings. sysprm_change_parameter_values applies
a list. sysprm_obtain_parameters is the read counterpart.
db_set_system_parameters / db_get_system_parameters
(compat/db_admin.c) are the SQL-API drivers.
xsysprm_change_server_parameters, xsysprm_obtain_server_parameters,
xsysprm_get_force_server_parameters, xsysprm_dump_server_parameters,
xsysprm_get_pl_context_parameters are the server-side RPC stubs.
sysprm_tune_client_parameters is the client post-register hook
that pulls PRM_FORCE_SERVER values.
sysprm_session_init_session_parameters is the server-side
reconcile-at-attach logic.
Wire format. sysprm_pack_sysprm_value /
..._unpack_..._value cover one SYSPRM_VALUE. The
sysprm_pack_session_parameters / ..._unpack_... pair handles
the per-session array shipped at xboot_register_client. The
sysprm_pack_assign_values / ..._unpack_... pair handles the
change-list. sysprm_free_assign_values is the freer.
Diagnostics and teardown. sysprm_dump_parameters and
xsysprm_dump_server_parameters,
sysprm_print_parameters_for_qry_string (plan-cache key),
sysprm_print_parameters_for_ha_repl (HA replication), prm_print
(per-slot formatter), prm_rewrite_int_list, plus the debug-build
sanity checks sysprm_check_id_order and prm_check_parameters.
sysprm_final is the process-shutdown walker.
Position hints (as of updated:)
Section titled “Position hints (as of updated:)”| Symbol | File / lines |
|---|---|
enum param_id / PARAM_ID | system_parameter.h:97-534 |
| Static / dynamic flag macros | system_parameter.h:606-646 |
SYSPRM_DATATYPE / SYSPRM_VALUE / SESSION_PARAM / SYSPRM_ASSIGN_VALUE | system_parameter.h:539-578 |
SYSPRM_PARAM (slot struct) | system_parameter.h:706-721 |
PRM_SERVER_SESSION macro | system_parameter.h:681-683 |
Inline prm_get_*_value getters | system_parameter.h:819-947 |
PRM_NAME_* macros | system_parameter.c:120-797 |
NULL_SYSPRM_PARAM_VALUE | system_parameter.c:1007 |
SYSPRM_PARAM prm_Def[] | system_parameter.c:1010-5331 |
prm_Def_session_idx[] | system_parameter.c:5333 |
MAX_SYSTEM_PARAMS / num_session_parameters | system_parameter.c:5335-5339 |
PARAM_VALUE_SHARE[] | system_parameter.c:5341-5374 |
cached_session_parameters | system_parameter.c:5383 |
Keyword tables (boolean_words, …) | system_parameter.c:5399-5530 |
sysprm_dump_parameters | system_parameter.c:5847 |
sysprm_set_er_log_file | system_parameter.c:5919 |
sysprm_check_id_order | system_parameter.c:5963 |
sysprm_load_and_init_internal | system_parameter.c:6015 |
sysprm_load_and_init / ..._client / _reload_and_init | system_parameter.c:6285-6315 |
prm_load_by_section | system_parameter.c:6350 |
prm_read_and_parse_ini_file | system_parameter.c:6574 |
prm_check_environment | system_parameter.c:7091 |
sysprm_validate_change_parameters | system_parameter.c:7196 |
sysprm_make_default_values | system_parameter.c:7322 |
sysprm_change_parameter_values | system_parameter.c:7402 |
sysprm_obtain_parameters | system_parameter.c:7983 |
xsysprm_change_server_parameters | system_parameter.c:8124 |
xsysprm_obtain_server_parameters | system_parameter.c:8140 |
xsysprm_get_force_server_parameters | system_parameter.c:8165 |
xsysprm_get_pl_context_parameters | system_parameter.c:8223 |
sysprm_get_range | system_parameter.c:8380 |
prm_set | system_parameter.c:9167 |
sysprm_set_value / ..._internal | system_parameter.c:9183-9362 |
sysprm_find_shared_system_parameter | system_parameter.c:9366 |
prm_set_force | system_parameter.c:9471 |
prm_set_default / ..._internal | system_parameter.c:9489-9589 |
prm_find | system_parameter.c:9597 |
sysprm_final | system_parameter.c:9783 |
prm_tune_parameters | system_parameter.c:9865 |
sysprm_tune_client_parameters | system_parameter.c:10266 |
prm_set_compound | system_parameter.c:10310 |
prm_get_next_param_value | system_parameter.c:10347 |
prm_get_value | system_parameter.c:10486 |
prm_set_integer_value / ..._bool / ..._float / ..._string / ..._integer_list / ..._bigint | system_parameter.c:10533-10650 |
sysprm_pack_session_parameters / ..._unpack_... | system_parameter.c:11118-11233 |
sysprm_pack_assign_values / ..._unpack_... | system_parameter.c:11243-11357 |
sysprm_free_assign_values | system_parameter.c:11366 |
sysprm_session_init_session_parameters | system_parameter.c:11447 |
sysprm_get_session_parameters_count | system_parameter.c:12127 |
Conf file cubrid.conf | conf/cubrid.conf:25-75 |
db_set_system_parameters | compat/db_admin.c:2879 |
db_get_system_parameters | compat/db_admin.c:3014 |
Cross-check Notes
Section titled “Cross-check Notes”A few details surface only by reading prm_Def[] against subsystem
call sites:
PRM_ID_OPTIMIZER_RESERVE_02 … _20are placeholder slots carryingPRM_OBSOLETED. New optimizer parameters reuse a reserved slot rather than bumpingPRM_LAST_ID, keeping the enum-id ↔ network-protocol mapping stable across versions.PRM_ID_HA_MODE_FOR_SA_UTILS_ONLYis a back-channel: under SA-modeprm_tune_parametersforcibly resetsha_modeto OFF, but stashes the configured value here so the utility’s HA-aware logging path can still find it. There is no user-facing way to set it directly.- HA conf is loaded twice. The first
prm_read_and_parse_ini_filecall passesSYSPRM_IGNORE_HAto skipPRM_FOR_HA; the second passes the opposite to readcubrid_ha.conf. This is the only place the loader runs twice in one boot. PRM_FOR_HA_CONTEXTis replication-aware: when a master changes such a parameter viaSET SYSTEM PARAMETERS, the HA log applier walks the table and reapplies on the replica.PRM_FOR_PL_CONTEXTis forwarded once at PL/SP attach viaxsysprm_get_pl_context_parameters. Subsequent changes to those parameters are not pushed to the JVM; callers that need live updates must rebind.- Compound vs. share — the lines blur.
PRM_COMPOUNDsets several others by side-effect;PARAM_VALUE_SHAREbinds two ids to the same storage.sysprm_set_valueorders them as “write → alias propagate → compound cascade”. A parameter that is both compound and half of a share pair would loop without the recursive guard inprm_set_compound; today no parameter is both, so the case is unexercised. - Environment outranks conf.
prm_check_environmentruns after the conf file, so an exportedCUBRID_DATA_BUFFER_SIZE=1Gbeatsdata_buffer_size=512Mincubrid.conf. This matches Postgres’PGOPTIONSprecedence and inverts the MySQL convention. prm_tune_parametersmutates withoutPRM_SET. The tuner callsprm_setwithset_flag=false, so a tuned value changes but thePRM_DEFAULT_USEDflag remains, and the dump routine still describes the parameter as “default”. This is deliberate — the tuner is engine policy, not user intent — but it means thedefault_markerin a dump is not always the compile-time default.
Open Questions
Section titled “Open Questions”PRM_FOR_QRY_STRINGplan-cache key cost. Iterating the whole table to build the plan-cache key string is hot; a precomputed bitmap would help, but no evidence of that work in tree.- Should
PRM_FOR_HA_CONTEXTparameters be auto-derived? Today every HA-context parameter is hand-flagged. The real invariant is “any parameter that affects deterministic SQL semantics must be replicated”; encoding that automatically would be brittle but valuable. - Are
_RESERVEslots required for ABI? Their cost is table space, dump-output noise, and developer attention; the alternative (append-and-bump-version) is what most other engines do. CUBRID’s rationale is defensible but a one-time format break could drop the slots. - Reload + session parameters.
sysprm_reload_and_initresets only the global table; sessions that have local copies are not notified. A reload ofPRM_ID_LK_TIMEOUT_SECSis invisible to existing sessions until theySET SYSTEM PARAMETERSor reconnect. Whether that is intended is uncommented. force_value×PRM_FOR_SESSIONis fragile. A force value is reapplied at the tail of every load viaprm_setagainst the global slot, but for a session parameter that path takes the per-session detour and lands on the current thread’s session, not the global default. No caller currently exercises this case.
Sources
Section titled “Sources”src/base/system_parameter.c— the implementation (12 272 lines).src/base/system_parameter.h— public types, inline getters, flag definitions (957 lines).conf/cubrid.conf— the user-facing default configuration (75 lines, sample-only; the install ships a longer one).src/compat/db_admin.c—db_set_system_parameters,db_get_system_parameters, the SQL-facing wrappers.- Subsystem call sites grep-able via
prm_get_*_value (PRM_ID_*), e.g.pgbuf_Pool.num_buffers = prm_get_integer_value (PRM_ID_PB_NBUFFERS);insrc/storage/page_buffer.c,wait_msecs = prm_get_integer_value (PRM_ID_LK_TIMEOUT_SECS);insrc/transaction/lock_manager.c,log_No_logging = prm_get_bool_value (PRM_ID_LOG_NO_LOGGING);insrc/transaction/log_manager.c. - Adjacent docs:
cubrid-boot.mdfor how the loader is wired into process startup;cubrid-server-session.mdfor theSESSION_STATE::session_parametersarray and thexsession_check_sessionreconnect path.