Hi, now on Drupal core the cache.container is using the database cache also when you have set it on the cache.container, the solution around this is set directly on $settings['bootstrap_container_definition'] definition, but now the DrupalMemcacheFactory don't have a static method that we can use to get the DrupalBackEnd instance...

  $loader = new \Composer\Autoload\ClassLoader();
  $loader->addPsr4('Drupal\\memcache\\', 'modules/contrib/memcache/src');
  $loader->register();

  $settings['bootstrap_container_definition'] = [
    'parameters' => [],
    'services' => [
      'database' => [
        'class' => 'Drupal\Core\Database\Connection',
        'factory' => 'Drupal\Core\Database\Database::getConnection',
        'arguments' => ['default'],
      ],
      'settings.container' => [
        'class' => 'Drupal\Core\Site\Settings',
        'factory' => 'Drupal\Core\Site\Settings::getInstance',
      ],
      'memcache.config.container' => [
        'class' => 'Drupal\memcache\DrupalMemcacheConfig',
        'arguments' => ['@settings.container'],
      ],
      'memcache.backend.cache.container' => [
        'class' => 'Drupal\memcache\DrupalMemcacheFactory',
        'factory' => 'Drupal\memcache\DrupalMemcacheFactory::getInstance',
        'arguments' => ['@memcache.config.container'],
      ],
      'lock.container' => [
        'class' => 'Drupal\memcache\Lock\MemcacheLockBackend',
        'arguments' => ['container', '@memcache.backend.cache.container'],
      ],
      'cache.container' => [
        'class' => 'Drupal\memcache\MemcacheBackend',
        'arguments' => ['container', '@memcache.backend.cache.container', '@lock.container', '@memcache.config.container', '@cache_tags_provider.container'],
      ],
      'cache_tags_provider.container' => [
        'class' => 'Drupal\Core\Cache\DatabaseCacheTagsChecksum',
        'arguments' => ['@database'],
      ],
    ]
  ];

This should be the code to override it, but we don't have that static method. My suggestion is to create the static method inside the DrupalMemcacheFactory class, What you guys think about it?

Which that we can just override the cache container using memcache

The code for the static method should be like this

  /**
   * Get the right memcache drupal class.
   *
   * @param \Drupal\memcache\DrupalMemcacheConfig $settings
   * @return \Drupal\memcache\DrupalMemcache|\Drupal\memcache\DrupalMemcached
   */
  public static function getInstance(DrupalMemcacheConfig $settings) {
    $preferred = $settings->get('extension', NULL);
    if (isset($preferred) && class_exists($preferred)) {
      $extension= $preferred;
    }
    // If no extension is set, default to Memcache. The Memcached extension has
    // some features that the older extension lacks but also an unfixed bug that
    // affects cache clears.
    // @see http://pecl.php.net/bugs/bug.php?id=16829
    elseif (class_exists('Memcache')) {
      $extension = 'Memcache';
    }
    elseif (class_exists('Memcached')) {
      $extension = 'Memcached';
    }
    else {
      throw new MemcacheException('No Memcache extension found');
    }

    // Create a new Memcache object. Each cluster gets its own Memcache
    // object.
    // @todo Can't add a custom memcache class here yet.
    if ($extension == 'Memcached') {
      return new DrupalMemcached($settings);
    }

    return new DrupalMemcache($settings);
  }

I cannot instantiate the class directly because I need to make the decision between the Memcache or memcached...

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

guilopes created an issue. See original summary.

guilopes’s picture

A better solution for the method would be something like this

  public static function getInstance(DrupalMemcacheConfig $settings, $bin = NULL) {
    $memcacheFactory = new \Drupal\memcache\DrupalMemcacheFactory($settings);
    return $memcacheFactory->get($bin);
  }
guilopes’s picture

I've found a best way to do that

  $settings['bootstrap_container_definition'] = [
    'parameters' => [],
    'services' => [
      'database' => [
        'class' => 'Drupal\Core\Database\Connection',
        'factory' => 'Drupal\Core\Database\Database::getConnection',
        'arguments' => ['default'],
      ],
      'settings' => [
        'class' => 'Drupal\Core\Site\Settings',
        'factory' => 'Drupal\Core\Site\Settings::getInstance',
      ],
      'memcache.config' => [
        'class' => 'Drupal\memcache\DrupalMemcacheConfig',
        'arguments' => ['@settings'],
      ],
      'memcache.backend.cache.factory' => [
        'class' => 'Drupal\memcache\DrupalMemcacheFactory',
        'arguments' => ['@memcache.config']
      ],
      'memcache.backend.cache.container' => [
        'class' => 'Drupal\memcache\DrupalMemcacheFactory',
        'factory' => ['@memcache.backend.cache.factory', 'get'],
        'arguments' => ['container'],
      ],
      'lock.container' => [
        'class' => 'Drupal\memcache\Lock\MemcacheLockBackend',
        'arguments' => ['container', '@memcache.backend.cache.container'],
      ],
      'cache.container' => [
        'class' => 'Drupal\memcache\MemcacheBackend',
        'arguments' => ['container', '@memcache.backend.cache.container', '@lock.container', '@memcache.config', '@cache_tags_provider.container'],
      ],
      'cache_tags_provider.container' => [
        'class' => 'Drupal\Core\Cache\DatabaseCacheTagsChecksum',
        'arguments' => ['@database'],
      ],
    ],
  ];
