I've install latest DEV, only nodewords was enabled. Ran all updates and than enabled basic_metatags. The tags haven't shown up in the admin/content/nodewords.

CommentFileSizeAuthor
#7 Voila_Capture_41.png61.51 KBavpaderno

Comments

avpaderno’s picture

Status: Active » Postponed (maintainer needs more info)

Did you enable the meta tags that should be edited, and the ones that should be added in the HTML output?

hass’s picture

The problem is - that the checkboxes are not shown at all - nothing can be selected until all caches are cleared or maybe the nodewords cache only. I have only pressed the flush cache in admin_menu and then all checkboxes appeared unchecked.

avpaderno’s picture

Status: Postponed (maintainer needs more info) » Active

One of the update functions flushes the cache; first, it flushed only the module cache, and now it flushed Drupal cache as well.

avpaderno’s picture

The update function I am talking of is the following:

/**
 * Implementation of hook_update_NN().
 */
function nodewords_update_6127() {
  $tables = array(
    'cache', 'cache_block', 'cache_filter', 'cache_nodewords', 'cache_page',
  );

  foreach ($tables as $table) {
    cache_clear_all('*', $table, TRUE);
  }

  $ret[] = array(
    'success' => TRUE,
    'query' => 'CLEAR DRUPAL CACHE',
  );

  return $ret;
}

I renamed the function to nodewords_update_6130(). If the problem is the cache, then the problem should be resolved.
I will check if there are some functions that need to clear the module cache, and they are not cleaning it.

hass’s picture

If the cache have data and you enable the submodule - I think you need to clear the cache via hook_enable/disable in the submodule that adds the new meta tags to the cached list... not via the update hook in nodewords that is not executed on submodule enable...

I have not tested this, but you can try - disable basic meta, clear all your caches, go to the page admin/content/nodewords, (than the checkboxes may be cached) and than enable the basic meta and see if the checkboxes appear or not. I need to test this myself later...

avpaderno’s picture

StatusFileSize
new61.51 KB

Doing as you reported I get this (see the attached screenshot).

avpaderno’s picture

Title: Still caching issues » Caching issues are still present
Status: Active » Fixed

I changed the modules code, which now cleans the cache every time the module is enabled/disabled.

Thanks for the report, and the help.

hass’s picture

Status: Fixed » Active

Reopen - the implementation is badly designed and prove to make headaches.

nodewords_get_possible_tags() does not verify if the tags currently returned from all modules have the same hash as the cached value. This is buggy by design. The design need to be changed in the way how check_markup() works.

1. module_implements('nodewords_tags_info') to get all tags, currently "hookable" on the system
2. Create a hash value of the tags
3. Select the DB if the current hash is available (see cache_menu, cache_filter how this is done)
4. If found, use the cached value, otherwise save the new cache
5. Make sure the variable is only cached for max one day by default.
6. Remove hook_enable/disable requirement in all modules implementing tags.

Is it possible that there are ONLY two row entries in the cache_nodewords table (pages = empty, tags_info)? If this is really true - it's better to reuse the core "cache" table and drop cache_nodewords. No idea what pages is for - it's empty in my production and development system.

hass’s picture

Title: Caching issues are still present » Use hash as key with tags_info to prevent caching issues

Changed title

avpaderno’s picture

Title: Use hash as key with tags_info to prevent caching issues » Caching issues are still present

Some notes about comment #9.

  1. Modules that implement meta tags needs already to implement hook_nodewords_info(); from the comment, it seems the module is not implementing such custom hook, which is not true.
  2. A hashing code is useful if the code gets as input the original value used to create the hashing code; hashing codes are used to save passwords, and the code that verifies if the entered password is right compares the hashing code of the entered password with the saved hashing code.
    filter.module uses a hashing code because it checks if the text passed to the function has been already filtered, and saved in the cache; it cannot use the text to populate the field cid (which is just 255 characters long), and it uses the MD5 code, which is unique (or it is supposed to be unique) for each input given.
  3. To know if a hash code is present, the code should get the original value used to create the hash code; this means the code should do something like this:
    • Ask to the modules the list of the meta tags they implement.
    • Verify if there is already in cache the hash code for the meta tags it gets.
    • If the hash code exists, use the data present in the cache.

    The purpose of the cache is to avoid to ask to the modules the meta tags they implement (which would be useless, when there are no changes in the list of implement meta tags); if the code needs to compare the data returned from the modules with the cached data, it is useless to have cached data.

  4. See the previous point.
  5. To limit the temporal validity of the cache can be done; differently from the data cached by filter.module, the data cached from nodewords.module are not supposed to change frequently.
  6. Even limiting the validity of the cached data to one day, a module could be disabled before one day is passed; if such hooks would be removed, the cache would contain stale data, if one module would be enabled / disabled.
