--[[ - @author Bruno Massa - @file cache.lua - Ajato can store persistent information in a very optimized way. - Instead building a page that is the same to all users, the resulting - page can be cached and accessed lately, without any further building - process. It speeds up the entire process ]] --[[ - Expire data from the cache. If called without arguments, expirable - entries will be cleared from the cache_page table. - - @param cid - If set, the cache ID to delete. Otherwise, all cache entries that can - expire are deleted - @param db_table - If set, the table db_table to delete from. Mandatory - argument if cid is set - @param wildcard - If set to TRUE, the cid is treated as a substring - to match rather than a complete ID. The match is a right hand - match. If '*' is given as cid, the table db_table will be emptied ]] function ajato_cache_clear_all(cid, db_table, wildcard) if not cid and not db_table then cache_clear_all(nil, 'cache_page') return end if not cid then if variable_get('cache_lifetime', 0) then -- We store the time in the current user's user['cache'] variable which -- will be saved into the sessions table by sess_write(). We then -- simulate that the cache was flushed for this user by not returning -- cached data that was cached before the timestamp. user['cache'] = os.time(); local cache_flush = variable_get('cache_flush', 0) if not cache_flush then -- This is the first request to clear the cache, start a timer. variable_set('cache_flush', os.time()) elseif os.time() > (cache_flush + variable_get('cache_lifetime', 0)) then -- Clear the cache for everyone, cache_flush_delay seconds have -- passed since the first request to clear the cache. db_query('DELETE FROM {%s} WHERE expire != %d AND expire < %d', db_table, CACHE_PERMANENT, os.time()) variable_set('cache_flush', 0) end else -- No minimum cache lifetime, flush all temporary cache entries now. db_query('DELETE FROM {%s} WHERE expire != %d AND expire < %d', db_table, CACHE_PERMANENT, os.time()) end else if wildcard then if cid == '*' then db_query('DELETE FROM {'.. db_table ..'}') else db_query('DELETE FROM {'.. db_table ..'} WHERE cid LIKE "%s%%"', cid) end else db_query('DELETE FROM {'.. db_table ..'} WHERE cid = %q', cid) end end end --[[ - Return data from the persistent cache. Data may be stored as either - plain text or as serialized data. It will automatically return - unserialized tables. - - @param key - String, The cache ID of the data to retrieve. - @param only_data - Boolean, True to return only the cached data - @param dd_table - String, The database table to store the data in. Valid core values - are 'cache_filter', 'cache_menu', 'cache_page', or 'cache' for the - default cache. - @return - String or unserialized Table, the cached data ]] function ajato_cache_get(key, only_data, db_table) -- Initialize variables db_table = db_table or 'cache' -- Garbage collection necessary when enforcing a minimum cache lifetime local cache_flush = ajato_variable_get('cache_flush', 0) if cache_flush and (cache_flush + ajato_variable_get('cache_lifetime', 0) <= os.time()) then -- Time to flush old cache data db_query('DELETE FROM {%s} WHERE expire != %d AND expire <= %d', db_table, 0, cache_flush) -- ajato_variable_set('cache_flush', 0) end -- Load the cache data local cache = db_results(db_query([[SELECT data, created, headers, expire, serialized FROM {%s} WHERE cid = %q]], db_table, key)) if type(cache) == 'table' and cache['data'] then -- If the data is permanent or we're not enforcing a minimum cache lifetime -- always return the cached data if cache['expire'] == 0 or not ajato_variable_get('cache_lifetime', 0) then if cache['serialized'] then cache['data'] = ajato_unserialize(cache['data']) end -- If enforcing a minimum cache lifetime, validate that the data is -- currently valid for this user before we return it by making sure the -- cache entry was created before the timestamp in the current session's -- cache timer. The cache variable is loaded into the user object else if user['cache'] and user['cache'] > cache['created'] then -- This cache data is too old and thus not valid for us, ignore it return false else if cache['serialized'] then cache['data'] = ajato_unserialize(cache['data']) end end end -- Only return the data if requested if only_data then return cache['data'] else return cache end end return false end --[[ - Store data in the persistent cache. - - The persistent cache is split up into four database - tables. Contributed modules can add additional tables. - - 'cache_page': This table stores generated pages for anonymous - users. This is the only table affected by the page cache setting on - the administrator panel. - - 'cache_menu': Stores the cachable part of the users' menus. - - 'cache_filter': Stores filtered pieces of content. This table is - periodically cleared of stale entries by cron. - - 'cache': Generic cache storage table. - - The reasons for having several tables are as follows: - - smaller tables allow for faster selects and inserts - - we try to put fast changing cache items and rather static - ones into different tables. The effect is that only the fast - changing tables will need a lot of writes to disk. The more - static tables will also be better cachable with MySQL's query cache - - @param cid - String, The cache ID of the data to store - @param data - Any type, The data to store in the cache. Complex data types will be - automatically serialized before insertion. Strings will be stored as - plain text and not serialized - @param db_table - String, The table to store the data in. Valid core values are - 'cache_filter', 'cache_menu', 'cache_page', or 'cache' - @param expire - One of the following values: - - CACHE_PERMANENT (0): Indicates that the item should never be removed unless - explicitly told to using cache_clear_all() with a cache ID. - - CACHE_TEMPORARY (?): Indicates that the item should be removed at the next - general cache wipe - - A Unix timestamp: Indicates that the item should be kept at least until - the given time, after which it behaves like CACHE_TEMPORARY - @param headers - HTML, A string containing HTTP header information for cached pages ]] function ajato_cache_set(cid, data, db_table, expire, headers) -- Initialize variables db_table = db_table or 'cache' expire = expire or 0 headers = headers or '' local serialized = 0 -- Serialize the table if type(data) == 'table' then data = ajato_serialize(data) serialized = 1 end -- Get the current time local created = os.time() -- Update or insert the new cache value local result = db_query([[UPDATE {%s} SET data = %q, created = %d, expire = %d, headers = %q, serialized = %d WHERE cid = %q]], db_table, data, created, expire, headers, serialized, cid) if not result or result == 0 then db_query([[INSERT INTO {%s} (cid, data, created, expire, headers, serialized) VALUES (%q, %q, %d, %d, %q, %d)]], db_table, cid, data, created, expire, headers, serialized); end end