function State::setMultiple

Same name and namespace in other branches
  1. 11.x core/lib/Drupal/Core/State/State.php \Drupal\Core\State\State::setMultiple()
  2. 10 core/lib/Drupal/Core/State/State.php \Drupal\Core\State\State::setMultiple()
  3. 9 core/lib/Drupal/Core/State/State.php \Drupal\Core\State\State::setMultiple()
  4. 8.9.x core/lib/Drupal/Core/State/State.php \Drupal\Core\State\State::setMultiple()

Saves key/value pairs.

Parameters

array $data: An associative array of key/value pairs.

Overrides StateInterface::setMultiple

File

core/lib/Drupal/Core/State/State.php, line 104

Class

State
Provides the state system using a key value store.

Namespace

Drupal\Core\State

Code

public function setMultiple(array $data) {
  $lock_name = $this->getCid() . ':' . CacheCollector::class;
  $lock_acquired = $this->lock
    ->acquire($lock_name);
  $this->lazyLoadCache();
  foreach ($data as $key => $value) {
    $this->registerKeySetDuringRequest($key, $value, parent::get($key));
    if (isset(self::$deprecatedState[$key])) {
      // phpcs:ignore Drupal.Semantics.FunctionTriggerError
      @trigger_error(self::$deprecatedState[$key]['message'], E_USER_DEPRECATED);
      $data[self::$deprecatedState[$key]['replacement']] = $value;
      unset($data[$key]);
    }
  }
  $this->keyValueStore
    ->setMultiple($data);
  // If another request had a cache miss before this request, and also hasn't
  // written to cache yet, then it may already have read the previous value
  // from the database and could write it to the cache at the end of the
  // request. To avoid this race condition, attempt to acquire a lock and
  // write to the cache immediately. This allows the race condition detection
  // in CacheCollector::updateCache() to work. We write to the cache whether
  // or not we acquire the lock, because CacheCollector::updateCache() handles
  // the case where there was no cache item at the beginning of the request,
  // but one was written by another request before ::updateCache() is called
  // - the new cache item functions as a tombstone record in this case.
  foreach ($data as $key => $value) {
    $this->storage[$key] = $value;
    // The key might have been marked for deletion.
    unset($this->keysToRemove[$key]);
    $this->persist($key);
  }
  if (!$lock_acquired) {
    // If we were unable to acquire a lock, immediately write the cache item
    // anyway. This acts as a tombstone for other requests that have not
    // reached a cache write yet: writing an (empty) item makes a concurrent
    // request that loaded a different item - or no item - detect the change
    // by content in ::updateCache() and back out. It also ensures that the
    // end of this request will detect that the cache item has changed.
    $this->cache
      ->set($this->getCid(), [], CacheBackendInterface::CACHE_PERMANENT, $this->tags);
    $this->cacheInvalidated = TRUE;
    // Wait for the lock to become available for a maximum of one second, then
    // attempt to acquire the lock again. If we can't acquire the lock, then
    // the one second that has passed should have given most processes that
    // were in progress time to complete anyway.
    $this->lock
      ->wait($lock_name, 1);
    $lock_acquired = $this->lock
      ->acquire($lock_name);
    // If we were unable to acquire the lock even after waiting, write the
    // cache item a second time, this will override any cache writes in the
    // interim.
    if (!$lock_acquired) {
      $this->cache
        ->set($this->getCid(), [], CacheBackendInterface::CACHE_PERMANENT, $this->tags);
    }
  }
  if ($lock_acquired) {
    // Write the new value within the lock. A concurrent request that read an
    // earlier cache item will detect the change when it compares the data
    // fingerprint in CacheCollector::updateCache(), even if both writes
    // happened within the same millisecond. This is why no sleep is needed to
    // force distinct cache item creation timestamps.
    // @see \Drupal\Core\Cache\CacheCollector::updateCache()
    $this->cache
      ->set($this->getCid(), $data, CacheBackendInterface::CACHE_PERMANENT, $this->tags);
    // Because we've updated the cache within a lock here, we don't need to do
    // so again at the end of the request. Other requests can safely start
    // rebuilding the cache after this point.
    $this->lock
      ->release($lock_name);
    $this->cacheInvalidated = FALSE;
    $this->keysToPersist = [];
    $this->keysToRemove = [];
  }
}

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.