*/ final class MigrationsLock { /** * Name of the options row holding the lock. * * @since 4.3.2 * @var string */ const OPTION = 'actirise_migrations_lock'; /** * Age after which a held lock is considered abandoned, in seconds. * * @since 4.3.2 * @var int */ const TTL = 600; /** * Take the lock. * * @since 4.3.2 * @return bool Whether this caller now holds it. */ public static function acquire() { /** @var \wpdb $wpdb */ global $wpdb; $now = (string) time(); $insert = $wpdb->prepare( // @phpstan-ignore-next-line argument.type "INSERT IGNORE INTO {$wpdb->options} (option_name, option_value, autoload) VALUES (%s, %s, 'no')", // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared self::OPTION, $now ); if ( is_string( $insert ) && 1 === $wpdb->query( $insert ) ) { // phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.NotPrepared -- Prepared just above. return true; } $held_since = $wpdb->get_var( // phpcs:ignore WordPress.DB.DirectDatabaseQuery $wpdb->prepare( // @phpstan-ignore-next-line argument.type "SELECT option_value FROM {$wpdb->options} WHERE option_name = %s", // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared self::OPTION ) ); if ( is_numeric( $held_since ) && (int) $now - (int) $held_since < self::TTL ) { return false; } // Conditional on the value just read, so of two callers finding the same // stale lock only one takes it over. $takeover = $wpdb->prepare( // @phpstan-ignore-next-line argument.type "UPDATE {$wpdb->options} SET option_value = %s WHERE option_name = %s AND option_value = %s", // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared $now, self::OPTION, is_scalar( $held_since ) ? (string) $held_since : '' ); return is_string( $takeover ) && 1 === $wpdb->query( $takeover ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.NotPrepared -- Prepared just above. } /** * Release the lock. * * @since 4.3.2 * @return void */ public static function release() { /** @var \wpdb $wpdb */ global $wpdb; $wpdb->delete( $wpdb->options, array( 'option_name' => self::OPTION ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery } }