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