--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mooncached.lua Sat Jul 31 19:15:27 2010 +0100 @@ -0,0 +1,90 @@ +local server = require "net.server"; +local log = require "util.logger".init("memcached"); +local memcache = require "util.memcache"; + +local cache = memcache.new(); + +local memcached_listener = {}; +local command_handlers = {}; + +--- Network handlers + +function memcached_listener.onconnect(conn) +end + +function memcached_listener.onincoming(conn, line) + local command, params_pos = line:match("^(%S+) ?()"); + local command_handler = command_handlers[command]; + if command_handler then + local ok, err = command_handler(conn, line:sub(params_pos)); + if ok == false then + conn:write("CLIENT_ERROR "..err.."\r\n"); + end + elseif command then + log("warn", "Client sent unknown command: %s", command); + conn:write("ERROR\r\n"); + end +end + +function memcached_listener.ondisconnect(conn, err) +end + +--- Command handlers + +function command_handlers.set(conn, params) + local key, flags, exptime, bytes, reply = params:match("(%S+) (%d+) (%d+) (%d+) ?(.*)$"); + flags, exptime, bytes, reply = tonumber(flags), tonumber(exptime), tonumber(bytes), reply ~= "noreply"; + if not (flags and exptime and bytes) then + return false, "Invalid parameter(s)"; + end + conn:set_mode("*a"); + local received_count, received_buffer = 0, {}; + local function handle_data(conn, data) + log("debug", "Received data of length "..#data.." out of "..bytes); + received_count = received_count + #data; + received_buffer[#received_buffer+1] = data; + if received_count >= bytes then + received_buffer = table.concat(received_buffer); + local ok, err = cache:set(key, flags, exptime, received_buffer:sub(1,bytes)); + if ok then + conn:send("STORED\r\n"); + else + conn:send("SERVER_ERROR "..(err or "Unknown error").."\r\n"); + end + conn:setlistener(memcached_listener); + conn:set_mode("*l"); + if received_count > bytes then + log("debug", "Re-handling %d extra bytes", received_count-bytes); + memcached_listener.onincoming(conn, received_buffer:sub(bytes+1)); + end + end + end + conn:setlistener({ + onincoming = handle_data; + ondisconnect = memcached_listener.ondisconnect; + }); + log("debug", "Waiting for "..bytes.." bytes from client"); + return true; +end + +function command_handlers.get(conn, keys) + for key in keys:gmatch("%S+") do + local flags, data = cache:get(key); + if flags then + conn:write("VALUE "..key.." "..flags.." "..#data.."\r\n"..data.."\r\n"); + end + end + conn:write("END\r\n"); + return true; +end + +function command_handlers.quit(conn) + conn:close(); + return true; +end + +logger.setwriter(function (name, level, format, ...) return print(name, level, format:format(...)); end); + +server.addserver("*", 11211, memcached_listener, "*l"); + +server.loop();