LDEV-6293 — `getSystemMetrics()` datasource pool keying fixed (incremental breaking change)

Heads-up for anyone monitoring Lucee datasource pool health via getSystemMetrics(). A bug in how the function keyed its datasourceConnections entries has been fixed in 6.2.7.12, 7.0.4.28, and 7.1.0.109 — and the fix is breaking for a small number of consumers. Worth a quick read if you scrape this metric.

What was wrong

getSystemMetrics().datasourceConnections returned a struct keyed by
datasource.hashCode(). When two pools wrapped the same DataSource
object — possible whenever a cfquery uses credentials that differ from the datasource’s own — the entries collided and silently overwrote each other. Operators saw fewer pool entries and inaccurate per-entry counts than the system actually had.

The same loop also had a typo (idle += getNumWaiters() where it should have been waiters += ...) which made the top-level waitingForConn total always zero and double-counted waiters into idleDatasourceConnections.

Concrete example

Suppose mydb is queried both bare (uses datasource’s own creds) and
with an explicit read-only user:

queryExecute( "select 1", {}, { datasource: "mydb" } );
queryExecute( "select 1", {}, { datasource: "mydb", username: "readonly", password: "secret" } );

Before — both pools collide on datasource.hashCode(), one
overwrites the other:

datasourceConnections: {
  "1234567890": {
    name:                      "mydb",
    idleDatasourceConnections: 1,    // only one pool's data, the other is gone
    ...
  }
}

After — distinct entries, with username exposed:

datasourceConnections: {
  "mydb:sa:499602d2": {
    name:                      "mydb",
    username:                  "sa",
    idleDatasourceConnections: 1,
    ...
  },
  "mydb:readonly:499602d2": {
    name:                      "mydb",
    username:                  "readonly",
    idleDatasourceConnections: 1,
    ...
  }
}

What changes

Breaking

  1. Entry keys are now strings, not integers. Format is name:user:hashHex, e.g. "mydb:sa:499602d2" (was "1234567890").
    Code that parses keys as integers — val(key), int(key) — now
    gets 0. Code that iterates with for k in struct and looks up
    entries by the inner name field continues to work unchanged.

  2. Top-level totals shift. waitingForConn now reports actual waiter count (was always 0). idleDatasourceConnections now reports only idle connections (no longer includes waiters). Anything trending these values will see a one-time step.

  3. More entries visible. Pools that previously collided now appear as distinct entries. structCount(datasourceConnections) may return more than before for any datasource with multiple credential variations.

Additive (non-breaking)

  • Each entry now exposes a username field. Dashboards can filter by user without parsing the key.

Migration

  • If you parse keys as numbers anywhere — switch to iterating and using
    the inner name / username fields.
  • If you alert on waitingForConn == 0 as a healthy state — re-tune the
    threshold; the metric is now meaningful.
  • If you compare idleDatasourceConnections against historical values —
    expect a step change downward.

Versions

Branch Version
6.2 LTS 6.2.7.12-SNAPSHOT
7.0 stable 7.0.4.28-SNAPSHOT
7.1 dev 7.1.0.109-SNAPSHOT

Links

Questions or feedback welcome on the ticket or here.

1 Like