]> git.mxchange.org Git - friendica.git/blob - src/Core/Lock/Factory/Lock.php
Move KeyValuePairStorage to strategies
[friendica.git] / src / Core / Lock / Factory / Lock.php
1 <?php
2 /**
3  * @copyright Copyright (C) 2010-2023, the Friendica project
4  *
5  * @license GNU AGPL version 3 or any later version
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU Affero General Public License as
9  * published by the Free Software Foundation, either version 3 of the
10  * License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU Affero General Public License for more details.
16  *
17  * You should have received a copy of the GNU Affero General Public License
18  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
19  *
20  */
21
22 namespace Friendica\Core\Lock\Factory;
23
24 use Friendica\Core\Cache\Factory\Cache;
25 use Friendica\Core\Cache\Capability\ICanCacheInMemory;
26 use Friendica\Core\Cache\Enum;
27 use Friendica\Core\Config\Capability\IManageConfigValues;
28 use Friendica\Core\Lock\Capability\ICanLock;
29 use Friendica\Core\Lock\Type;
30 use Friendica\Database\Database;
31 use Psr\Log\LoggerInterface;
32
33 /**
34  * Class LockFactory
35  *
36  * @package Friendica\Core\Cache
37  *
38  * A basic class to generate a LockDriver
39  */
40 class Lock
41 {
42         /**
43          * @var string The default driver for caching
44          */
45         const DEFAULT_DRIVER = 'default';
46
47         /**
48          * @var IManageConfigValues The configuration to read parameters out of the config
49          */
50         private $config;
51
52         /**
53          * @var Database The database connection in case that the cache is used the dba connection
54          */
55         private $dba;
56
57         /**
58          * @var Cache The memory cache driver in case we use it
59          */
60         private $cacheFactory;
61
62         /**
63          * @var LoggerInterface The Friendica Logger
64          */
65         private $logger;
66
67         public function __construct(Cache $cacheFactory, IManageConfigValues $config, Database $dba, LoggerInterface $logger)
68         {
69                 $this->cacheFactory = $cacheFactory;
70                 $this->config       = $config;
71                 $this->dba          = $dba;
72                 $this->logger       = $logger;
73         }
74
75         public function create()
76         {
77                 $lock_type = $this->config->get('system', 'lock_driver', self::DEFAULT_DRIVER);
78
79                 try {
80                         switch ($lock_type) {
81                                 case Enum\Type::MEMCACHE:
82                                 case Enum\Type::MEMCACHED:
83                                 case Enum\Type::REDIS:
84                                 case Enum\Type::APCU:
85                                         $cache = $this->cacheFactory->createLocal($lock_type);
86                                         if ($cache instanceof ICanCacheInMemory) {
87                                                 return new Type\CacheLock($cache);
88                                         } else {
89                                                 throw new \Exception(sprintf('Incompatible cache driver \'%s\' for lock used', $lock_type));
90                                         }
91                                 case 'database':
92                                         return new Type\DatabaseLock($this->dba);
93                                 case 'semaphore':
94                                         return new Type\SemaphoreLock();
95                                 default:
96                                         return self::useAutoDriver();
97                         }
98                 } catch (\Exception $exception) {
99                         $this->logger->alert('Driver \'' . $lock_type . '\' failed - Fallback to \'useAutoDriver()\'', ['exception' => $exception]);
100                         return self::useAutoDriver();
101                 }
102         }
103
104         /**
105          * This method tries to find the best - local - locking method for Friendica
106          *
107          * The following sequence will be tried:
108          * 1. Semaphore Locking
109          * 2. Cache Locking
110          * 3. Database Locking
111          *
112          * @return ICanLock
113          */
114         private function useAutoDriver()
115         {
116                 // 1. Try to use Semaphores for - local - locking
117                 if (function_exists('sem_get')) {
118                         try {
119                                 return new Type\SemaphoreLock();
120                         } catch (\Exception $exception) {
121                                 $this->logger->warning('Using Semaphore driver for locking failed.', ['exception' => $exception]);
122                         }
123                 }
124
125                 // 2. Try to use Cache Locking (don't use the DB-Cache Locking because it works different!)
126                 $cache_type = $this->config->get('system', 'cache_driver', 'database');
127                 if ($cache_type != Enum\Type::DATABASE) {
128                         try {
129                                 $cache = $this->cacheFactory->createLocal($cache_type);
130                                 if ($cache instanceof ICanCacheInMemory) {
131                                         return new Type\CacheLock($cache);
132                                 }
133                         } catch (\Exception $exception) {
134                                 $this->logger->warning('Using Cache driver for locking failed.', ['exception' => $exception]);
135                         }
136                 }
137
138                 // 3. Use Database Locking as a Fallback
139                 return new Type\DatabaseLock($this->dba);
140         }
141 }