Lock::release()   A
last analyzed

Complexity

Conditions 3
Paths 5

Size

Total Lines 28
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 18
c 1
b 0
f 0
nc 5
nop 0
dl 0
loc 28
rs 9.6666
1
<?php
2
/**
3
 * Created by PhpStorm.
4
 * User: hugh.li
5
 * Date: 2021/6/8
6
 * Time: 7:42 下午.
7
 */
8
9
namespace HughCube\Laravel\OTS\Cache;
10
11
use Aliyun\OTS\Consts\ColumnTypeConst;
12
use Aliyun\OTS\Consts\ComparatorTypeConst;
13
use Aliyun\OTS\Consts\LogicalOperatorConst;
14
use Aliyun\OTS\Consts\RowExistenceExpectationConst;
15
use Aliyun\OTS\OTSClientException;
16
use Aliyun\OTS\OTSServerException;
17
use HughCube\Laravel\OTS\Connection;
18
19
class Lock extends \Illuminate\Cache\Lock
20
{
21
    use Attribute;
22
23
    /**
24
     * Lock constructor.
25
     *
26
     * @param Connection  $ots
27
     * @param string      $table
28
     * @param string      $prefix
29
     * @param string      $name
30
     * @param int         $seconds
31
     * @param string|null $owner
32
     */
33
    public function __construct($ots, $table, $prefix, string $name, int $seconds, ?string $owner = null)
34
    {
35
        parent::__construct($name, $seconds, $owner);
36
37
        $this->ots = $ots;
38
        $this->table = $table;
39
        $this->prefix = $prefix;
40
        $this->type = 'lock';
41
    }
42
43
    /**
44
     * Attempt to acquire the lock.
45
     *
46
     * @throws OTSServerException
47
     * @throws OTSClientException
48
     *
49
     * @return bool
50
     */
51
    public function acquire(): bool
52
    {
53
        $request = [
54
            'table_name' => $this->getTable(),
55
            'condition'  => [
56
                'row_existence'    => RowExistenceExpectationConst::CONST_IGNORE,
57
                'column_condition' => [
58
                    'logical_operator' => LogicalOperatorConst::CONST_OR,
59
                    'sub_conditions'   => [
60
                        /** (`owner` != $this->owner OR `owner` IS NULL) AND (`expiration` >=  time()) */
61
                        [
62
                            'logical_operator' => LogicalOperatorConst::CONST_AND,
63
                            'sub_conditions'   => [
64
                                [
65
                                    'column_name'         => 'owner',
66
                                    'value'               => [$this->owner, ColumnTypeConst::CONST_STRING],
67
                                    'comparator'          => ComparatorTypeConst::CONST_NOT_EQUAL,
68
                                    'pass_if_missing'     => true,
69
                                    'latest_version_only' => true,
70
                                ],
71
                                [
72
                                    'column_name'         => 'expiration',
73
                                    'value'               => [$this->currentTime(), ColumnTypeConst::CONST_INTEGER],
74
                                    'comparator'          => ComparatorTypeConst::CONST_LESS_EQUAL,
75
                                    'pass_if_missing'     => true,
76
                                    'latest_version_only' => true,
77
                                ],
78
                            ],
79
                        ],
80
81
                        /** (`owner` = $this->owner OR `owner` IS NULL) */
82
                        [
83
84
                            'column_name'         => 'owner',
85
                            'value'               => [$this->owner, ColumnTypeConst::CONST_STRING],
86
                            'comparator'          => ComparatorTypeConst::CONST_EQUAL,
87
                            'pass_if_missing'     => true,
88
                            'latest_version_only' => true,
89
                        ],
90
                    ],
91
                ],
92
            ],
93
            'primary_key'       => $this->makePrimaryKey($this->name),
94
            'attribute_columns' => $this->makeAttributeColumns(time(), $this->seconds),
95
        ];
96
97
        try {
98
            $response = $this->getOts()->putRow($request);
0 ignored issues
show
Bug introduced by
The method putRow() 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

98
            $response = $this->getOts()->/** @scrutinizer ignore-call */ putRow($request);
Loading history...
99
100
            return isset($response['primary_key'], $response['attribute_columns']);
101
        } catch (OTSServerException $exception) {
102
            if ('OTSConditionCheckFail' === $exception->getOTSErrorCode()) {
103
                return false;
104
            }
105
106
            throw $exception;
107
        }
108
    }
109
110
    /**
111
     * Release the lock.
112
     *
113
     * @throws OTSClientException
114
     * @throws OTSServerException
115
     *
116
     * @return bool
117
     */
118
    public function release(): bool
119
    {
120
        $request = [
121
            'table_name' => $this->getTable(),
122
            'condition'  => [
123
                'row_existence' => RowExistenceExpectationConst::CONST_EXPECT_EXIST,
124
                /** (`owner` = $this->owner) */
125
                'column_condition' => [
126
                    'column_name'         => 'owner',
127
                    'value'               => $this->owner,
128
                    'comparator'          => ComparatorTypeConst::CONST_EQUAL,
129
                    'pass_if_missing'     => false,
130
                    'latest_version_only' => true,
131
                ],
132
            ],
133
            'primary_key' => $this->makePrimaryKey($this->name),
134
        ];
135
136
        try {
137
            $response = $this->getOts()->deleteRow($request);
0 ignored issues
show
Bug introduced by
The method deleteRow() 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

137
            $response = $this->getOts()->/** @scrutinizer ignore-call */ deleteRow($request);
Loading history...
138
139
            return isset($response['primary_key'], $response['attribute_columns']);
140
        } catch (OTSServerException $exception) {
141
            if ('OTSConditionCheckFail' === $exception->getOTSErrorCode()) {
142
                return false;
143
            }
144
145
            throw $exception;
146
        }
147
    }
148
149
    /**
150
     * Releases this lock in disregard of ownership.
151
     *
152
     * @throws OTSClientException
153
     * @throws OTSServerException
154
     *
155
     * @return bool
156
     */
157
    public function forceRelease(): bool
158
    {
159
        $request = [
160
            'table_name'  => $this->getTable(),
161
            'condition'   => RowExistenceExpectationConst::CONST_IGNORE,
162
            'primary_key' => $this->makePrimaryKey($this->name),
163
        ];
164
165
        $response = $this->getOts()->deleteRow($request);
166
167
        return isset($response['primary_key'], $response['attribute_columns']);
0 ignored issues
show
Bug Best Practice introduced by
The expression return IssetNode returns the type boolean which is incompatible with the return type mandated by Illuminate\Contracts\Cache\Lock::forceRelease() of void.

In the issue above, the returned value is violating the contract defined by the mentioned interface.

Let's take a look at an example:

interface HasName {
    /** @return string */
    public function getName();
}

class Name {
    public $name;
}

class User implements HasName {
    /** @return string|Name */
    public function getName() {
        return new Name('foo'); // This is a violation of the ``HasName`` interface
                                // which only allows a string value to be returned.
    }
}
Loading history...
168
    }
169
170
    /**
171
     * Returns the owner value written into the driver for this lock.
172
     *
173
     * @throws OTSClientException
174
     * @throws OTSServerException
175
     *
176
     * @return mixed|string
177
     */
178
    protected function getCurrentOwner()
179
    {
180
        $request = [
181
            'table_name'   => $this->getTable(),
182
            'primary_key'  => $this->makePrimaryKey($this->name),
183
            'max_versions' => 1,
184
        ];
185
186
        $response = $this->getOts()->getRow($request);
0 ignored issues
show
Bug introduced by
The method getRow() 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

186
        $response = $this->getOts()->/** @scrutinizer ignore-call */ getRow($request);
Loading history...
187
188
        if (null === $this->parseValueInOtsResponse($response)) {
189
            return '';
190
        }
191
192
        foreach ($response['attribute_columns'] as $attribute) {
193
            if ('owner' === $attribute[0]) {
194
                return $attribute[1];
195
            }
196
        }
197
198
        return '';
199
    }
200
}
201