hass’s picture

Modules that implement meta tags needs already to implement hook_nodewords_info(); from the comment, it seems the module is not implementing such custom hook, which is not true.

If nodewords_get_possible_tags() is called it does get an idea that cached data is outdated. Nevertheless other modules may implement the hook_nodewords_tags_info() correctly they are not able to invalidate the cache without flushing the cache manually. This is why the issue occurrences.

filter.module uses a hashing code because it checks if the text passed to the function has been already filtered, and saved in the cache;

Yes, and this is what nodewords caching logic is missing. If a module adds an additional tag the cache is not automatically updated. This may be easily solved by hashing the array and use the hash as key. See below... the IF is always TRUE if something is in the cache. If the cache is empty - it returns an empty array for all times - until the cache has been cleared. module_implements('nodewords_tags_info') is never executed if cache key 'tags_info' exists. This is the source of this caching issues.

function nodewords_get_possible_tags() {
  if ($cache = cache_get('tags_info', 'cache_nodewords')) {
    return $cache->data;
  }
  else {
    $tags = array();

    // Allow third-party modules to alter the  meta tags list, or to add new
    // meta tags.
    foreach (module_implements('nodewords_tags_info') as $module) {
      if (module_hook($module, 'nodewords_api')) {

Hashing may be the wrong way here, not sure - but the current tag_info implementation is broken and does not automatically refresh if modules defining tags for nodewords are enabled/disabled.

avpaderno’s picture

If a module adds an additional tag the cache is not automatically updated.

The module that adds additional meta tags should also call cache_clear_all('tags_info', 'cache_nodewords').

the current tag_info implementation is broken and does not automatically refresh if modules defining tags for nodewords are enabled/disabled

The actual implementations of hook_enable() and hook_disable() do call cache_clear_all('tags_info', 'cache_nodewords'). Also, when a table cache contains stale data, the table is cleared out; no module updates a cache table when it clears the cache (re-populating the cache table is normally done when the data that should be in the cache are requested, which happens in a different time than when the cache is cleared).

hass’s picture

I know the workaround for the reason that I've suggested this first before I fully understood the real source of this caching bugs.

If you know any place in core that works this way for hook_info api calls I would be happy to learn, but I wasn't able to find one. hook_actions_info seems not to have cached results and there is no place in core where it's required for a module to implement cache clear on enable/disable if a module implements hook_info. This is not developer friendly and more complex than it should/need to be.

avpaderno’s picture

As you are suggesting to remove the cache used by the module, then the issue title should be changed to Remove the cache tables used by the module.

hass’s picture

I have no idea why this is cached as I haven't developed it and have not added this bug to the code. Understanding buggy code and the intention why this have been implemented in this way cannot be done by me. There is also no documentation in the code that may explain the reasons - or I missed it.

Have you measured the speed differences? If you'd like to keep the cached value I would suggest to use the hashing of the array to solve the invalidation issues.

avpaderno’s picture

I would suggest to use the hashing of the array to solve the invalidation issues.

Hashing code cannot be used, when you don't have the original value used to create the hash code.

filter.module uses a hash code because it knows the text that needs to be passed through the input format, and it checks if it saved the result in cache. The cache entry is named after the text to cache, and the function uses md5() because the database field is limited to 255 characters (while the text can be longer than 255 characters).

Similar code cannot be used from nodewords.module, which doesn't know the name of the meta tag without to first query the modules that implement meta tags.

function check_markup($text, $format = FILTER_FORMAT_DEFAULT, $check = TRUE) {
  // When $check = TRUE, do an access check on $format.
  if (isset($text) && (!$check || filter_access($format))) {
    $format = filter_resolve_format($format);

    // Check for a cached version of this piece of text.
    $cache_id = $format .':'. md5($text);
    if ($cached = cache_get($cache_id, 'cache_filter')) {
      return $cached->data;
    }
    // ...
}
hass’s picture

If you'd like to keep this cache… Do you have any idea how to invalidate the cache automatically? Is the caching required?

avpaderno’s picture

I removed the cache, which was not avoiding any database access (except for the entry pages, which contained a limited number of entries).

avpaderno’s picture

Status: Active » Fixed

As there are not been comments reporting any cache issues (which could not exist anymore because the relative code has been removed), I am marking this report as fixed.

hass’s picture

Have you removed all hook_enable/disable functions from all submodules and revamped the caching logic to work reliable?

Status: Fixed » Closed (fixed)

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