hello vonnie
d e v o n
TVSTRANGERTHINGS

Product Placement
"I'm Dorothy Gale from Kansas"

roma★

@theartofmadeline
🪼

JBB: An Artblog!
h

祝日 / Permanent Vacation
Cosimo Galluzzi
Today's Document
No title available
DEAR READER
Peter Solarz
$LAYYYTER

★
Lint Roller? I Barely Know Her
macklin celebrini has autism
seen from United States
seen from Greece

seen from United States

seen from United States
seen from Philippines

seen from Türkiye

seen from Italy

seen from United Kingdom

seen from United States

seen from Singapore
seen from Belgium
seen from United States
seen from United Kingdom

seen from Bangladesh
seen from United States

seen from Singapore

seen from Malaysia

seen from Bulgaria

seen from United States

seen from Türkiye
@torchboxdrupal
Apache Solr Search with Solr > 4.7
Solr 4.x brings a plethora of improvements over 3.x and 1.x. All our new projects use 4.x and we try to upgrade any existing client implementations where and when possible. Last week we upgraded another client. The transition was smooth, except for odd entries in the indexing log and, is it turned out, nodes missing from the index.
java.lang.Thread.run(Thread.java:745)\nCaused by: java.lang.IllegalArgumentException: Document contains at least one immense term in field=\"sm_field_body\" (whose UTF8 encoding is longer than the max length 32766), all of which were skipped. Please correct the analyzer to not produce such terms. The prefix of the first immense term is: '[32, 67, 97, 116, 104, 101, 114, 105, 110, 101, 32, 66, 101, 97, 114, 100, 115, 104, 97, 119, 32, 67, 97, 116, 104, 101, 114, 105, 110, 101]...', original message: bytes can be at most 32766 in length; got 108809 [...] Caused by: org.apache.lucene.util.BytesRefHash$MaxBytesLengthExceededException: bytes can be at most 32766 in length; got 108809
It so happens, the Solr notes on upgrading from prior versions contain the following:
Prior to Solr 4.8, terms that exceeded Lucene's MAX_TERM_LENGTH were silently ignored when indexing documents. Begining with Solr 4.8, a document an error will be generated when attempting to index a document with a term that is too large. If you wish to continue to have large terms ignored, use solr.LengthFilterFactory in all of your Analyzers. See LUCENE-5472 for more details.
Drupal Apache Solr fields are prefixed with a set of characters that denote the dynamic field nature and follow the Solr convention. e.g. ss_ means "single-value string field", sm_ — "multi-value string field".
In our case sm_field_body and any sm_* fields are declared as solr.StrField fields which are not analyzed, just stored as is. Previously, fields larger than the allowed 32k limit were simply ignored, but not anymore.
In usual Solr configurations, a StrField could be truncated using TruncateFieldUpdateProcessorFactory
<processor class="solr.TruncateFieldUpdateProcessorFactory"> <str name="typeClass">solr.StrField</str> <int name="maxLength">100</int> </processor>
However, since sm_* fields are not processed, we need a different solution that does not involve modifying the core Solr configuration. And that comes as a simple hook implementation in a custom module.
<?php /** * Implements hook_apachesolr_index_documents_alter() * * Fix for https://issues.apache.org/jira/browse/LUCENE-5472 */ function apachesolr_tweaks_apachesolr_index_documents_alter(array &$documents, $entity, $entity_type, $env_id) { foreach ($documents as $id => $document) { if (empty($documents[$id]->sm_field_body)) { continue; } foreach ($documents[$id]->sm_field_body as $index => $value) { $documents[$id]->sm_field_body[$index] = truncate_utf8($value, 31000); } } }
The above hook_apachesolr_index_documents_alter() implementation looks specifically at sm_field_body as that was the culprit in our case. You can follow the approach to alter any indexed field.
Once deployed, the indexing could continue without issues and all of the content is now searchable.
H/T to Rupert for the hook suggestion.
At Torchbox, we are working with our existing clients to move to a HTTPS-only setup.
There are plenty of reasons websites should switch to HTTPS: - It offers the strongest guarantee of reliable information and secure transmission. - GOV.UK recommend it in their Service design manual. - Google uses it as a search ranking signal. - Using mixed mode is better than nothing, but leaves you open to attacks.
Contrary to popular belief, HTTPS is not slow. The link above will prove it.
We hope to move to an encrypted future, for all the right reasons.
Display Suite code fields
We've been using code fields for all little while now so I thought it best to do a little write up on how we've recently used them.
We have a site which used a list field to select which background image to use on a field. It was to illustrate what kind of specie the page was about. It was straight-forward and worked well. But the client wanted to adapt on this and make each illustration of the species, this would mean having at least 80 different images in the CSS file and the client would have to come to us when they wanted it updating. Not really ideal.
So with the power of two new fields and a Display Suite code field we created them something they could manage themselves.
Firstly, we added two image fields, one for each hover state. We decided not to use sprites because it would mean the client would need to make them and the less work they have to do the better.
Then we created the code field. This is the code we put into Field code
<?php if (!empty($entity->field_custom_illustration_hover)) : ?> <div class="illustration-ds-field" style="background-image: url([node:field_custom_illustration_hover])"> <a href="[node:url]"><img src="[node:field_custom_illustration]" /></a> </div> <?php endif; ?>
What we are doing here is saying if the hover field isn't empty then add a div with a background of the custom illustration hover field and a link to the node URL and display an image of the custom illustration.
One field I really recommend filling in on the Display Suite code fields is Limit field. If you use a lot of fields, DS ones or otherwise, they soon build up in your content type. So seeing as we only want to use this field in our Species content type and on our slider view mode we've got a value of species|slider, you can use * for selecting all which is handy.
Then back in our slider view mode we should find the new field, simply replacing the old one for this one and a few CSS tweaks to line up the background image with the image and a bit of opacity hover magic and it working like the old slider did but now the client is in control of the images.
Drupal, IE9 and CSS selector limits
We recently encountered a tricksy issue on one of our client sites. A piece of work had been deployed to live, at which point some (but by no means all) of the styles broke in IE9 at a certain screen resolution.
My first reaction was to scour the code I had just deployed - had I inadvertently broken the CSS on the affected elements? I could find no link at all to them. Also, the site looked fine in IE9 on my local build.
My next step was to import the live data to my local build. At that point, I was able to repeat the issue on my local build, and I realised that the issue was occurring if the CSS was aggregated and compressed, but not otherwise.
But here's the odd thing: my local build had had the CSS uncompressed for development purposes prior to the DB import, but I had also tried compressing it before importing the live data, and the issue was not repeatable. The live site had undergone a couple of core Drupal updates, so my best guess as to why this was is that there was a recent change in core Drupal as to the way that CSS is aggregated and compressed.
The next step was to find why the bug was happening and to resolve it, and why it had only manifested itself with the deployment of some unrelated code (and it was here that several colleagues got involved with the problem).
It clearly was't related to IE's limit on the number of stylesheets loaded, as this was occurring after concatenation rather than before it. After some digging we thought it might be related to the number of CSS rules allowed. A number of places on the internet report that there is a limit of 4095 rules per sheet, but in fact this is not strictly true (and a quick tally showed we were below this count). The limit is in fact in the number of selectors, e.g. h1,h2,h3{color:red} is one rule, but contains 3 selectors. Counting up the number of selectors showed that the new work that had been deployed had pushed us over that selector limit.
The solution in the end, after much detailed debugging, was to remove the mobile stylesheet from the theme's .info file and add it via drupal_add_css() in hook_preprocess_html. In this case it was a stylesheet needed on every page of the site but the benefit of adding stylesheets via hook_preprocess_html() is that if it is not needed site-wide then every_page can be set to FALSE.
The final thing to consider is how to prevent this happening again, as it is a bug that occurs without warning when a certain number of selectors is reached. A block visible only to admin users that detects the number of selectors and flashes a warning with bells and whistles was one suggestion, and another was adapting our nagios alerts module to include a warning when the CSS selector limit was reached.
Configurable cache expiration for busy websites
A standard approach to improving the performance of Drupal sites is to increase the time pages are cached for. This could be either through the database cache you get out of the box, but when you employ an external caching mechanism like Varnish you have an extra component that needs to be kept in line with your wider cache expiration requirements.
Our Chatham House project saw us raise the TTL of cached pages to 1 hour to avoid having to regenerate pages. However, content editors were finding it frustrating that they couldn't publish breaking content in a timely manner without affecting the wider performance of the website.
We suggested leaving the standard TTLs but implementing the expire and purge modules to provide a standardised way for key changes to tell Varnish when to drop a cached item. The rules integration of expire means the website can react to a key page (eg: the homepage node or major section index pages) events such as the change in moderation state to 'Published' and then issue a PURGE request to Varnish for the appropriate URL.
So far so good, although when changes that are displayed on the homepage that aren't controlled from the homepage node (eg: blocks) are made we found the easiest solution was to give administrators a very simple admin form to issue PURGE requests to Varnish for specific URLs. This means that if the existing rule sets don't quite cover an edge case nobody has thought of, then the administrators at Chatham House can still keep their content moving with minimal effort.
I released a sandbox module called purge_expirepath that provides this. I would hope to see this incorporated into either the expire or purge modules at some stage in the future, but for now it's available for anyone to use.
Fixing out of memory issues on pages using Token
The editors of a recent large Drupal website built by Torchbox started having strange experiences when trying to add or edit certain nodes. At first, the page would freeze for about a minute. After a while, it would serve partial content with no styling or result in full WSOD.
A quick inspection of the logs revealed out of memory issues. We increased the PHP memory limit to allow the editors use the site.
Armed with Xdebug and a fresh copy of the database and codebase, we dived into the issue. It did not take long to identify the culprit:
Several Token functions with over 10k calls!
It turns out one of the recently added fields was token-enabled. By default, Token renders all available tokens in its token browser. However, when the site has a large number of fields, all the variations make for one giant list that gets rendered for each token-enabled form element. This cause the browser to freeze when displaying the page. It also contributed to PHP running out of memory.
A d.o. issue queue search led to https://www.drupal.org/node/1684984. Token allows fetching the available token list in a dialog on demand, rather than displaying huge trees on the page. Except... contributed modules must explicitly ask for the token browser dialog:
<?php ... // Show the token browser. $form['available_tokens'] = array( '#value' => 'Browse available tokens', '#theme' => 'token_tree', '#token_types' => array($instance['entity_type']), '#weight' => 100, '#dialog' => TRUE, ); ?>
Unfortunately not all do. The solution is to force all contributed modules to use the token browser dialog. We created a simple helper module that did the task brilliantly.
The result? The fix showed a 10x decrease in the Xdebug dump size (from over 240Mb to 24Mb). We were able to change the PHP memory limit to values even lower than in the beginning. Plus editors enjoy fast node forms again.
If you had similar issues, you can get the helper module from GitHub. And do consider opening d.o. issues for any contributed module that does not yet use the '#dialog' => TRUE option to display available tokens.
Announcing our latest site: Quality Watch
It's been a while since we posted on the team tumblr, and what better way to break the ice than with an announcement of a new client site launch?
The latest addition to our portfolio is Quality Watch: a website to support a research programme run by The Nuffield Trust and The Health Foundation to examine the effects of economic austerity in the NHS.
It's built on Drupal 7, is mobile first, is functional right down to IE7 and leveraged our whitelabel features to kick start the build process. There was a requirement to provide an interface between the website and the research team (whose tools of the trade are predominantly spreadsheets), so we suggested github to store data about their charts and maps. We wrote custom code to pull changes from that repo and turn them into Drupal nodes and pretty rendered charts/maps using highcharts.js/polymaps.js respectively.
This new site represents a fantastic result for Team Drupal owing to the tight delivery timescale and some challenging requirements. We think the end result speaks for itself and if you haven't already, we'd encourage you to go have a look at it right now... preferably at least twice to see how it behaves between media queries!
http://www.qualitywatch.org.uk
Implementing most popular content listings in Drupal powered by Google Analytics data
We recently implemented a feature to display ‘most popular’ content on the WRAP and Zero Waste Scotland websites in order to improve the visibility of popular content on their existing taxonomy pages and complement the existing ‘Latest content’ listings.
A high level overview of the feature can be found on my recent Torchbox.com blog post. This post is the technical compliment to it where I can elaborate on some of the decisions and implementations of what went into the feature.
Choosing a data source:
Drupal comes with its own internal statistics module which can be used to track how many users have viewed a given node. It’s not particularly sophisticated and relies on a session of some variety to be able to associate a view event to a node. With something like Pressflow (or Drupal 7) anonymous users no longer have an anonymous session cookie set to ensure compatibility with HTTP caches such as Varnish.
In the same manner, contrib modules such as radioactivity also rely on an active user session (anonymous or otherwise) and can also add a significant level of database load (update queries on every node view event) on high traffic sites. Even by queueing some of these updates in-memory through something like memcached and flushing to the database at less frequent intervals there is still a significant performance consideration on top of incompatibility with Varnish.
WRAP and ZWS had well established Google Analytics profiles and Analytics has a great API. The downsides are that Analytics doesn’t understand which paths are nodes, which are views based and what taxonomy term a certain path relates to. On balance, this is perfectly acceptable, and this is covered a little later in the post.
Given the richness of the data stored by Analytics, the ease of access and compatibility with Varnish (Analytics events/calls are client side), and variety of filters and metrics, it was became fairly clear that using Analytics to provide the data for scoring our content according to unique page views would be a good fit.
Introducing logical separations of concern in the whole process
Nobody likes a ‘superman’ function or class that tries to do everything. We’ve probably all seen them at one stage or another...
function mymodule_update_node_score($node, $score) claims to do one discrete task, but when you look inside we might find it updates one thing, clears the cache, maybe even loads another, related node and updates something in that too.
This kind of approach might well result in functional code, but in the long term it makes the end to end process brittle (how do errors get handled? does the return type (if any) change depending on the context of the current task?), harder to diagnose/follow and therefore more expensive to maintain.
So, we split the problem into a few logical tasks:
Structuring the Analytics query:
We used the Google Analytics Query Explorer tool provided by Google to help test the various criteria we needed to include against the existing data. In this case, we were asking something along the lines of:
"Please can I have the domain, page path and unique page views for this Analytics profile from the last three months... but don't count anything that hasn't got a unique page view in that period of time and ignore anything with these legacy URL paths."
Talking to Google Analytics:
The google_analytics_reports module was originally written to grab data from Analytics and display them in Drupal. We’re only interested in the included google_analytics_api module as it does the heavy lifting of communicating with the Analytics API based on the query format we fine tuned in the analytics query explorer.
Storing the result set from Analytics:
For better or worse the google_analytics_api module gave us a pretty large result object (>1MB of text when serialized in PHP). So much so that it caused a failure when trying to store it in memcached which has a maximum size per object of 1MB. So the memcached daemon complained and the Drupal memcache module quietly failed.
To get around this we decided to configure the Drupal memcache module to keep the results from our query in the database by submitting a patch for the google_analytics_reports module. The use of a drush make file for this project allows modules, themes, libraries and patches submitted to, or hosted on drupal.org very easy to incorporate, manage and version control.
Processing the result set
Providing we had cached data to work with we would go through each result, check the path and see if it was a node and if so take its corresponding unique page views value and add it to our list of things to update.
Finally, once we were done with the result set we could quickly iterate over our list of things to update and turn these into SQL commands to update our table. A few thousand inserts/updates on a simple, indexed table structure doesn’t take long at all.
Scoring nodes?
At first we got caught up in the procedural aspect of interrogating Analytics about paths from the site. For example, a mindset of: “For each taxonomy term, work out what nodes are tagged, get their paths, match these against Analytics and then update their scores”.
It didn’t take long to see the flaw in that process. Not only was it complex in the detail, it would be inefficient and likely teeter on the edge of the daily Analytics API quotas; either by querying per-node (yuck) or getting far too much (>10k rows) data per request.
However, by reducing the query size to a sensible date range, carefully filtering out clear non-node/404/obsolete URL paths we were left with a decent query that provided unique page views over the last 3 months for all WRAP/ZWS domains. By using a 3 month date range we ensured both that the overall result set wasn’t insanely large and also has the benefit of providing a natural expiry point for results. For example, a press release may generate a spike in page views over a one week period, but in the event that page views tailed off it would eventually slip from the rankings. In contrast, consistently popular content would retain a high ranking and would reflect the interest in it.
Abstracting this further and removing the Drupal ‘internals’ from the problem we realised if we kept a score (ie: unique page views) against each node we could let Drupal concern itself with selecting content by domain/language/taxonomy term/publish state. As all the sites were were concerned with were hosted on the same database and managed with the domain access module, this was generally something we could leave to Drupal views.
Storing the node scores:
One option was to add a new integer CCK field to each content type on the site. This would immediately integrate it with views (to power the listings) and would also benefit from field permissions.
We opted to keep scores in a database table in the interests of performance. The daily cron task to update node scores from the result set from Google Analytics would involve several thousand sequential node_load() and node_save() operations and this would not help the site’s performance. A wider concern was that node_save() invokes the cache_clear_all() function before it returns. Several thousand sequential full cache clears on a large site? No thanks!
Accepting that we introduced a custom schema, we needed to integrate it with the bits of Drupal we were hoping to use. A few minutes extra work implementing hook_views_data() exposed our node_score table to views and allowed us to use that data to sort our nodes in our listings. It also meant that updating this table with several thousand results takes 2-3 seconds and doesn’t have a discernable impact in site performance at all.
Frond end tweaks
By this stage we had our data from Analytics stored in and available to Drupal. We made a new view block (based on the latest content listing) and changed the criteria required for selecting and sorting nodes. For the most part, all the existing CSS styles were re-used and existing JavaScript to control the listing filters remained valid.
The final custom work required was some additional Javascript to provide a toggle between the two displays and manipulate the DOM slightly to allow us to fit the original design and pretend we didn’t have two completely independent views blocks. This Javascript was very much a progressive enhancement rather than graceful degradation. Without Javascript the pages and listings still function as they need to but appear one above the other.
All custom code (server side and client side) was managed within a single custom Drupal module, meaning that in the event the module was switched off the collection pages would revert back to their previous state.
We also made use of the block caches to further lower the resource footprint of this functionality. The content is only refreshed nightly, so we didn’t see the need to regenerate the markup over and over each time a logged in user views the page or the Varnish cache expires. Every little helps in that respect.
New machine, new hostname to choose...
After months of minor annoyances with Linux Mint I recently converted back to a MBP/OS X for day to day work.
Most machines at Torchbox have some kind of clever hostname... for Macs you'll find machines such as aroni, kerel etc... my old Dell was monte.
All the good names had been taken for prefixes of 'Mac'... so I opted for something grey, round(ish) and powerful... and an amusing childhood story sprang to mind: The Glerp.
I am now johan@glerp
Varnish and Drupal 7.20/21 DoS vulnerability handling
The recent security releases for Drupal 7.20 and 7.21 fix a security vulnerability in the form of a possible denial of service attack where large numbers of requests to generate on-demand image styles could result in very high CPU loads.
The fix introduces a token that is appended to the path for an image derivative, for example, previous URLs like /sites/default/files/styles/thumbnail/public/field/image/example.png now have a token such as /sites/default/files/styles/thumbnail/public/field/image/example.png?itok=zD_VaCaD.
The upshot of this being each request can be validated server side and invalid/DoS requests can be safely discarded, reducing the potential load on a server.
The downside is that any kind of HTTP accellerator or cache that relies on URL based identification is more or less invalidated as each request to the same image path will have a different, unique token.
The 7.21 release makes some effort to limit the impact by allowing site administrators to set the
$conf['image_allow_insecure_derivatives'] = TRUE;
Drupal variable. This provides partial protection by safeguarding against the most serious form of the vulnerability, but permits requests to standard image derivatives without the token validation.
Changing the Varnish hashing algorithm
We employ the use of Varnish as an HTTP accellerator for most of our clients' sites. We also wanted to ensure that anonymous requests to /sites/default/files/styles/thumbnail/public/field/image/example.png and /sites/default/files/styles/thumbnail/public/field/image/example.png?itok=zD_VaCaD are treated as the same cached resource instead of having two separate cache items. You can do this with the following adjustment to your VCL file:
sub vcl_hash { set req.hash += req.http.host; set req.hash += regsub(req.url, "\?(.*)itok=.+[^&]", "\1"); return (hash); }
In plain terms, this configuration uses a regular expression to effectively ignore the itok token when generating a hash value for the item when it's cached.
Debugging your regex
There isn't really a console for debugging your Varnish regsub regex. One option is to add a custom HTTP header in vcl.fetch which lets you examine what your regex is doing. For instance:
sub vcl_fetch { set beresp.http.X-Regex = regsub("Your URL to check", "Your regex", "Any substitutions"); }
It's then easy enough to check the response headers with any decent HTTP debugger or curl and examine the value of that header.
Varnish: safely checking/using your VCL file
If you're running Varnish 2.1 or earlier, be very careful when looking to test your VCL file configuration before reloading/restarting the service. Most documentation you'll find through search results will advise the following:
$ sudo varnishd -C -f /path/to/mysetup.vcl # Don't do this!
This runs the Varnish daemon in compile mode, the idea being if your VCL file is invalid compilation will fail and the daemon exits. When successful, you get the output of your VCL file. Apparently, the project maintainers for Varnish feel this is an adequate method of checking syntax. I don't, but it doesn't appear to be changing anytime soon.
Varnish 2.1 doesn't have the -C option, but it will output the VCL file anyway (looking like a success) and more importantly (and much less obvious!) - you'll end up spawning a new Varnish daemon. Depending on your default settings it will end up allocating a fixed chunk of memory for it's use.
Let's assume that default is 1GB of memory and you are busy tweaking your VCL file. You run varnishd in what you think is compile (and exit) mode, but what's really happening is you're inadvertently spawning new Varnish daemons. Eventually you run out of memory and the server dies.
Oh my!
Safely testing/reloading the VCL file
The safest way to test a VCL file is to use varnishadm:
$ sudo varnishadm -T 127.0.0.1:6082 -S /etc/varnish/secret vcl.load / <some-identifier-for-the-vlc-file>
this loads (and parses) the VCL file and adds it to a buffer (identified with the identifier you give it).
$ sudo varnishadm -T 127.0.0.1:6082 -S /etc/varnish/secret vcl.use / <your-unique-identifier>
This command tells Varnish to use the VCL file from the buffer of your choice. The great thing here is it will hot-swap in the new VCL file without the need to restart the service, which will clear your existing cache.
On Debian machines you can sometimes find this script which will check your VCL file:
$ sudo /usr/share/varnish/reload-vcl
This runs both the aforementioned vcl.load and vcl.use. If you only want to parse/check the syntax of your VCL file, add the -c parameter to only run vcl.load.
Even if you're running a recent version of Varnish you're likely to be better off with this approach than simply firing up the daemon or restarting the service.
Time to move to MariaDB?
Torchbox recently sent several developers to DrupalCamp London 2013, who came back with tales of VMs paved with gold, Drupal Themers laying slain by the roadside and a new fangled work of the devil - MariaDB!
But seriously, an excellent time was had by all. It's always interesting to see where your company's practices bench against others and one area that piqued our interest was speeding up our development VM using nginx and possibly MariaDB.
MariaDB is a replacement for MySQL with one eye on a possible future where Oracle take a bad turn with MySQL development and strand loyal users. The suggestion to use it instead of MySQL indicated there were performance benefits to be had, but having look around for benchmark stats we've found some conflicting results.
Exhibit A from DimitriK indicates MySQL 5.5 just beats MariaDB 5.5 but MySQL 5.6 destroys it:
http://dimitrik.free.fr/blog/archives/2013/02/mysql-performance-mysql-56-vs-mysql-55-vs-mariadb-55.html
Exhibit B from MariaDB indicates even the older MariaDB 5.3 seems a worthy adversary to MySQL 5.6:
http://blog.mariadb.org/mariadb-5-3-optimizer-benchmark/
Exhibit C, also from MariaDB shows MariaDB 10 (still in alpha) benching very close to MySQL 5.6:
http://blog.mariadb.org/sysbench-oltp-mysql-5-6-vs-mariadb-10-0/
Exhibit D, from mysqlperformanceblog suggesting MariaDB's Hash Joins offer huge benefits, but not in all situations:
http://www.mysqlperformanceblog.com/2012/05/31/a-case-for-mariadbs-hash-joins/
Granted these are not all based on the same points of comparison but the general picture is confused and we're no closer to making a decision. Clearly MariaDB has benefits, but if Drupal is brimming with join queries of the like that MariaDB can't handle well, it wouldn't be a wise move.
If anyone has examples of MariaDB benching well in the wild with Drupal, we'd love to hear from you.
We'll update when we learn more.
Be aware when caching large data objects in Drupal
TL;DR: Memcache fails silently when trying to store data greater than its defined slab size. You can also specify what cache bins are used and which are ignored and pushed through to the database.
Most of the websites we put into production make use of the memcache module to take some of the strain off the database server. By its nature Drupal is very database centric and although it offers the ability to cache a variety of things there is always the underlying overhead of disk I/O or network latency when communicating with a database. Memcache allows Drupal to store its cached data in memory which is much faster.
A recent project involved retrieving a relatively large amount of data from Google Analytics API using the google_analytics_reports module, caching it and using it to update content rankings. While the query itself succeeded and we received its payload, the data was mysteriously unavailable when trying to retrieve it from the cache. Cue a hunt to track it down!
Look in your database tables, duh?
Hmm... no data there. Not surprising really, because we were using memcache :)
Telnet then?
Yes, you could do this to peek at what memcache has (nice overview of how). What's probably easier is to use drush eval to natively ask Drupal to run cache_get('some-identifier') which means you don't need to faff with dealing with whatever memcache/database/cardboard box instance you happen to be using to store things in.
Still no data!?
cache_get() did not show any results either and that was indeed odd. A quick test of another query with a single result DID show up. This started to ring a few bells...
The size of the original query payload returned was big enough to exceed the 1MB slab size memcache uses. Evidently, it was failing to insert a cache item but that failure was not communicated or was not visible to the person/process invoking cache_set().
Next steps:
While it would be preferable to reduce the query payload size to be something more reasonable this would involve picking apart the code in the google_analytics_reports contrib module... and we didn't want to suggest removing the large 'data' component of it's response object if someone else had a genuine use for it. We could also consider narrowing the query to return less data... or maybe retrieve it in batches.
We could also consider increasing the memcache slab size to cover the size of our data, but this didn't feel right given the single, niche requirement and the real possibility of getting the memcache memory handling settings wrong and running out of memory further down the line.
In the end...
I submitted a patch to the google_analytics_reports module which allows the cache options parameter to specify which cache bin to use.
The memcache settings in settings.php were changed to ensure that things using the cache_analytics bin were passed back to the database, which can store a larger volume of data per cache item.
We're also considering reporting the silently failing cache_insert to the memcache maintainers.
Torchbox have got three tickets to Drupalcamp London. Hope to see you there!
Drupal's Solr config and false matching
Drupal's Apache Solr module comes with a configuration file to add to Solr, called solrconfig.xml. There's a lot of complex default settings in there that help to fine-tune Solr results. And while that means that Solr is a powerful solution for Drupal search, it also means that its configuration can be quite opaque.
One thing we've found is that by default the search results are very generous: if you search for e.g. "cute cat", you will get back all responses that contain "cat" OR "cute"; the only concession to the two keywords is that matches on both will be considered more relevant, and appear towards the top.
This is the result of the mm or "minimum matches" parameter. In solrconfig.xml, you can change this for a given requestHandler: most likely you'll want to do it for the default one, whose name attribute is drupal!
To change mm, look for the string:
<requestHandler name="drupal" default="true"> ... <str name="mm"><!-- Some value in here --></str>
And change that value as you see fit
Note that percentage matching is not the same as numeric matching: 100% does not equal 1. Rather: a number N means "if M terms are searched for, must match at least min(M, N)"; whereas a percentage P means "if M terms are searched for, must match at least M*P". So P=100% is the strictest possible match.
Twitter pull loses time_ago
Drupal's Twitter Pull module is a useful one: not just for its own UI elements, but also for getting tweets to format yourself. However, in a recent version change, it lost its $tweet->time_ago property on the tweet objects.
You can recreate this straightforwardly using the following PHP snippet:
<?php $tweet->time_ago = format_interval(time() - $t->timestamp); ?>
It's a minor pain but if you've exposed your own theme implementations to preprocess hooks - and why wouldn't you? - then it should be easy to put in e.g. your template.php.