Passed
Push — v9 ( 39dd2f...56991e )
by Georges
03:15
created

ClusterPoolAbstract::setClusterPoolsAggregator()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 2
nc 2
nop 0
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
3
/**
4
 *
5
 * This file is part of Phpfastcache.
6
 *
7
 * @license MIT License (MIT)
8
 *
9
 * For full copyright and license information, please see the docs/CREDITS.txt file.
10
 *
11
 * @author  Georges.L (Geolim4)  <[email protected]>
12
 *
13
 */
14
15
declare(strict_types=1);
16
17
namespace Phpfastcache\Cluster;
18
19
use Phpfastcache\Cluster\Drivers\FullReplication\Driver as FullReplicationCluster;
20
use Phpfastcache\Cluster\Drivers\MasterSlaveReplication\Driver as MasterSlaveReplicationCluster;
21
use Phpfastcache\Cluster\Drivers\RandomReplication\Driver as RandomReplicationCluster;
22
use Phpfastcache\Cluster\Drivers\SemiReplication\Driver as SemiReplicationCluster;
23
use Phpfastcache\Config\ConfigurationOption;
24
use Phpfastcache\Core\Item\ExtendedCacheItemInterface;
25
use Phpfastcache\Core\Pool\ExtendedCacheItemPoolInterface;
26
use Phpfastcache\Core\Pool\TaggableCacheItemPoolTrait;
27
use Phpfastcache\Entities\DriverIO;
28
use Phpfastcache\Entities\DriverStatistic;
29
use Phpfastcache\Event\EventManagerInterface;
30
use Phpfastcache\EventManager;
31
use Phpfastcache\Exceptions\PhpfastcacheCoreException;
32
use Phpfastcache\Exceptions\PhpfastcacheDriverCheckException;
33
use Phpfastcache\Exceptions\PhpfastcacheDriverConnectException;
34
use Phpfastcache\Exceptions\PhpfastcacheDriverException;
35
use Phpfastcache\Exceptions\PhpfastcacheInvalidArgumentException;
36
use Phpfastcache\Exceptions\PhpfastcacheIOException;
37
use Phpfastcache\Exceptions\PhpfastcacheLogicException;
38
use Psr\Cache\CacheItemInterface;
39
use Psr\Cache\InvalidArgumentException;
40
41
abstract class ClusterPoolAbstract implements ClusterPoolInterface
42
{
43
    use TaggableCacheItemPoolTrait;
44
    use ClusterPoolTrait {
45
        TaggableCacheItemPoolTrait::__construct as private __parentConstruct;
46
    }
47
48
    public const STRATEGY = [
49
        AggregatorInterface::STRATEGY_FULL_REPLICATION => FullReplicationCluster::class,
50
        AggregatorInterface::STRATEGY_SEMI_REPLICATION => SemiReplicationCluster::class,
51
        AggregatorInterface::STRATEGY_MASTER_SLAVE => MasterSlaveReplicationCluster::class,
52
        AggregatorInterface::STRATEGY_RANDOM_REPLICATION => RandomReplicationCluster::class,
53
    ];
54
55
    /**
56
     * @var AggregatablePoolInterface[]
57
     */
58
    protected array $clusterPools;
59
60
    /**
61
     * ClusterPoolAbstract constructor.
62
     * @param string $clusterName
63
     * @param EventManagerInterface $em
64
     * @param ExtendedCacheItemPoolInterface ...$driverPools
65
     * @throws PhpfastcacheDriverCheckException
66
     * @throws PhpfastcacheDriverConnectException
67
     * @throws PhpfastcacheInvalidArgumentException
68
     * @throws PhpfastcacheCoreException
69
     * @throws PhpfastcacheDriverException
70
     * @throws PhpfastcacheIOException
71
     */
72
    public function __construct(string $clusterName, EventManagerInterface $em, AggregatablePoolInterface ...$driverPools)
73
    {
74
        if (count($driverPools) < 2) {
75
            throw new PhpfastcacheInvalidArgumentException('A cluster requires at least two pools to be working.');
76
        }
77
        $this->clusterPools = $driverPools;
78
        $this->__parentConstruct(new ConfigurationOption(), $clusterName, $em);
79
        $this->setEventManager(EventManager::getInstance());
80
        $this->setClusterPoolsAggregator();
81
    }
82
83
    protected function setClusterPoolsAggregator(): void
84
    {
85
        foreach ($this->clusterPools as $clusterPool) {
86
            $clusterPool->setAggregatedBy($this);
87
        }
88
    }
89
90
    /**
91
     * @inheritDoc
92
     */
93
    public function getIO(): DriverIO
94
    {
95
        $io = new DriverIO();
96
        foreach ($this->clusterPools as $clusterPool) {
97
            $io->setReadHit($io->getReadHit() + $clusterPool->getIO()->getReadHit())
98
                ->setReadMiss($io->getReadMiss() + $clusterPool->getIO()->getReadMiss())
99
                ->setWriteHit($io->getWriteHit() + $clusterPool->getIO()->getWriteHit());
100
        }
101
        return $io;
102
    }
103
104
    /**
105
     * @inheritDoc
106
     */
107
    public function getClusterPools(): array
108
    {
109
        return $this->clusterPools;
110
    }
111
112
    /**
113
     * @inheritDoc
114
     */
115
    public function getConfigs(): array
116
    {
117
        $configs = [];
118
119
        foreach ($this->getClusterPools() as $clusterPool) {
120
            $configs[$clusterPool->getDriverName()] = $clusterPool->getConfig();
121
        }
122
123
        return $configs;
124
    }
125
126
    /**
127
     * @inheritDoc
128
     */
129
    public function getItems(array $keys = []): iterable
130
    {
131
        $items = [];
132
133
        foreach ($keys as $key) {
134
            $items[$key] = $this->getItem($key);
135
        }
136
137
        return $items;
138
    }
139
    /**
140
     * Shared method used by All Clusters
141
     */
142
143
    /**
144
     * @inheritDoc
145
     */
146
    public function deleteItems(array $keys): bool
147
    {
148
        $hasDeletedOnce = false;
149
        foreach ($this->clusterPools as $driverPool) {
150
            if ($result = $driverPool->deleteItems($keys)) {
151
                $hasDeletedOnce = $result;
152
            }
153
        }
154
        // Return true only if at least one backend confirmed the "clear" operation
155
        return $hasDeletedOnce;
156
    }
157
158
    /**
159
     * @param CacheItemInterface $item
160
     * @return bool
161
     * @throws InvalidArgumentException
162
     * @throws PhpfastcacheLogicException
163
     */
164
    public function saveDeferred(CacheItemInterface $item): bool
165
    {
166
        /** @var ExtendedCacheItemInterface $item */
167
        $hasSavedOnce = false;
168
        foreach ($this->clusterPools as $driverPool) {
169
            $poolItem = $this->getStandardizedItem($item, $driverPool);
170
            if ($result = $driverPool->saveDeferred($poolItem)) {
171
                $hasSavedOnce = $result;
172
            }
173
        }
174
        // Return true only if at least one backend confirmed the "commit" operation
175
        return $hasSavedOnce;
176
    }
177
178
    /**
179
     * @param ExtendedCacheItemInterface $item
180
     * @param ExtendedCacheItemPoolInterface $driverPool
181
     * @return ExtendedCacheItemInterface
182
     * @throws InvalidArgumentException
183
     * @throws PhpfastcacheLogicException
184
     */
185
    protected function getStandardizedItem(ExtendedCacheItemInterface $item, ExtendedCacheItemPoolInterface $driverPool): ExtendedCacheItemInterface
186
    {
187
        if (!$item->doesItemBelongToThatDriverBackend($driverPool)) {
188
            /**
189
             * Avoid infinite loop
190
             */
191
            if ($driverPool === $this) {
0 ignored issues
show
introduced by
The condition $driverPool === $this is always false.
Loading history...
192
                /** @var ExtendedCacheItemInterface $itemPool */
193
                $itemClass = $driverPool::getItemClass();
194
                $itemPool = new $itemClass($this, $item->getKey(), $this->getEventManager());
195
                $item->cloneInto($itemPool, $driverPool);
196
197
                return $itemPool;
198
            }
199
200
            $itemPool = $driverPool->getItem($item->getKey());
201
            $item->cloneInto($itemPool, $driverPool);
202
203
            return $itemPool;
204
        }
205
206
        return $item->setEventManager($this->getEventManager());
207
    }
208
209
    /**
210
     * @return DriverStatistic
211
     */
212
    public function getStats(): DriverStatistic
213
    {
214
        $stats = new DriverStatistic();
215
        $stats->setInfo(
216
            sprintf(
217
                'Using %d pool(s): %s',
218
                \count($this->clusterPools),
219
                \implode(
220
                    ', ',
221
                    \array_map(
222
                        static fn (ExtendedCacheItemPoolInterface $pool) => \get_class($pool),
223
                        $this->clusterPools
224
                    )
225
                )
226
            )
227
        );
228
229
        $stats->setSize(
230
            (int)\array_sum(
231
                \array_map(
232
                    static fn (ExtendedCacheItemPoolInterface $pool) => $pool->getStats()->getSize(),
233
                    $this->clusterPools
234
                )
235
            )
236
        );
237
238
        $stats->setData(
239
            \implode(
240
                ', ',
241
                \array_map(
242
                    static fn (ExtendedCacheItemPoolInterface $pool) => $pool->getStats()->getData(),
243
                    $this->clusterPools
244
                )
245
            )
246
        );
247
248
        return $stats;
249
    }
250
}
251