Cacheismo is a non-blocking single threaded high performance scriptable memcache. Instead of storing bytes or blobs in the cache, it can store objects defined in lua. No need to get the object, modify it and then save it back (with retry). Directly modify object state in the cache itself by invoking methods of your objects. Because it is single threaded, modifications are automatically atomic. It is best suited for managing volatile application state at super speed (70K requests per second per core). Memcached would be more useful if your objects don't change much. But if they are changed frequently, memcached's update mechanism using retries would give you significantly low performance.
It comes with a default implementation of a quota object. You can change it as it suits you without touching the c code. Here is how to use it.
Note that these are memached get requests with special keys encoding our intent. The keys follow the following syntax:
<ObjectType>:<Method>:<ObjectKey>:<Arg1>:<Arg2>
Object type is "quota". Cacheismo has other object types as well and more can be added by adding new lua scripts. Methods for quota object are "new", "addandcheck", "reset". Object key we are using is "userKey". You would need key per user. Number of arguments would vary depending upon the method. Here new takes 2 args, addandcheck takes 1 and reset takes 0.
get quota:new:userKey:10:hour
VALUE quota:new:userKey:10:hour 0 7
CREATED
-- Creates a new quota object in cacheismo, that enforces 10 requests per hour.
get quota:addandcheck:userKey:10
VALUE quota:addandcheck:userKey:10 0 8
QUOTA_OK
-- Checking if user can use 10 units of quota. This succeeds. It is easy to create a default user object if it doesn't exist in this call also, instead of forcing users to always do a new first.
get quota:addandcheck:userKey:1
VALUE quota:addandcheck:userKey:1 0 14
QUOTA_EXCEEDED
-- Checking if user can use 1 more unit of quota. This fails as user exhausted it in previous call.
get quota:reset:userKey
VALUE quota:reset:userKey 0 8
QUOTA_OK
-- Reset the quota back to 0.
Cacheismo can do around 70K such operations per second running on single core. Like memcached, if single instance is not enough, multiple instances can be used. Cacheismo supports memcached ascii protocol. So any memcached client can be used to access it.
Introduction to cacheismo
=========================================================
-- simple quota implementation
local quotaTypesMap = { month = 1, day = 1, hour = 1 }
local function findExpiresAt(quotaType)
local current = os.date("*t")
if (quotaType == "month") then
current.month = current.month + 1
current.day = 1
current.hour = 0
current.min = 0
current.sec = 1
elseif (quotaType == "day") then
current.day = current.day + 1
current.hour = 0
current.min = 0
current.sec = 1
else
current.hour = current.hour+1
current.min = 0
current.sec = 1
end
return os.time(current)
end
local function new(limit, quotaType)
if (quotaTypesMap[quotaType] == nil) then
return nil
end
local object = {}
object.limit = tonumber(limit)
object.type = quotaType
object.count = 0
object.expiresAt = findExpiresAt(quotaType)
return object
end
local function addandcheck(object, value)
local toUseValue = 1
if (value ~= nil) then
toUseValue = tonumber(value)
end
if (os.time() > object.expiresAt) then
object.count = 0;
object.expiresAt = findExpiresAt(object.type)
end
if ((object.count + toUseValue) > object.limit) then
return -1
else
object.count = object.count + toUseValue
return 0
end
end
local function reset(object)
if (os.time() > object.expiresAt) then
object.count = 0
object.expiresAt = findExpiresAt(object.type)
end
object.count = 0
return 0
end
===================================================================
It comes with a default implementation of a quota object. You can change it as it suits you without touching the c code. Here is how to use it.
Note that these are memached get requests with special keys encoding our intent. The keys follow the following syntax:
<ObjectType>:<Method>:<ObjectKey>:<Arg1>:<Arg2>
Object type is "quota". Cacheismo has other object types as well and more can be added by adding new lua scripts. Methods for quota object are "new", "addandcheck", "reset". Object key we are using is "userKey". You would need key per user. Number of arguments would vary depending upon the method. Here new takes 2 args, addandcheck takes 1 and reset takes 0.
get quota:new:userKey:10:hour
VALUE quota:new:userKey:10:hour 0 7
CREATED
-- Creates a new quota object in cacheismo, that enforces 10 requests per hour.
get quota:addandcheck:userKey:10
VALUE quota:addandcheck:userKey:10 0 8
QUOTA_OK
-- Checking if user can use 10 units of quota. This succeeds. It is easy to create a default user object if it doesn't exist in this call also, instead of forcing users to always do a new first.
get quota:addandcheck:userKey:1
VALUE quota:addandcheck:userKey:1 0 14
QUOTA_EXCEEDED
-- Checking if user can use 1 more unit of quota. This fails as user exhausted it in previous call.
get quota:reset:userKey
VALUE quota:reset:userKey 0 8
QUOTA_OK
-- Reset the quota back to 0.
Cacheismo can do around 70K such operations per second running on single core. Like memcached, if single instance is not enough, multiple instances can be used. Cacheismo supports memcached ascii protocol. So any memcached client can be used to access it.
Introduction to cacheismo
=========================================================
-- simple quota implementation
local quotaTypesMap = { month = 1, day = 1, hour = 1 }
local function findExpiresAt(quotaType)
local current = os.date("*t")
if (quotaType == "month") then
current.month = current.month + 1
current.day = 1
current.hour = 0
current.min = 0
current.sec = 1
elseif (quotaType == "day") then
current.day = current.day + 1
current.hour = 0
current.min = 0
current.sec = 1
else
current.hour = current.hour+1
current.min = 0
current.sec = 1
end
return os.time(current)
end
local function new(limit, quotaType)
if (quotaTypesMap[quotaType] == nil) then
return nil
end
local object = {}
object.limit = tonumber(limit)
object.type = quotaType
object.count = 0
object.expiresAt = findExpiresAt(quotaType)
return object
end
local function addandcheck(object, value)
local toUseValue = 1
if (value ~= nil) then
toUseValue = tonumber(value)
end
if (os.time() > object.expiresAt) then
object.count = 0;
object.expiresAt = findExpiresAt(object.type)
end
if ((object.count + toUseValue) > object.limit) then
return -1
else
object.count = object.count + toUseValue
return 0
end
end
local function reset(object)
if (os.time() > object.expiresAt) then
object.count = 0
object.expiresAt = findExpiresAt(object.type)
end
object.count = 0
return 0
end
===================================================================