Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
// This file is part of Moodle - http://moodle.org/
3
//
4
// Moodle is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8
//
9
// Moodle is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13
//
14
// You should have received a copy of the GNU General Public License
15
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
16
 
17
/**
18
 * Cache store - base class
19
 *
20
 * This file is part of Moodle's cache API, affectionately called MUC.
21
 * It contains the components that are required in order to use caching.
22
 *
23
 * @package    core
24
 * @category   cache
25
 * @copyright  2012 Sam Hemelryk
26
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
27
 */
28
 
29
defined('MOODLE_INTERNAL') || die();
30
 
31
/**
32
 * Cache store interface.
33
 *
34
 * This interface defines the static methods that must be implemented by every cache store plugin.
35
 * To ensure plugins implement this class the abstract cache_store class implements this interface.
36
 *
37
 * @package    core
38
 * @category   cache
39
 * @copyright  2012 Sam Hemelryk
40
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
41
 */
42
interface cache_store_interface {
43
    /**
44
     * Static method to check if the store requirements are met.
45
     *
46
     * @return bool True if the stores software/hardware requirements have been met and it can be used. False otherwise.
47
     */
48
    public static function are_requirements_met();
49
 
50
    /**
51
     * Static method to check if a store is usable with the given mode.
52
     *
53
     * @param int $mode One of cache_store::MODE_*
54
     */
55
    public static function is_supported_mode($mode);
56
 
57
    /**
58
     * Returns the supported features as a binary flag.
59
     *
60
     * @param array $configuration The configuration of a store to consider specifically.
61
     * @return int The supported features.
62
     */
63
    public static function get_supported_features(array $configuration = array());
64
 
65
    /**
66
     * Returns the supported modes as a binary flag.
67
     *
68
     * @param array $configuration The configuration of a store to consider specifically.
69
     * @return int The supported modes.
70
     */
71
    public static function get_supported_modes(array $configuration = array());
72
 
73
    /**
74
     * Generates an instance of the cache store that can be used for testing.
75
     *
76
     * Returns an instance of the cache store, or false if one cannot be created.
77
     *
78
     * @param cache_definition $definition
79
     * @return cache_store|false
80
     */
81
    public static function initialise_test_instance(cache_definition $definition);
82
 
83
    /**
84
     * Generates the appropriate configuration required for unit testing.
85
     *
86
     * @return array Array of unit test configuration data to be used by initialise().
87
     */
88
    public static function unit_test_configuration();
89
}
90
 
91
/**
92
 * Abstract cache store class.
93
 *
94
 * All cache store plugins must extend this base class.
95
 * It lays down the foundation for what is required of a cache store plugin.
96
 *
97
 * @since Moodle 2.4
98
 * @package    core
99
 * @category   cache
100
 * @copyright  2012 Sam Hemelryk
101
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
102
 */
