Модуль для контроля кэширования блоков в Drupal 6.x

Главные вкладки

Аватар пользователя batbug batbug 25 февраля 2009 в 13:25

Одна из самых больших проблем в быстродействии друпала - блоки. Блоки в шестом друпале практически не кэшируются. В своё время для пятой версии был написан замечательный модуль blockcache, а мною - его модификация. В Друпал-6 blockcache вошел в урезанном виде, оставив минимальные настройки кэширования блоков лишь для разработчиков модулей, а для простых пользователей не осталось ничего. Небольшие подвижки произошли с выходом модуля blockcache_alter, который позволяет админу сайта менять режим кэширования для каждого блока, но это лишь слабая пародия на всё то, что предлагает blockcache для пятёрки. Поэтому мною был модифицирован blockcache_alter, и теперь в нём есть все фичи от оригинального blockcache + мои модификации. К сожалению, без патча ядра не обошлось. Но это того стоит.

Итак, новые возможности.

  1. можно выбрать тип кэширования (не кэшировать, кэшировать раз и навсегда, кэшировать для каждой роли отдельно, отдельно для каждого пользователя, для каждой страницы + комбинации)
  2. можно выбирать насколько закешировать блок. По истечении указанного времени блок будет обновлён
  3. можно выбрать события, когда блок будет обновлен, даже если время из п.2 ещё не истекло (обновление нод/обновление комментария/регистрация пользователя/логин-логаут).
  4. Если в п.3 отмечены пункты а) и б), то можно указать ноды какого типа вызовут обновление блока. Это полезно чтобы не обновлять лишние блоки, а обновлять только нужные. Подробнее об этом я писал в моей модификации под пятерку.

В сумме комбинация этих настроек позволяет ОЧЕНЬ гибко настроить кэширование блоков. И это особенно полезно будет на тех сайтах, где много блоков на странице. Мой мод кэширует любые блоки, даже от views.

Однако, как я говорил, требуется хак ядра, ибо кэширование блоков производится лишь в одном месте, когда формируется регион шаблона. Находим файл block.module, нужная нам функция - block_list(). Примерно 400ая строка.

Находим эту часть (примерно 469 строка):

<?php
          if (!count(module_implements('node_grants')) && $_SERVER['REQUEST_METHOD'] == 'GET' && ($cid = _block_get_cache_id($block)) && ($cache = cache_get($cid, 'cache_block'))) {
            $array = $cache->data;
          }
          else {
            $array = module_invoke($block->module, 'block', 'view', $block->delta);
            if (isset($cid)) {
              cache_set($cid, $array, 'cache_block', CACHE_TEMPORARY);
            }
          }
?>

и заменяем на такую:

<?php
         if (!count(module_implements('node_grants')) && $_SERVER['REQUEST_METHOD'] == 'GET' && ($cid = _block_get_cache_id($block)) && ($cache = cache_get($cid, 'cache_block'))) {
            $array = $cache->data;
          }
          else {
            $array = module_invoke($block->module, 'block', 'view', $block->delta);
            if (isset($cid)) {
              $blocklife = variable_get('bc_life_' . $block->module . '_' . $block->delta, '');
        $blocklife = (int)$blocklife;
        if($blocklife > 1) {
                 cache_set($cid, $array, 'cache_block', $blocklife + time());
            }
        else {
              cache_set($cid, $array, 'cache_block', CACHE_TEMPORARY);
        }

    if (variable_get('bca_debug', FALSE) && user_access('administer nodes')) {
    drupal_set_message('Block re-cached: ' . $block->title . '_' . $block->module . '_' . $block->delta . '_' . $blocklife . '_' . time());
                }

            }
          }
?>

Без патча ничего кэшироваться не будет.

Также в моём моде появилась страница настроек (admin/settings/blockcache_alter), где можно включить вывод отладочной информации о том, когда какой блок обновился.

И еще одно замечание: многие друпальщики любят выводить блоки в произвольных местах следующим сниппетом

<?php
$block = module_invoke('block', 'block', 'view', '14');
print $block['content'];
?>

Выяснилось, что в шестерке данный код выведет блок без кэширования, потому что обычно в этом случае блок не активирован и он не привязан ни к одному региону. Для обхода этой проблемы используйте следующий сниппет:

