Skip to content

v2: db.php drop-in for early-query coverage and zero-overhead observation#32

Open
mrtwebdesign wants to merge 2 commits into
developmentfrom
feat/v2-db-dropin
Open

v2: db.php drop-in for early-query coverage and zero-overhead observation#32
mrtwebdesign wants to merge 2 commits into
developmentfrom
feat/v2-db-dropin

Conversation

@mrtwebdesign
Copy link
Copy Markdown
Contributor

Summary

  • Adds HCQG_DB class (db.php) extending wpdb with conditional backtracing and first-query SET SESSION MAX_EXECUTION_TIME, eliminating the ~10% CPU overhead of SAVEQUERIES at 100% observation and covering pre-init queries (autoloaded options, auth/usermeta, WC session bootstrap)
  • Mu-plugin coordination via dropin_active() — gates logging source, SAVEQUERIES usage, and SET SESSION method so v1 behavior is preserved when the drop-in is absent
  • Dependency guard on mu-plugin startup — returns early with a log warning if any companion class-hcqg-*.php file is missing, preventing fatal errors during partial uploads to live sites
  • README updated with v2 installation instructions (upload order, db.php deployment, Query Monitor conflict notes)
  • 11 new tests covering drop-in detection, v2 logging codepath, and v2 SET SESSION delegation

Status

Not production-ready — needs staging validation before merge:

  • Verify conditional backtracing captures slow queries correctly on a real WooCommerce request
  • Verify SET SESSION is applied before wp_load_alloptions() in enforce mode
  • Confirm no regressions in v1 behavior when db.php is absent
  • Measure before/after CPU overhead at 100% observation on a representative page

Related

🤖 Generated with Claude Code

mrtwebdesign and others added 2 commits May 14, 2026 16:30
Adds HCQG_DB (extends wpdb) for two capabilities the mu-plugin alone
cannot provide: SET SESSION MAX_EXECUTION_TIME at connection time
(covering pre-init queries like wp_load_alloptions), and conditional
backtracing that replaces SAVEQUERIES — dropping 100% observation
overhead from ~10% CPU to near zero.

Mu-plugin coordination: dropin_active() gates three codepaths so the
mu-plugin reads from hcqg_slow_queries when the drop-in is present
and falls back to SAVEQUERIES when it isn't.

Safety: dependency guard on the mu-plugin returns early with a log
warning if any companion class file is missing, preventing fatal
errors during partial uploads.

README updated with v2 installation instructions including upload
order, db.php deployment, and Query Monitor conflict notes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds ?hcqg_test=1 URL param (admin-only) that fires a 6-second
SLEEP query to validate the slow-query logging pipeline end-to-end.

README: quick-test section at top, dependency guard docs, single-file
distribution note for future.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a v2 db.php drop-in path for Hypercart Query Guard, coordinating it with the existing MU-plugin so query observation can avoid SAVEQUERIES overhead and enforcement can begin before init.

Changes:

  • Adds HCQG_DB drop-in with conditional slow-query capture and first-query session timeout handling.
  • Updates MU-plugin coordination for drop-in detection, logging source selection, and session limit delegation.
  • Adds README installation/test guidance and PHPUnit coverage for MU-plugin/drop-in coordination.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
db.php Adds the v2 WordPress database drop-in implementation.
hypercart-query-guard.php Adds dependency guard, drop-in coordination, diagnostic query, and v2 logging/session paths.
README.md Documents quick test flow and v2 drop-in installation/operation.
tests/bootstrap.php Extends stubs for drop-in simulation and logger capture.
tests/DbDropinTest.php Adds tests for drop-in detection, slow-query logging routing, and session delegation.
Comments suppressed due to low confidence (3)

db.php:206

  • When the limit changes from a positive value to 0, this method updates the cached value but does not execute SET SESSION MAX_EXECUTION_TIME = 0. Any session that already received the pre-init/default cap will keep that cap, so callers cannot actually clear the limit for unlimited contexts.
		if ( $limit_ms > 0 ) {
			@mysqli_query( $this->dbh, sprintf( 'SET SESSION MAX_EXECUTION_TIME = %d', $limit_ms ) );
		}

README.md:59

  • This overstates standalone behavior: the drop-in only applies SET SESSION MAX_EXECUTION_TIME in enforce mode, while the documented default mode is observe. Without the mu-plugin and without an explicit enforce constant, standalone installs will not have SET SESSION protection active.
- **db.php present, mu-plugin present** — full v2 behavior. The mu-plugin detects the drop-in and uses it for logging and tiered limit updates.
- **db.php present, mu-plugin absent** — drop-in runs standalone. Conditional backtracing and SET SESSION protection are active, but there is no structured logging, no tiered limits, and no admin-search fallback notice.

db.php:39

  • The comment says compatibility is tested through WordPress 6.8, but the warning ceiling is set to 6.9 and the check only warns when the running version is greater than that. As written, an untested 6.9 install would not emit the compatibility warning.
	// Tested against WordPress 5.5 – 6.8. The override relies on query()
	// returning int|bool and _do_query() being private (not called through
	// the vtable). If core refactors _do_query into a protected method or
	// changes query()'s signature, the assertion below will fire.
	const WP_VERSION_FLOOR   = '5.5';
	const WP_VERSION_CEILING = '6.9';

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread hypercart-query-guard.php
Comment on lines +929 to +937
// v2 drop-in: update the cached limit and re-apply via raw mysqli.
// This also caches the per-context limit so reconnect/rotation
// re-applies the correct tier instead of the pre-init default.
if ( self::dropin_active() ) {
static $dropin_last_limit = null;
if ( $dropin_last_limit === $limit_ms ) {
return;
}
$wpdb->hcqg_update_limit( $limit_ms );
Comment thread hypercart-query-guard.php
public static function maybe_run_diagnostic_query() {
if ( ! isset( $_GET['hcqg_test'] ) || ! current_user_can( 'manage_options' ) ) {
return;
}
Comment thread db.php
Comment on lines +94 to +96
if ( defined( 'HYPERCART_QUERY_GUARD_WARN_THRESHOLD_MS' ) ) {
$this->hcqg_warn_threshold_s = max( 0, (int) HYPERCART_QUERY_GUARD_WARN_THRESHOLD_MS ) / 1000;
}
Comment thread README.md

## Quick test

Append `?hcqg_test=1` to any URL while logged in as admin. This fires a 6-second `SELECT SLEEP(6)` that triggers the slow-query logging pipeline. Check `debug.log` (or your Hypercart_Logger output) for a `slow_query` event to confirm end-to-end operation.
Comment thread tests/DbDropinTest.php

use PHPUnit\Framework\TestCase;

class DbDropinTest extends TestCase {
Comment thread db.php
Comment on lines +131 to +135
public function query( $query ) {
// Enforce: apply or re-apply SET SESSION on first query / reconnect / rotation.
if ( $this->hcqg_enforce &&
( ! $this->hcqg_session_applied || $this->hcqg_last_dbh !== $this->dbh ) ) {
$this->hcqg_apply_session();
Comment thread db.php
// Tested against WordPress 5.5 – 6.8. The override relies on query()
// returning int|bool and _do_query() being private (not called through
// the vtable). If core refactors _do_query into a protected method or
// changes query()'s signature, the assertion below will fire.
Comment thread hypercart-query-guard.php
Comment on lines +45 to +47
if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
error_log( '[hypercart_query_guard][error] Missing required file: ' . basename( $hcqg_file ) . ' — plugin disabled.' );
}
Comment thread db.php
exit;
}

class HCQG_DB extends wpdb {
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants