Ticket #1139: Memcached.lua

File Memcached.lua, 5.5 kB (added by Terminar, 17 months ago)

lua Memcached module

Line 
1
2--Copyright (c) 2006 Neil Richardson (nrich@iinet.net.au)
3--
4--Permission is hereby granted, free of charge, to any person obtaining a copy
5--of this software and associated documentation files (the "Software"), to deal
6--in the Software without restriction, including without limitation the rights
7--to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8--copies of the Software, and to permit persons to whom the Software is
9--furnished to do so, subject to the following conditions:
10--
11--The above copyright notice and this permission notice shall be included in all
12--copies or substantial portions of the Software.
13--
14--THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15--IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16--FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17--AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18--LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19--OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
20--IN THE SOFTWARE.
21
22require("socket")
23
24Memcached = {
25
26    set = function(cache, key, value)
27        return _store(cache, 'set', key, value)
28    end,
29
30    add = function(cache, key, value)
31        return _store(cache, 'add', key, value)
32    end,
33
34    replace = function(cache, key, value)
35        return _store(cache, 'replace', key, value)
36    end,
37
38    get = function(cache, key)
39        return _retrieve(cache, 'get ' .. key)
40    end,
41
42    delete = function(cache, key)
43        local res = _send(cache, 'delete ' .. key)
44
45        if res == 'NOT_FOUND' then
46            return nil
47        end
48
49        if res ~= 'DELETED' then
50            error("Error deleting '" .. key .. "': " .. res)
51            return nil
52        end
53
54        return true
55    end,
56
57    incr = function(cache, key, val)
58        if val == nil then 
59            val = 1
60        end
61       
62        local res = _send(cache, 'incr ' .. key .. ' ' .. val)
63
64        if res == 'ERROR' or res == 'CLIENT_ERROR' then
65            error("Error incrementing '" .. key .. "': " .. res)
66        end
67
68        return res
69    end,
70
71    decr = function(cache, key, val)
72        if val == nil then 
73            val = 1
74        end
75       
76        local res = _send(cache, 'decr ' .. key .. ' ' .. val)
77
78        if res == 'ERROR' or res == 'CLIENT_ERROR' then
79            error("Error incrementing '" .. key .. "': " .. res)
80        end
81
82        return res
83    end,
84
85    Connect = function(address, port)
86        if address == nil then
87            error('No host address defined')
88        end
89
90        if port == nil then
91            port = 11211
92        end
93
94        local client = socket.connect(address, port)
95
96        if not client then
97            error('Could not connect to ' .. address .. ':' .. port)
98        end
99
100        function _send(cache, str)
101            local socket = cache.socket
102
103            socket:send(str .. "\r\n")
104            local line, err = socket:receive()
105   
106            if not err then return line end
107        end
108
109        function _store(cache, op, key, value)
110            local len = string.len(value)
111            local cmd = op .. ' ' .. key .. ' 0 0 ' .. len .. '\n' .. value
112
113            local res = _send(cache, cmd)
114
115            if res ~= 'STORED' then
116                error("Error storing '" .. key .. "': " .. res)
117                return nil
118            end
119
120            return true
121        end
122
123        function _retrieve(cache, str)
124            local socket = cache.socket
125
126            socket:send(str .. '\n')
127
128            local data = {}
129            while true do
130                local line, err = socket:receive()
131
132                if line == 'END' then
133                    break
134                elseif string.sub(line, 1, 5) == 'VALUE' then
135                else
136                    table.insert(data, line)
137                end
138            end
139
140            if table.getn(data) == 0 then 
141                return nil
142            end
143
144            local datastring = table.concat(data, '\n')
145
146            return datastring
147
148        end
149
150        local cache = {
151            socket = client,
152
153            set = Memcached.set,
154            add = Memcached.add,
155            replace = Memcached.replace,
156            get = Memcached.get,
157            delete = Memcached.delete,
158            incr = Memcached.incr,
159            decr = Memcached.decr,
160        }
161
162        return cache
163    end
164}
165
166--
167-- Memcached.lua
168--
169-- A pure lua implementation of a simple memcached client. Only 1 memcached server is currently supported. Requires the luasocket library.
170-- See http://www.danga.com/memcached/ for more information about memcached.
171--
172--
173--
174-- Synopsis
175--
176-- require('Memcached')
177--
178-- memcache = Memcached.Connect('some.host.com', 11000)
179--
180-- memcache:set('some_key', 1234)
181-- memcache:add('new_key', 'add new value')
182-- memcache:replace('existing_key', 'replace old value')
183--
184-- cached_data = memcache:get('some_key')
185--
186-- memcache:delete('old_key')
187--
188--
189--
190-- Methods:
191--
192-- memcache = Memcached.Connect(host[, port])
193--    Connect to memcached server at 'host' on port number 'port'. If port is not provider, port 11211 is used.
194--   
195-- memcache:set(key, value)
196--    Unconditionally sets a key to a given value in the memcache.
197--     
198-- memcache:add(key, value)
199--    Like set, but only stores in memcache if the key doesn't already exist.
200--   
201-- memcache:replace(key, value)
202--    Like set, but only stores in memcache if the key already exists. The opposite of add.
203--   
204-- value = memcache:get(key)
205--    Retrieves a key from the memcache. Returns the value or nil
206--   
207-- memcache:delete(key)
208--    Deletes a key. Returns true on deletion, nil if the key was not found.
209--   
210-- value = memcache:incr(key[, value])
211--   Sends a command to the server to atomically increment the value for key by value, or by 1 if value is nil.
212--   Returns nil if key doesn't exist on server, otherwise it returns the new value after incrementing. Value should be zero or greater.
213--   
214-- value = memcache:decr(key[, value])
215--   Like incr, but decrements. Unlike incr, underflow is checked and new values are capped at 0. If server value is 1, a decrement of 2 returns 0, not -1.
216--