<?php
$block = module_invoke('blockcache_alter', 'block', 'view', 'block,14');
print $block['content'];
?>

В последнем параметре через запятую укажите модуль и дельту нужного блока и всё получится Smile Например, код выше выведет блок 14 из модуля block, а код

<?php
$block = module_invoke('blockcache_alter', 'block', 'view', 'views,popular-block');
print $block['content'];
?>

выведет блок "popular-block" из вьюсов.

К посту прикреплена моя, уже готовая версия модуля blockcache_alter.

ВложениеРазмер
Иконка пакета blockcache_alter_new_by_batbug1.zip13.5 КБ

Комментарии

Аватар пользователя batbug batbug 25 февраля 2009 в 19:54

У себя этот модуль включен уже месяц, никаких глюков не замечено, но было бы неплохо, если бы кто-то еще попробовал его в действии. Багрепорты тоже приветствуются.

Аватар пользователя batbug batbug 26 февраля 2009 в 9:19

"<a href="mailto:GDI@drupal.org">GDI@drupal.org</a>" wrote:
А в архив модуля добавить инструкции по хаку ядра.

Добавил.

"<a href="mailto:GDI@drupal.org">GDI@drupal.org</a>" wrote:
Может на drupal.org написать, пусть они добавят в ядро этот код.

Я написал автору модуля blockcache_alter в issues, но пока нет никакой реакции. В принципе почти все это можно было взять из blockcache5, а почему разработчики ядра не стали - не знаю, наверно это массам не нужно. Даже друпалу.ру интереснее кнопки к буедитору доделать Wink

Аватар пользователя T-34 T-34 6 марта 2009 в 1:32

А как проверить, что кэширование работает? Модуль использует таблицу cache_block? У меня она пуста, и судя по логу запросов, сниппет из одного блока выполняется при каждом обновлении страницы, хотя в настройках блока включено вечное кэширование.
block.module я патчил

Аватар пользователя batbug batbug 6 марта 2009 в 6:34

"T-34" wrote:
сниппет из одного блока выполняется при каждом обновлении страницы, хотя в настройках блока включено вечное кэширование.

Какие параметры кэширования заданы, кроме времени? И, кстати, сколько это "вечное"?

Аватар пользователя T-34 T-34 6 марта 2009 в 15:29

batbug wrote:
На странице настроек производительности сайта не забудьте разрешить кэширование блоков!

Включил, ничего не изменилось. Таблица cache_block пуста. Это не может быть связано с тем, что обновлял сайт с пятерки, на которой стоял Block Cache?

batbug wrote:
Какие параметры кэширования заданы, кроме времени? И, кстати, сколько это "вечное"?

В "производительности" стоит время жизни кэша 5 минут. В настройках блоков ставлю Cache once for everything (global), Cache lifetime оставляю пустым и ставлю Refresh when A comment is added/updated/deleted в одном блоке, A node is added/updated/deleted и A comment is added/updated/deleted в другом, и т.п. relation в первом случае оставляю пустым, во втором отмечаю требуемые типы.

Аватар пользователя batbug batbug 6 марта 2009 в 6:59

Кстати! Совсем забыл! На странице настроек производительности сайта не забудьте разрешить кэширование блоков!

Аватар пользователя Dan Dan 6 марта 2009 в 10:48

"<a href="mailto:GDI@drupal.org">GDI@drupal.org</a>" wrote:
Может на drupal.org написать, пусть они добавят в ядро этот код. А в архив модуля добавить инструкции по хаку ядра.

надо не инструкцию, а патч.

Аватар пользователя batbug batbug 6 марта 2009 в 18:38

"T-34" wrote:
Включил, ничего не изменилось. Таблица cache_block пуста. Это не может быть связано с тем, что обновлял сайт с пятерки, на которой стоял Block Cache?

Да-да, скорее всего, у меня тоже возникали с этим проблемы. Вам нужно пересоздать таблицу cache_block. Можете посмотреть ее в инсталляторе д.6 или воспользоваться моим кодом для мускула

