Example #1
0
 /**
  * Retrieves an array of values for an array of keys.
  *
  * Using this function comes with potential performance implications.
  * Not all cache stores will support get_many/set_many operations and in order to replicate this functionality will call
  * the equivalent singular method for each item provided.
  * This should not deter you from using this function as there is a performance benefit in situations where the cache store
  * does support it, but you should be aware of this fact.
  *
  * @param array $keys The keys of the data being requested.
  *      Each key can be any structure although using a scalar string or int is recommended in the interests of performance.
  *      In advanced cases an array may be useful such as in situations requiring the multi-key functionality.
  * @param int $strictness One of IGNORE_MISSING or MUST_EXIST.
  * @return array An array of key value pairs for the items that could be retrieved from the cache.
  *      If MUST_EXIST was used and not all keys existed within the cache then an exception will be thrown.
  *      Otherwise any key that did not exist will have a data value of false within the results.
  * @throws coding_exception
  */
 public function get_many(array $keys, $strictness = IGNORE_MISSING)
 {
     $this->check_tracked_user();
     $parsedkeys = array();
     $keymap = array();
     foreach ($keys as $key) {
         $parsedkey = $this->parse_key($key);
         $parsedkeys[$key] = $parsedkey;
         $keymap[$parsedkey] = $key;
     }
     $result = $this->get_store()->get_many($parsedkeys);
     $return = array();
     $missingkeys = array();
     $hasmissingkeys = false;
     foreach ($result as $parsedkey => $value) {
         $key = $keymap[$parsedkey];
         if ($value instanceof cache_ttl_wrapper) {
             /* @var cache_ttl_wrapper $value */
             if ($value->has_expired()) {
                 $this->delete($keymap[$parsedkey]);
                 $value = false;
             } else {
                 $value = $value->data;
             }
         }
         if ($value instanceof cache_cached_object) {
             /* @var cache_cached_object $value */
             $value = $value->restore_object();
         }
         $return[$key] = $value;
         if ($value === false) {
             $hasmissingkeys = true;
             $missingkeys[$parsedkey] = $key;
         }
     }
     if ($hasmissingkeys) {
         // We've got missing keys - we've got to check any loaders or data sources.
         $loader = $this->get_loader();
         $datasource = $this->get_datasource();
         if ($loader !== false) {
             foreach ($loader->get_many($missingkeys) as $key => $value) {
                 if ($value !== false) {
                     $return[$key] = $value;
                     unset($missingkeys[$parsedkeys[$key]]);
                 }
             }
         }
         $hasmissingkeys = count($missingkeys) > 0;
         if ($datasource !== false && $hasmissingkeys) {
             // We're still missing keys but we've got a datasource.
             foreach ($datasource->load_many_for_cache($missingkeys) as $key => $value) {
                 if ($value !== false) {
                     $return[$key] = $value;
                     unset($missingkeys[$parsedkeys[$key]]);
                 }
             }
             $hasmissingkeys = count($missingkeys) > 0;
         }
     }
     if ($hasmissingkeys && $strictness === MUST_EXIST) {
         throw new coding_exception('Requested key did not exist in any cache stores and could not be loaded.');
     }
     if ($this->perfdebug) {
         $hits = 0;
         $misses = 0;
         foreach ($return as $value) {
             if ($value === false) {
                 $misses++;
             } else {
                 $hits++;
             }
         }
         cache_helper::record_cache_hit($this->storetype, $this->get_definition()->get_id(), $hits);
         cache_helper::record_cache_miss($this->storetype, $this->get_definition()->get_id(), $misses);
     }
     return $return;
 }
Example #2
0
 /**
  * Retrieves the value for the given key from the cache.
  *
  * @param string|int $key The key for the data being requested.
  *      It can be any structure although using a scalar string or int is recommended in the interests of performance.
  *      In advanced cases an array may be useful such as in situations requiring the multi-key functionality.
  * @param int $strictness One of IGNORE_MISSING | MUST_EXIST
  * @return mixed|false The data from the cache or false if the key did not exist within the cache.
  * @throws moodle_exception
  */
 public function get($key, $strictness = IGNORE_MISSING)
 {
     // Check the tracked user.
     $this->check_tracked_user();
     // 2. Parse the key.
     $parsedkey = $this->parse_key($key);
     // 3. Get it from the store.
     $result = false;
     $session = $this->get_session_data();
     if (array_key_exists($parsedkey, $session)) {
         $result = $session[$parsedkey];
         if ($result instanceof cache_ttl_wrapper) {
             if ($result->has_expired()) {
                 $this->get_store()->delete($parsedkey);
                 $result = false;
             } else {
                 $result = $result->data;
             }
         }
         if ($result instanceof cache_cached_object) {
             $result = $result->restore_object();
         }
     }
     // 4. Load if from the loader/datasource if we don't already have it.
     $setaftervalidation = false;
     if ($result === false) {
         if ($this->perfdebug) {
             cache_helper::record_cache_miss('**static session**', $this->get_definition()->get_id());
         }
         if ($this->get_loader() !== false) {
             // We must pass the original (unparsed) key to the next loader in the chain.
             // The next loader will parse the key as it sees fit. It may be parsed differently
             // depending upon the capabilities of the store associated with the loader.
             $result = $this->get_loader()->get($key);
         } else {
             if ($this->get_datasource() !== false) {
                 $result = $this->get_datasource()->load_for_cache($key);
             }
         }
         $setaftervalidation = $result !== false;
     } else {
         if ($this->perfdebug) {
             cache_helper::record_cache_hit('**static session**', $this->get_definition()->get_id());
         }
     }
     // 5. Validate strictness.
     if ($strictness === MUST_EXIST && $result === false) {
         throw new moodle_exception('Requested key did not exist in any cache stores and could not be loaded.');
     }
     // 6. Set it to the store if we got it from the loader/datasource.
     if ($setaftervalidation) {
         $this->set($key, $result);
     }
     // 7. Make sure we don't pass back anything that could be a reference.
     //    We don't want people modifying the data in the cache.
     if (!is_scalar($result)) {
         // If data is an object it will be a reference.
         // If data is an array if may contain references.
         // We want to break references so that the cache cannot be modified outside of itself.
         // Call the function to unreference it (in the best way possible).
         $result = $this->unref($result);
     }
     return $result;
 }