guilopes’s picture

the following patch add the documentation to the module. with this configuration you have no cache tables in the database anymore

guilopes’s picture

Status: Active » Needs review
guilopes’s picture

is it possible to add this documentation? it's a non code change

mxh’s picture

Status: Needs review » Needs work

@guilopes Nice, many thanks for this!
I have tested your approach and it works. Your documentation is currently missing the class loading part, please add this to the documentation.

Please note: You should always be able to have a $class_loader variable being usable inside settings.php, see also Settings::initialize. I'm currently using this in my settings.php:

<?php
if (class_exists('Memcache', FALSE) || class_exists('Memcached', FALSE)) {
  $class_loader->addPsr4('Drupal\\memcache\\', 'modules/contrib/memcache/src');

  // Define custom bootstrap container definition to use Memcache for cache.container.
  $settings['bootstrap_container_definition'] = [
    'parameters' => [],
    'services' => [
      'database' => [
        'class' => 'Drupal\Core\Database\Connection',
        'factory' => 'Drupal\Core\Database\Database::getConnection',
        'arguments' => ['default'],
      ],
      'settings' => [
        'class' => 'Drupal\Core\Site\Settings',
        'factory' => 'Drupal\Core\Site\Settings::getInstance',
      ],
      'memcache.config' => [
        'class' => 'Drupal\memcache\DrupalMemcacheConfig',
        'arguments' => ['@settings'],
      ],
      'memcache.backend.cache.factory' => [
        'class' => 'Drupal\memcache\DrupalMemcacheFactory',
        'arguments' => ['@memcache.config']
      ],
      'memcache.backend.cache.container' => [
        'class' => 'Drupal\memcache\DrupalMemcacheFactory',
        'factory' => ['@memcache.backend.cache.factory', 'get'],
        'arguments' => ['container'],
      ],
      'lock.container' => [
        'class' => 'Drupal\memcache\Lock\MemcacheLockBackend',
        'arguments' => ['container', '@memcache.backend.cache.container'],
      ],
      'cache_tags_provider.container' => [
        'class' => 'Drupal\Core\Cache\DatabaseCacheTagsChecksum',
        'arguments' => ['@database'],
      ],
      'cache.container' => [
        'class' => 'Drupal\memcache\MemcacheBackend',
        'arguments' => ['container', '@memcache.backend.cache.container', '@lock.container', '@memcache.config', '@cache_tags_provider.container'],
      ],
    ],
  ];
}
?>
guilopes’s picture

Status: Needs work » Needs review
FileSize
2.39 KB

Thanks @mxh, I've updated it on the following patch ;)

guilopes’s picture

can me merge this documentation ?

damiankloip’s picture

This looks good! Just a couple of things:

  1. +++ b/README.txt
    @@ -171,6 +171,54 @@ Memcache locks can be enabled through the services.yml file.
    +By default Drupal start the cache_container on the database, in order to override that you can use the following code on your settings.php file. Make sure that the $class_load->addPsr4 is poiting to the right location of memcache (on this case modules/contrib/memcache/src)
    

    s/starts/start

    Also, this is way above 80 chars, can you split this text into multiple lines with limit of 80 chars per line please?

  2. +++ b/README.txt
    @@ -171,6 +171,54 @@ Memcache locks can be enabled through the services.yml file.
    +if (class_exists('Memcache', FALSE) || class_exists('Memcached', FALSE)) {
    

    how come we need this check? does code from settings get loaded multiple times or something?

guilopes’s picture

Thanks @damiankloip, it's updated

afi13’s picture

Assigned: guilopes » Unassigned
Status: Needs review » Reviewed & tested by the community

Ok for me

  • damiankloip committed 730f0ef on 8.x-2.x
    Issue #2882755 by guilopes, mxh, damiankloip, afi13: Move container to...
damiankloip’s picture

Status: Reviewed & tested by the community » Fixed

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

ericpugh’s picture

Would the new code block in README.txt replace the default settings?
$settings['cache']['default'] = 'cache.backend.memcache';

I'm getting a fatal error 'cache.backend.memcache' service not found.

guilopes’s picture

@ericpught if you doesn't have the memcache module enabled you should include the memcache.services.yml as well