diff -Nru lua-nginx-memcached-0.10/debian/changelog lua-nginx-memcached-0.14/debian/changelog --- lua-nginx-memcached-0.10/debian/changelog 2012-11-28 22:21:30.000000000 +0000 +++ lua-nginx-memcached-0.14/debian/changelog 2019-02-08 16:02:53.000000000 +0000 @@ -1,3 +1,12 @@ +lua-nginx-memcached (0.14-1) unstable; urgency=medium + + * New upstream release. + * Refreshed package standards: + - Updated watchfile + - Bump up standard versions. + + -- Ulises Vitulli Fri, 08 Feb 2019 13:02:53 -0300 + lua-nginx-memcached (0.10-1) unstable; urgency=low * Initial release. (Closes: #693098) diff -Nru lua-nginx-memcached-0.10/debian/changelog.upstream lua-nginx-memcached-0.14/debian/changelog.upstream --- lua-nginx-memcached-0.10/debian/changelog.upstream 2012-11-28 22:19:17.000000000 +0000 +++ lua-nginx-memcached-0.14/debian/changelog.upstream 2019-02-08 16:02:53.000000000 +0000 @@ -1,3 +1,183 @@ +commit 2564138c76e3307711e8d0eb14e8f07cba318097 +Author: Yichun Zhang (agentzh) +Date: Wed Jan 27 13:44:48 2016 -0800 + + optimize: reduced table.concat() calls while constructing memcached requests, which can lead to fewer Lua string creation operations. + +commit 3ae28d1c0c3d97477a169a30fd454e3cc5e89ec7 +Author: Yichun Zhang (agentzh) +Date: Wed Jan 27 13:42:16 2016 -0800 + + bugfix: get() did not return server error responses. thanks Lorenz Bauer for the report. + +commit 5fb6da02eeff4b467d339321e83cafcb1cfd35fd +Author: Yichun Zhang (agentzh) +Date: Wed Jan 27 13:29:46 2016 -0800 + + bugfix: gets() did not return server error responses. thanks Lorenz Bauer for the report. + +commit 00cddf2bceaa1f3df02c9015c9683b2b9f6e83b4 +Author: Yichun Zhang (agentzh) +Date: Wed Jan 27 13:23:17 2016 -0800 + + updated tests to reflect recent changes. + +commit cd069e911400bd543937dec2e886282d06c085ad +Author: Yichun Zhang (agentzh) +Date: Wed Jan 27 13:21:50 2016 -0800 + + get(): simplified the error messages so that the caller can check the error more easily. + +commit de35ff86981006bd21edacc6d28b322ecefbd3ab +Author: Yichun Zhang (agentzh) +Date: Mon Jan 25 15:20:53 2016 -0800 + + doc: various updates. + +commit f9be0cc2d03c7f656d9db44ff58697d1d0c979fe +Author: Yichun Zhang (agentzh) +Date: Mon Nov 23 23:24:36 2015 +0800 + + added a .gitattributes file to correct GitHub's language tag. + +commit ce28d2409b20e06e33dc5a33605786e7d2b2594f +Author: Yichun Zhang (agentzh) +Date: Thu Aug 28 12:13:37 2014 -0700 + + feature: set_timeout() now returns the result of the operation. thanks Guanlan Dai for the report. + +commit 7975df1ac14ef4e4919776ebf1db17632c1a6de0 +Author: Yichun Zhang (agentzh) +Date: Tue Apr 1 14:47:49 2014 -0700 + + suppressed a false positive in libdl. + +commit 88d9022fc5a45f6c444f91e82ec8d1fb2a4d3bfe +Author: Yichun Zhang (agentzh) +Date: Fri Jan 10 16:58:24 2014 -0800 + + doc: updated the copyright year. + +commit 89a37a4e5ac208268753aa269b049b905ceb9186 +Author: Yichun Zhang (agentzh) +Date: Fri Jan 10 16:55:46 2014 -0800 + + bumped version to 0.13. + +commit 750505f717b87dee784c56df05048b18a17b305d +Author: Yichun Zhang (agentzh) +Date: Wed Jan 8 12:44:26 2014 -0800 + + fixed a test case that could fail in slow testing mode. + +commit 5a0db168493c51df2647b069771861238e359f76 +Author: Yichun Zhang (agentzh) +Date: Tue Dec 24 16:57:55 2013 -0800 + + optimize: saved one cosocket receive() call in the get() and gets() methods. + +commit a1770687186484ac333625a006dfc6a44a1488ae +Author: Yichun Zhang (agentzh) +Date: Tue Dec 24 16:34:55 2013 -0800 + + bugfix: the memcached connection might enter a bad state when read timeout happens because ngx_lua's cosocket reading calls no longer automatically close the connection in this case. thanks Dane Knecht for the report. + +commit 599a5f73f48722096357a618166ecb097f85ba97 +Author: Yichun Zhang (agentzh) +Date: Thu Dec 5 14:56:30 2013 -0800 + + use Test::Nginx::Socket::Lua instead of Test::Nginx::Socket in our test suite so that we can run existing tests with lua-resty-core. + +commit 4cada021d390da89564473d1f11d0034e3567e85 +Author: Yichun Zhang (agentzh) +Date: Sun Oct 27 17:49:01 2013 -0700 + + doc: markdown formatting fixes. + +commit 98876a491ba1a97e9d640188ca00510752ddb778 +Author: Yichun Zhang (agentzh) +Date: Sun Oct 27 17:31:52 2013 -0700 + + doc: added Table of Contents. + +commit c517d74a50e33bc8144dc864d4d35dea581ba311 +Author: Yichun Zhang (agentzh) +Date: Sun Oct 27 16:11:40 2013 -0700 + + doc: various formatting improvements. + +commit c3b05d76a24615596830a3a5afdbb7fa4bf11f01 +Author: Yichun Zhang (agentzh) +Date: Thu Oct 3 11:06:43 2013 -0700 + + docs: added new section "Automatic Error Logging". + +commit e53e7853499f89fdbd7eb24fa0ce0860edab2ef0 +Author: Yichun Zhang (agentzh) +Date: Sun Sep 22 23:51:40 2013 -0700 + + optimize: no longer use lua tables and table.concat() to construct simple memcached query strings. this gives 6.75t/foo.t_ overall speed up for trivial set + get examples when LuaJIT 2.0.2 is used. + +commit ed2bcb3c458059e383d7d7b1fabb489f2aee5a6a +Author: Yichun Zhang (agentzh) +Date: Sun Sep 22 23:24:13 2013 -0700 + + bumped version to 0.12. + +commit 4cba65cf753d4038497c82589346aa11ddfca586 +Author: Yichun Zhang (agentzh) +Date: Sun Sep 22 14:32:12 2013 -0700 + + docs: use limited (10 sec) max idel timeout for in-pool connections in the code sample. + +commit fce69f1fa570b543e51175434894494553927471 +Author: Yichun Zhang (agentzh) +Date: Thu Sep 19 13:43:56 2013 -0700 + + optimize: eliminated table.insert() because it is slower than "tb[#tb + 1] = val". + +commit 2f7d5dd5c3b45e4ec1bf7c138a8765ab83d24ff1 +Author: Yichun Zhang (agentzh) +Date: Thu Sep 19 13:38:41 2013 -0700 + + refactor: avoided using Lua's module() function for defining our Lua modules because it has bad side effects. + +commit 5c228d322f3a7a232d19bc75778257a38c9dd770 +Author: Yichun Zhang (agentzh) +Date: Thu Sep 19 13:35:35 2013 -0700 + + updated the copyright notice. + +commit 10abe2f0d0cba6cfbdae22d48cd70df4c890d9bc +Author: agentzh (Yichun Zhang) +Date: Thu Apr 11 11:31:00 2013 -0700 + + docs: check the return values of the "set_keepalive" method. + +commit a40906dd0236bafad75fea704449312d4d31e981 +Author: agentzh (Yichun Zhang) +Date: Wed Mar 27 12:43:44 2013 -0700 + + bumped version to 0.11. + +commit af8343756051188c4c5cb92be9879c17d402f487 +Author: agentzh (Yichun Zhang) +Date: Tue Mar 26 18:31:34 2013 -0700 + + made a test less possible to fail in slow testing mode. + +commit 2798959f462b9c8e2d61329fb159130d4e28e397 +Author: agentzh (Yichun Zhang) +Date: Tue Mar 26 12:29:15 2013 -0700 + + typo in docs. + +commit 5d30dc85846a38aef18a1efea27afb0bf4e76ebe +Author: agentzh (Yichun Zhang) +Date: Tue Mar 26 12:26:48 2013 -0700 + + feature: added new method "touch" for the new memcached command "touch". thanks merlin for the patch in pull #5. + commit d6e69448700a37e62f3a6e50361b9a325d1de153 Author: agentzh (Yichun Zhang) Date: Fri Nov 23 21:40:14 2012 -0800 diff -Nru lua-nginx-memcached-0.10/debian/compat lua-nginx-memcached-0.14/debian/compat --- lua-nginx-memcached-0.10/debian/compat 2012-11-28 22:18:31.000000000 +0000 +++ lua-nginx-memcached-0.14/debian/compat 2019-02-08 16:02:53.000000000 +0000 @@ -1 +1 @@ -8 +11 diff -Nru lua-nginx-memcached-0.10/debian/control lua-nginx-memcached-0.14/debian/control --- lua-nginx-memcached-0.10/debian/control 2012-11-28 22:22:26.000000000 +0000 +++ lua-nginx-memcached-0.14/debian/control 2019-02-08 16:02:53.000000000 +0000 @@ -2,8 +2,8 @@ Section: interpreters Priority: optional Maintainer: Ulises Vitulli -Build-Depends: debhelper (>= 8), dh-lua -Standards-Version: 3.9.3 +Build-Depends: debhelper (>= 11), dh-lua +Standards-Version: 4.3.0.1 Homepage: https://github.com/agentzh/lua-resty-memcached Package: lua-nginx-memcached @@ -19,6 +19,6 @@ developers making use of the Lua programming language to script and construct extremely high-performance web applications capable to handle 10K+ connections. - . + . Note that this module works for both nginx (provided by nginx-extras) and the OpenResty bundle. diff -Nru lua-nginx-memcached-0.10/debian/copyright lua-nginx-memcached-0.14/debian/copyright --- lua-nginx-memcached-0.10/debian/copyright 2012-11-28 22:22:47.000000000 +0000 +++ lua-nginx-memcached-0.14/debian/copyright 2019-02-08 16:02:53.000000000 +0000 @@ -1,13 +1,11 @@ -Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: lua-resty-memcached Upstream-Contact: Yichun "agentzh" Zhang (章亦春) Source: https://github.com/agentzh/lua-resty-memcached Files: * -Copyright: 2012, by Yichun "agentzh" Zhang (章亦春) . -License: BSD - -License: BSD +Copyright: 2012, by Yichun "agentzh" Zhang (章亦春) . +License: BSD-2-clause Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: . diff -Nru lua-nginx-memcached-0.10/debian/rules lua-nginx-memcached-0.14/debian/rules --- lua-nginx-memcached-0.10/debian/rules 2012-11-28 22:18:31.000000000 +0000 +++ lua-nginx-memcached-0.14/debian/rules 2019-02-08 16:02:53.000000000 +0000 @@ -5,4 +5,3 @@ override_dh_installchangelogs: dh_installchangelogs debian/changelog.upstream - diff -Nru lua-nginx-memcached-0.10/debian/watch lua-nginx-memcached-0.14/debian/watch --- lua-nginx-memcached-0.10/debian/watch 2012-11-28 22:19:49.000000000 +0000 +++ lua-nginx-memcached-0.14/debian/watch 2019-02-08 16:02:53.000000000 +0000 @@ -1,4 +1,3 @@ -version=3 -opts="versionmangle=s/.*v(.*)/$1/" \ - http://githubredir.debian.net/github/agentzh/lua-resty-memcached/(.*).tar.gz - +version=4 +opts=filenamemangle=s/.+\/v?(\d\S+)\.tar\.gz/-$1\.tar\.gz/ \ + https://github.com/agentzh/lua-resty-memcached/tags .*/v?(\d\S+)\.tar\.gz diff -Nru lua-nginx-memcached-0.10/.gitattributes lua-nginx-memcached-0.14/.gitattributes --- lua-nginx-memcached-0.10/.gitattributes 1970-01-01 00:00:00.000000000 +0000 +++ lua-nginx-memcached-0.14/.gitattributes 2016-01-27 21:44:48.000000000 +0000 @@ -0,0 +1 @@ +*.t linguist-language=Text diff -Nru lua-nginx-memcached-0.10/lib/resty/memcached.lua lua-nginx-memcached-0.14/lib/resty/memcached.lua --- lua-nginx-memcached-0.10/lib/resty/memcached.lua 2012-11-24 05:40:14.000000000 +0000 +++ lua-nginx-memcached-0.14/lib/resty/memcached.lua 2016-01-27 21:44:48.000000000 +0000 @@ -1,4 +1,4 @@ --- Copyright (C) 2012 Yichun Zhang (agentzh) +-- Copyright (C) Yichun Zhang (agentzh), CloudFlare Inc. local sub = string.sub @@ -7,21 +7,21 @@ local match = string.match local tcp = ngx.socket.tcp local strlen = string.len -local insert = table.insert local concat = table.concat local setmetatable = setmetatable local type = type local error = error -module(...) +local _M = { + _VERSION = '0.13' +} -_VERSION = '0.10' local mt = { __index = _M } -function new(self, opts) +function _M.new(self, opts) local sock, err = tcp() if not sock then return nil, err @@ -50,17 +50,18 @@ end -function set_timeout(self, timeout) +function _M.set_timeout(self, timeout) local sock = self.sock if not sock then return nil, "not initialized" end - return sock:settimeout(timeout) + sock:settimeout(timeout) + return 1 end -function connect(self, ...) +function _M.connect(self, ...) local sock = self.sock if not sock then return nil, "not initialized" @@ -84,16 +85,18 @@ local escape_key = self.escape_key local cmd = {"get"} + local n = 1 for i = 1, nkeys do - insert(cmd, " ") - insert(cmd, escape_key(keys[i])) + cmd[n + 1] = " " + cmd[n + 2] = escape_key(keys[i]) + n = n + 2 end - insert(cmd, "\r\n") + cmd[n + 1] = "\r\n" -- print("multi get cmd: ", cmd) - local bytes, err = sock:send(concat(cmd)) + local bytes, err = sock:send(cmd) if not bytes then return nil, err end @@ -104,6 +107,9 @@ while true do local line, err = sock:receive() if not line then + if err == "timeout" then + sock:close() + end return nil, err end @@ -114,19 +120,26 @@ local key, flags, len = match(line, '^VALUE (%S+) (%d+) (%d+)$') -- print("key: ", key, "len: ", len, ", flags: ", flags) - if key then + if not key then + return nil, line + end - local data, err = sock:receive(len) - if not data then - return nil, err + local data, err = sock:receive(len) + if not data then + if err == "timeout" then + sock:close() end + return nil, err + end - results[unescape_key(key)] = {data, flags} + results[unescape_key(key)] = {data, flags} - data, err = sock:receive(2) -- discard the trailing CRLF - if not data then - return nil, err + data, err = sock:receive(2) -- discard the trailing CRLF + if not data then + if err == "timeout" then + sock:close() end + return nil, err end end @@ -134,7 +147,7 @@ end -function get(self, key) +function _M.get(self, key) if type(key) == "table" then return _multi_get(self, key) end @@ -144,15 +157,17 @@ return nil, nil, "not initialized" end - local cmd = {"get ", self.escape_key(key), "\r\n"} - local bytes, err = sock:send(concat(cmd)) + local bytes, err = sock:send("get " .. self.escape_key(key) .. "\r\n") if not bytes then - return nil, nil, "failed to send command: " .. (err or "") + return nil, nil, err end local line, err = sock:receive() if not line then - return nil, nil, "failed to receive 1st line: " .. (err or "") + if err == "timeout" then + sock:close() + end + return nil, nil, err end if line == 'END' then @@ -161,24 +176,25 @@ local flags, len = match(line, '^VALUE %S+ (%d+) (%d+)$') if not flags then - return nil, nil, "bad line: " .. line + return nil, nil, line end -- print("len: ", len, ", flags: ", flags) local data, err = sock:receive(len) if not data then - return nil, nil, "failed to receive data chunk: " .. (err or "") - end - - line, err = sock:receive(2) -- discard the trailing CRLF - if not line then - return nil, nil, "failed to receive CRLF: " .. (err or "") + if err == "timeout" then + sock:close() + end + return nil, nil, err end - line, err = sock:receive() -- discard "END\r\n" + line, err = sock:receive(7) -- discard the trailing "\r\nEND\r\n" if not line then - return nil, nil, "failed to receive END CRLF: " .. (err or "") + if err == "timeout" then + sock:close() + end + return nil, nil, err end return data, flags @@ -199,16 +215,17 @@ local escape_key = self.escape_key local cmd = {"gets"} - + local n = 1 for i = 1, nkeys do - insert(cmd, " ") - insert(cmd, escape_key(keys[i])) + cmd[n + 1] = " " + cmd[n + 2] = escape_key(keys[i]) + n = n + 2 end - insert(cmd, "\r\n") + cmd[n + 1] = "\r\n" -- print("multi get cmd: ", cmd) - local bytes, err = sock:send(concat(cmd)) + local bytes, err = sock:send(cmd) if not bytes then return nil, err end @@ -219,6 +236,9 @@ while true do local line, err = sock:receive() if not line then + if err == "timeout" then + sock:close() + end return nil, err end @@ -231,19 +251,26 @@ -- print("key: ", key, "len: ", len, ", flags: ", flags) - if key then + if not key then + return nil, line + end - local data, err = sock:receive(len) - if not data then - return nil, err + local data, err = sock:receive(len) + if not data then + if err == "timeout" then + sock:close() end + return nil, err + end - results[unescape_key(key)] = {data, flags, cas_uniq} + results[unescape_key(key)] = {data, flags, cas_uniq} - data, err = sock:receive(2) -- discard the trailing CRLF - if not data then - return nil, err + data, err = sock:receive(2) -- discard the trailing CRLF + if not data then + if err == "timeout" then + sock:close() end + return nil, err end end @@ -251,7 +278,7 @@ end -function gets(self, key) +function _M.gets(self, key) if type(key) == "table" then return _multi_gets(self, key) end @@ -261,14 +288,16 @@ return nil, nil, nil, "not initialized" end - local cmd = {"gets ", self.escape_key(key), "\r\n"} - local bytes, err = sock:send(concat(cmd)) + local bytes, err = sock:send("gets " .. self.escape_key(key) .. "\r\n") if not bytes then return nil, nil, err end local line, err = sock:receive() if not line then + if err == "timeout" then + sock:close() + end return nil, nil, nil, err end @@ -285,16 +314,17 @@ local data, err = sock:receive(len) if not data then + if err == "timeout" then + sock:close() + end return nil, nil, nil, err end - line, err = sock:receive(2) -- discard the trailing CRLF - if not line then - return nil, nil, nil, err - end - - line, err = sock:receive() -- discard "END\r\n" + line, err = sock:receive(7) -- discard the trailing "\r\nEND\r\n" if not line then + if err == "timeout" then + sock:close() + end return nil, nil, nil, err end @@ -305,12 +335,14 @@ local function _expand_table(value) local segs = {} local nelems = #value + local nsegs = 0 for i = 1, nelems do local seg = value[i] + nsegs = nsegs + 1 if type(seg) == "table" then - insert(segs, _expand_table(seg)) + segs[nsegs] = _expand_table(seg) else - insert(segs, seg) + segs[nsegs] = seg end end return concat(segs) @@ -335,16 +367,19 @@ value = _expand_table(value) end - local req = {cmd, " ", self.escape_key(key), " ", flags, " ", exptime, " ", - strlen(value), "\r\n", value, "\r\n"} - - local bytes, err = sock:send(concat(req)) + local req = cmd .. " " .. self.escape_key(key) .. " " .. flags .. " " + .. exptime .. " " .. strlen(value) .. "\r\n" .. value + .. "\r\n" + local bytes, err = sock:send(req) if not bytes then return nil, err end local data, err = sock:receive() if not data then + if err == "timeout" then + sock:close() + end return nil, err end @@ -356,32 +391,32 @@ end -function set(self, ...) +function _M.set(self, ...) return _store(self, "set", ...) end -function add(self, ...) +function _M.add(self, ...) return _store(self, "add", ...) end -function replace(self, ...) +function _M.replace(self, ...) return _store(self, "replace", ...) end -function append(self, ...) +function _M.append(self, ...) return _store(self, "append", ...) end -function prepend(self, ...) +function _M.prepend(self, ...) return _store(self, "prepend", ...) end -function cas(self, key, value, cas_uniq, exptime, flags) +function _M.cas(self, key, value, cas_uniq, exptime, flags) if not exptime then exptime = 0 end @@ -395,19 +430,23 @@ return nil, "not initialized" end - local req = {"cas ", self.escape_key(key), " ", flags, " ", exptime, " ", - strlen(value), " ", cas_uniq, "\r\n", value, "\r\n"} + local req = "cas " .. self.escape_key(key) .. " " .. flags .. " " + .. exptime .. " " .. strlen(value) .. " " .. cas_uniq + .. "\r\n" .. value .. "\r\n" -- local cjson = require "cjson" -- print("request: ", cjson.encode(req)) - local bytes, err = sock:send(concat(req)) + local bytes, err = sock:send(req) if not bytes then return nil, err end local line, err = sock:receive() if not line then + if err == "timeout" then + sock:close() + end return nil, err end @@ -421,7 +460,7 @@ end -function delete(self, key) +function _M.delete(self, key) local sock = self.sock if not sock then return nil, "not initialized" @@ -429,15 +468,18 @@ key = self.escape_key(key) - local req = {"delete ", key, "\r\n"} + local req = "delete " .. key .. "\r\n" - local bytes, err = sock:send(concat(req)) + local bytes, err = sock:send(req) if not bytes then return nil, err end local res, err = sock:receive() if not res then + if err == "timeout" then + sock:close() + end return nil, err end @@ -449,7 +491,7 @@ end -function set_keepalive(self, ...) +function _M.set_keepalive(self, ...) local sock = self.sock if not sock then return nil, "not initialized" @@ -459,7 +501,7 @@ end -function get_reused_times(self) +function _M.get_reused_times(self) local sock = self.sock if not sock then return nil, "not initialized" @@ -469,7 +511,7 @@ end -function flush_all(self, time) +function _M.flush_all(self, time) local sock = self.sock if not sock then return nil, "not initialized" @@ -477,7 +519,7 @@ local req if time then - req = concat({"flush_all ", time, "\r\n"}) + req = "flush_all " .. time .. "\r\n" else req = "flush_all\r\n" end @@ -489,6 +531,9 @@ local res, err = sock:receive() if not res then + if err == "timeout" then + sock:close() + end return nil, err end @@ -506,15 +551,18 @@ return nil, "not initialized" end - local req = {cmd, " ", self.escape_key(key), " ", value, "\r\n"} + local req = cmd .. " " .. self.escape_key(key) .. " " .. value .. "\r\n" - local bytes, err = sock:send(concat(req)) + local bytes, err = sock:send(req) if not bytes then return nil, err end local line, err = sock:receive() if not line then + if err == "timeout" then + sock:close() + end return nil, err end @@ -526,17 +574,17 @@ end -function incr(self, key, value) +function _M.incr(self, key, value) return _incr_decr(self, "incr", key, value) end -function decr(self, key, value) +function _M.decr(self, key, value) return _incr_decr(self, "decr", key, value) end -function stats(self, args) +function _M.stats(self, args) local sock = self.sock if not sock then return nil, "not initialized" @@ -544,7 +592,7 @@ local req if args then - req = concat({"stats ", args, "\r\n"}) + req = "stats " .. args .. "\r\n" else req = "stats\r\n" end @@ -555,9 +603,13 @@ end local lines = {} + local n = 0 while true do local line, err = sock:receive() if not line then + if err == "timeout" then + sock:close() + end return nil, err end @@ -566,7 +618,8 @@ end if not match(line, "ERROR") then - insert(lines, line) + n = n + 1 + lines[n] = line else return nil, line end @@ -577,7 +630,7 @@ end -function version(self) +function _M.version(self) local sock = self.sock if not sock then return nil, "not initialized" @@ -590,6 +643,9 @@ local line, err = sock:receive() if not line then + if err == "timeout" then + sock:close() + end return nil, err end @@ -602,7 +658,7 @@ end -function quit(self) +function _M.quit(self) local sock = self.sock if not sock then return nil, "not initialized" @@ -617,19 +673,22 @@ end -function verbosity(self, level) +function _M.verbosity(self, level) local sock = self.sock if not sock then return nil, "not initialized" end - local bytes, err = sock:send(concat({"verbosity ", level, "\r\n"})) + local bytes, err = sock:send("verbosity " .. level .. "\r\n") if not bytes then return nil, err end local line, err = sock:receive() if not line then + if err == "timeout" then + sock:close() + end return nil, err end @@ -641,22 +700,42 @@ end -function close(self) +function _M.touch(self, key, exptime) local sock = self.sock if not sock then return nil, "not initialized" end - return sock:close() + local bytes, err = sock:send("touch " .. self.escape_key(key) .. " " + .. exptime .. "\r\n") + if not bytes then + return nil, err + end + + local line, err = sock:receive() + if not line then + if err == "timeout" then + sock:close() + end + return nil, err + end + + -- moxi server from couchbase returned stored after touching + if line == "TOUCHED" or line =="STORED" then + return 1 + end + return nil, line end -local class_mt = { - -- to prevent use of casual module global variables - __newindex = function (table, key, val) - error('attempt to write to undeclared variable "' .. key .. '"') +function _M.close(self) + local sock = self.sock + if not sock then + return nil, "not initialized" end -} -setmetatable(_M, class_mt) + return sock:close() +end + +return _M diff -Nru lua-nginx-memcached-0.10/README.markdown lua-nginx-memcached-0.14/README.markdown --- lua-nginx-memcached-0.10/README.markdown 2012-11-24 05:40:14.000000000 +0000 +++ lua-nginx-memcached-0.14/README.markdown 2016-01-27 21:44:48.000000000 +0000 @@ -3,6 +3,44 @@ lua-resty-memcached - Lua memcached client driver for the ngx_lua based on the cosocket API +Table of Contents +================= + +* [Name](#name) +* [Status](#status) +* [Description](#description) +* [Synopsis](#synopsis) +* [Methods](#methods) + * [new](#new) + * [connect](#connect) + * [set](#set) + * [set_timeout](#set_timeout) + * [set_keepalive](#set_keepalive) + * [get_reused_times](#get_reused_times) + * [close](#close) + * [add](#add) + * [replace](#replace) + * [append](#append) + * [prepend](#prepend) + * [get](#get) + * [gets](#gets) + * [cas](#cas) + * [touch](#touch) + * [flush_all](#flush_all) + * [delete](#delete) + * [incr](#incr) + * [decr](#decr) + * [stats](#stats) + * [version](#version) + * [quit](#quit) + * [verbosity](#verbosity) +* [Automatic Error Logging](#automatic-error-logging) +* [Limitations](#limitations) +* [TODO](#todo) +* [Author](#author) +* [Copyright and License](#copyright-and-license) +* [See Also](#see-also) + Status ====== @@ -18,11 +56,12 @@ This Lua library takes advantage of ngx_lua's cosocket API, which ensures 100% nonblocking behavior. -Note that at least [ngx_lua 0.5.0rc29](https://github.com/chaoslawful/lua-nginx-module/tags) or [ngx_openresty 1.0.15.7](http://openresty.org/#Download) is required. +Note that at least [ngx_lua 0.5.0rc29](https://github.com/chaoslawful/lua-nginx-module/tags) or [OpenResty 1.0.15.7](http://openresty.org/#Download) is required. Synopsis ======== +```lua lua_package_path "/path/to/lua-resty-memcached/lib/?.lua;;"; server { @@ -73,8 +112,12 @@ ngx.say("dog: ", res) -- put it into the connection pool of size 100, - -- with 0 idle timeout - memc:set_keepalive(0, 100) + -- with 10 seconds max idle timeout + local ok, err = memc:set_keepalive(10000, 100) + if not ok then + ngx.say("cannot set keepalive: ", err) + return + end -- or just close the connection right away: -- local ok, err = memc:close() @@ -85,12 +128,17 @@ '; } } +``` + +[Back to TOC](#table-of-contents) Methods ======= The `key` argument provided in the following methods will be automatically escaped according to the URI escaping rules before sending to the memcached server. +[Back to TOC](#table-of-contents) + new --- `syntax: memc, err = memcached:new(opts?)` @@ -100,13 +148,18 @@ It accepts an optional `opts` table argument. The following options are supported: * `key_transform` -: an array table containing two functions for escaping and unescaping the -: memcached keys, respectively. By default, -: the memcached keys will be escaped and unescaped as URI components, that is + an array table containing two functions for escaping and unescaping the + memcached keys, respectively. By default, + the memcached keys will be escaped and unescaped as URI components, that is + +```lua memached:new{ key_transform = { ngx.escape_uri, ngx.unescape_uri } } +``` + +[Back to TOC](#table-of-contents) connect ------- @@ -118,6 +171,8 @@ Before actually resolving the host name and connecting to the remote backend, this method will always look up the connection pool for matched idle connections created by previous calls of this method. +[Back to TOC](#table-of-contents) + set --- `syntax: ok, err = memc:set(key, value, exptime, flags)` @@ -128,22 +183,32 @@ strings that are supposed to be concatenated as a whole (without any delimiters). For example, +```lua memc:set("dog", {"a ", {"kind of"}, " animal"}) +``` is functionally equivalent to +```lua memc:set("dog", "a kind of animal") +``` The `exptime` parameter is optional, defaults to `0`. The `flags` parameter is optional, defaults to `0`. +[Back to TOC](#table-of-contents) + set_timeout ---------- -`syntax: memc:set_timeout(time)` +`syntax: ok, err = memc:set_timeout(time)` Sets the timeout (in ms) protection for subsequent operations, including the `connect` method. +Returns 1 when successful and nil plus a string describing the error otherwise. + +[Back to TOC](#table-of-contents) + set_keepalive ------------ `syntax: ok, err = memc:set_keepalive(max_idle_timeout, pool_size)` @@ -156,6 +221,8 @@ Only call this method in the place you would have called the `close` method instead. Calling this method will immediately turn the current memcached object into the `closed` state. Any subsequent operations other than `connect()` on the current objet will return the `closed` error. +[Back to TOC](#table-of-contents) + get_reused_times ---------------- `syntax: times, err = memc:get_reused_times()` @@ -164,6 +231,8 @@ If the current connection does not come from the built-in connection pool, then this method always returns `0`, that is, the connection has never been reused (yet). If the connection comes from the connection pool, then the return value is always non-zero. So this method can also be used to determine if the current connection comes from the pool. +[Back to TOC](#table-of-contents) + close ----- `syntax: ok, err = memc:close()` @@ -173,6 +242,8 @@ In case of success, returns `1`. In case of errors, returns `nil` with a string describing the error. +[Back to TOC](#table-of-contents) + add --- `syntax: ok, err = memc:add(key, value, exptime, flags)` @@ -183,11 +254,15 @@ strings that are supposed to be concatenated as a whole (without any delimiters). For example, +```lua memc:add("dog", {"a ", {"kind of"}, " animal"}) +``` is functionally equivalent to +```lua memc:add("dog", "a kind of animal") +``` The `exptime` parameter is optional, defaults to `0`. @@ -195,6 +270,8 @@ In case of success, returns `1`. In case of errors, returns `nil` with a string describing the error. +[Back to TOC](#table-of-contents) + replace ------- `syntax: ok, err = memc:replace(key, value, exptime, flags)` @@ -205,11 +282,15 @@ strings that are supposed to be concatenated as a whole (without any delimiters). For example, +```lua memc:replace("dog", {"a ", {"kind of"}, " animal"}) +``` is functionally equivalent to +```lua memc:replace("dog", "a kind of animal") +``` The `exptime` parameter is optional, defaults to `0`. @@ -217,6 +298,8 @@ In case of success, returns `1`. In case of errors, returns `nil` with a string describing the error. +[Back to TOC](#table-of-contents) + append ------ `syntax: ok, err = memc:append(key, value, exptime, flags)` @@ -227,11 +310,15 @@ strings that are supposed to be concatenated as a whole (without any delimiters). For example, +```lua memc:append("dog", {"a ", {"kind of"}, " animal"}) +``` is functionally equivalent to +```lua memc:append("dog", "a kind of animal") +``` The `exptime` parameter is optional, defaults to `0`. @@ -239,6 +326,8 @@ In case of success, returns `1`. In case of errors, returns `nil` with a string describing the error. +[Back to TOC](#table-of-contents) + prepend ------- `syntax: ok, err = memc:prepend(key, value, exptime, flags)` @@ -249,11 +338,15 @@ strings that are supposed to be concatenated as a whole (without any delimiters). For example, +```lua memc:prepend("dog", {"a ", {"kind of"}, " animal"}) +``` is functionally equivalent to +```lua memc:prepend("dog", "a kind of animal") +``` The `exptime` parameter is optional, defaults to `0`. @@ -261,6 +354,8 @@ In case of success, returns `1`. In case of errors, returns `nil` with a string describing the error. +[Back to TOC](#table-of-contents) + get --- `syntax: value, flags, err = memc:get(key)` @@ -282,6 +377,8 @@ In case of errors, `nil` will be returned, and the second return value will be a string describing the error. +[Back to TOC](#table-of-contents) + gets ---- `syntax: value, flags, cas_unique, err = memc:gets(key)` @@ -292,6 +389,8 @@ This method is usually used together with the `cas` method. +[Back to TOC](#table-of-contents) + cas --- `syntax: ok, err = memc:cas(key, value, cas_unique, exptime?, flags?)` @@ -301,6 +400,20 @@ The `cas_unique` argument can be obtained from the `gets` method. +[Back to TOC](#table-of-contents) + +touch +--- +`syntax: ok, err = memc:touch(key, exptime)` + +Update the expiration time of an existing key. + +Returns `1` for success or `nil` with a string describing the error otherwise. + +This method was first introduced in the `v0.11` release. + +[Back to TOC](#table-of-contents) + flush_all --------- `syntax: ok, err = memc:flush_all(time?)` @@ -310,6 +423,8 @@ In case of success, returns `1`. In case of errors, returns `nil` with a string describing the error. +[Back to TOC](#table-of-contents) + delete ------ `syntax: ok, err = memc:delete(key)` @@ -320,6 +435,8 @@ In case of success, returns `1`. In case of errors, returns `nil` with a string describing the error. +[Back to TOC](#table-of-contents) + incr ---- `syntax: new_value, err = memc:incr(key, delta)` @@ -328,6 +445,8 @@ Returns the new value after incrementation in success, and `nil` with a string describing the error in case of failures. +[Back to TOC](#table-of-contents) + decr ---- `syntax: new_value, err = memc:decr(key, value)` @@ -336,6 +455,8 @@ Returns the new value after decrementation in success, and `nil` with a string describing the error in case of failures. +[Back to TOC](#table-of-contents) + stats ----- `syntax: lines, err = memc:stats(args?)` @@ -346,6 +467,8 @@ If the `args` argument is omitted, general server statistics is returned. Possible `args` argument values are `items`, `sizes`, `slabs`, among others. +[Back to TOC](#table-of-contents) + version ------- `syntax: version, err = memc:version(args?)` @@ -354,6 +477,8 @@ In case of error, it returns `nil` with a string describing the error. +[Back to TOC](#table-of-contents) + quit ---- `syntax: ok, err = memc:quit()` @@ -364,6 +489,8 @@ Generally you can just directly call the `close` method to achieve the same effect. +[Back to TOC](#table-of-contents) + verbosity --------- `syntax: ok, err = memc:verbosity(level)` @@ -372,6 +499,21 @@ Returns `1` in case of success and `nil` other wise. In case of failures, another string value will also be returned to describe the error. +[Back to TOC](#table-of-contents) + +Automatic Error Logging +======================= + +By default the underlying [ngx_lua](http://wiki.nginx.org/HttpLuaModule) module +does error logging when socket errors happen. If you are already doing proper error +handling in your own Lua code, then you are recommended to disable this automatic error logging by turning off [ngx_lua](http://wiki.nginx.org/HttpLuaModule)'s [lua_socket_log_errors](http://wiki.nginx.org/HttpLuaModule#lua_socket_log_errors) directive, that is, + +```nginx + lua_socket_log_errors off; +``` + +[Back to TOC](#table-of-contents) + Limitations =========== @@ -386,23 +528,29 @@ variables or in the `ngx.ctx` table. These places all have their own data copies for each request. +[Back to TOC](#table-of-contents) + TODO ==== * implement the memcached pipelining API. * implement the UDP part of the memcached ascii protocol. +[Back to TOC](#table-of-contents) + Author ====== -Yichun "agentzh" Zhang (章亦春) +Yichun "agentzh" Zhang (章亦春) , CloudFlare Inc. + +[Back to TOC](#table-of-contents) Copyright and License ===================== This module is licensed under the BSD license. -Copyright (C) 2012, by Yichun "agentzh" Zhang (章亦春) . +Copyright (C) 2012-2016, by Yichun "agentzh" Zhang (章亦春) , CloudFlare Inc. All rights reserved. @@ -414,6 +562,8 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +[Back to TOC](#table-of-contents) + See Also ======== * the ngx_lua module: http://wiki.nginx.org/HttpLuaModule @@ -421,3 +571,5 @@ * the [lua-resty-redis](https://github.com/agentzh/lua-resty-redis) library. * the [lua-resty-mysql](https://github.com/agentzh/lua-resty-mysql) library. +[Back to TOC](#table-of-contents) + diff -Nru lua-nginx-memcached-0.10/t/mock.t lua-nginx-memcached-0.14/t/mock.t --- lua-nginx-memcached-0.10/t/mock.t 2012-11-24 05:40:14.000000000 +0000 +++ lua-nginx-memcached-0.14/t/mock.t 2016-01-27 21:44:48.000000000 +0000 @@ -1,11 +1,11 @@ # vim:set ft= ts=4 sw=4 et: -use Test::Nginx::Socket; +use Test::Nginx::Socket::Lua; use Cwd qw(cwd); repeat_each(2); -plan tests => repeat_each() * (4 * blocks() + 1); +plan tests => repeat_each() * (4 * blocks() + 4); my $pwd = cwd(); @@ -62,3 +62,132 @@ --- no_error_log [error] + + +=== TEST 2: continue using the obj when read timeout happens +--- http_config eval: $::HttpConfig +--- config + location /t { + content_by_lua ' + local memcached = require "resty.memcached" + local memc = memcached:new() + + local ok, err = memc:connect("127.0.0.1", 1921); + if not ok then + ngx.say("failed to connect: ", err) + return + end + + memc:set_timeout(100) -- 0.1 sec + + for i = 1, 2 do + local data, flags, err = memc:get("foo") + if not data and err then + ngx.say("failed to get: ", err) + else + ngx.say("get: ", data); + end + ngx.sleep(0.1) + end + + memc:close() + '; + } +--- request +GET /t +--- tcp_listen: 1921 +--- tcp_query_len: 9 +--- tcp_query eval +"get foo\r\n" +--- tcp_reply eval +"VALUE foo 0 5\r\nhello\r\nEND\r\n" +--- tcp_reply_delay: 150ms +--- response_body +failed to get: timeout +failed to get: closed +--- error_log +lua tcp socket read timed out + + + +=== TEST 3: gets multi getting error responses +--- http_config eval: $::HttpConfig +--- config + location /t { + content_by_lua ' + local memcached = require "resty.memcached" + local memc = memcached:new() + + memc:set_timeout(1000) -- 1 sec + + local ok, err = memc:connect("127.0.0.1", 1921); + if not ok then + ngx.say("failed to connect: ", err) + return + end + + local res, err = memc:gets({"dog", "cat"}) + if not res then + ngx.say("failed to gets: ", err) + return + end + + ngx.say("gets: ", table.concat(res, ", ")); + + memc:close() + '; + } +--- request +GET /t +--- tcp_listen: 1921 +--- tcp_query_len: 14 +--- tcp_query eval +"gets dog cat\r\n" +--- tcp_reply eval +"SERVER_ERROR\r\n" +--- response_body +failed to gets: SERVER_ERROR +--- no_error_log +[error] + + + +=== TEST 4: get multi getting error responses +--- http_config eval: $::HttpConfig +--- config + location /t { + content_by_lua ' + local memcached = require "resty.memcached" + local memc = memcached:new() + + memc:set_timeout(1000) -- 1 sec + + local ok, err = memc:connect("127.0.0.1", 1921); + if not ok then + ngx.say("failed to connect: ", err) + return + end + + local res, err = memc:get({"dog", "cat"}) + if not res then + ngx.say("failed to get: ", err) + return + end + + ngx.say("get: ", table.concat(res, ", ")); + + memc:close() + '; + } +--- request +GET /t +--- tcp_listen: 1921 +--- tcp_query_len: 13 +--- tcp_query eval +"get dog cat\r\n" +--- tcp_reply eval +"SERVER_ERROR\r\n" +--- response_body +failed to get: SERVER_ERROR +--- no_error_log +[error] diff -Nru lua-nginx-memcached-0.10/t/sanity.t lua-nginx-memcached-0.14/t/sanity.t --- lua-nginx-memcached-0.10/t/sanity.t 2012-11-24 05:40:14.000000000 +0000 +++ lua-nginx-memcached-0.14/t/sanity.t 2016-01-27 21:44:48.000000000 +0000 @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et: -use Test::Nginx::Socket; +use Test::Nginx::Socket::Lua; use Cwd qw(cwd); repeat_each(2); @@ -30,7 +30,7 @@ local memcached = require "resty.memcached" local memc = memcached:new() - memc:set_timeout(1000) -- 1 sec + assert(memc:set_timeout(1000)) -- 1 sec local ok, err = memc:connect("127.0.0.1", $TEST_NGINX_MEMCACHED_PORT) if not ok then diff -Nru lua-nginx-memcached-0.10/t/tableset.t lua-nginx-memcached-0.14/t/tableset.t --- lua-nginx-memcached-0.10/t/tableset.t 2012-11-24 05:40:14.000000000 +0000 +++ lua-nginx-memcached-0.14/t/tableset.t 2016-01-27 21:44:48.000000000 +0000 @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et: -use Test::Nginx::Socket; +use Test::Nginx::Socket::Lua; use Cwd qw(cwd); repeat_each(2); diff -Nru lua-nginx-memcached-0.10/t/touch.t lua-nginx-memcached-0.14/t/touch.t --- lua-nginx-memcached-0.10/t/touch.t 1970-01-01 00:00:00.000000000 +0000 +++ lua-nginx-memcached-0.14/t/touch.t 2016-01-27 21:44:48.000000000 +0000 @@ -0,0 +1,115 @@ +# vim:set ft= ts=4 sw=4 et: + +use Test::Nginx::Socket::Lua; +use Cwd qw(cwd); + +repeat_each(2); + +plan tests => repeat_each() * (2 * blocks()); + +my $pwd = cwd(); + +our $HttpConfig = qq{ + lua_package_path "$pwd/lib/?.lua;;"; +}; + +$ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; + +no_long_string(); +no_diff(); + +run_tests(); + +__DATA__ + +=== TEST 1: basic +--- http_config eval: $::HttpConfig +--- config + location /t { + content_by_lua ' + local key = "dog&cat&rabbit" + local memcached = require "resty.memcached" + local memc = memcached:new() + memc:set_timeout(1000) -- 1 sec + + local ok, err = memc:connect("127.0.0.1", $TEST_NGINX_MEMCACHED_PORT) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + local ok, err = memc:flush_all() + if not ok then + ngx.say("failed to flush all: ", err) + return + end + + local ok, err = memc:set(key, "value", 1) + if not ok then + ngx.say("failed to set ", key, ": ", err) + return + end + + local ok, err = memc:touch(key, 120) -- 120sec + if not ok then + ngx.say("failed to touch ", key, ": ", err) + return + end + + ngx.say("touch: ", ok) + + ngx.sleep(1.1) + + local val, err = memc:get(key) + if not val then + ngx.say("failed to get ", key, ": ", err) + return + end + + ngx.say("get key: ", val) + '; + } +--- request + GET /t +--- response_body +touch: 1 +get key: value + + + +=== TEST 2: not exists +--- http_config eval: $::HttpConfig +--- config + location /t { + content_by_lua ' + local key = "dog&cat&rabbit" + local memcached = require "resty.memcached" + local memc = memcached:new() + memc:set_timeout(1000) -- 1 sec + + local ok, err = memc:connect("127.0.0.1", $TEST_NGINX_MEMCACHED_PORT) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + local ok, err = memc:flush_all() + if not ok then + ngx.say("failed to flush all: ", err) + return + end + + local ok, err = memc:touch(key, 120) --120sec + if not ok then + ngx.say("failed to touch ", key, ": ", err) + return + end + + ngx.say("touch: ", ok) + '; + } +--- request + GET /t +--- response_body +failed to touch dog&cat&rabbit: NOT_FOUND + diff -Nru lua-nginx-memcached-0.10/t/version.t lua-nginx-memcached-0.14/t/version.t --- lua-nginx-memcached-0.10/t/version.t 2012-11-24 05:40:14.000000000 +0000 +++ lua-nginx-memcached-0.14/t/version.t 2016-01-27 21:44:48.000000000 +0000 @@ -1,6 +1,6 @@ # vim:set ft= ts=4 sw=4 et: -use Test::Nginx::Socket; +use Test::Nginx::Socket::Lua; use Cwd qw(cwd); repeat_each(2); diff -Nru lua-nginx-memcached-0.10/valgrind.suppress lua-nginx-memcached-0.14/valgrind.suppress --- lua-nginx-memcached-0.10/valgrind.suppress 2012-11-24 05:40:14.000000000 +0000 +++ lua-nginx-memcached-0.14/valgrind.suppress 2016-01-27 21:44:48.000000000 +0000 @@ -534,4 +534,16 @@ fun:ngx_palloc_block fun:ngx_palloc } - +{ + + Memcheck:Cond + fun:index + fun:expand_dynamic_string_token + fun:_dl_map_object + fun:map_doit + fun:_dl_catch_error + fun:do_preload + fun:dl_main + fun:_dl_sysdep_start + fun:_dl_start +}