CREATE TABLE IF NOT EXISTS `cache_block` (
  `cid` varchar(255) NOT NULL default '',
  `data` longblob,
  `expire` int(11) NOT NULL default '0',
  `created` int(11) NOT NULL default '0',
  `headers` text,
  `serialized` smallint(6) NOT NULL default '0',
  PRIMARY KEY  (`cid`),
  KEY `expire` (`expire`)
)
Аватар пользователя T-34 T-34 6 марта 2009 в 23:30

batbug wrote:
Вам нужно пересоздать таблицу cache_block.

Ага, спасибо, теперь записи в ней появляются.

Уфф, полчаса искал причину того, почему блоки не берутся из кэша - оказалось, что это только под админом.

Супер. Вывод кэшированного блока со сниппетом через вьюс вместо просто вывода сниппета через вьюс сократил Page execution time в 2 раза Smile

Аватар пользователя Dan Dan 6 марта 2009 в 21:42

Кстати, Drupal позволяет перекрыть свой механизм кэширования своими функциями. Вы прошерстили эту тему, может быть возможно без хака ядра заюзать дополнительное кэширование для блоков?

Аватар пользователя batbug batbug 7 марта 2009 в 6:54

"Dan" wrote:
Кстати, Drupal позволяет перекрыть свой механизм кэширования своими функциями. Вы прошерстили эту тему, может быть возможно без хака ядра заюзать дополнительное кэширование для блоков?

Блоки кэшируются лишь в одном месте - в block_list(), во время рендера страницы. Я искал способ перекрыть эту функцию, но ничего не придумал. Если кто-то подскажет, буду сильно благодарен.

А что касается "перекрывать механизм кэширования", я так понимаю, под этим имеется в виду функции cache_set/cache_get, а в нашем случае требуется перекрыть момент кэширования.

"T-34" wrote:
Супер. Вывод кэшированного блока со сниппетом через вьюс вместо просто вывода сниппета через вьюс сократил Page execution time в 2 раза :)

У меня на главной 11 вьюсов выводятся за 200 запросов и полсекунды - и это для авторизованных юзеров!

Аватар пользователя shp shp 29 марта 2009 в 0:22

batbug, просмотрев ваш все-таки состоявшийся разговор с автором blockcache_alter, а также dev-версию оригинального blockcache_alter и ваши патчи, я так понял, что эти патчи он все-таки включил к себе в модуль?

Правда, в одном патче условие у него
<?php if (!count(module_implements('node_grants'))
&& $_SERVER['REQUEST_METHOD'] == 'GET' && ($cid = _block_get_cache_id($block))
&& ($cache = cache_get($cid, 'cache_block'))) ?>
зачем-то проверяется 2 раза Smile

Какие у вас дальнейшие планы по поводу своего модуля, если выйдет релиз blockcache_alter с вашими патчами? Будете параллельно поддерживать свою версию с доп. настройками?

P.S. Кстати, обновление кэша блока после неких событий (ваши доп. настройки), по идее, можно сделать через триггеры, которые появились в шестерке.

Аватар пользователя batbug batbug 29 марта 2009 в 19:46

"shp" wrote:
также dev-версию оригинального blockcache_alter и ваши патчи, я так понял, что эти патчи он все-таки включил к себе в модуль?

Да, можно брать дев-релиз http://drupal.org/node/395422

"shp" wrote:
Правда, в одном патче условие у него
зачем-то проверяется 2 раза :)

Хмм, в дев-версии не нашел такого.

"shp" wrote:
Какие у вас дальнейшие планы по поводу своего модуля, если выйдет релиз blockcache_alter с вашими патчами? Будете параллельно поддерживать свою версию с доп. настройками?

Моя версия она вполне самодостаточна и рабочая. Для всех рекомендовал бы сейчас ставить версию автора, так как он ее сделал покрасивее, а работает она также как и моя. Еще важный момент, автор модуля предусмотрел ситуации c node_grants хуком, что для многих может быть важно.

Я лично пока не ставил на свой production эту новую дев-версию, так как я консерватор Smile у меня все работает и ладно Smile

Собственных новых версий пока не планирую.

"shp" wrote:
P.S. Кстати, обновление кэша блока после неких событий (ваши доп. настройки), по идее, можно сделать через триггеры, которые появились в шестерке.

