*/
private $mTrxWriteDuration = 0.0;
+ /** @var IDatabase|null Lazy handle to the master DB this server replicates from */
+ private $lazyMasterHandle;
+
/**
* @since 1.21
* @var resource File handle for upgrade
}
}
+ /**
+ * Set a lazy-connecting DB handle to the master DB (for replication status purposes)
+ *
+ * @param IDatabase $conn
+ * @since 1.27
+ */
+ public function setLazyMasterHandle( IDatabase $conn ) {
+ $this->lazyMasterHandle = $conn;
+ }
+
+ /**
+ * @return IDatabase|null
+ * @see setLazyMasterHandle()
+ * @since 1.27
+ */
+ public function getLazyMasterHandle() {
+ return $this->lazyMasterHandle;
+ }
+
/**
* @return TransactionProfiler
*/
}
if ( $this->debug() ) {
- wfDebugLog( 'queries', sprintf( "%s: %s", $this->mDBname, $sql ) );
+ wfDebugLog( 'queries', sprintf( "%s: %s", $this->mDBname, $commentedSql ) );
}
$queryId = MWDebug::query( $sql, $fname, $isMaster );
* @param string|array $cond The condition array. See DatabaseBase::select() for details.
* @param string $fname The function name of the caller.
* @param string|array $options The query options. See DatabaseBase::select() for details.
+ * @param string|array $join_conds The join conditions. See DatabaseBase::select() for details.
*
* @return bool|array The values from the field, or false on failure
* @throws DBUnexpectedError
* @since 1.25
*/
public function selectFieldValues(
- $table, $var, $cond = '', $fname = __METHOD__, $options = array()
+ $table, $var, $cond = '', $fname = __METHOD__, $options = array(), $join_conds = array()
) {
if ( $var === '*' ) { // sanity
throw new DBUnexpectedError( $this, "Cannot use a * field: got '$var'" );
$options = array( $options );
}
- $res = $this->select( $table, $var, $cond, $fname, $options );
+ $res = $this->select( $table, $var, $cond, $fname, $options, $join_conds );
if ( $res === false ) {
return false;
}
list( $phpCallback ) = $callback;
$this->clearFlag( DBO_TRX ); // make each query its own transaction
call_user_func( $phpCallback );
- $this->setFlag( $autoTrx ? DBO_TRX : 0 ); // restore automatic begin()
+ if ( $autoTrx ) {
+ $this->setFlag( DBO_TRX ); // restore automatic begin()
+ } else {
+ $this->clearFlag( DBO_TRX ); // restore auto-commit
+ }
} catch ( Exception $e ) {
if ( $ePrior ) {
MWExceptionHandler::logException( $ePrior );
}
$ePrior = $e;
+ // Some callbacks may use startAtomic/endAtomic, so make sure
+ // their transactions are ended so other callbacks don't fail
+ if ( $this->trxLevel() ) {
+ $this->rollback( __METHOD__ );
+ }
}
}
} while ( count( $this->mTrxIdleCallbacks ) );
}
}
+ final public function doAtomicSection( $fname, $callback ) {
+ if ( !is_callable( $callback ) ) {
+ throw new UnexpectedValueException( "Invalid callback." );
+ };
+
+ $this->startAtomic( $fname );
+ try {
+ call_user_func_array( $callback, array( $this, $fname ) );
+ } catch ( Exception $e ) {
+ $this->rollback( $fname );
+ throw $e;
+ }
+ $this->endAtomic( $fname );
+ }
+
/**
* Begin a transaction. If a transaction is already in progress,
* that transaction will be committed before the new transaction is started.
return true;
}
- /**
- * Get the slave lag when the current transaction started
- * or a general lag estimate if not transaction is active
- *
- * This is useful when transactions might use snapshot isolation
- * (e.g. REPEATABLE-READ in innodb), so the "real" lag of that data
- * is this lag plus transaction duration. If they don't, it is still
- * safe to be pessimistic. In AUTO-COMMIT mode, this still gives an
- * indication of the staleness of subsequent reads.
- *
- * @return array ('lag': seconds, 'since': UNIX timestamp of BEGIN)
- * @since 1.27
- */
public function getSessionLagStatus() {
return $this->getTransactionLagStatus() ?: $this->getApproximateLagStatus();
}
* is this lag plus transaction duration. If they don't, it is still
* safe to be pessimistic. This returns null if there is no transaction.
*
- * @return array|null ('lag': seconds, 'since': UNIX timestamp of BEGIN)
+ * @return array|null ('lag': seconds or false on error, 'since': UNIX timestamp of BEGIN)
* @since 1.27
*/
public function getTransactionLagStatus() {
/**
* Get a slave lag estimate for this server
*
- * @return array ('lag': seconds, 'since': UNIX timestamp of estimate)
+ * @return array ('lag': seconds or false on error, 'since': UNIX timestamp of estimate)
* @since 1.27
*/
public function getApproximateLagStatus() {
* @param IDatabase $db1
* @param IDatabase ...
* @return array Map of values:
- * - lag: highest lag of any of the DBs
+ * - lag: highest lag of any of the DBs or false on error (e.g. replication stopped)
* - since: oldest UNIX timestamp of any of the DB lag estimates
* - pending: whether any of the DBs have uncommitted changes
* @since 1.27
foreach ( func_get_args() as $db ) {
/** @var IDatabase $db */
$status = $db->getSessionLagStatus();
- $res['lag'] = max( $res['lag'], $status['lag'] );
+ if ( $status['lag'] === false ) {
+ $res['lag'] = false;
+ } elseif ( $res['lag'] !== false ) {
+ $res['lag'] = max( $res['lag'], $status['lag'] );
+ }
$res['since'] = min( $res['since'], $status['since'] );
$res['pending'] = $res['pending'] ?: $db->writesPending();
}
return $res;
}
- /**
- * Get slave lag. Currently supported only by MySQL.
- *
- * Note that this function will generate a fatal error on many
- * installations. Most callers should use LoadBalancer::safeGetLag()
- * instead.
- *
- * @return int Database replication lag in seconds
- */
public function getLag() {
return 0;
}