Example #3
0
 /**
  * Retrieves an array of values for an array of keys.
  *
  * Using this function comes with potential performance implications.
  * Not all cache stores will support get_many/set_many operations and in order to replicate this functionality will call
  * the equivalent singular method for each item provided.
  * This should not deter you from using this function as there is a performance benefit in situations where the cache store
  * does support it, but you should be aware of this fact.
  *
  * @param array $keys The keys of the data being requested.
  *      Each key can be any structure although using a scalar string or int is recommended in the interests of performance.
  *      In advanced cases an array may be useful such as in situations requiring the multi-key functionality.
  * @param int $strictness One of IGNORE_MISSING or MUST_EXIST.
  * @return array An array of key value pairs for the items that could be retrieved from the cache.
  *      If MUST_EXIST was used and not all keys existed within the cache then an exception will be thrown.
  *      Otherwise any key that did not exist will have a data value of false within the results.
  * @throws coding_exception
  */
 public function get_many(array $keys, $strictness = IGNORE_MISSING)
 {
     $this->check_tracked_user();
     $parsedkeys = array();
     $keymap = array();
     foreach ($keys as $key) {
         $parsedkey = $this->parse_key($key);
         $parsedkeys[$key] = $parsedkey;
         $keymap[$parsedkey] = $key;
     }
     $result = $this->get_store()->get_many($parsedkeys);
     $return = array();
     $missingkeys = array();
     $hasmissingkeys = false;
     foreach ($result as $parsedkey => $value) {
         $key = $keymap[$parsedkey];
         if ($value instanceof cache_ttl_wrapper) {
             /* @var cache_ttl_wrapper $value */
             if ($value->has_expired()) {
                 $this->delete($keymap[$parsedkey]);
                 $value = false;
             } else {
                 $value = $value->data;
             }
         }
         if ($value instanceof cache_cached_object) {
             /* @var cache_cached_object $value */
             $value = $value->restore_object();
         } else {
             if (!$this->get_store()->supports_dereferencing_objects() && !is_scalar($value)) {
                 // If data is an object it will be a reference.
                 // If data is an array if may contain references.
                 // We want to break references so that the cache cannot be modified outside of itself.
                 // Call the function to unreference it (in the best way possible).
                 $value = $this->unref($value);
             }
         }
         $return[$key] = $value;
         if ($value === false) {
             $hasmissingkeys = true;
             $missingkeys[$parsedkey] = $key;
         }
     }
     if ($hasmissingkeys) {
         // We've got missing keys - we've got to check any loaders or data sources.
         $loader = $this->get_loader();
         $datasource = $this->get_datasource();
         if ($loader !== false) {
             foreach ($loader->get_many($missingkeys) as $key => $value) {
                 if ($value !== false) {
                     $return[$key] = $value;
                     unset($missingkeys[$parsedkeys[$key]]);
                 }
             }
         }
         $hasmissingkeys = count($missingkeys) > 0;
         if ($datasource !== false && $hasmissingkeys) {
             // We're still missing keys but we've got a datasource.
             foreach ($datasource->load_many_for_cache($missingkeys) as $key => $value) {
                 if ($value !== false) {
                     $return[$key] = $value;
                     unset($missingkeys[$parsedkeys[$key]]);
                 }
             }
             $hasmissingkeys = count($missingkeys) > 0;
         }
     }
     if ($hasmissingkeys && $strictness === MUST_EXIST) {
         throw new coding_exception('Requested key did not exist in any cache stores and could not be loaded.');
     }
     if ($this->perfdebug) {
         $hits = 0;
         $misses = 0;
         foreach ($return as $value) {
             if ($value === false) {
                 $misses++;
             } else {
                 $hits++;
             }
         }
         cache_helper::record_cache_hit($this->storetype, $this->get_definition(), $hits);
         cache_helper::record_cache_miss($this->storetype, $this->get_definition(), $misses);
     }
     return $return;
 }
Example #4
0
 /**
  * Returns the item from the persist cache if it exists there.
  *
  * @param string $key The parsed key
  * @return mixed|false The data from the persist cache or false if it wasn't there.
  */
 protected function get_from_persist_cache($key)
 {
     if (is_array($key)) {
         $key = $key['key'];
     }
     if (!$this->persist || !array_key_exists($key, $this->persistcache)) {
         $result = false;
     } else {
         $data = $this->persistcache[$key];
         if (!$this->has_a_ttl() || !$data instanceof cache_ttl_wrapper) {
             if ($data instanceof cache_cached_object) {
                 $data = $data->restore_object();
             }
             $result = $data;
         } else {
             if ($data->has_expired()) {
                 $this->delete_from_persist_cache($key);
                 $result = false;
             } else {
                 if ($data instanceof cache_cached_object) {
                     $data = $data->restore_object();
                 }
                 $result = $data->data;
             }
         }
     }
     if ($result) {
         if ($this->perfdebug) {
             cache_helper::record_cache_hit('** static persist **', $this->definition->get_id());
         }
         return $result;
     } else {
         if ($this->perfdebug) {
             cache_helper::record_cache_miss('** static persist **', $this->definition->get_id());
         }
         return false;
     }
 }