Да, вполне, делайте Smile
Я триггеры вообще никогда не трогал, так что заниматься этим не планирую пока.
Но была мысль добавить в настройки блоков обновление по крону, что несложно.

Аватар пользователя shp shp 31 марта 2009 в 19:47

batbug wrote:
Хмм, в дев-версии не нашел такого.

Да, я забыл, что это патч Smile Там одна строка меняется на другую, а я подумал, что в исходнике 2 одинаковых строки.

Аватар пользователя rmcippo rmcippo 8 апреля 2009 в 11:41

Поставил blockcache_alter-6.x-1.x-dev.tar.gz пропатчил block.module этим патчем blockcache_alter_with_node_grants.patch, поставил кеширование на блок последних новостей cache once for everything, refresh when: A node is added/updated/deleted и A comment is added/updated/deleted для Relation: Новости. Cache lifetime: оставил пустым, но в cache_block так ничего и не записывается. Пересоздавал таблицу cache_block, как здесь написано - ничего не помогает. У меня стоит модуль ограничения доступа: Content Access, поэтому стандартное кеширование блоков друпала не работает (Написано: кеширование блоков не работает при использовании модулей ограничивающих доступ к содержанию) Может, из-за этого? Но я пробовал отключать модуль Content Access (но не удалял его) но все равно в cache_block ничего не записывается. Подскажите, пожалуйста, в чем может тут быть дело? Спасибо

Аватар пользователя batbug batbug 8 апреля 2009 в 12:43

1) На странице настроек производительности сайта не забудьте разрешить кэширование блоков.

2) Кэширование никогда не работает под рутом (uid = 1)

"rmcippo" wrote:
У меня стоит модуль ограничения доступа: Content Access, поэтому стандартное кеширование блоков друпала не работает (Написано: кеширование блоков не работает при использовании модулей ограничивающих доступ к содержанию) Может, из-за этого?

Тоже возможно.

Аватар пользователя rmcippo rmcippo 8 апреля 2009 в 13:59

batbug wrote:
1) На странице настроек производительности сайта не забудьте разрешить кэширование блоков.

2) Кэширование никогда не работает под рутом (uid = 1)

"rmcippo" wrote:
У меня стоит модуль ограничения доступа: Content Access, поэтому стандартное кеширование блоков друпала не работает (Написано: кеширование блоков не работает при использовании модулей ограничивающих доступ к содержанию) Может, из-за этого?

Тоже возможно.

Модуль Content Access удалил, На странице настроек -->быстродействие --> разрешил кеширование блоков, но записей в таблице cache_block все равно не появляется. Может, что-то еще упустил?

Аватар пользователя rmcippo rmcippo 8 апреля 2009 в 14:04

