mirror of
https://github.com/NNTmux/newznab-tmux.git
synced 2026-08-28 17:01:16 +00:00
CS fixes
This commit is contained in:
@@ -50,6 +50,19 @@ return new class extends Migration
|
||||
'ix_releases_nzb_creation_queue',
|
||||
];
|
||||
|
||||
/**
|
||||
* Narrowed to `CHAR(32) ascii` as part of this rebuild rather than in a
|
||||
* follow-up migration: the `guid` charset change already forces
|
||||
* `ALGORITHM=COPY`, so folding these in costs nothing, whereas a separate
|
||||
* migration would force a second full table rebuild.
|
||||
*
|
||||
* @var list<string>
|
||||
*/
|
||||
private const array CLAIM_TOKEN_COLUMNS = [
|
||||
'nzb_creation_claim_token',
|
||||
'additional_pp_claim_token',
|
||||
];
|
||||
|
||||
public function up(): void
|
||||
{
|
||||
if (! Schema::hasTable('releases')) {
|
||||
@@ -275,6 +288,11 @@ return new class extends Migration
|
||||
|
||||
$specifications[] = 'MODIFY `guid` CHAR(36) CHARACTER SET ascii COLLATE ascii_general_ci NOT NULL';
|
||||
$specifications[] = "MODIFY `leftguid` CHAR(1) CHARACTER SET ascii COLLATE ascii_general_ci NOT NULL COMMENT 'The first letter of the release guid'";
|
||||
foreach (self::CLAIM_TOKEN_COLUMNS as $column) {
|
||||
if (Schema::hasColumn('releases', $column)) {
|
||||
$specifications[] = 'MODIFY `'.$column.'` CHAR(32) CHARACTER SET ascii COLLATE ascii_general_ci NULL';
|
||||
}
|
||||
}
|
||||
foreach (self::REMOVED_RELEASE_COLUMNS as $column) {
|
||||
if (Schema::hasColumn('releases', $column)) {
|
||||
$specifications[] = 'DROP COLUMN `'.$column.'`';
|
||||
@@ -286,7 +304,7 @@ return new class extends Migration
|
||||
'ADD UNIQUE INDEX `ux_releases_guid` (`guid`)',
|
||||
'ADD INDEX `ix_releases_predb_id` (`predb_id`)',
|
||||
'ADD INDEX `ix_releases_size` (`size`)',
|
||||
'ADD INDEX `ix_releases_add_pp_claim_queue` (`passwordstatus`, `haspreview`, `nzbstatus`, `leftguid`, `postdate` DESC, `id`, `additional_pp_claimed_at`)',
|
||||
'ADD INDEX `ix_releases_add_pp_claim_queue` (`passwordstatus`, `haspreview`, `nzbstatus`, `leftguid`, `postdate` DESC, `id`, `additional_pp_claimed_at`, `size`)',
|
||||
'ADD INDEX `ix_releases_nzb_creation_group_queue` (`nzbstatus`, `groups_id`, `postdate` DESC, `id`, `nzb_creation_claimed_at`)',
|
||||
'ADD INDEX `ix_releases_nzb_creation_global_queue` (`nzbstatus`, `postdate` DESC, `id`, `nzb_creation_claimed_at`)',
|
||||
];
|
||||
@@ -311,7 +329,7 @@ return new class extends Migration
|
||||
$table->index('predb_id', 'ix_releases_predb_id');
|
||||
$table->index('size', 'ix_releases_size');
|
||||
$table->index(
|
||||
['passwordstatus', 'haspreview', 'nzbstatus', 'leftguid', 'postdate', 'id', 'additional_pp_claimed_at'],
|
||||
['passwordstatus', 'haspreview', 'nzbstatus', 'leftguid', 'postdate', 'id', 'additional_pp_claimed_at', 'size'],
|
||||
'ix_releases_add_pp_claim_queue',
|
||||
);
|
||||
$table->index(
|
||||
@@ -345,6 +363,8 @@ return new class extends Migration
|
||||
...$specifications,
|
||||
'MODIFY `guid` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL',
|
||||
"MODIFY `leftguid` CHAR(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'The first letter of the release guid'",
|
||||
'MODIFY `nzb_creation_claim_token` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL',
|
||||
'MODIFY `additional_pp_claim_token` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL',
|
||||
'ADD COLUMN `updatetime` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP AFTER `adddate`',
|
||||
'ADD COLUMN `gid` VARCHAR(32) NULL AFTER `updatetime`',
|
||||
'ADD COLUMN `source` SMALLINT UNSIGNED NULL',
|
||||
|
||||
+69
-45
@@ -9,22 +9,30 @@ use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
/**
|
||||
* Follow-up to the releases normalization rebuild.
|
||||
* Catch-up migration for installs that already ran
|
||||
* `2026_08_13_001652_normalize_and_optimize_releases_table` before it was
|
||||
* extended to cover these two changes:
|
||||
*
|
||||
* 1. Appends `size` to `ix_releases_add_pp_claim_queue`. Every additional
|
||||
* 1. `size` appended to `ix_releases_add_pp_claim_queue`. Every additional
|
||||
* post-processing candidate query filters `size > min AND size < max`
|
||||
* ({@see AdditionalCandidateQuery::applyPredicates()}),
|
||||
* but `size` was not in the index, so each candidate that later failed the
|
||||
* size filter still cost a primary key lookup. Appending it after the
|
||||
* existing columns keeps the equality prefix and the `postdate DESC`
|
||||
* ordering intact while enabling index condition pushdown.
|
||||
* 2. Narrows both claim tokens to `CHAR(32) ascii`. They only ever hold
|
||||
* ({@see AdditionalCandidateQuery::applyPredicates()}), but `size` was not in
|
||||
* the index, so each candidate that later failed the size filter still cost a
|
||||
* primary key lookup. Appending it after the existing columns keeps the
|
||||
* equality prefix and the `postdate DESC` ordering intact while enabling
|
||||
* index condition pushdown.
|
||||
* 2. Both claim tokens narrowed to `CHAR(32) ascii`. They only ever hold
|
||||
* `bin2hex(random_bytes(16))`, so `VARCHAR(64)` utf8mb4 reserved four bytes
|
||||
* per character for hex digits.
|
||||
*
|
||||
* `releases.imdbid` is deliberately left alone: it joins `movieinfo.imdbid`,
|
||||
* and changing the charset on one side only would force an implicit conversion
|
||||
* that disables index usage on that join.
|
||||
* Both now happen inside the normalization rebuild's single `ALTER`, because the
|
||||
* claim token type change is `ALGORITHM=COPY` only and would otherwise force a
|
||||
* second full table rebuild. This migration therefore no-ops on any install that
|
||||
* ran the merged version, and `down()` is intentionally empty: the normalization
|
||||
* migration's own `down()` restores the legacy column types and index shape.
|
||||
*
|
||||
* `releases.imdbid` is deliberately left alone: it joins `movieinfo.imdbid`, and
|
||||
* changing the charset on one side only would force an implicit conversion that
|
||||
* disables index usage on that join.
|
||||
*/
|
||||
return new class extends Migration
|
||||
{
|
||||
@@ -42,17 +50,24 @@ return new class extends Migration
|
||||
return;
|
||||
}
|
||||
|
||||
$indexNeedsSize = ! $this->ppClaimIndexCoversSize();
|
||||
$columnsToNarrow = $this->claimTokenColumnsToNarrow();
|
||||
|
||||
if (! $indexNeedsSize && $columnsToNarrow === []) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->isMariaDbOrMySql()) {
|
||||
$specifications = [];
|
||||
if ($this->indexExists(self::PP_CLAIM_INDEX)) {
|
||||
$specifications[] = 'DROP INDEX `'.self::PP_CLAIM_INDEX.'`';
|
||||
}
|
||||
$specifications[] = 'ADD INDEX `'.self::PP_CLAIM_INDEX.'` (`passwordstatus`, `haspreview`, `nzbstatus`,'
|
||||
.' `leftguid`, `postdate` DESC, `id`, `additional_pp_claimed_at`, `size`)';
|
||||
foreach (self::CLAIM_TOKEN_COLUMNS as $column) {
|
||||
if (Schema::hasColumn('releases', $column)) {
|
||||
$specifications[] = 'MODIFY `'.$column.'` CHAR(32) CHARACTER SET ascii COLLATE ascii_general_ci NULL';
|
||||
if ($indexNeedsSize) {
|
||||
if ($this->indexExists(self::PP_CLAIM_INDEX)) {
|
||||
$specifications[] = 'DROP INDEX `'.self::PP_CLAIM_INDEX.'`';
|
||||
}
|
||||
$specifications[] = 'ADD INDEX `'.self::PP_CLAIM_INDEX.'` (`passwordstatus`, `haspreview`, `nzbstatus`,'
|
||||
.' `leftguid`, `postdate` DESC, `id`, `additional_pp_claimed_at`, `size`)';
|
||||
}
|
||||
foreach ($columnsToNarrow as $column) {
|
||||
$specifications[] = 'MODIFY `'.$column.'` CHAR(32) CHARACTER SET ascii COLLATE ascii_general_ci NULL';
|
||||
}
|
||||
|
||||
DB::statement('ALTER TABLE '.$this->table('releases').' '.implode(', ', $specifications));
|
||||
@@ -60,6 +75,10 @@ return new class extends Migration
|
||||
return;
|
||||
}
|
||||
|
||||
if (! $indexNeedsSize) {
|
||||
return;
|
||||
}
|
||||
|
||||
Schema::table('releases', function (Blueprint $table): void {
|
||||
if ($this->indexExists(self::PP_CLAIM_INDEX)) {
|
||||
$table->dropIndex(self::PP_CLAIM_INDEX);
|
||||
@@ -71,39 +90,44 @@ return new class extends Migration
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
/**
|
||||
* Intentionally empty. The normalization migration owns both changes now, and
|
||||
* its `down()` restores the legacy column types and index definition. Undoing
|
||||
* them here as well would trigger a redundant full table rebuild.
|
||||
*/
|
||||
public function down(): void {}
|
||||
|
||||
private function ppClaimIndexCoversSize(): bool
|
||||
{
|
||||
if (! Schema::hasTable('releases')) {
|
||||
return;
|
||||
foreach (Schema::getIndexes('releases') as $index) {
|
||||
if (($index['name'] ?? null) === self::PP_CLAIM_INDEX) {
|
||||
return in_array('size', $index['columns'] ?? [], true);
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->isMariaDbOrMySql()) {
|
||||
$specifications = [];
|
||||
if ($this->indexExists(self::PP_CLAIM_INDEX)) {
|
||||
$specifications[] = 'DROP INDEX `'.self::PP_CLAIM_INDEX.'`';
|
||||
}
|
||||
$specifications[] = 'ADD INDEX `'.self::PP_CLAIM_INDEX.'` (`passwordstatus`, `haspreview`, `nzbstatus`,'
|
||||
.' `leftguid`, `postdate` DESC, `id`, `additional_pp_claimed_at`)';
|
||||
foreach (self::CLAIM_TOKEN_COLUMNS as $column) {
|
||||
if (Schema::hasColumn('releases', $column)) {
|
||||
$specifications[] = 'MODIFY `'.$column.'` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL';
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
DB::statement('ALTER TABLE '.$this->table('releases').' '.implode(', ', $specifications));
|
||||
|
||||
return;
|
||||
/** @return list<string> */
|
||||
private function claimTokenColumnsToNarrow(): array
|
||||
{
|
||||
if (! $this->isMariaDbOrMySql()) {
|
||||
return [];
|
||||
}
|
||||
|
||||
Schema::table('releases', function (Blueprint $table): void {
|
||||
if ($this->indexExists(self::PP_CLAIM_INDEX)) {
|
||||
$table->dropIndex(self::PP_CLAIM_INDEX);
|
||||
$types = [];
|
||||
foreach (Schema::getColumns('releases') as $column) {
|
||||
$types[$column['name']] = strtolower((string) ($column['type'] ?? ''));
|
||||
}
|
||||
|
||||
$pending = [];
|
||||
foreach (self::CLAIM_TOKEN_COLUMNS as $column) {
|
||||
if (isset($types[$column]) && ! str_starts_with($types[$column], 'char(32)')) {
|
||||
$pending[] = $column;
|
||||
}
|
||||
$table->index(
|
||||
['passwordstatus', 'haspreview', 'nzbstatus', 'leftguid', 'postdate', 'id', 'additional_pp_claimed_at'],
|
||||
self::PP_CLAIM_INDEX,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
return $pending;
|
||||
}
|
||||
|
||||
private function indexExists(string $name): bool
|
||||
|
||||
@@ -1324,7 +1324,7 @@ CREATE TABLE `releases` (
|
||||
`videostatus` tinyint(1) NOT NULL DEFAULT 0,
|
||||
`nzbstatus` tinyint(1) NOT NULL DEFAULT 0,
|
||||
`nzb_creation_claimed_at` timestamp NULL DEFAULT NULL,
|
||||
`nzb_creation_claim_token` varchar(64) DEFAULT NULL,
|
||||
`nzb_creation_claim_token` char(32) CHARACTER SET ascii COLLATE ascii_general_ci DEFAULT NULL,
|
||||
`iscategorized` tinyint(1) NOT NULL DEFAULT 0,
|
||||
`isrenamed` tinyint(1) NOT NULL DEFAULT 0,
|
||||
`proc_pp` tinyint(1) NOT NULL DEFAULT 0,
|
||||
@@ -1337,7 +1337,7 @@ CREATE TABLE `releases` (
|
||||
`proc_crc32` tinyint(1) NOT NULL DEFAULT 0 COMMENT 'Has the release been crc32 processed',
|
||||
`pp_timeout_count` tinyint(4) NOT NULL DEFAULT 0 COMMENT 'Number of times this release timed out during additional post-processing',
|
||||
`additional_pp_claimed_at` timestamp NULL DEFAULT NULL,
|
||||
`additional_pp_claim_token` varchar(64) DEFAULT NULL,
|
||||
`additional_pp_claim_token` char(32) CHARACTER SET ascii COLLATE ascii_general_ci DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `ux_releases_guid` (`guid`),
|
||||
KEY `ix_releases_groupsid` (`groups_id`,`passwordstatus`),
|
||||
@@ -1362,7 +1362,7 @@ CREATE TABLE `releases` (
|
||||
KEY `ix_releases_adddate_id` (`adddate`,`id`),
|
||||
KEY `ix_releases_predb_id` (`predb_id`),
|
||||
KEY `ix_releases_size` (`size`),
|
||||
KEY `ix_releases_add_pp_claim_queue` (`passwordstatus`,`haspreview`,`nzbstatus`,`leftguid`,`postdate` DESC,`id`,`additional_pp_claimed_at`),
|
||||
KEY `ix_releases_add_pp_claim_queue` (`passwordstatus`,`haspreview`,`nzbstatus`,`leftguid`,`postdate` DESC,`id`,`additional_pp_claimed_at`,`size`),
|
||||
KEY `ix_releases_nzb_creation_group_queue` (`nzbstatus`,`groups_id`,`postdate` DESC,`id`,`nzb_creation_claimed_at`),
|
||||
KEY `ix_releases_nzb_creation_global_queue` (`nzbstatus`,`postdate` DESC,`id`,`nzb_creation_claimed_at`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
@@ -76,7 +76,7 @@ final class ReleaseSchemaOptimizationMigrationMariaDbTest extends TestCase
|
||||
$this->assertFalse(Schema::hasColumn('releases', 'proc_sorter'));
|
||||
$this->assertFalse(Schema::hasColumn('release_comments', 'gid'));
|
||||
$this->assertSame(
|
||||
['passwordstatus', 'haspreview', 'nzbstatus', 'leftguid', 'postdate', 'id', 'additional_pp_claimed_at'],
|
||||
['passwordstatus', 'haspreview', 'nzbstatus', 'leftguid', 'postdate', 'id', 'additional_pp_claimed_at', 'size'],
|
||||
$this->indexColumns('ix_releases_add_pp_claim_queue'),
|
||||
);
|
||||
$this->assertSame(
|
||||
@@ -114,13 +114,11 @@ final class ReleaseSchemaOptimizationMigrationMariaDbTest extends TestCase
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function claim_token_and_pp_index_follow_up_narrows_columns_and_adds_size(): void
|
||||
public function rebuild_narrows_claim_tokens_and_covers_size_in_one_pass(): void
|
||||
{
|
||||
$this->seedLegacyData();
|
||||
$this->migration()->up();
|
||||
$followUp = $this->followUpMigration();
|
||||
|
||||
$followUp->up();
|
||||
$this->migration()->up();
|
||||
|
||||
$this->assertSame(
|
||||
['passwordstatus', 'haspreview', 'nzbstatus', 'leftguid', 'postdate', 'id', 'additional_pp_claimed_at', 'size'],
|
||||
@@ -135,13 +133,55 @@ final class ReleaseSchemaOptimizationMigrationMariaDbTest extends TestCase
|
||||
DB::table('releases')->where('id', 1)->update(['additional_pp_claim_token' => $token]);
|
||||
$this->assertSame($token, DB::table('releases')->where('id', 1)->value('additional_pp_claim_token'));
|
||||
|
||||
$followUp->down();
|
||||
$this->migration()->down();
|
||||
|
||||
$this->assertSame('varchar(64)', strtolower($this->columnType('additional_pp_claim_token')));
|
||||
$this->assertSame('varchar(64)', strtolower($this->columnType('nzb_creation_claim_token')));
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function follow_up_migration_is_a_no_op_once_the_rebuild_covers_it(): void
|
||||
{
|
||||
$this->seedLegacyData();
|
||||
$this->migration()->up();
|
||||
|
||||
$before = $this->releasesCreateStatement();
|
||||
$this->followUpMigration()->up();
|
||||
|
||||
$this->assertSame($before, $this->releasesCreateStatement());
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function follow_up_migration_upgrades_an_install_left_on_the_old_shape(): void
|
||||
{
|
||||
$this->seedLegacyData();
|
||||
$this->migration()->up();
|
||||
|
||||
DB::statement(
|
||||
'ALTER TABLE `'.$this->table('releases').'` '
|
||||
.'DROP INDEX `ix_releases_add_pp_claim_queue`, '
|
||||
.'ADD INDEX `ix_releases_add_pp_claim_queue` (`passwordstatus`, `haspreview`, `nzbstatus`, `leftguid`,'
|
||||
.' `postdate` DESC, `id`, `additional_pp_claimed_at`), '
|
||||
.'MODIFY `nzb_creation_claim_token` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL, '
|
||||
.'MODIFY `additional_pp_claim_token` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL'
|
||||
);
|
||||
|
||||
$this->followUpMigration()->up();
|
||||
|
||||
$this->assertSame(
|
||||
['passwordstatus', 'haspreview', 'nzbstatus', 'leftguid', 'postdate', 'id', 'additional_pp_claimed_at'],
|
||||
['passwordstatus', 'haspreview', 'nzbstatus', 'leftguid', 'postdate', 'id', 'additional_pp_claimed_at', 'size'],
|
||||
$this->indexColumns('ix_releases_add_pp_claim_queue'),
|
||||
);
|
||||
$this->assertSame('varchar(64)', strtolower($this->columnType('additional_pp_claim_token')));
|
||||
foreach (['nzb_creation_claim_token', 'additional_pp_claim_token'] as $column) {
|
||||
$this->assertSame('char(32)', strtolower($this->columnType($column)));
|
||||
}
|
||||
}
|
||||
|
||||
private function releasesCreateStatement(): string
|
||||
{
|
||||
$row = DB::selectOne('SHOW CREATE TABLE `'.$this->table('releases').'`');
|
||||
|
||||
return (string) ($row->{'Create Table'} ?? '');
|
||||
}
|
||||
|
||||
private function createSchema(): void
|
||||
|
||||
Reference in New Issue
Block a user