LuaCache is an extension that exposes MediaWiki's ObjectCache through a Lua interface, which can be used to store data between requests.
Applications[]
LuaCache has two main applications: sitewide storage for results of expensive queries, and mitigation of performance issues with modules used on a very large number of pages.
Query caching[]
LuaCache can be used to cache the results of expensive DPL or Cargo queries, as it will be faster to access the cache than to perform the query again. However, LuaCache is slower than VariablesLua, so a fallback chain might look like: local variable → VariablesLua → LuaCache → expensive query.
Link table thinning[]
When a data module is used on a page, any change to the data module will require a re-evaluation of that page. When a data module is used on a large number of pages, has to be frequently updated, but most updates only affect a small subset of pages using the data, the result is that the wiki has to regularly perform useless re-evaluation of pages that would not be changed. Using LuaCache to store the data may cause issues typical to caching (requiring pages to be purged or null-edited), but is likely to significantly thin the number of pages the engine believes are "dependent" on the data module. (This number is also known as the number of "transclusions" listed on Special:WhatLinksHere for that page.) As a case of LuaCache use from Leaguepedia, the transclusions count for a data module dropped from approximately 100 thousand pages to 7 pages.
Usage[]
Cache object[]
To access the object cache, the cache object must be acquired first. This can be done as follows:
local cache = require 'mw.ext.LuaCache'
cache.get[]
cache.get( key )
Returns the value stored in the cache under the given (string) key.
If there is no value stored under the given key, nil
is returned.
cache.set[]
cache.set( key, value )
cache.set( key, value, exptime )
Stores the given value in the cache under the given (string) key. Optionally, an exptime (expiration time) in seconds may be specified. Returns true
if the value is successfully stored, false
otherwise.
cache.getMulti[]
cache.getMulti( keys )
Retrieves the values stored under the keys given in the supplied array of strings and then constructs and returns a table of the values associated with their respective keys.
cache.setMulti[]
cache.setMulti( data )
cache.setMulti( data, exptime )
Accepts a table of data and stores the value in each row in the cache under its respective key. Optionally, an exptime (expiration time) in seconds may be specified, which will be applied to each cache entry.
cache.delete[]
cache.delete( key )
Removes the cache entry identified by the given (string) key.
Example[]
-- Module:Demo
local p = {}
local cache = require 'mw.ext.LuaCache'
function p.test(frame)
local args = frame.args
local keyPrefix = args[1] or 'sample'
local sampleValue = {
hello = 'World',
name = 'Alyanah',
counter = 0
}
local results = {}
local handleValue = function(r)
if r ~= nil then
sampleValue.counter = (r.counter or 0) + 1
table.insert(results, 'Hello: ' .. tostring(r.hello))
table.insert(results, 'Name: ' .. tostring(r.name))
table.insert(results, 'Counter: ' .. tostring(r.counter))
else
table.insert(results, '(nil)')
end
end
-- Get an item from the cache
-- This will be nil the first time this function is run,
-- and it will have a value afterwards for as long as the
-- item remains in cache.
local singleTestKey = keyPrefix .. '.singleTest'
local res = cache.get(singleTestKey)
table.insert(results, 'cache.get(\'' .. singleTestKey .. '\')')
handleValue(res)
-- Set an item in the cache
res = cache.set(singleTestKey, sampleValue)
table.insert(results, 'cache.set returned ' .. tostring(res))
-- Get the item from the cache again
res = cache.get(singleTestKey)
table.insert(results, 'cache.get(\'' .. singleTestKey .. '\')')
handleValue(res)
table.insert(results, '')
-- Set the item in the cache with a 30s expiration
res = cache.set(singleTestKey, sampleValue, 30)
table.insert(results, 'cache.set returned ' .. tostring(res))
-- Set multiple items in the cache
res = cache.setMulti({
[keyPrefix .. '.multiTest.1'] = {
when = 'now',
what = '불고기'
},
[keyPrefix .. '.multiTest.2'] = {
when = 'tomorrow',
what = '김치찌개'
},
[keyPrefix .. '.multiTest.3'] = {
when = 'yesterday',
what = '순두부찌개'
}
})
table.insert(results, 'cache.setMulti returned ' .. tostring(res))
-- Get one of the items from the cache
res = cache.get(keyPrefix .. '.multiTest.2')
if res then
table.insert(results, 'When: ' .. tostring(res.when))
table.insert(results, 'What: ' .. tostring(res.what))
else
table.insert(results, '(nil)')
end
-- Delete one of the items from the cache
res = cache.delete(keyPrefix .. '.multiTest.2')
table.insert(results, 'cache.delete returned ' .. tostring(res))
-- Get all of those items
res = cache.getMulti({
keyPrefix .. '.multiTest.1',
keyPrefix .. '.multiTest.2',
keyPrefix .. '.multiTest.3',
})
for k, v in pairs(res) do
table.insert(results, tostring(k) .. ' = ')
if v and type(v) == 'table' then
table.insert(results, 'When: ' .. tostring(v.when))
table.insert(results, 'What: ' .. tostring(v.what))
else
table.insert(results, tostring(v))
end
end
-- Format the results as preformatted wikitext
return ' ' .. table.concat(results, '\n ')
end
return p
{{#invoke:Demo|test}}
produces:
cache.get('sample.singleTest') (nil) cache.set returned true cache.get('sample.singleTest') Hello: World Name: Alyanah Counter: 0 cache.set returned true cache.setMulti returned true When: tomorrow What: 김치찌개 cache.delete returned true sample.multiTest.3 = When: yesterday What: 순두부찌개 sample.multiTest.1 = When: now What: 불고기