diff --git a/.upgradenotes/MDL-71257-2024090908154016.yml b/.upgradenotes/MDL-71257-2024090908154016.yml new file mode 100644 index 00000000000..11cad5a400b --- /dev/null +++ b/.upgradenotes/MDL-71257-2024090908154016.yml @@ -0,0 +1,14 @@ +issueNumber: MDL-71257 +notes: + core: + - message: >- + The methods `want_read_slave` and `perf_get_reads_slave` in + `lib/dml/moodle_database.php` have been deprecated in favour of + renamed versions that substitute `slave` for `replica`. + type: deprecated + - message: >- + The trait `moodle_read_slave_trait` has been deprecated in favour of a + functionally identical version called `moodle_read_replica_trait`. + The renamed trait substitutes the terminology of `slave` with `replica`, + and `master` with `primary`. + type: deprecated diff --git a/config-dist.php b/config-dist.php index c0fb1163afb..1a17cf1bbc6 100644 --- a/config-dist.php +++ b/config-dist.php @@ -110,41 +110,41 @@ $CFG->dboptions = array( // Currently supported only with mysqli, mariadb, and aurora drivers. /* 'connecttimeout' => null, // Set connect timeout in seconds. Not all drivers support it. - 'readonly' => [ // Set to read-only slave details, to get safe reads - // from there instead of the master node. Optional. + 'readonly' => [ // Set to read-only replica details, to get safe reads + // from there instead of the primary node. Optional. // Currently supported by pgsql and mysqli variety classes. // If not supported silently ignored. - 'instance' => [ // Readonly slave connection parameters + 'instance' => [ // Readonly replica connection parameters [ - 'dbhost' => 'slave.dbhost', - 'dbport' => '', // Defaults to master port - 'dbuser' => '', // Defaults to master user - 'dbpass' => '', // Defaults to master password + 'dbhost' => 'replica.dbhost', + 'dbport' => '', // Defaults to primary port + 'dbuser' => '', // Defaults to primary user + 'dbpass' => '', // Defaults to primary password ], [...], ], Instance(s) can alternatively be specified as: - 'instance' => 'slave.dbhost', - 'instance' => ['slave.dbhost1', 'slave.dbhost2'], - 'instance' => ['dbhost' => 'slave.dbhost', 'dbport' => '', 'dbuser' => '', 'dbpass' => ''], + 'instance' => 'replica.dbhost', + 'instance' => ['replica.dbhost1', 'replica.dbhost2'], + 'instance' => ['dbhost' => 'replica.dbhost', 'dbport' => '', 'dbuser' => '', 'dbpass' => ''], - 'connecttimeout' => 2, // Set read-only slave connect timeout in seconds. See above. - 'latency' => 0.5, // Set read-only slave sync latency in seconds. + 'connecttimeout' => 2, // Set read-only replica connect timeout in seconds. See above. + 'latency' => 0.5, // Set read-only replica sync latency in seconds. // When 'latency' seconds have lapsed after an update to a table - // it is deemed safe to use readonly slave for reading from the table. + // it is deemed safe to use readonly replica for reading from the table. // It is optional, defaults to 1 second. If you want once written to a table - // to always use master handle for reading set it to something ridiculosly big, + // to always use primary handle for reading set it to something ridiculosly big, // eg 10. // Lower values increase the performance, but setting it too low means - // missing the master-slave sync. - 'exclude_tables' => [ // Tables to exclude from read-only slave feature. + // missing the primary-replica sync. + 'exclude_tables' => [ // Tables to exclude from read-only replica feature. 'table1', // Should not be used, unless in rare cases when some area of the system 'table2', // is malfunctioning and you still want to use readonly feature. ], // Then one can exclude offending tables while investigating. - More info available in lib/dml/moodle_read_slave_trait.php where the feature is implemented. + More info available in lib/dml/moodle_read_replica_trait.php where the feature is implemented. ] */ // For all database config settings see https://docs.moodle.org/en/Database_settings diff --git a/lib/dml/moodle_database.php b/lib/dml/moodle_database.php index 73653196e85..602120a5abb 100644 --- a/lib/dml/moodle_database.php +++ b/lib/dml/moodle_database.php @@ -2879,16 +2879,52 @@ abstract class moodle_database { /** * Returns whether we want to connect to slave database for read queries. * @return bool Want read only connection + * @deprecated Since Moodle 5.0. See MDL-71257. + * @todo Final deprecation in Moodle 6.0. See MDL-83171. */ + #[\core\attribute\deprecated( + replacement: 'want_read_replica', + since: '5.0', + mdl: 'MDL-71257', + reason: 'Renamed' + )] public function want_read_slave(): bool { + \core\deprecation::emit_deprecation_if_present(__FUNCTION__); + return false; + } + + /** + * Returns whether we want to connect to replica database for read queries. + * + * @return bool Want read only connection. + */ + public function want_read_replica(): bool { return false; } /** * Returns the number of reads before first write done by this database. * @return int Number of reads. + * @deprecated Since Moodle 5.0 + * @todo Final deprecation in Moodle 6.0. See MDL-83171. */ + #[\core\attribute\deprecated( + replacement: 'perf_get_reads_replica', + since: '5.0', + mdl: 'MDL-71257', + reason: 'Renamed' + )] public function perf_get_reads_slave(): int { + \core\deprecation::emit_deprecation_if_present(__FUNCTION__); + return 0; + } + + /** + * Returns the number of reads before first write done by this database. + * + * @return int Number of reads. + */ + public function perf_get_reads_replica(): int { return 0; } diff --git a/lib/dml/moodle_read_replica_trait.php b/lib/dml/moodle_read_replica_trait.php new file mode 100644 index 00000000000..000b0b8174b --- /dev/null +++ b/lib/dml/moodle_read_replica_trait.php @@ -0,0 +1,462 @@ +. + +/** + * Trait that adds read-only replica connection capability. + * + * Trait to wrap connect() method of database driver classes that gives + * ability to use read only replica instances for SELECT queries. For the + * databases that support replication and read only connections to the replica. + * If the replica connection is configured there will be two database handles + * created, one for the primary and another one for the replica. If there's no + * replica specified everything uses primary handle. + * + * Classes that use this trait need to rename existing connect() method to + * raw_connect(). In addition, they need to provide get_db_handle() and + * set_db_handle() methods, due to dbhandle attributes not being named + * consistently across the database driver classes. + * + * Read only replica connection is configured in the $CFG->dboptions['readonly'] + * array. + * - It supports multiple 'instance' entries, in case one is not accessible, + * but only one (first connectable) instance is used. + * - 'latency' option: primary -> replica sync latency in seconds (will probably + * be a fraction of a second). A table being written to is deemed fully synced + * after that period and suitable for replica read. Defaults to 1 sec. + * - 'exclude_tables' option: a list of tables that never go to the replica for + * querying. The feature is meant to be used in emergency only, so the + * readonly feature can still be used in case there is a rogue query that + * does not go through the standard dml interface or some other unaccounted + * situation. It should not be used under normal circumstances, and its use + * indicates a problem in the system that needs addressig. + * + * Choice of the database handle is based on following: + * - SQL_QUERY_INSERT, UPDATE and STRUCTURE record table from the query + * in the $written array and microtime() the event. For those queries primary + * write handle is used. + * - SQL_QUERY_AUX queries will always use the primary write handle because they + * are used for transaction start/end, locking etc. In that respect, query_start() and + * query_end() *must not* be used during the connection phase. + * - SQL_QUERY_AUX_READONLY queries will use the primary write handle if in a transaction. + * - SELECT queries will use the primary write handle if: + * -- any of the tables involved is a temp table + * -- any of the tables involved is listed in the 'exclude_tables' option + * -- any of the tables involved is in the $written array: + * * current microtime() is compared to the write microrime, and if more than + * latency time has passed the replica handle is used + * * otherwise (not enough time passed) we choose the primary write handle + * If none of the above conditions are met the replica instance is used. + * + * A 'latency' example: + * - we have set $CFG->dboptions['readonly']['latency'] to 0.2. + * - a SQL_QUERY_UPDATE to table tbl_x happens, and it is recorded in + * the $written array + * - 0.15 seconds later SQL_QUERY_SELECT with tbl_x is requested - the primary + * connection is used + * - 0.10 seconds later (0.25 seconds after SQL_QUERY_UPDATE) another + * SQL_QUERY_SELECT with tbl_x is requested - this time more than 0.2 secs + * has gone and primary -> replica sync is assumed, so the replica connection is + * used again. + * + * @package core + * @category dml + * @copyright 2024 David Woloszyn + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +trait moodle_read_replica_trait { + + /** @var resource Primary write database handle. */ + protected $dbhwrite; + + /** @var resource Replica read only database handle. */ + protected $dbhreadonly; + + /** @var bool Connect to replica database for read queries. */ + private $wantreadreplica = false; + + /** @var int The number of reads done by the read only database. */ + private $readsreplica = 0; + + /** @var int Replica letency in seconds. */ + private $replicalatency = 1; + + /** @var bool Structure changed status. */ + private $structurechange = false; + + /** @var array Track tables being written to. */ + private $written = []; + + /** @var array Tables to exclude from using dbhreadonly. */ + private $readexclude = []; + + /** @var string The database host. */ + private $pdbhost; + + /** @var string The database username. */ + private $pdbuser; + + /** @var string The database username's password. */ + private $pdbpass; + + /** @var string The name of the database being connected to. */ + private $pdbname; + + /** @var mixed String means moodle db prefix, false used for external databases where prefix not used. */ + private $pprefix; + + /** @var array|null Driver specific options. */ + private $pdboptions; + + /** + * Gets db handle currently used with queries. + * + * @return resource + */ + abstract protected function get_db_handle(); + + /** + * Sets db handle to be used with subsequent queries. + * + * @param resource $dbh + */ + abstract protected function set_db_handle($dbh): void; + + /** + * Connect to db. + * + * The real connection establisment, called from connect() and set_dbhwrite(). + * + * @param string $dbhost The database host. + * @param string $dbuser The database username. + * @param string $dbpass The database username's password. + * @param string $dbname The name of the database being connected to. + * @param mixed $prefix String means moodle db prefix, false used for external databases where prefix not used. + * @param array|null $dboptions Driver specific options. + * @return bool + * @throws dml_connection_exception + */ + abstract protected function raw_connect( + string $dbhost, + string $dbuser, + string $dbpass, + string $dbname, + $prefix, + ?array $dboptions = null + ): bool; + + /** + * Connect to db. + * + * The connection parameters processor that sets up stage for primary write and replica readonly handles. + * Must be called before other methods. + * + * @param string $dbhost The database host. + * @param string $dbuser The database username. + * @param string $dbpass The database username's password. + * @param string $dbname The name of the database being connected to. + * @param mixed $prefix String means moodle db prefix, false used for external databases where prefix not used. + * @param array|null $dboptions Driver specific options. + * @return bool + * @throws dml_connection_exception + */ + public function connect($dbhost, $dbuser, $dbpass, $dbname, $prefix, ?array $dboptions = null) { + $this->pdbhost = $dbhost; + $this->pdbuser = $dbuser; + $this->pdbpass = $dbpass; + $this->pdbname = $dbname; + $this->pprefix = $prefix; + $this->pdboptions = $dboptions; + + $logconnection = false; + if ($dboptions) { + if (isset($dboptions['readonly'])) { + $this->wantreadreplica = true; + $dboptionsro = $dboptions['readonly']; + + if (isset($dboptionsro['connecttimeout'])) { + $dboptions['connecttimeout'] = $dboptionsro['connecttimeout']; + } else if (!isset($dboptions['connecttimeout'])) { + $dboptions['connecttimeout'] = 2; // Default readonly connection timeout. + } + if (isset($dboptionsro['latency'])) { + $this->replicalatency = $dboptionsro['latency']; + } + if (isset($dboptionsro['exclude_tables'])) { + $this->readexclude = $dboptionsro['exclude_tables']; + if (!is_array($this->readexclude)) { + throw new configuration_exception('exclude_tables must be an array'); + } + } + $dbport = isset($dboptions['dbport']) ? $dboptions['dbport'] : null; + + $replicas = $dboptionsro['instance']; + if (!is_array($replicas) || !isset($replicas[0])) { + $replicas = [$replicas]; + } + + if (count($replicas) > 1) { + // Don't shuffle for unit tests as order is important for them to pass. + if (!PHPUNIT_TEST) { + // Randomise things a bit. + shuffle($replicas); + } + } + + // Find first connectable readonly replica. + $rodb = []; + foreach ($replicas as $replica) { + if (!is_array($replica)) { + $replica = ['dbhost' => $replica]; + } + foreach (['dbhost', 'dbuser', 'dbpass'] as $dbparam) { + $rodb[$dbparam] = isset($replica[$dbparam]) ? $replica[$dbparam] : $$dbparam; + } + $dboptions['dbport'] = isset($replica['dbport']) ? $replica['dbport'] : $dbport; + + try { + $this->raw_connect($rodb['dbhost'], $rodb['dbuser'], $rodb['dbpass'], $dbname, $prefix, $dboptions); + $this->dbhreadonly = $this->get_db_handle(); + if ($logconnection) { + debugging( + "Readonly db connection succeeded for host {$rodb['dbhost']}" + ); + } + break; + } catch (dml_connection_exception $e) { + debugging( + "Readonly db connection failed for host {$rodb['dbhost']}: {$e->debuginfo}" + ); + $logconnection = true; + } + } + // ... lock_db queries always go to primary. + // Since it is a lock and as such marshalls concurrent connections, + // it is best to leave it out and avoid primary/replica latency. + $this->readexclude[] = 'lock_db'; + // ... and sessions. + $this->readexclude[] = 'sessions'; + } + } + if (!$this->dbhreadonly) { + try { + $this->set_dbhwrite(); + } catch (dml_connection_exception $e) { + debugging( + "Readwrite db connection failed for host {$this->pdbhost}: {$e->debuginfo}" + ); + throw $e; + } + if ($logconnection) { + debugging( + "Readwrite db connection succeeded for host {$this->pdbhost}" + ); + } + } + + return true; + } + + /** + * Set database handle to readwrite primary. + * + * Will connect if required. Calls set_db_handle(). + */ + private function set_dbhwrite(): void { + // Lazy connect to read/write primary. + if (!$this->dbhwrite) { + $temptables = $this->temptables; + $this->raw_connect($this->pdbhost, $this->pdbuser, $this->pdbpass, $this->pdbname, $this->pprefix, $this->pdboptions); + if ($temptables) { + $this->temptables = $temptables; // Restore temptables, so we don't get separate sets for rw and ro. + } + $this->dbhwrite = $this->get_db_handle(); + } + $this->set_db_handle($this->dbhwrite); + } + + /** + * Returns whether we want to connect to replica database for read queries. + * + * @return bool Want read only connection. + */ + public function want_read_replica(): bool { + return $this->wantreadreplica; + } + + /** + * Returns the number of reads done by the read only database. + * + * @return int Number of reads. + */ + public function perf_get_reads_replica(): int { + return $this->readsreplica; + } + + /** + * On DBs that support it, switch to transaction mode and begin a transaction. + * + * @return moodle_transaction + */ + public function start_delegated_transaction() { + $this->set_dbhwrite(); + return parent::start_delegated_transaction(); + } + + /** + * Called before each db query. + * + * @param string $sql + * @param array|null $params An array of parameters. + * @param int $type type of query + * @param mixed $extrainfo driver specific extra information + */ + protected function query_start($sql, ?array $params, $type, $extrainfo = null) { + parent::query_start($sql, $params, $type, $extrainfo); + $this->select_db_handle($type, $sql); + } + + /** + * This should be called immediately after each db query. It does a clean up of resources. + * + * @param mixed $result The db specific result obtained from running a query. + */ + protected function query_end($result) { + if ($this->written) { + // Adjust the written time. + array_walk($this->written, function (&$val) { + if ($val === true) { + $val = microtime(true); + } + }); + } + + parent::query_end($result); + } + + /** + * Select appropriate db handle - readwrite or readonly. + * + * @param int $type Type of query. + * @param string $sql The sql to use. + */ + protected function select_db_handle(int $type, string $sql): void { + if ($this->dbhreadonly && $this->can_use_readonly($type, $sql)) { + $this->readsreplica++; + $this->set_db_handle($this->dbhreadonly); + return; + } + $this->set_dbhwrite(); + } + + /** + * Check if The query qualifies for readonly connection execution. + * + * Logging queries are exempt, those are write operations that circumvent standard query_start/query_end paths. + * + * @param int $type Type of query. + * @param string $sql The sql to use. + * @return bool + */ + protected function can_use_readonly(int $type, string $sql): bool { + if ($this->loggingquery) { + return false; + } + + if (during_initial_install()) { + return false; + } + + // Transactions are done as AUX, we cannot play with that. + switch ($type) { + case SQL_QUERY_AUX_READONLY: + // SQL_QUERY_AUX_READONLY may read the structure data. + // We don't have a way to reliably determine whether it is safe to go to readonly if the structure has changed. + return !$this->structurechange; + case SQL_QUERY_SELECT: + if ($this->transactions) { + return false; + } + + $now = null; + foreach ($this->table_names($sql) as $tablename) { + if (in_array($tablename, $this->readexclude)) { + return false; + } + + if ($this->temptables && $this->temptables->is_temptable($tablename)) { + return false; + } + + if (isset($this->written[$tablename])) { + $now = $now ?: microtime(true); + + if ($now - $this->written[$tablename] < $this->replicalatency) { + return false; + } + unset($this->written[$tablename]); + } + } + + return true; + case SQL_QUERY_INSERT: + case SQL_QUERY_UPDATE: + foreach ($this->table_names($sql) as $tablename) { + $this->written[$tablename] = true; + } + return false; + case SQL_QUERY_STRUCTURE: + $this->structurechange = true; + foreach ($this->table_names($sql) as $tablename) { + if (!in_array($tablename, $this->readexclude)) { + $this->readexclude[] = $tablename; + } + } + return false; + } + return false; + } + + /** + * Indicates delegated transaction finished successfully. + * + * Set written times after outermost transaction finished. + * + * @param moodle_transaction $transaction The transaction to commit. + * @throws dml_transaction_exception Creates and throws transaction related exceptions. + */ + public function commit_delegated_transaction(moodle_transaction $transaction) { + if ($this->written) { + // Adjust the written time. + $now = microtime(true); + foreach ($this->written as $tablename => $when) { + $this->written[$tablename] = $now; + } + } + + parent::commit_delegated_transaction($transaction); + } + + /** + * Parse table names from query. + * + * @param string $sql The sql to use. + * @return array + */ + protected function table_names(string $sql): array { + preg_match_all('/\b'.$this->prefix.'([a-z][A-Za-z0-9_]*)/', $sql, $match); + return $match[1]; + } +} diff --git a/lib/dml/moodle_read_slave_trait.php b/lib/dml/moodle_read_slave_trait.php index d6ef531b5fb..16981a178f2 100644 --- a/lib/dml/moodle_read_slave_trait.php +++ b/lib/dml/moodle_read_slave_trait.php @@ -21,9 +21,15 @@ * @category dml * @copyright 2018 Srdjan Janković, Catalyst IT * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @deprecated Since Moodle 5.0. See MDL-71257. + * @todo Final deprecation in Moodle 6.0. See MDL-83171. */ - -defined('MOODLE_INTERNAL') || die(); +#[\core\attribute\deprecated( + replacement: moodle_read_replica_trait::class, + since: '5.0', + mdl: 'MDL-71257', + reason: 'Renamed' +)] /** * Trait to wrap connect() method of database driver classes that gives @@ -144,8 +150,17 @@ trait moodle_read_slave_trait { * @param array $dboptions driver specific options * @return bool true * @throws dml_connection_exception if error + * @deprecated Since Moodle 5.0. See MDL-71257. + * @todo Final deprecation in Moodle 6.0. See MDL-83171. */ + #[\core\attribute\deprecated( + replacement: 'moodle_read_replica_trait::connect', + since: '5.0', + mdl: 'MDL-71257', + reason: 'Renamed trait' + )] public function connect($dbhost, $dbuser, $dbpass, $dbname, $prefix, ?array $dboptions = null) { + \core\deprecation::emit_deprecation_if_present(__FUNCTION__); $this->pdbhost = $dbhost; $this->pdbuser = $dbuser; $this->pdbpass = $dbpass; @@ -263,24 +278,51 @@ trait moodle_read_slave_trait { /** * Returns whether we want to connect to slave database for read queries. * @return bool Want read only connection + * @deprecated Since Moodle 5.0. See MDL-71257. + * @todo Final deprecation in Moodle 6.0. See MDL-83171. */ + #[\core\attribute\deprecated( + replacement: 'moodle_read_replica_trait::want_read_replica', + since: '5.0', + mdl: 'MDL-71257', + reason: 'Renamed trait' + )] public function want_read_slave(): bool { + \core\deprecation::emit_deprecation_if_present(__FUNCTION__); return $this->wantreadslave; } /** * Returns the number of reads done by the read only database. * @return int Number of reads. + * @deprecated Since Moodle 5.0. See MDL-71257. + * @todo Final deprecation in Moodle 6.0. See MDL-83171. */ + #[\core\attribute\deprecated( + replacement: 'moodle_read_replica_trait::perf_get_reads_replica', + since: '5.0', + mdl: 'MDL-71257', + reason: 'Renamed trait' + )] public function perf_get_reads_slave(): int { + \core\deprecation::emit_deprecation_if_present(__FUNCTION__); return $this->readsslave; } /** * On DBs that support it, switch to transaction mode and begin a transaction * @return moodle_transaction + * @deprecated Since Moodle 5.0. See MDL-71257. + * @todo Final deprecation in Moodle 6.0. See MDL-83171. */ + #[\core\attribute\deprecated( + replacement: 'moodle_read_replica_trait::start_delegated_transaction', + since: '5.0', + mdl: 'MDL-71257', + reason: 'Renamed trait' + )] public function start_delegated_transaction() { + \core\deprecation::emit_deprecation_if_present(__FUNCTION__); $this->set_dbhwrite(); return parent::start_delegated_transaction(); } @@ -405,8 +447,17 @@ trait moodle_read_slave_trait { * @param moodle_transaction $transaction The transaction to commit * @return void * @throws dml_transaction_exception Creates and throws transaction related exceptions. + * @deprecated Since Moodle 5.0. See MDL-71257. + * @todo Final deprecation in Moodle 6.0. See MDL-83171. */ + #[\core\attribute\deprecated( + replacement: 'moodle_read_replica_trait::commit_delegated_transaction', + since: '5.0', + mdl: 'MDL-71257', + reason: 'Renamed trait' + )] public function commit_delegated_transaction(moodle_transaction $transaction) { + \core\deprecation::emit_deprecation_if_present(__FUNCTION__); if ($this->written) { // Adjust the written time. $now = microtime(true); diff --git a/lib/dml/mysqli_native_moodle_database.php b/lib/dml/mysqli_native_moodle_database.php index 0e38f0b3a37..45bd69d463c 100644 --- a/lib/dml/mysqli_native_moodle_database.php +++ b/lib/dml/mysqli_native_moodle_database.php @@ -25,7 +25,7 @@ defined('MOODLE_INTERNAL') || die(); require_once(__DIR__.'/moodle_database.php'); -require_once(__DIR__.'/moodle_read_slave_trait.php'); +require_once(__DIR__.'/moodle_read_replica_trait.php'); require_once(__DIR__.'/mysqli_native_moodle_recordset.php'); require_once(__DIR__.'/mysqli_native_moodle_temptables.php'); @@ -37,8 +37,8 @@ require_once(__DIR__.'/mysqli_native_moodle_temptables.php'); * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class mysqli_native_moodle_database extends moodle_database { - use moodle_read_slave_trait { - can_use_readonly as read_slave_can_use_readonly; + use moodle_read_replica_trait { + can_use_readonly as read_replica_can_use_readonly; } /** @var array $sslmodes */ @@ -652,12 +652,12 @@ class mysqli_native_moodle_database extends moodle_database { * @return bool */ protected function can_use_readonly(int $type, string $sql): bool { - // ... *_LOCK queries always go to master. + // ... *_LOCK queries always go to primary. if (preg_match('/\b(GET|RELEASE)_LOCK/i', $sql)) { return false; } - return $this->read_slave_can_use_readonly($type, $sql); + return $this->read_replica_can_use_readonly($type, $sql); } /** diff --git a/lib/dml/pgsql_native_moodle_database.php b/lib/dml/pgsql_native_moodle_database.php index f7d70c040df..5b9f2f164d9 100644 --- a/lib/dml/pgsql_native_moodle_database.php +++ b/lib/dml/pgsql_native_moodle_database.php @@ -25,7 +25,7 @@ defined('MOODLE_INTERNAL') || die(); require_once(__DIR__.'/moodle_database.php'); -require_once(__DIR__.'/moodle_read_slave_trait.php'); +require_once(__DIR__.'/moodle_read_replica_trait.php'); require_once(__DIR__.'/pgsql_native_moodle_recordset.php'); require_once(__DIR__.'/pgsql_native_moodle_temptables.php'); @@ -37,11 +37,11 @@ require_once(__DIR__.'/pgsql_native_moodle_temptables.php'); * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class pgsql_native_moodle_database extends moodle_database { - use moodle_read_slave_trait { - select_db_handle as read_slave_select_db_handle; - can_use_readonly as read_slave_can_use_readonly; - query_start as read_slave_query_start; - query_end as read_slave_query_end; + use moodle_read_replica_trait { + select_db_handle as read_replica_select_db_handle; + can_use_readonly as read_replica_can_use_readonly; + query_start as read_replica_query_start; + query_end as read_replica_query_end; } /** @var array $sslmodes */ @@ -297,7 +297,7 @@ class pgsql_native_moodle_database extends moodle_database { * @return void */ protected function select_db_handle(int $type, string $sql): void { - $this->read_slave_select_db_handle($type, $sql); + $this->read_replica_select_db_handle($type, $sql); if (preg_match('/^DECLARE (crs\w*) NO SCROLL CURSOR/', $sql, $match)) { $cursor = $match[1]; @@ -318,7 +318,7 @@ class pgsql_native_moodle_database extends moodle_database { * @return bool */ protected function can_use_readonly(int $type, string $sql): bool { - // ... pg_*lock queries always go to master. + // ... pg_*lock queries always go to primary. if (preg_match('/\bpg_\w*lock/', $sql)) { return false; } @@ -328,7 +328,7 @@ class pgsql_native_moodle_database extends moodle_database { return false; } - return $this->read_slave_can_use_readonly($type, $sql); + return $this->read_replica_can_use_readonly($type, $sql); } @@ -341,7 +341,7 @@ class pgsql_native_moodle_database extends moodle_database { * @return void */ protected function query_start($sql, ?array $params, $type, $extrainfo=null) { - $this->read_slave_query_start($sql, $params, $type, $extrainfo); + $this->read_replica_query_start($sql, $params, $type, $extrainfo); // pgsql driver tends to send debug to output, we do not need that. $this->last_error_reporting = error_reporting(0); } @@ -355,7 +355,7 @@ class pgsql_native_moodle_database extends moodle_database { // reset original debug level error_reporting($this->last_error_reporting); try { - $this->read_slave_query_end($result); + $this->read_replica_query_end($result); if ($this->savepointpresent && !in_array( $this->last_type, diff --git a/lib/dml/tests/dml_mysqli_read_slave_test.php b/lib/dml/tests/dml_mysqli_read_replica_test.php similarity index 89% rename from lib/dml/tests/dml_mysqli_read_slave_test.php rename to lib/dml/tests/dml_mysqli_read_replica_test.php index 1e25a16cdfc..a52f7dfbb3d 100644 --- a/lib/dml/tests/dml_mysqli_read_slave_test.php +++ b/lib/dml/tests/dml_mysqli_read_replica_test.php @@ -29,10 +29,10 @@ use moodle_database; defined('MOODLE_INTERNAL') || die(); -require_once(__DIR__.'/fixtures/read_slave_moodle_database_mock_mysqli.php'); +require_once(__DIR__.'/fixtures/read_replica_moodle_database_mock_mysqli.php'); /** - * DML mysqli_native_moodle_database read slave specific tests + * DML mysqli_native_moodle_database read replica specific tests * * @package core * @category dml @@ -40,7 +40,7 @@ require_once(__DIR__.'/fixtures/read_slave_moodle_database_mock_mysqli.php'); * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later * @covers \mysqli_native_moodle_database */ -final class dml_mysqli_read_slave_test extends \database_driver_testcase { +final class dml_mysqli_read_replica_test extends \database_driver_testcase { /** * Test readonly handle is not used for reading from special pg_*() call queries, * pg_try_advisory_lock and pg_advisory_unlock. @@ -48,19 +48,19 @@ final class dml_mysqli_read_slave_test extends \database_driver_testcase { * @return void */ public function test_lock(): void { - $DB = new read_slave_moodle_database_mock_mysqli(); + $DB = new read_replica_moodle_database_mock_mysqli(); - $this->assertEquals(0, $DB->perf_get_reads_slave()); + $this->assertEquals(0, $DB->perf_get_reads_replica()); $DB->query_start("SELECT GET_LOCK('lock',1)", null, SQL_QUERY_SELECT); $this->assertTrue($DB->db_handle_is_rw()); $DB->query_end(null); - $this->assertEquals(0, $DB->perf_get_reads_slave()); + $this->assertEquals(0, $DB->perf_get_reads_replica()); $DB->query_start("SELECT RELEASE_LOCK('lock',1)", null, SQL_QUERY_SELECT); $this->assertTrue($DB->db_handle_is_rw()); $DB->query_end(null); - $this->assertEquals(0, $DB->perf_get_reads_slave()); + $this->assertEquals(0, $DB->perf_get_reads_replica()); } /** @@ -91,25 +91,25 @@ final class dml_mysqli_read_slave_test extends \database_driver_testcase { $db2->connect($cfg->dbhost, $cfg->dbuser, $cfg->dbpass, $cfg->dbname, $cfg->prefix, $cfg->dboptions); $reads = $db2->perf_get_reads(); - $readsprimary = $reads - $db2->perf_get_reads_slave(); + $readsprimary = $reads - $db2->perf_get_reads_replica(); // Readonly handle queries. $db2->setup_is_unicodedb(); $this->assertGreaterThan($reads, $reads = $db2->perf_get_reads()); - $this->assertEquals($readsprimary, $reads - $db2->perf_get_reads_slave()); + $this->assertEquals($readsprimary, $reads - $db2->perf_get_reads_replica()); $db2->get_tables(); $this->assertGreaterThan($reads, $reads = $db2->perf_get_reads()); - $this->assertEquals($readsprimary, $reads - $db2->perf_get_reads_slave()); + $this->assertEquals($readsprimary, $reads - $db2->perf_get_reads_replica()); $db2->get_indexes('course'); $this->assertGreaterThan($reads, $reads = $db2->perf_get_reads()); - $this->assertEquals($readsprimary, $reads - $db2->perf_get_reads_slave()); + $this->assertEquals($readsprimary, $reads - $db2->perf_get_reads_replica()); $db2->get_columns('course'); $this->assertGreaterThan($reads, $reads = $db2->perf_get_reads()); - $this->assertEquals($readsprimary, $reads - $db2->perf_get_reads_slave()); + $this->assertEquals($readsprimary, $reads - $db2->perf_get_reads_replica()); // Readwrite handle queries. @@ -119,16 +119,16 @@ final class dml_mysqli_read_slave_test extends \database_driver_testcase { $rcm->invoke($db2); $this->assertGreaterThan($reads, $reads = $db2->perf_get_reads()); - $this->assertGreaterThan($readsprimary, $readsprimary = $reads - $db2->perf_get_reads_slave()); + $this->assertGreaterThan($readsprimary, $readsprimary = $reads - $db2->perf_get_reads_replica()); } $db2->get_dbengine(); $this->assertGreaterThan($reads, $reads = $db2->perf_get_reads()); - $this->assertGreaterThan($readsprimary, $readsprimary = $reads - $db2->perf_get_reads_slave()); + $this->assertGreaterThan($readsprimary, $readsprimary = $reads - $db2->perf_get_reads_replica()); $db2->get_row_format('course'); $this->assertGreaterThan($reads, $reads = $db2->perf_get_reads()); - $this->assertGreaterThan($readsprimary, $readsprimary = $reads - $db2->perf_get_reads_slave()); + $this->assertGreaterThan($readsprimary, $readsprimary = $reads - $db2->perf_get_reads_replica()); } /** @@ -136,7 +136,7 @@ final class dml_mysqli_read_slave_test extends \database_driver_testcase { * * @return void */ - public function test_real_readslave_connect_fail_host(): void { + public function test_real_readreplica_connect_fail_host(): void { global $DB; if ($DB->get_dbfamily() != 'mysql') { @@ -182,7 +182,7 @@ final class dml_mysqli_read_slave_test extends \database_driver_testcase { * * @return void */ - public function test_real_readslave_connect_fail_dbname(): void { + public function test_real_readreplica_connect_fail_dbname(): void { global $DB; if ($DB->get_dbfamily() != 'mysql') { diff --git a/lib/dml/tests/dml_pgsql_read_slave_test.php b/lib/dml/tests/dml_pgsql_read_replica_test.php similarity index 90% rename from lib/dml/tests/dml_pgsql_read_slave_test.php rename to lib/dml/tests/dml_pgsql_read_replica_test.php index 0fff68d7c71..d164923e378 100644 --- a/lib/dml/tests/dml_pgsql_read_slave_test.php +++ b/lib/dml/tests/dml_pgsql_read_replica_test.php @@ -30,10 +30,10 @@ use xmldb_table; defined('MOODLE_INTERNAL') || die(); -require_once(__DIR__.'/fixtures/read_slave_moodle_database_mock_pgsql.php'); +require_once(__DIR__.'/fixtures/read_replica_moodle_database_mock_pgsql.php'); /** - * DML pgsql_native_moodle_database read slave specific tests + * DML pgsql_native_moodle_database read replica specific tests * * @package core * @category dml @@ -41,14 +41,14 @@ require_once(__DIR__.'/fixtures/read_slave_moodle_database_mock_pgsql.php'); * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later * @covers \pgsql_native_moodle_database */ -class dml_pgsql_read_slave_test extends \advanced_testcase { +class dml_pgsql_read_replica_test extends \advanced_testcase { /** * Test correct database handles are used for cursors * * @return void */ public function test_cursors(): void { - $DB = new read_slave_moodle_database_mock_pgsql(); + $DB = new read_replica_moodle_database_mock_pgsql(); // Declare a cursor on a table that has not been written to. list($sql, $params, $type) = $DB->fix_sql_params("SELECT * FROM {table}"); @@ -96,14 +96,14 @@ class dml_pgsql_read_slave_test extends \advanced_testcase { * @return void */ public function test_read_pg_table(): void { - $DB = new read_slave_moodle_database_mock_pgsql(); + $DB = new read_replica_moodle_database_mock_pgsql(); - $this->assertEquals(0, $DB->perf_get_reads_slave()); + $this->assertEquals(0, $DB->perf_get_reads_replica()); $DB->query_start('SELECT pg_whatever(1)', null, SQL_QUERY_SELECT); $this->assertTrue($DB->db_handle_is_ro()); $DB->query_end(null); - $this->assertEquals(1, $DB->perf_get_reads_slave()); + $this->assertEquals(1, $DB->perf_get_reads_replica()); } /** @@ -113,15 +113,15 @@ class dml_pgsql_read_slave_test extends \advanced_testcase { * @return void */ public function test_read_pg_lock_table(): void { - $DB = new read_slave_moodle_database_mock_pgsql(); + $DB = new read_replica_moodle_database_mock_pgsql(); - $this->assertEquals(0, $DB->perf_get_reads_slave()); + $this->assertEquals(0, $DB->perf_get_reads_replica()); foreach (['pg_try_advisory_lock', 'pg_advisory_unlock'] as $fn) { $DB->query_start("SELECT $fn(1)", null, SQL_QUERY_SELECT); $this->assertTrue($DB->db_handle_is_rw()); $DB->query_end(null); - $this->assertEquals(0, $DB->perf_get_reads_slave()); + $this->assertEquals(0, $DB->perf_get_reads_replica()); } } @@ -154,29 +154,29 @@ class dml_pgsql_read_slave_test extends \advanced_testcase { $db2->connect($cfg->dbhost, $cfg->dbuser, $cfg->dbpass, $cfg->dbname, $cfg->prefix, $cfg->dboptions); $reads = $db2->perf_get_reads(); - $readsprimary = $reads - $db2->perf_get_reads_slave(); + $readsprimary = $reads - $db2->perf_get_reads_replica(); // Readonly handle queries. $db2->get_server_info(); $this->assertGreaterThan($reads, $reads = $db2->perf_get_reads()); - $this->assertGreaterThan($readsprimary, $readsprimary = $reads - $db2->perf_get_reads_slave()); + $this->assertGreaterThan($readsprimary, $readsprimary = $reads - $db2->perf_get_reads_replica()); $db2->setup_is_unicodedb(); $this->assertGreaterThan($reads, $reads = $db2->perf_get_reads()); - $this->assertEquals($readsprimary, $reads - $db2->perf_get_reads_slave()); + $this->assertEquals($readsprimary, $reads - $db2->perf_get_reads_replica()); $db2->get_tables(); $this->assertGreaterThan($reads, $reads = $db2->perf_get_reads()); - $this->assertEquals($readsprimary, $reads - $db2->perf_get_reads_slave()); + $this->assertEquals($readsprimary, $reads - $db2->perf_get_reads_replica()); $db2->get_indexes('course'); $this->assertGreaterThan($reads, $reads = $db2->perf_get_reads()); - $this->assertEquals($readsprimary, $reads - $db2->perf_get_reads_slave()); + $this->assertEquals($readsprimary, $reads - $db2->perf_get_reads_replica()); $db2->get_columns('course'); $this->assertGreaterThan($reads, $reads = $db2->perf_get_reads()); - $this->assertEquals($readsprimary, $reads - $db2->perf_get_reads_slave()); + $this->assertEquals($readsprimary, $reads - $db2->perf_get_reads_replica()); // Readwrite handle queries. @@ -188,7 +188,7 @@ class dml_pgsql_read_slave_test extends \advanced_testcase { $dbman->create_table($table); $db2->get_columns($tablename); $this->assertGreaterThan($reads, $reads = $db2->perf_get_reads()); - $this->assertGreaterThan($readsprimary, $reads - $db2->perf_get_reads_slave()); + $this->assertGreaterThan($readsprimary, $reads - $db2->perf_get_reads_replica()); } /** @@ -233,11 +233,11 @@ class dml_pgsql_read_slave_test extends \advanced_testcase { // We need to go through the creation proces twice. // create_temp_table() performs some reads before the temp table is created. // First time around those reads should go to ro ... - $reads = $db2->perf_get_reads_slave(); + $reads = $db2->perf_get_reads_replica(); $db2->get_columns('silly_test_table'); $db2->get_records('silly_test_table'); - $this->assertEquals($reads, $db2->perf_get_reads_slave()); + $this->assertEquals($reads, $db2->perf_get_reads_replica()); $table2 = new xmldb_table('silly_test_table2'); $table2->add_field('id', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL, XMLDB_SEQUENCE); @@ -248,7 +248,7 @@ class dml_pgsql_read_slave_test extends \advanced_testcase { // ... but once the first temp table is created no more ro reads should occur. $db2->get_columns('silly_test_table2'); $db2->get_records('silly_test_table2'); - $this->assertEquals($reads, $db2->perf_get_reads_slave()); + $this->assertEquals($reads, $db2->perf_get_reads_replica()); // Make database driver happy. $dbman->drop_table($table2); @@ -260,7 +260,7 @@ class dml_pgsql_read_slave_test extends \advanced_testcase { * * @return void */ - public function test_real_readslave_connect_fail(): void { + public function test_real_readreplica_connect_fail(): void { global $DB; if ($DB->get_dbfamily() != 'postgres') { diff --git a/lib/dml/tests/dml_read_slave_test.php b/lib/dml/tests/dml_read_replica_test.php similarity index 85% rename from lib/dml/tests/dml_read_slave_test.php rename to lib/dml/tests/dml_read_replica_test.php index c85f477b773..7b8936c322e 100644 --- a/lib/dml/tests/dml_read_slave_test.php +++ b/lib/dml/tests/dml_read_replica_test.php @@ -27,8 +27,8 @@ namespace core; defined('MOODLE_INTERNAL') || die(); -require_once(__DIR__.'/fixtures/read_slave_moodle_database_table_names.php'); -require_once(__DIR__.'/fixtures/read_slave_moodle_database_special.php'); +require_once(__DIR__.'/fixtures/read_replica_moodle_database_table_names.php'); +require_once(__DIR__.'/fixtures/read_replica_moodle_database_special.php'); require_once(__DIR__.'/../../tests/fixtures/event_fixtures.php'); /** @@ -38,9 +38,9 @@ require_once(__DIR__.'/../../tests/fixtures/event_fixtures.php'); * @category dml * @copyright 2018 Catalyst IT * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - * @covers \moodle_read_slave_trait + * @covers \moodle_read_replica_trait */ -final class dml_read_slave_test extends \database_driver_testcase { +final class dml_read_replica_test extends \database_driver_testcase { /** @var float */ static private $dbreadonlylatency = 0.8; @@ -51,7 +51,7 @@ final class dml_read_slave_test extends \database_driver_testcase { * @param bool $wantlatency * @param mixed $readonly * @param mixed $dbclass - * @return read_slave_moodle_database $db + * @return read_replica_moodle_database $db */ public function new_db( $wantlatency = false, @@ -60,8 +60,8 @@ final class dml_read_slave_test extends \database_driver_testcase { ['dbhost' => 'test_ro2', 'dbport' => 2, 'dbuser' => 'test2', 'dbpass' => 'test2'], ['dbhost' => 'test_ro3', 'dbport' => 3, 'dbuser' => 'test3', 'dbpass' => 'test3'], ], - $dbclass = read_slave_moodle_database::class - ): read_slave_moodle_database { + $dbclass = read_replica_moodle_database::class + ): read_replica_moodle_database { $dbhost = 'test_rw'; $dbname = 'test'; $dbuser = 'test'; @@ -78,8 +78,8 @@ final class dml_read_slave_test extends \database_driver_testcase { } /** - * Asert that the mock handle returned from read_slave_moodle_database methods - * is a readonly slave handle. + * Asert that the mock handle returned from read_replica_moodle_database methods + * is a readonly replica handle. * * @param string $handle * @return void @@ -89,7 +89,7 @@ final class dml_read_slave_test extends \database_driver_testcase { } /** - * moodle_read_slave_trait::table_names() test data provider + * moodle_read_replica_trait::table_names() test data provider * * @return array * @dataProvider table_names_provider @@ -133,7 +133,7 @@ final class dml_read_slave_test extends \database_driver_testcase { } /** - * Test moodle_read_slave_trait::table_names() query parser. + * Test moodle_read_replica_trait::table_names() query parser. * * @param string $sql * @param array $tables @@ -141,7 +141,7 @@ final class dml_read_slave_test extends \database_driver_testcase { * @dataProvider table_names_provider */ public function test_table_names($sql, $tables): void { - $db = new read_slave_moodle_database_table_names(); + $db = new read_replica_moodle_database_table_names(); $this->assertEquals($tables, $db->table_names($db->fix_sql_params($sql)[0])); } @@ -155,19 +155,19 @@ final class dml_read_slave_test extends \database_driver_testcase { public function test_read_read_write_read(): void { $DB = $this->new_db(true); - $this->assertEquals(0, $DB->perf_get_reads_slave()); + $this->assertEquals(0, $DB->perf_get_reads_replica()); $this->assertNull($DB->get_dbhwrite()); $handle = $DB->get_records('table'); $this->assert_readonly_handle($handle); - $readsslave = $DB->perf_get_reads_slave(); - $this->assertGreaterThan(0, $readsslave); + $readsreplica = $DB->perf_get_reads_replica(); + $this->assertGreaterThan(0, $readsreplica); $this->assertNull($DB->get_dbhwrite()); $handle = $DB->get_records('table2'); $this->assert_readonly_handle($handle); - $readsslave = $DB->perf_get_reads_slave(); - $this->assertGreaterThan(1, $readsslave); + $readsreplica = $DB->perf_get_reads_replica(); + $this->assertGreaterThan(1, $readsreplica); $this->assertNull($DB->get_dbhwrite()); $now = microtime(true); @@ -177,14 +177,14 @@ final class dml_read_slave_test extends \database_driver_testcase { if (microtime(true) - $now < self::$dbreadonlylatency) { $handle = $DB->get_records('table'); $this->assertEquals('test_rw::test:test', $handle); - $this->assertEquals($readsslave, $DB->perf_get_reads_slave()); + $this->assertEquals($readsreplica, $DB->perf_get_reads_replica()); sleep(1); } $handle = $DB->get_records('table'); $this->assert_readonly_handle($handle); - $this->assertEquals($readsslave + 1, $DB->perf_get_reads_slave()); + $this->assertEquals($readsreplica + 1, $DB->perf_get_reads_replica()); } /** @@ -195,13 +195,13 @@ final class dml_read_slave_test extends \database_driver_testcase { public function test_read_write_write(): void { $DB = $this->new_db(); - $this->assertEquals(0, $DB->perf_get_reads_slave()); + $this->assertEquals(0, $DB->perf_get_reads_replica()); $this->assertNull($DB->get_dbhwrite()); $handle = $DB->get_records('table'); $this->assert_readonly_handle($handle); - $readsslave = $DB->perf_get_reads_slave(); - $this->assertGreaterThan(0, $readsslave); + $readsreplica = $DB->perf_get_reads_replica(); + $this->assertGreaterThan(0, $readsreplica); $this->assertNull($DB->get_dbhwrite()); $handle = $DB->insert_record_raw('table', array('name' => 'blah')); @@ -209,7 +209,7 @@ final class dml_read_slave_test extends \database_driver_testcase { $handle = $DB->update_record_raw('table', array('id' => 1, 'name' => 'blah2')); $this->assertEquals('test_rw::test:test', $handle); - $this->assertEquals($readsslave, $DB->perf_get_reads_slave()); + $this->assertEquals($readsreplica, $DB->perf_get_reads_replica()); } /** @@ -220,34 +220,34 @@ final class dml_read_slave_test extends \database_driver_testcase { public function test_write_read_read(): void { $DB = $this->new_db(); - $this->assertEquals(0, $DB->perf_get_reads_slave()); + $this->assertEquals(0, $DB->perf_get_reads_replica()); $this->assertNull($DB->get_dbhwrite()); $handle = $DB->insert_record_raw('table', array('name' => 'blah')); $this->assertEquals('test_rw::test:test', $handle); - $this->assertEquals(0, $DB->perf_get_reads_slave()); + $this->assertEquals(0, $DB->perf_get_reads_replica()); $handle = $DB->get_records('table'); $this->assertEquals('test_rw::test:test', $handle); - $this->assertEquals(0, $DB->perf_get_reads_slave()); + $this->assertEquals(0, $DB->perf_get_reads_replica()); $handle = $DB->get_records_sql("SELECT * FROM {table2} JOIN {table}"); $this->assertEquals('test_rw::test:test', $handle); - $this->assertEquals(0, $DB->perf_get_reads_slave()); + $this->assertEquals(0, $DB->perf_get_reads_replica()); sleep(1); $handle = $DB->get_records('table'); $this->assert_readonly_handle($handle); - $this->assertEquals(1, $DB->perf_get_reads_slave()); + $this->assertEquals(1, $DB->perf_get_reads_replica()); $handle = $DB->get_records('table2'); $this->assert_readonly_handle($handle); - $this->assertEquals(2, $DB->perf_get_reads_slave()); + $this->assertEquals(2, $DB->perf_get_reads_replica()); $handle = $DB->get_records_sql("SELECT * FROM {table2} JOIN {table}"); $this->assert_readonly_handle($handle); - $this->assertEquals(3, $DB->perf_get_reads_slave()); + $this->assertEquals(3, $DB->perf_get_reads_replica()); } /** @@ -259,12 +259,12 @@ final class dml_read_slave_test extends \database_driver_testcase { $DB = $this->new_db(); $DB->add_temptable('temptable1'); - $this->assertEquals(0, $DB->perf_get_reads_slave()); + $this->assertEquals(0, $DB->perf_get_reads_replica()); $this->assertNull($DB->get_dbhwrite()); $handle = $DB->get_records('temptable1'); $this->assertEquals('test_rw::test:test', $handle); - $this->assertEquals(0, $DB->perf_get_reads_slave()); + $this->assertEquals(0, $DB->perf_get_reads_replica()); $DB->delete_temptable('temptable1'); } @@ -277,12 +277,12 @@ final class dml_read_slave_test extends \database_driver_testcase { public function test_read_excluded_tables(): void { $DB = $this->new_db(); - $this->assertEquals(0, $DB->perf_get_reads_slave()); + $this->assertEquals(0, $DB->perf_get_reads_replica()); $this->assertNull($DB->get_dbhwrite()); $handle = $DB->get_records('exclude'); $this->assertEquals('test_rw::test:test', $handle); - $this->assertEquals(0, $DB->perf_get_reads_slave()); + $this->assertEquals(0, $DB->perf_get_reads_replica()); } /** @@ -383,7 +383,7 @@ final class dml_read_slave_test extends \database_driver_testcase { $this->with_global_db(function () { global $DB; - $DB = $this->new_db(true, ['test_ro'], read_slave_moodle_database_special::class); + $DB = $this->new_db(true, ['test_ro'], read_replica_moodle_database_special::class); $DB->set_tables([ 'config_plugins' => [ 'columns' => [ @@ -456,13 +456,13 @@ final class dml_read_slave_test extends \database_driver_testcase { $DB = $this->new_db(false, 'test_ro_fail'); - $this->assertEquals(0, $DB->perf_get_reads_slave()); + $this->assertEquals(0, $DB->perf_get_reads_replica()); $this->assertNotNull($DB->get_dbhwrite()); $handle = $DB->get_records('table'); $this->assertEquals('test_rw::test:test', $handle); - $readsslave = $DB->perf_get_reads_slave(); - $this->assertEquals(0, $readsslave); + $readsreplica = $DB->perf_get_reads_replica(); + $this->assertEquals(0, $readsreplica); $debugging = array_map(function ($d) { return $d->message; @@ -475,7 +475,7 @@ final class dml_read_slave_test extends \database_driver_testcase { } /** - * In multiple slaves scenario, test failed readonly connection falls back to + * In multiple replicas scenario, test failed readonly connection falls back to * another readonly connection. * * @return void @@ -485,13 +485,13 @@ final class dml_read_slave_test extends \database_driver_testcase { $DB = $this->new_db(false, ['test_ro_fail', 'test_ro_ok']); - $this->assertEquals(0, $DB->perf_get_reads_slave()); + $this->assertEquals(0, $DB->perf_get_reads_replica()); $this->assertNull($DB->get_dbhwrite()); $handle = $DB->get_records('table'); $this->assertEquals('test_ro_ok::test:test', $handle); - $readsslave = $DB->perf_get_reads_slave(); - $this->assertEquals(1, $readsslave); + $readsreplica = $DB->perf_get_reads_replica(); + $this->assertEquals(1, $readsreplica); $debugging = array_map(function ($d) { return $d->message; @@ -530,7 +530,7 @@ final class dml_read_slave_test extends \database_driver_testcase { $this->with_global_db(function () { global $DB; - $DB = $this->new_db(true, ['test_ro'], read_slave_moodle_database_special::class); + $DB = $this->new_db(true, ['test_ro'], read_replica_moodle_database_special::class); $DB->set_tables([ 'lock_db' => [ 'columns' => [ @@ -540,7 +540,7 @@ final class dml_read_slave_test extends \database_driver_testcase { ] ]); - $this->assertEquals(0, $DB->perf_get_reads_slave()); + $this->assertEquals(0, $DB->perf_get_reads_replica()); $this->assertNull($DB->get_dbhwrite()); $lockfactory = new \core\lock\db_record_lock_factory('default'); @@ -550,7 +550,7 @@ final class dml_read_slave_test extends \database_driver_testcase { $lock = $lockfactory->get_lock('abc', 2); $lock->release(); - $this->assertEquals(0, $DB->perf_get_reads_slave()); + $this->assertEquals(0, $DB->perf_get_reads_replica()); $this->assertTrue($DB->perf_get_reads() > 0); }); } @@ -565,7 +565,7 @@ final class dml_read_slave_test extends \database_driver_testcase { global $DB, $CFG; $CFG->dbsessions = true; - $DB = $this->new_db(true, ['test_ro'], read_slave_moodle_database_special::class); + $DB = $this->new_db(true, ['test_ro'], read_replica_moodle_database_special::class); $DB->set_tables([ 'sessions' => [ 'columns' => [ @@ -574,13 +574,13 @@ final class dml_read_slave_test extends \database_driver_testcase { ] ]); - $this->assertEquals(0, $DB->perf_get_reads_slave()); + $this->assertEquals(0, $DB->perf_get_reads_replica()); $this->assertNull($DB->get_dbhwrite()); $session = new \core\session\database(); $session->read('dummy'); - $this->assertEquals(0, $DB->perf_get_reads_slave()); + $this->assertEquals(0, $DB->perf_get_reads_replica()); $this->assertTrue($DB->perf_get_reads() > 0); }); diff --git a/lib/dml/tests/dml_test.php b/lib/dml/tests/dml_test.php index d4390771354..3f3d625db80 100644 --- a/lib/dml/tests/dml_test.php +++ b/lib/dml/tests/dml_test.php @@ -5706,9 +5706,9 @@ EOD; if (!isset($cfg->dboptions)) { $cfg->dboptions = array(); } - // If we have a readonly slave situation, we need to either observe + // If we have a readonly replica situation, we need to either observe // the latency, or if the latency is not specified we need to take - // the slave out because the table may not have propagated yet. + // the replica out because the table may not have propagated yet. if (isset($cfg->dboptions['readonly'])) { if (isset($cfg->dboptions['readonly']['latency'])) { usleep(intval(1000000 * $cfg->dboptions['readonly']['latency'])); diff --git a/lib/dml/tests/fixtures/read_slave_moodle_database.php b/lib/dml/tests/fixtures/read_replica_moodle_database.php similarity index 95% rename from lib/dml/tests/fixtures/read_slave_moodle_database.php rename to lib/dml/tests/fixtures/read_replica_moodle_database.php index 3a6f1d04b8b..a5a840254d7 100644 --- a/lib/dml/tests/fixtures/read_slave_moodle_database.php +++ b/lib/dml/tests/fixtures/read_replica_moodle_database.php @@ -15,7 +15,7 @@ // along with Moodle. If not, see . /** - * Database driver test class for testing moodle_read_slave_trait + * Database driver test class for testing moodle_read_replica_trait * * @package core * @category dml @@ -28,18 +28,18 @@ namespace core; defined('MOODLE_INTERNAL') || die(); require_once(__DIR__.'/test_moodle_database.php'); -require_once(__DIR__.'/../../moodle_read_slave_trait.php'); +require_once(__DIR__.'/../../moodle_read_replica_trait.php'); /** - * Database driver test class with moodle_read_slave_trait + * Database driver test class with moodle_read_replica_trait * * @package core * @category dml * @copyright 2018 Catalyst IT * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -class read_slave_moodle_database extends test_moodle_database { - use \moodle_read_slave_trait; +class read_replica_moodle_database extends test_moodle_database { + use \moodle_read_replica_trait; /** @var string */ protected $handle; diff --git a/lib/dml/tests/fixtures/read_slave_moodle_database_mock_mysqli.php b/lib/dml/tests/fixtures/read_replica_moodle_database_mock_mysqli.php similarity index 90% rename from lib/dml/tests/fixtures/read_slave_moodle_database_mock_mysqli.php rename to lib/dml/tests/fixtures/read_replica_moodle_database_mock_mysqli.php index 14289a1d5d3..66a57ef04a4 100644 --- a/lib/dml/tests/fixtures/read_slave_moodle_database_mock_mysqli.php +++ b/lib/dml/tests/fixtures/read_replica_moodle_database_mock_mysqli.php @@ -15,7 +15,7 @@ // along with Moodle. If not, see . /** - * Database driver test class for testing mysqli_native_moodle_database with moodle_read_slave_trait + * Database driver test class for testing mysqli_native_moodle_database with moodle_read_replica_trait * * @package core * @category dml @@ -28,7 +28,7 @@ namespace core; defined('MOODLE_INTERNAL') || die(); require_once(__DIR__.'/../../mysqli_native_moodle_database.php'); -require_once(__DIR__.'/test_moodle_read_slave_trait.php'); +require_once(__DIR__.'/test_moodle_read_replica_trait.php'); /** * Database driver mock test class that exposes some methods @@ -38,8 +38,8 @@ require_once(__DIR__.'/test_moodle_read_slave_trait.php'); * @copyright 2018 Catalyst IT * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -class read_slave_moodle_database_mock_mysqli extends \mysqli_native_moodle_database { - use test_moodle_read_slave_trait; +class read_replica_moodle_database_mock_mysqli extends \mysqli_native_moodle_database { + use test_moodle_read_replica_trait; /** * Return tables in database WITHOUT current prefix diff --git a/lib/dml/tests/fixtures/read_slave_moodle_database_mock_pgsql.php b/lib/dml/tests/fixtures/read_replica_moodle_database_mock_pgsql.php similarity index 84% rename from lib/dml/tests/fixtures/read_slave_moodle_database_mock_pgsql.php rename to lib/dml/tests/fixtures/read_replica_moodle_database_mock_pgsql.php index a59573b35c1..e0a8029749b 100644 --- a/lib/dml/tests/fixtures/read_slave_moodle_database_mock_pgsql.php +++ b/lib/dml/tests/fixtures/read_replica_moodle_database_mock_pgsql.php @@ -15,7 +15,7 @@ // along with Moodle. If not, see . /** - * Database driver test class for testing pgsql_native_moodle_database with moodle_read_slave_trait + * Database driver test class for testing pgsql_native_moodle_database with moodle_read_replica_trait * * @package core * @category dml @@ -28,7 +28,7 @@ namespace core; defined('MOODLE_INTERNAL') || die(); require_once(__DIR__.'/../../pgsql_native_moodle_database.php'); -require_once(__DIR__.'/test_moodle_read_slave_trait.php'); +require_once(__DIR__.'/test_moodle_read_replica_trait.php'); /** * Database driver mock test class that exposes some methods @@ -38,6 +38,6 @@ require_once(__DIR__.'/test_moodle_read_slave_trait.php'); * @copyright 2018 Catalyst IT * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -class read_slave_moodle_database_mock_pgsql extends \pgsql_native_moodle_database { - use test_moodle_read_slave_trait; +class read_replica_moodle_database_mock_pgsql extends \pgsql_native_moodle_database { + use test_moodle_read_replica_trait; } diff --git a/lib/dml/tests/fixtures/read_slave_moodle_database_special.php b/lib/dml/tests/fixtures/read_replica_moodle_database_special.php similarity index 88% rename from lib/dml/tests/fixtures/read_slave_moodle_database_special.php rename to lib/dml/tests/fixtures/read_replica_moodle_database_special.php index ad7a4988462..d21e55948e2 100644 --- a/lib/dml/tests/fixtures/read_slave_moodle_database_special.php +++ b/lib/dml/tests/fixtures/read_replica_moodle_database_special.php @@ -15,7 +15,7 @@ // along with Moodle. If not, see . /** - * Database driver test class for testing moodle_read_slave_trait + * Database driver test class for testing moodle_read_replica_trait * * @package core * @category dml @@ -27,17 +27,17 @@ namespace core; defined('MOODLE_INTERNAL') || die(); -require_once(__DIR__.'/read_slave_moodle_database.php'); +require_once(__DIR__.'/read_replica_moodle_database.php'); /** - * Database driver mock test class that uses read_slave_moodle_recordset_special + * Database driver mock test class that uses read_replica_moodle_recordset_special * * @package core * @category dml * @copyright 2018 Catalyst IT * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -class read_slave_moodle_database_special extends read_slave_moodle_database { +class read_replica_moodle_database_special extends read_replica_moodle_database { /** * Returns empty array * @param string $sql the SQL select query to execute. @@ -52,7 +52,7 @@ class read_slave_moodle_database_special extends read_slave_moodle_database { } /** - * Returns read_slave_moodle_database::get_records_sql() + * Returns read_replica_moodle_database::get_records_sql() * For the tests where we need both fake result and dbhandle info. * @param string $sql the SQL select query to execute. * @param array $params array of sql parameters @@ -74,7 +74,7 @@ class read_slave_moodle_database_special extends read_slave_moodle_database { */ public function get_recordset_sql($sql, ?array $params = null, $limitfrom = 0, $limitnum = 0) { $dbhandle = parent::get_recordset_sql($sql, $params); - return new read_slave_moodle_recordset_special(); + return new read_replica_moodle_recordset_special(); } /** @@ -97,7 +97,7 @@ class read_slave_moodle_database_special extends read_slave_moodle_database { * @copyright 2018 Catalyst IT * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -class read_slave_moodle_recordset_special extends \moodle_recordset { +class read_replica_moodle_recordset_special extends \moodle_recordset { /** * Iterator interface * @return void diff --git a/lib/dml/tests/fixtures/read_slave_moodle_database_table_names.php b/lib/dml/tests/fixtures/read_replica_moodle_database_table_names.php similarity index 86% rename from lib/dml/tests/fixtures/read_slave_moodle_database_table_names.php rename to lib/dml/tests/fixtures/read_replica_moodle_database_table_names.php index c5ec5fff7e8..02dcb4d33b4 100644 --- a/lib/dml/tests/fixtures/read_slave_moodle_database_table_names.php +++ b/lib/dml/tests/fixtures/read_replica_moodle_database_table_names.php @@ -15,7 +15,7 @@ // along with Moodle. If not, see . /** - * Database driver test class for testing moodle_read_slave_trait + * Database driver test class for testing moodle_read_replica_trait * * @package core * @category dml @@ -27,7 +27,7 @@ namespace core; defined('MOODLE_INTERNAL') || die(); -require_once(__DIR__.'/read_slave_moodle_database.php'); +require_once(__DIR__.'/read_replica_moodle_database.php'); /** * Database driver test class that exposes table_names() @@ -37,7 +37,7 @@ require_once(__DIR__.'/read_slave_moodle_database.php'); * @copyright 2018 Catalyst IT * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -class read_slave_moodle_database_table_names extends read_slave_moodle_database { +class read_replica_moodle_database_table_names extends read_replica_moodle_database { /** * @var string */ diff --git a/lib/dml/tests/fixtures/read_slave_moodle_recordset_special.php b/lib/dml/tests/fixtures/read_replica_moodle_recordset_special.php similarity index 92% rename from lib/dml/tests/fixtures/read_slave_moodle_recordset_special.php rename to lib/dml/tests/fixtures/read_replica_moodle_recordset_special.php index 67115a7abe8..9a43639d320 100644 --- a/lib/dml/tests/fixtures/read_slave_moodle_recordset_special.php +++ b/lib/dml/tests/fixtures/read_replica_moodle_recordset_special.php @@ -15,7 +15,7 @@ // along with Moodle. If not, see . /** - * Database driver test class for testing moodle_read_slave_trait + * Database driver test class for testing moodle_read_replica_trait * * @package core * @category dml @@ -33,7 +33,7 @@ defined('MOODLE_INTERNAL') || die(); * @copyright 2018 Catalyst IT * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -class read_slave_moodle_recordset_special extends moodle_recordset { +class read_replica_moodle_recordset_special extends moodle_recordset { /** * Iterator interface * @return void diff --git a/lib/dml/tests/fixtures/test_moodle_read_slave_trait.php b/lib/dml/tests/fixtures/test_moodle_read_replica_trait.php similarity index 91% rename from lib/dml/tests/fixtures/test_moodle_read_slave_trait.php rename to lib/dml/tests/fixtures/test_moodle_read_replica_trait.php index 6826c3d9362..7e2d0fe05b6 100644 --- a/lib/dml/tests/fixtures/test_moodle_read_slave_trait.php +++ b/lib/dml/tests/fixtures/test_moodle_read_replica_trait.php @@ -15,7 +15,7 @@ // along with Moodle. If not, see . /** - * Read slave helper that exposes selected moodle_read_slave_trait metods + * Read replica helper that exposes selected moodle_read_replica_trait mehtods. * * @package core * @category dml @@ -28,14 +28,14 @@ namespace core; use ReflectionProperty; /** - * Read slave helper that exposes selected moodle_read_slave_trait metods + * Read replica helper that exposes selected moodle_read_replica_trait methods. * * @package core * @category dml * @copyright 2018 Catalyst IT * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -trait test_moodle_read_slave_trait { +trait test_moodle_read_replica_trait { /** * Constructs a mock db driver * @@ -52,7 +52,7 @@ trait test_moodle_read_slave_trait { $this->prefix = 'test_'; // Default, not to leave empty. - $rcp = new ReflectionProperty(parent::class, 'wantreadslave'); + $rcp = new ReflectionProperty(parent::class, 'wantreadreplica'); $rcp->setValue($this, true); $this->dbhwrite = $rw; diff --git a/lib/moodlelib.php b/lib/moodlelib.php index 9bb601c258c..8d341200759 100644 --- a/lib/moodlelib.php +++ b/lib/moodlelib.php @@ -9012,10 +9012,10 @@ function get_performance_info() { $info['html'] .= '
  • DB reads/writes: '.$info['dbqueries'].'
  • '; $info['txt'] .= 'db reads/writes: '.$info['dbqueries'].' '; - if ($DB->want_read_slave()) { - $info['dbreads_slave'] = $DB->perf_get_reads_slave(); - $info['html'] .= '
  • DB reads from slave: '.$info['dbreads_slave'].'
  • '; - $info['txt'] .= 'db reads from slave: '.$info['dbreads_slave'].' '; + if ($DB->want_read_replica()) { + $info['dbreads_replica'] = $DB->perf_get_reads_replica(); + $info['html'] .= '
  • DB reads from replica: '.$info['dbreads_replica'].'
  • '; + $info['txt'] .= 'db reads from replica: '.$info['dbreads_replica'].' '; } $info['dbtime'] = round($DB->perf_get_queries_time(), 5);