Community Central
Community Central

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: 불고기

External links[]