rmcippo][quote=batbug wrote:
но записей в таблице cache_block все равно не появляется. Может, что-то еще упустил?
Поторопился написать, запись пошла, спасибо за помощь

Аватар пользователя rmcippo rmcippo 8 апреля 2009 в 23:06

batbug wrote:
Пожалуйста. Так в чем ошибка была?
Ошибки, как таковой, не было, просто модуль кеширования не работает совместно с модулями, ограничивающими доступ к содержанию. Последовательно протестировал работу blockcache_alter с модулями ограничения доступа: Content Access и Private. С включенными этими модулями кеширование не происходит. Как тут можно выйти из положения и чтобы кеширование было, и чтобы работал один из модулей: Content Access или Private? Можете что-нибудь посоветовать? Спасибо

Аватар пользователя shp shp 12 апреля 2009 в 22:20

Новость запоздала на 2 недели, но все же Smile

Появился новый релиз "оригинального" blockcache_alter

Есть и патчи, и настройки кэширования, и страница настроек модуля. В readme - инструкции при выводе блоков программным способом, которые приводил batbug.

Аватар пользователя batbug batbug 13 апреля 2009 в 5:40

"rmcippo" wrote:
Как тут можно выйти из положения и чтобы кеширование было, и чтобы работал один из модулей: Content Access или Private? Можете что-нибудь посоветовать? Спасибо

В новом релизе два патча, один из них вроде как раз для вашего случая, там нет проверки на node_grants, но его надо применять осторожно.

Аватар пользователя rmcippo rmcippo 15 апреля 2009 в 3:23

batbug wrote:
"rmcippo" wrote:
Как тут можно выйти из положения и чтобы кеширование было, и чтобы работал один из модулей: Content Access или Private? Можете что-нибудь посоветовать? Спасибо

В новом релизе два патча, один из них вроде как раз для вашего случая, там нет проверки на node_grants, но его надо применять осторожно.
Я автору написал, что проблемы с модулями ограничения доступа, он отреагировал и быстро подправил, вроде пофиксил проблему, работает нормально. Скажите, а почему почему патч без проверки на node_grants нужно применять осторожно?

Аватар пользователя batbug batbug 15 апреля 2009 в 6:56

node_grants - это проверки на доступ к данным на уровне отдельных пользователей (не ролей). если вы отмените их, то возможно возникновение ситуаций, когда человек с одними правами зайдет на страницу, блок закэшируется и туда попадут данные, которые не должны видеть другие пользователии. Т.о. в данном случае надо аккуратно расставлять параметры кэширования для блоков, чтобы не кэшировалось то, что может представлять опасность.

Аватар пользователя rmcippo rmcippo 15 апреля 2009 в 12:54

batbug wrote:
node_grants - это проверки на доступ к данным на уровне отдельных пользователей (не ролей). если вы отмените их, то возможно возникновение ситуаций, когда человек с одними правами зайдет на страницу, блок закэшируется и туда попадут данные, которые не должны видеть другие пользователии. Т.о. в данном случае надо аккуратно расставлять параметры кэширования для блоков, чтобы не кэшировалось то, что может представлять опасность.
Правильно ли я понял, что если доступ к контенту только на уровне ролей (на уровне пользователей разграничения нет), то отключить проверки node_grants можно без каких-либо отрицательных последствий? Спасибо еще раз.

Аватар пользователя Dan Dan 15 апреля 2009 в 11:57

"batbug" wrote:
чтобы не кэшировалось то, что может представлять опасность

Пример? Скорее не опасность, а приватность Smile Потому как даже если закешируется админ-меню, в любом случае нельзя будет залезть в админку, если нет прав.

Аватар пользователя batbug batbug 15 апреля 2009 в 12:16

Это вопрос семантики, и он меня не сильно волнует. В любом случае, яндексу с гуглом не стоит тыкаться по системным ссылкам, тем самым вызывая 403 ошибку, тем самым создавая ненужную нагрузку, а уж посетителям сайта видеть системные пути вообще нельзя, среди них бывают разные школьнеги-кулхацкеры.

Аватар пользователя batbug batbug 15 апреля 2009 в 13:53

"rmcippo" wrote:
Правильно ли я понял, что если доступ к контенту только на уровне ролей (на уровне пользователей разграничения нет), то отключить проверки node_grants можно без каких-либо отрицательных последствий?

Думаю, да.

Аватар пользователя iluhin iluhin 30 июня 2009 в 21:15

отличный модуль, спасибо! Поставил на 6.х точно не замерял, но по ощущениям, в минимум в 2 раза быстрее все стало работать!

Аватар пользователя Paldru Paldru 20 августа 2009 в 18:04

"shp" wrote:
Появился новый релиз "оригинального" blockcache_alter

Там нужно патчить с помощью .paptch. А можете обьяснить как вручную пропатчить block.module, потому как патчами я пользоваться не умею Sad

Аватар пользователя T-34 T-34 20 августа 2009 в 23:01

Открываете патч и файл, который нужно пропатчить. В патче строки, перед которым стоит минус, находите в исходном файле и заменяете на те, что с плюсом.
или посмотрите http://drupal.ru/node/28171

Аватар пользователя Shevskay Shevskay 21 августа 2009 в 13:09

Здравствуйте, хочется то же blockcache на drupal 6, а не получается, помогите пожалуйста? На drupal 5 он работал нормально, а на drupal 6 так и не работает. Включаю выдает кучу ошибок, выключаю ни одной ошибки. То что здесь выше советовали, не знаю как реализовать, может помогло бы, а именно "пересоздать таблицу cache_block" как это сделать, подскажите пожалуйста?

Вот некоторые из возникающих ошибок:

user warning: Unknown column 'serialized' in 'field list' query: SELECT data, created, headers, expire, serialized FROM cache_block WHERE cid = 'sape:0:tapestry:ru:r.1' in /home/k/knatalya/fizkult-ura.ru/public_html/includes/cache.inc on line 26.

user warning: Unknown column 'serialized' in 'field list' query: UPDATE cache_block SET data = 'a:2:{s:7:\"subject\";s:19:\"Sape - блок - 0\";s:7:\"content\";s:40:\"

\n

\n \n\";}', created = 1250780544, expire = -1, headers = '', serialized = 1 WHERE cid = 'sape:0:tapestry:ru:r.1' in /home/k/knatalya/fizkult-ura.ru/public_html/includes/cache.inc on line 109.

Аватар пользователя batbug batbug 21 августа 2009 в 7:38

"Shevskay" wrote:
Здравствуйте, хочется то же blockcache на drupal 6, а не получается, помогите пожалуйста? На drupal 5 он работал нормально, а на drupal 6 так и не работает. Включаю выдает кучу ошибок, выключаю ни одной ошибки. То что здесь выше советовали, не знаю как реализовать, может помогло бы, а именно "пересоздать таблицу cache_block" как это сделать, подскажите пожалуйста?

Открываете phpmyadmin, находите таблицу cache_block, удаляете её целиком, затем находите в phpmyadmin кнопку для вставки SQL-кода и вставляете:

CREATE TABLE IF NOT EXISTS `cache_block` (
  `cid` varchar(255) NOT NULL default '',
  `data` longblob,
  `expire` int(11) NOT NULL default '0',
  `created` int(11) NOT NULL default '0',
  `headers` text,
  `serialized` smallint(6) NOT NULL default '0',
  PRIMARY KEY  (`cid`),
  KEY `expire` (`expire`)
)
Аватар пользователя Shevskay Shevskay 21 августа 2009 в 13:05

Спасибо за советы. Сделала так:

"batbug" wrote:
Открываете phpmyadmin, находите таблицу cache_block, удаляете её целиком, затем находите в phpmyadmin кнопку для вставки SQL-кода и вставляете:

CREATE TABLE IF NOT EXISTS `cache_block` (
`cid` varchar(255) NOT NULL default '',
`data` longblob,
`expire` int(11) NOT NULL default '0',
`created` int(11) NOT NULL default '0',
`headers` text,
`serialized` smallint(6) NOT NULL default '0',
PRIMARY KEY (`cid`),
KEY `expire` (`expire`)
)

помогло, все ошибки исчезли, спасибо большущее batbug.

Аватар пользователя T-34 T-34 8 октября 2009 в 22:16

На друпале 6.14 почему-то опять не работает кэширование в Block Cache Alter... Пересоздал таблицу cache_block - не помогло. Кто-нибудь сталкивался?

Аватар пользователя Gukov Yor Gukov Yor 4 декабря 2009 в 15:25

Блин, всё перепробовал и таблицу удалял и кэш чистил и всё что описано выше, но белую страницу после сохранения в админке исправить не могу....

Аватар пользователя wolfXXXL wolfXXXL 11 мая 2010 в 13:56

"rmcippo" wrote:
У меня стоит модуль ограничения доступа: Content Access, поэтому стандартное кеширование блоков друпала не работает (Написано: кеширование блоков не работает при использовании модулей ограничивающих доступ к содержанию)

"batbug" wrote:
В новом релизе два патча, один из них вроде как раз для вашего случая, там нет проверки на node_grants, но его надо применять осторожно.

Спасибо Ваши комменты помогли найти и решить проблему "не кэширования" блоков из-за Content Access.

Аватар пользователя AP AP 13 сентября 2011 в 12:35

Поставил Block Cache Alter
Таблица block cache пустая. Захожу в блоки, ставлю кешировать. Сохраняю, выхожу - захожу заново в блок - стоит "не кешировать".

Аватар пользователя AP AP 13 сентября 2011 в 12:43

Вернее не так, на каких то блоках настройка сохраняется, а на каких то - сколько не меняй - все равно стоит не кешировать