Passed
Push — master ( 2bd1bb...6033fd )
by hugh
08:09
created

CacheGc::parsePkRange()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 17
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 11
nc 1
nop 0
dl 0
loc 17
rs 9.9
c 0
b 0
f 0
1
<?php
2
/**
3
 * Created by PhpStorm.
4
 * User: hugh.li
5
 * Date: 2021/6/9
6
 * Time: 7:25 下午.
7
 */
8
9
namespace HughCube\Laravel\OTS\Commands;
10
11
use Aliyun\OTS\Consts\ColumnTypeConst;
12
use Aliyun\OTS\Consts\ComparatorTypeConst;
13
use Aliyun\OTS\Consts\DirectionConst;
14
use Aliyun\OTS\Consts\OperationTypeConst;
15
use Aliyun\OTS\Consts\PrimaryKeyTypeConst;
16
use Aliyun\OTS\Consts\RowExistenceExpectationConst;
17
use Aliyun\OTS\OTSClientException;
18
use Aliyun\OTS\OTSServerException;
19
use Carbon\Carbon;
20
use HughCube\Laravel\OTS\Cache\Store;
21
use Illuminate\Console\Command;
22
use Illuminate\Contracts\Cache\Repository;
23
use Illuminate\Support\Collection;
24
use Illuminate\Support\Facades\Cache;
25
use InvalidArgumentException;
26
27
class CacheGc extends Command
28
{
29
    /**
30
     * The console command name.
31
     *
32
     * @var string
33
     */
34
    protected $signature = 'ots:gc-cache
35
                        {--cache=ots : name of cache. }
36
                        {--expired_duration=2592000 : The data that has expired is cleared. }';
37
38
    /**
39
     * The console command description.
40
     *
41
     * @var string
42
     */
43
    protected $description = 'ots cache gc';
44
45
    /**
46
     * @return void
47
     * @throws OTSClientException
48
     * @throws OTSServerException
49
     */
50
    public function handle()
51
    {
52
        $store = $this->getCache()->getStore();
53
        if (!$store instanceof Store) {
54
            $this->warn('Only OTS cache can be processed.');
55
            return;
56
        }
57
58
        $rowCount = 0;
59
        list($startPk, $endPk) = $this->parsePkRange();
60
        while (!empty($startPk)) {
61
            $request = [
62
                'table_name' => $store->getIndexTable(),
63
                'max_versions' => 1,
64
                'direction' => DirectionConst::CONST_FORWARD,
65
                'inclusive_start_primary_key' => $startPk,
66
                'exclusive_end_primary_key' => $endPk,
67
                'limit' => 200,
68
            ];
69
            $response = $store->getOts()->getRange($request);
0 ignored issues
show
Bug introduced by
The method getRange() does not exist on HughCube\Laravel\OTS\Connection. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

69
            $response = $store->getOts()->/** @scrutinizer ignore-call */ getRange($request);
Loading history...
70
71
            /** 删除查询出来的数据 */
72
            if (!empty($rows = $this->parseDeleteRows($response))) {
73
                $store->getOts()->batchWriteRow([
0 ignored issues
show
Bug introduced by
The method batchWriteRow() does not exist on HughCube\Laravel\OTS\Connection. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

73
                $store->getOts()->/** @scrutinizer ignore-call */ batchWriteRow([
Loading history...
74
                    'tables' => [
75
                        ['table_name' => $store->getTable(), 'rows' => $rows]
76
                    ]
77
                ]);
78
            }
79
80
            /** 下一次轮询的key */
81
            $startPk = $response['next_start_primary_key'];
82
83
            $rowCount += count($rows);
84
            $this->comment(sprintf(
85
                '%s Delete %s rows from the "%s" table.',
86
                Carbon::now()->format('Y-m-d H:i:s.u'),
87
                count($rows),
88
                $store->getTable()
89
            ));
90
        }
91
    }
92
93
    protected function getCache(): Repository
94
    {
95
        return Cache::store(($this->option('cache') ?: null));
96
    }
97
98
    protected function getExpiredDuration(): int
99
    {
100
        $duration = intval($this->option('expired_duration'));
101
        if ($duration < 24 * 3600) {
102
            throw new InvalidArgumentException('At least one day expired before it can be cleaned.');
103
        }
104
105
        return $duration;
106
    }
107
108
    protected function parsePkRange(): array
109
    {
110
        $startPk = [
111
            ['expiration', 1],
112
            ['key', null, PrimaryKeyTypeConst::CONST_INF_MIN],
113
            ['prefix', null, PrimaryKeyTypeConst::CONST_INF_MIN],
114
            ['type', null, PrimaryKeyTypeConst::CONST_INF_MIN],
115
        ];
116
117
        $endPk = [
118
            ['expiration', (time() - $this->getExpiredDuration())],
119
            ['key', null, PrimaryKeyTypeConst::CONST_INF_MAX],
120
            ['prefix', null, PrimaryKeyTypeConst::CONST_INF_MAX],
121
            ['type', null, PrimaryKeyTypeConst::CONST_INF_MAX],
122
        ];
123
124
        return [$startPk, $endPk];
125
    }
126
127
    protected function parseDeleteRows($response): array
128
    {
129
        $rows = [];
130
        foreach ($response['rows'] as $row) {
131
            $row = Collection::make($row['primary_key'])->keyBy(0);
132
            $rows[] = [
133
                'operation_type' => OperationTypeConst::CONST_DELETE,
134
                'condition' => [
135
                    'row_existence' => RowExistenceExpectationConst::CONST_IGNORE,
136
                    /** (Col2 <= 10) */
137
                    'column_condition' => [
138
                        'column_name' => 'expiration',
139
                        'value' => [time(), ColumnTypeConst::CONST_INTEGER],
140
                        'comparator' => ComparatorTypeConst::CONST_LESS_EQUAL,
141
                        'pass_if_missing' => true,
142
                        'latest_version_only' => true,
143
                    ],
144
                ],
145
                'primary_key' => [
146
                    $row->get('key'),
147
                    $row->get('prefix'),
148
                    $row->get('type'),
149
                ],
150
            ];
151
        }
152
        return $rows;
153
    }
154
}
155