Updated all the contrib modules to their latest versions.
[yaffs-website] / web / modules / contrib / memcache / src / Driver / DriverBase.php
1 <?php
2
3 namespace Drupal\memcache\Driver;
4
5 use Drupal\Component\Utility\Timer;
6 use Drupal\memcache\MemcacheSettings;
7 use Drupal\memcache\DrupalMemcacheInterface;
8
9 /**
10  * Class DriverBase.
11  */
12 abstract class DriverBase implements DrupalMemcacheInterface {
13
14   /**
15    * The memcache config object.
16    *
17    * @var \Drupal\memcache\MemcacheSettings
18    */
19   protected $settings;
20
21   /**
22    * The memcache object.
23    *
24    * @var \Memcache|\Memcached
25    *   E.g. \Memcache|\Memcached
26    */
27   protected $memcache;
28
29   /**
30    * The hash algorithm to pass to hash(). Defaults to 'sha1'.
31    *
32    * @var string
33    */
34   protected $hashAlgorithm;
35
36   /**
37    * The prefix memcache key for all keys.
38    *
39    * @var string
40    */
41   protected $prefix;
42
43   /**
44    * Stats for the entire request.
45    *
46    * @var array
47    */
48   protected static $stats = [
49     'all' => [],
50     'ops' => [],
51   ];
52
53   /**
54    * Constructs a DriverBase object.
55    *
56    * @param \Drupal\memcache\MemcacheSettings $settings
57    *   The memcache config object.
58    * @param \Memcached|\Memcache $memcache
59    *   An existing memcache connection object.
60    * @param string $bin
61    *   The class instance specific cache bin to use.
62    */
63   public function __construct(MemcacheSettings $settings, $memcache, $bin = NULL) {
64     $this->settings = $settings;
65     $this->memcache = $memcache;
66
67     $this->hashAlgorithm = $this->settings->get('key_hash_algorithm', 'sha1');
68
69     $prefix = $this->settings->get('key_prefix', '');
70     if ($prefix) {
71       $this->prefix = $prefix . ':';
72     }
73
74     if ($bin) {
75       $this->prefix .= $bin . ':';
76     }
77   }
78
79   /**
80    * {@inheritdoc}
81    */
82   public function get($key) {
83     $collect_stats = $this->statsInit();
84
85     $full_key = $this->key($key);
86     $result   = $this->memcache->get($full_key);
87
88     if ($collect_stats) {
89       $this->statsWrite('get', 'cache', [$full_key => (bool) $result]);
90     }
91
92     return $result;
93   }
94
95   /**
96    * {@inheritdoc}
97    */
98   public function key($key) {
99     $full_key = urlencode($this->prefix . '-' . $key);
100
101     // Memcache only supports key lengths up to 250 bytes.  If we have generated
102     // a longer key, we shrink it to an acceptable length with a configurable
103     // hashing algorithm. Sha1 was selected as the default as it performs
104     // quickly with minimal collisions.
105     if (strlen($full_key) > 250) {
106       $full_key = urlencode($this->prefix . '-' . hash($this->hashAlgorithm, $key));
107       $full_key .= '-' . substr(urlencode($key), 0, (250 - 1) - strlen($full_key) - 1);
108     }
109
110     return $full_key;
111   }
112
113   /**
114    * {@inheritdoc}
115    */
116   public function delete($key) {
117     $collect_stats = $this->statsInit();
118
119     $full_key = $this->key($key);
120     $result = $this->memcache->delete($full_key, 0);
121
122     if ($collect_stats) {
123       $this->statsWrite('delete', 'cache', [$full_key => $result]);
124     }
125
126     return $result;
127   }
128
129   /**
130    * {@inheritdoc}
131    */
132   public function flush() {
133     $collect_stats = $this->statsInit();
134
135     $result = $this->memcache->flush();
136
137     if ($collect_stats) {
138       $this->statsWrite('flush', 'cache', ['' => $result]);
139     }
140   }
141
142   /**
143    * Retrieves statistics recorded during memcache operations.
144    *
145    * @param string $stats_bin
146    *   The bin to retrieve statistics for.
147    * @param string $stats_type
148    *   The type of statistics to retrieve when using the Memcache extension.
149    * @param bool $aggregate
150    *   Whether to aggregate statistics.
151    */
152   public function stats($stats_bin = 'cache', $stats_type = 'default', $aggregate = FALSE) {
153
154     // The stats_type can be over-loaded with an integer slab id, if doing a
155     // cachedump.  We know we're doing a cachedump if $slab is non-zero.
156     $slab = (int) $stats_type;
157     $stats = [];
158
159     foreach ($this->getBins() as $bin => $target) {
160       if ($stats_bin == $bin) {
161         if (isset($this->memcache)) {
162           if ($this->memcache instanceof \Memcached) {
163             $stats[$bin] = $this->memcache->getStats();
164           }
165
166           // The PHP Memcache extension 3.x version throws an error if the stats
167           // type is NULL or not in {reset, malloc, slabs, cachedump, items,
168           // sizes}. If $stats_type is 'default', then no parameter should be
169           // passed to the Memcache memcache_get_extended_stats() function.
170           elseif ($this->memcache instanceof \Memcache) {
171             if ($stats_type == 'default' || $stats_type == '') {
172               $stats[$bin] = $this->memcache->getExtendedStats();
173             }
174
175             // If $slab isn't zero, then we are dumping the contents of a
176             // specific cache slab.
177             elseif (!empty($slab)) {
178               $stats[$bin] = $this->memcache->getStats('cachedump', $slab);
179             }
180             else {
181               $stats[$bin] = $this->memcache->getExtendedStats($stats_type);
182             }
183           }
184         }
185       }
186     }
187
188     // Optionally calculate a sum-total for all servers in the current bin.
189     if ($aggregate) {
190
191       // Some variables don't logically aggregate.
192       $no_aggregate = [
193         'pid',
194         'time',
195         'version',
196         'pointer_size',
197         'accepting_conns',
198         'listen_disabled_num',
199       ];
200
201       foreach ($stats as $bin => $servers) {
202         if (is_array($servers)) {
203           foreach ($servers as $server) {
204             if (is_array($server)) {
205               foreach ($server as $key => $value) {
206                 if (!in_array($key, $no_aggregate)) {
207                   if (isset($stats[$bin]['total'][$key])) {
208                     $stats[$bin]['total'][$key] += $value;
209                   }
210                   else {
211                     $stats[$bin]['total'][$key] = $value;
212                   }
213                 }
214               }
215             }
216           }
217         }
218       }
219     }
220
221     return $stats;
222   }
223
224   /**
225    * Helper function to get the bins.
226    */
227   public function getBins() {
228     $memcache_bins = \Drupal::configFactory()->getEditable('memcache.settings')->get('memcache_bins');
229     if (!isset($memcache_bins)) {
230       $memcache_bins = ['cache' => 'default'];
231     }
232
233     return $memcache_bins;
234   }
235
236   /**
237    * Helper function to get the servers.
238    */
239   public function getServers() {
240     $memcache_servers = \Drupal::configFactory()->getEditable('memcache.settings')->get('memcache_servers');
241     if (!isset($memcache_servers)) {
242       $memcache_servers = ['127.0.0.1:11211' => 'default'];
243     }
244
245     return $memcache_servers;
246   }
247
248   /**
249    * Helper function to get memcache.
250    */
251   public function getMemcache() {
252     return $this->memcache;
253   }
254
255   /**
256    * Helper function to get request stats.
257    */
258   public function requestStats() {
259     return self::$stats;
260   }
261
262   /**
263    * Returns an array of available statistics types.
264    */
265   public function statsTypes() {
266     if ($this->memcache instanceof \Memcache) {
267       // TODO: Determine which versions of the PECL memcache extension have
268       // these other stats types: 'malloc', 'maps', optionally detect this
269       // version and expose them.  These stats are "subject to change without
270       // warning" unfortunately.
271       return ['default', 'slabs', 'items', 'sizes'];
272     }
273     else {
274       // The Memcached PECL extension only offers the default statistics.
275       return ['default'];
276     }
277   }
278
279   /**
280    * Helper function to initialize the stats for a memcache operation.
281    */
282   protected function statsInit() {
283     static $drupal_static_fast;
284
285     if (!isset($drupal_static_fast)) {
286       $drupal_static_fast = &drupal_static(__FUNCTION__, ['variable_checked' => NULL, 'user_access_checked' => NULL]);
287     }
288     $variable_checked    = &$drupal_static_fast['variable_checked'];
289     $user_access_checked = &$drupal_static_fast['user_access_checked'];
290
291     // Confirm DRUPAL_BOOTSTRAP_VARIABLES has been reached. We don't use
292     // drupal_get_bootstrap_phase() as it's buggy. We can use variable_get()
293     // here because _drupal_bootstrap_variables() includes module.inc
294     // immediately after it calls variable_initialize().
295     // @codingStandardsIgnoreStart
296     // if (!isset($variable_checked) && function_exists('module_list')) {
297     //   $variable_checked = variable_get('show_memcache_statistics', FALSE);
298     // }
299     // If statistics are enabled we need to check user access.
300     // if (!empty($variable_checked) && !isset($user_access_checked) && !empty($GLOBALS['user']) && function_exists('user_access')) {
301     //   // Statistics are enabled and the $user object has been populated, so check
302     //   // that the user has access to view them.
303     //   $user_access_checked = user_access('access memcache statistics');
304     // }
305     // @codingStandardsIgnoreEnd
306     // Return whether or not statistics are enabled and the user can access
307     // them.
308     if ((!isset($variable_checked) || $variable_checked) && (!isset($user_access_checked) || $user_access_checked)) {
309       Timer::start('dmemcache');
310       return TRUE;
311     }
312     else {
313       return FALSE;
314     }
315   }
316
317   /**
318    * Memcache statistics to be displayed at end of page generation.
319    *
320    * @param string $action
321    *   The action being performed (get, set, etc...).
322    * @param string $bin
323    *   The memcache bin the action is being performed in.
324    * @param array $keys
325    *   Keyed array in the form (string)$cid => (bool)$success. The keys the
326    *   action is being performed on, and whether or not it was a success.
327    */
328   protected function statsWrite($action, $bin, array $keys) {
329
330     // Determine how much time elapsed to execute this action.
331     $time = Timer::read('dmemcache');
332
333     // Build the 'all' and 'ops' arrays displayed by memcache_admin.module.
334     foreach ($keys as $key => $success) {
335       self::$stats['all'][] = [
336         number_format($time, 2),
337         $action,
338         $bin,
339         $key,
340         $success ? 'hit' : 'miss',
341       ];
342       if (!isset(self::$stats['ops'][$action])) {
343         self::$stats['ops'][$action] = [$action, 0, 0, 0];
344       }
345       self::$stats['ops'][$action][1] += $time;
346       if ($success) {
347         self::$stats['ops'][$action][2]++;
348       }
349       else {
350         self::$stats['ops'][$action][3]++;
351       }
352     }
353   }
354
355 }