103
abstract class cache_store implements cache_store_interface {
104
 
105
    // Constants for features a cache store can support
106
 
107
    /**
108
     * Supports multi-part keys
109
     */
110
    const SUPPORTS_MULTIPLE_IDENTIFIERS = 1;
111
    /**
112
     * Ensures data remains in the cache once set.
113
     */
114
    const SUPPORTS_DATA_GUARANTEE = 2;
115
    /**
116
     * Supports a native ttl system.
117
     */
118
    const SUPPORTS_NATIVE_TTL = 4;
119
 
120
    /**
121
     * The cache is searchable by key.
122
     */
123
    const IS_SEARCHABLE = 8;
124
 
125
    /**
126
     * The cache store dereferences objects.
127
     *
128
     * When set, loaders will assume that all data coming from this store has already had all references
129
     * resolved.  So even for complex object structures it will not try to remove references again.
130
     */
131
    const DEREFERENCES_OBJECTS = 16;
132
 
133
    // Constants for the modes of a cache store
134
 
135
    /**
136
     * Application caches. These are shared caches.
137
     */
138
    const MODE_APPLICATION = 1;
139
    /**
140
     * Session caches. Just access to the PHP session.
141
     */
142
    const MODE_SESSION = 2;
143
    /**
144
     * Request caches. Static caches really.
145
     */
146
    const MODE_REQUEST = 4;
147
    /**
148
     * Static caches.
149
     */
150
    const STATIC_ACCEL = '** static accel. **';
151
 
152
    /**
153
     * Returned from get_last_io_bytes if this cache store doesn't support counting bytes read/sent.
154
     */
155
    const IO_BYTES_NOT_SUPPORTED = -1;
156
 
157
    /**
158
     * Constructs an instance of the cache store.
159
     *
160
     * The constructor should be responsible for creating anything needed by the store that is not
161
     * specific to a definition.
162
     * Tasks such as opening a connection to check it is available are best done here.
163
     * Tasks that are definition specific such as creating a storage area for the definition data
164
     * or creating key tables and indexs are best done within the initialise method.
165
     *
166
     * Once a store has been constructed the cache API will check it is ready to be intialised with
167
     * a definition by called $this->is_ready().
168
     * If the setup of the store failed (connection could not be established for example) then
169
     * that method should return false so that the store instance is not selected for use.
170
     *
171
     * @param string $name The name of the cache store
172
     * @param array $configuration The configuration for this store instance.
173
     */
174
    abstract public function __construct($name, array $configuration = array());
175
 
176
    /**
177
     * Returns the name of this store instance.
178
     * @return string
179
     */
180
    abstract public function my_name();
181
 
182
    /**
183
     * Initialises a new instance of the cache store given the definition the instance is to be used for.
184
     *
185
     * This function should be used to run any definition specific setup the store instance requires.
186
     * Tasks such as creating storage areas, or creating indexes are best done here.
187
     *
188
     * Its important to note that the initialise method is expected to always succeed.
189
     * If there are setup tasks that may fail they should be done within the __construct method
190
     * and should they fail is_ready should return false.
191
     *
192
     * @param cache_definition $definition
193
     */
194
    abstract public function initialise(cache_definition $definition);
195
 
196
    /**
197
     * Returns true if this cache store instance has been initialised.
198
     * @return bool
199
     */
200
    abstract public function is_initialised();
201
 
202
    /**
203
     * Returns true if this cache store instance is ready to use.
204
     * @return bool
205
     */
206
    public function is_ready() {
207
        return forward_static_call(array($this, 'are_requirements_met'));
208
    }
209
 
210
    /**
211
     * Retrieves an item from the cache store given its key.
212
     *
213
     * @param string $key The key to retrieve
214
     * @return mixed The data that was associated with the key, or false if the key did not exist.
215
     */
216
    abstract public function get($key);
217
 
218
    /**
219
     * Retrieves several items from the cache store in a single transaction.
220
     *
221
     * If not all of the items are available in the cache then the data value for those that are missing will be set to false.
222
     *
223
     * @param array $keys The array of keys to retrieve
224
     * @return array An array of items from the cache. There will be an item for each key, those that were not in the store will
225
     *      be set to false.
226
     */
227
    abstract public function get_many($keys);
228
 
229
    /**
230
     * Sets an item in the cache given its key and data value.
231
     *
232
     * @param string $key The key to use.
233
     * @param mixed $data The data to set.
234
     * @return bool True if the operation was a success false otherwise.
235
     */
236
    abstract public function set($key, $data);
237
 
238
    /**
239
     * Sets many items in the cache in a single transaction.
240
     *
241
     * @param array $keyvaluearray An array of key value pairs. Each item in the array will be an associative array with two
242
     *      keys, 'key' and 'value'.
243
     * @return int The number of items successfully set. It is up to the developer to check this matches the number of items
244
     *      sent ... if they care that is.
245
     */
246
    abstract public function set_many(array $keyvaluearray);
247
 
248
    /**
249
     * Deletes an item from the cache store.
250
     *
251
     * @param string $key The key to delete.
252
     * @return bool Returns true if the operation was a success, false otherwise.
253
     */
254
    abstract public function delete($key);
255
 
256
    /**
257
     * Deletes several keys from the cache in a single action.
258
     *
259
     * @param array $keys The keys to delete
260
     * @return int The number of items successfully deleted.
261
     */
262
    abstract public function delete_many(array $keys);
263
 
264
    /**
265
     * Purges the cache deleting all items within it.
266
     *
267
     * @return boolean True on success. False otherwise.
268
     */
269
    abstract public function purge();
270
 
271
    /**
272
     * @deprecated since 2.5
273
     * @see \cache_store::instance_deleted()
274
     */
275
    public function cleanup() {
276
        throw new coding_exception('cache_store::cleanup() can not be used anymore.' .
277
            ' Please use cache_store::instance_deleted() instead.');
278
    }
279
 
280
    /**
281
     * Performs any necessary operation when the store instance has been created.
282
     *
283
     * @since Moodle 2.5
284
     */
285
    public function instance_created() {
286
        // By default, do nothing.
287
    }
288
 
289
    /**
290
     * Performs any necessary operation when the store instance is being deleted.
291
     *
292
     * This method may be called before the store has been initialised.
293
     *
294
     * @since Moodle 2.5
295
     * @see cleanup()
296
     */
297
    public function instance_deleted() {
298
        if (method_exists($this, 'cleanup')) {
299
            // There used to be a legacy function called cleanup, it was renamed to instance delete.
300
            // To be removed in 2.6.
301
            $this->cleanup();
302
        }
303
    }
304
 
305
    /**
306
     * Returns true if the user can add an instance of the store plugin.
307
     *
308
     * @return bool
309
     */
310
    public static function can_add_instance() {
311
        return true;
312
    }
313
 
314
    /**
315
     * Returns true if the store instance guarantees data.
316
     *
317
     * @return bool
318
     */
319
    public function supports_data_guarantee() {
320
        return $this::get_supported_features() & self::SUPPORTS_DATA_GUARANTEE;
321
    }
322
 
323
    /**
324
     * Returns true if the store instance supports multiple identifiers.
325
     *
326
     * @return bool
327
     */
328
    public function supports_multiple_identifiers() {
329
        return $this::get_supported_features() & self::SUPPORTS_MULTIPLE_IDENTIFIERS;
330
    }
331
 
332
    /**
333
     * Returns true if the store instance supports native ttl.
334
     *
335
     * @return bool
336
     */
337
    public function supports_native_ttl() {
338
        return $this::get_supported_features() & self::SUPPORTS_NATIVE_TTL;
339
    }
340
 
341
    /**
342
     * Returns true if the store instance is searchable.
343
     *
344
     * @return bool
345
     */
346
    public function is_searchable() {
347
        return in_array('cache_is_searchable', class_implements($this));
348
    }
349
 
350
    /**
351
     * Returns true if the store automatically dereferences objects.
352
     *
353
     * @return bool
354
     */
355
    public function supports_dereferencing_objects() {
356
        return $this::get_supported_features() & self::DEREFERENCES_OBJECTS;
357
    }
358
 
359
    /**
360
     * Creates a clone of this store instance ready to be initialised.
361
     *
362
     * This method is used so that a cache store needs only be constructed once.
363
     * Future requests for an instance of the store will be given a cloned instance.
364
     *
365
     * If you are writing a cache store that isn't compatible with the clone operation
366
     * you can override this method to handle any situations you want before cloning.
367
     *
368
     * @param array $details An array containing the details of the store from the cache config.
369
     * @return cache_store
370
     */
371
    public function create_clone(array $details = array()) {
372
        // By default we just run clone.
373
        // Any stores that have an issue with this will need to override the create_clone method.
374
        return clone($this);
375
    }
376
 
377
    /**
378
     * Can be overridden to return any warnings this store instance should make to the admin.
379
     *
380
     * This should be used to notify things like configuration conflicts etc.
381
     * The warnings returned here will be displayed on the cache configuration screen.
382
     *
383
     * @return string[] An array of warning strings from the store instance.
384
     */
385
    public function get_warnings() {
386
        return array();
387
    }
388
 
389
    /**
390
     * Estimates the storage size used within this cache if the given value is stored with the
391
     * given key.
392
     *
393
     * This function is not exactly accurate; it does not necessarily take into account all the
394
     * overheads involved. It is only intended to give a good idea of the relative size of
395
     * different caches.
396
     *
397
     * The default implementation serializes both key and value and sums the lengths (as a rough
398
     * estimate which is probably good enough for everything unless the cache offers compression).
399
     *
400
     * @param mixed $key Key
401
     * @param mixed $value Value
402
     * @return int Size in bytes
403
     */
404
    public function estimate_stored_size($key, $value): int {
405
        return strlen(serialize($key)) + strlen(serialize($value));
406
    }
407
 
408
    /**
409
     * Gets the amount of memory/storage currently used by this cache store if known.
410
     *
411
     * This value should be obtained quickly from the store itself, if available.
412
     *
413
     * This is the total memory usage of the entire store, not for ther specific cache in question.
414
     *
415
     * Where not supported (default), will always return null.
416
     *
417
     * @return int|null Amount of memory used in bytes or null
418
     */
419
    public function store_total_size(): ?int {
420
        return null;
421
    }
422
 
423
    /**
424
     * Gets the amount of memory used by this specific cache within the store, if known.
425
     *
426
     * This function may be slow and should not be called in normal usage, only for administration
427
     * pages. The value is usually an estimate, and may not be available at all.
428
     *
429
     * When estimating, a number of sample items will be used for the estimate. If set to 50
430
     * (default), then this function will retrieve 50 random items and use that to estimate the
431
     * total size.
432
     *
433
     * The return value has the following fields:
434
     * - supported (true if any other values are completed)
435
     * - items (number of items)
436
     * - mean (mean size of one item in bytes)
437
     * - sd (standard deviation of item size in bytes, based on sample)
438
     * - margin (95% confidence margin for mean - will be 0 if exactly computed)
439
     *
440
     * @param int $samplekeys Number of samples to use
441
     * @return stdClass Object with information about the store size
442
     */
443
    public function cache_size_details(int $samplekeys = 50): stdClass {
444
        $result = (object)[
445
            'supported' => false,
446
            'items' => 0,
447
            'mean' => 0,
448
            'sd' => 0,
449
            'margin' => 0
450
        ];
451
 
452
        // If this cache isn't searchable, we don't know the answer.
453
        if (!$this->is_searchable()) {
454
            return $result;
455
        }
456
        $result->supported = true;
457
 
458
        // Get all the keys for the cache.
459
        $keys = $this->find_all();
460
        $result->items = count($keys);
461
 
462
        // Don't do anything else if there are no items.
463
        if ($result->items === 0) {
464
            return $result;
465
        }
466
 
467
        // Select N random keys.
468
        $exact = false;
469
        if ($result->items <= $samplekeys) {
470
            $samples = $keys;
471
            $exact = true;
472
        } else {
473
            $indexes = array_rand($keys, $samplekeys);
474
            $samples = [];
475
            foreach ($indexes as $index) {
476
                $samples[] = $keys[$index];
477
            }
478
        }
479
 
480
        // Get the random items from cache and estimate the size of each.
481
        $sizes = [];
482
        foreach ($samples as $samplekey) {
483
            $value = $this->get($samplekey);
484
            $sizes[] = $this->estimate_stored_size($samplekey, $value);
485
        }
486
        $number = count($sizes);
487
 
488
        // Calculate the mean and standard deviation.
489
        $result->mean = array_sum($sizes) / $number;
490
        $squarediff = 0;
491
        foreach ($sizes as $size) {
492
            $squarediff += ($size - $result->mean) ** 2;
493
        }
494
        $squarediff /= $number;
495
        $result->sd = sqrt($squarediff);
496
 
497
        // If it's not exact, also calculate the confidence interval.
498
        if (!$exact) {
499
            // 95% confidence has a Z value of 1.96.
500
            $result->margin = (1.96 * $result->sd) / sqrt($number);
501
        }
502
 
503
        return $result;
504
    }
505
 
506
    /**
507
     * Returns true if this cache store instance is both suitable for testing, and ready for testing.
508
     *
509
     * Cache stores that support being used as the default store for unit and acceptance testing should
510
     * override this function and return true if there requirements have been met.
511
     *
512
     * @return bool
513
     */
514
    public static function ready_to_be_used_for_testing() {
515
        return false;
516
    }
517
 
518
    /**
519
     * Gets the number of bytes read from or written to cache as a result of the last action.
520
     *
521
     * This includes calls to the functions get(), get_many(), set(), and set_many(). The number
522
     * is reset by calling any of these functions.
523
     *
524
     * This should be the actual number of bytes of the value read from or written to cache,
525
     * giving an impression of the network or other load. It will not be exactly the same amount
526
     * as netowrk traffic because of protocol overhead, key text, etc.
527
     *
528
     * If not supported, returns IO_BYTES_NOT_SUPPORTED.
529
     *
530
     * @return int Bytes read (or 0 if none/not supported)
531
     * @since Moodle 4.0
532
     */
533
    public function get_last_io_bytes(): int {
534
        return self::IO_BYTES_NOT_SUPPORTED;
535
    }
536
}