PruneCacheInvalidationDataCommand::handle()   A
last analyzed

Complexity

Conditions 5
Paths 9

Size

Total Lines 28
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
eloc 17
c 1
b 0
f 0
nc 9
nop 0
dl 0
loc 28
rs 9.3888
1
<?php
2
3
namespace Padosoft\SuperCacheInvalidate\Console;
4
5
use Illuminate\Console\Command;
6
use Illuminate\Support\Facades\DB;
7
8
class PruneCacheInvalidationDataCommand extends Command
9
{
10
    /**
11
     * The name and signature of the console command.
12
     *
13
     * @var string
14
     */
15
    protected $signature = 'supercache:prune-invalidation-data
16
                            {--months=1 : The number of months to retain data}';
17
18
    /**
19
     * The console command description.
20
     *
21
     * @var string
22
     */
23
    protected $description = 'Prune old cache invalidation data by dropping partitions';
24
25
    /**
26
     * Prune partitions in a table older than the retention partition key.
27
     *
28
     * @param string $tableName             The name of the table
29
     * @param int    $retentionPartitionKey The partition key cutoff
30
     */
31
    protected function pruneTable(string $tableName, int $retentionPartitionKey, ?int $minPartitionValueToExclude = 0): void
32
    {
33
        // Fetch partition names
34
        $partitions = $this->getPartitionsFromDb($tableName, $retentionPartitionKey, $minPartitionValueToExclude);
35
36
        if (empty($partitions)) {
37
            $this->info("No partitions to prune for table {$tableName}.");
38
39
            return;
40
        }
41
42
        // Build DROP PARTITION statement
43
        $partitionNames = implode(', ', array_map(function ($partition) {
44
            return $partition->PARTITION_NAME;
45
        }, $partitions));
46
47
        DB::statement("ALTER TABLE `{$tableName}` DROP PARTITION {$partitionNames}");
48
        $this->info("Pruned partitions: {$partitionNames} from table {$tableName}.");
49
    }
50
51
    /**
52
     * Execute the console command.
53
     */
54
    public function handle(): void
55
    {
56
        $months = (int) $this->option('months');
57
        $retentionDate = now()->subMonths($months);
58
59
        // Prune tables
60
        $this->pruneTable('cache_invalidation_timestamps', ($retentionDate->year * 100 + $retentionDate->week) + 1);
61
        $this->pruneTable('cache_invalidation_event_associations', ($retentionDate->year * 100 + $retentionDate->week) + 1);
62
63
        $shards = config('super_cache_invalidate.total_shards', 10);
64
        $priorities = [0, 1];
65
66
        $minPartitionValueToExclude = 0;
67
        foreach ($priorities as $priority) {
68
            for ($shard = 0; $shard < $shards; $shard++) {
69
                $minPartitionValueToExclude = ($priority * $shards) + $shard + 1;
70
            }
71
        }
72
        $arrPartitionValues = [];
73
        foreach ($priorities as $priority) {
74
            for ($shard = 0; $shard < $shards; $shard++) {
75
                $arrPartitionValues[] = (($retentionDate->year * 10000) + ($retentionDate->week * 100) + ($priority * $shards) + $shard) + 1;
76
            }
77
        }
78
        $maxPartitionValueToInclude = max($arrPartitionValues);
79
        $this->pruneTable('cache_invalidation_events', $maxPartitionValueToInclude, $minPartitionValueToExclude);
80
81
        $this->info('Old cache invalidation data has been pruned.');
82
    }
83
84
    /**
85
     * @param string $tableName
86
     * @param int $maxPartitionValueToInclude
87
     * @return array
88
     */
89
    protected function getPartitionsFromDb(string $tableName, int $maxPartitionValueToInclude, $minPartitionValueToExclude): array
90
    {
91
        $partitions = DB::select('
92
            SELECT PARTITION_NAME, PARTITION_DESCRIPTION
93
            FROM INFORMATION_SCHEMA.PARTITIONS
94
            WHERE TABLE_SCHEMA = DATABASE()
95
            AND TABLE_NAME = ?
96
            AND PARTITION_NAME IS NOT NULL
97
            AND PARTITION_DESCRIPTION < ? AND PARTITION_DESCRIPTION > ?
98
        ', [$tableName, $maxPartitionValueToInclude, $minPartitionValueToExclude]);
99
        return $partitions;
100
    }
101
}
102