]> git.mxchange.org Git - friendica.git/blob - src/Factory/LockFactory.php
Inverted condition
[friendica.git] / src / Factory / LockFactory.php
1 <?php
2 /**
3  * @copyright Copyright (C) 2010-2021, 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\Factory;
23
24 use Friendica\Core\Cache\IMemoryCache;
25 use Friendica\Core\Cache\Type;
26 use Friendica\Core\Config\IConfig;
27 use Friendica\Core\Lock;
28 use Friendica\Database\Database;
29 use Psr\Log\LoggerInterface;
30
31 /**
32  * Class LockFactory
33  *
34  * @package Friendica\Core\Cache
35  *
36  * A basic class to generate a LockDriver
37  */
38 class LockFactory
39 {
40         /**
41          * @var string The default driver for caching
42          */
43         const DEFAULT_DRIVER = 'default';
44
45         /**
46          * @var IConfig The configuration to read parameters out of the config
47          */
48         private $config;
49
50         /**
51          * @var Database The database connection in case that the cache is used the dba connection
52          */
53         private $dba;
54
55         /**
56          * @var CacheFactory The memory cache driver in case we use it
57          */
58         private $cacheFactory;
59
60         /**
61          * @var LoggerInterface The Friendica Logger
62          */
63         private $logger;
64
65         public function __construct(CacheFactory $cacheFactory, IConfig $config, Database $dba, LoggerInterface $logger)
66         {
67                 $this->cacheFactory = $cacheFactory;
68                 $this->config       = $config;
69                 $this->dba          = $dba;
70                 $this->logger       = $logger;
71         }
72
73         public function create()
74         {
75                 $lock_type = $this->config->get('system', 'lock_driver', self::DEFAULT_DRIVER);
76
77                 try {
78                         switch ($lock_type) {
79                                 case Type::MEMCACHE:
80                                 case Type::MEMCACHED:
81                                 case Type::REDIS:
82                                 case Type::APCU:
83                                         $cache = $this->cacheFactory->create($lock_type);
84                                         if ($cache instanceof IMemoryCache) {
85                                                 return new Lock\CacheLock($cache);
86                                         } else {
87                                                 throw new \Exception(sprintf('Incompatible cache driver \'%s\' for lock used', $lock_type));
88                                         }
89                                         break;
90
91                                 case 'database':
92                                         return new Lock\DatabaseLock($this->dba);
93                                         break;
94
95                                 case 'semaphore':
96                                         return new Lock\SemaphoreLock();
97                                         break;
98
99                                 default:
100                                         return self::useAutoDriver();
101                         }
102                 } catch (\Exception $exception) {
103                         $this->logger->alert('Driver \'' . $lock_type . '\' failed - Fallback to \'useAutoDriver()\'', ['exception' => $exception]);
104                         return self::useAutoDriver();
105                 }
106         }
107
108         /**
109          * This method tries to find the best - local - locking method for Friendica
110          *
111          * The following sequence will be tried:
112          * 1. Semaphore Locking
113          * 2. Cache Locking
114          * 3. Database Locking
115          *
116          * @return Lock\ILock
117          */
118         private function useAutoDriver()
119         {
120                 // 1. Try to use Semaphores for - local - locking
121                 if (function_exists('sem_get')) {
122                         try {
123                                 return new Lock\SemaphoreLock();
124                         } catch (\Exception $exception) {
125                                 $this->logger->warning('Using Semaphore driver for locking failed.', ['exception' => $exception]);
126                         }
127                 }
128
129                 // 2. Try to use Cache Locking (don't use the DB-Cache Locking because it works different!)
130                 $cache_type = $this->config->get('system', 'cache_driver', 'database');
131                 if ($cache_type != Type::DATABASE) {
132                         try {
133                                 $cache = $this->cacheFactory->create($cache_type);
134                                 if ($cache instanceof IMemoryCache) {
135                                         return new Lock\CacheLock($cache);
136                                 }
137                         } catch (\Exception $exception) {
138                                 $this->logger->warning('Using Cache driver for locking failed.', ['exception' => $exception]);
139                         }
140                 }
141
142                 // 3. Use Database Locking as a Fallback
143                 return new Lock\DatabaseLock($this->dba);
144         }
145 }