"Fossies" - the Fresh Open Source Software Archive

Member "memcached-1.6.15/t/startfile.lua" (30 Mar 2022, 9864 Bytes) of package /linux/www/memcached-1.6.15.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Lua source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. See also the latest Fossies "Diffs" side-by-side code changes report for "startfile.lua": 1.6.14_vs_1.6.15.

    1 -- WARNING: if you cause errors during configuration reload by putting
    2 -- incompatible data into the table returned by mcp_config_pools, the daeomon
    3 -- will exit.
    4 -- TODO: fallback cache for broken/overloaded zones.
    5 
    6 -- local zone could/should be fetched from environment or local file.
    7 -- doing so allows all configuration files to be identical, simplifying consistency checks.
    8 local my_zone = 'z1'
    9 
   10 local STAT_EXAMPLE <const> = 1
   11 local STAT_ANOTHER <const> = 2
   12 --mcp.tcp_keepalive(true)
   13 
   14 function mcp_config_pools(oldss)
   15     mcp.add_stat(STAT_EXAMPLE, "example")
   16     mcp.add_stat(STAT_ANOTHER, "another")
   17     mcp.backend_connect_timeout(5.5) -- 5 and a half second timeout.
   18     -- alias mcp.backend for convenience.
   19     -- important to alias global variables in routes where speed is concerned.
   20     local srv = mcp.backend
   21     -- local zones = { 'z1', 'z2', 'z3' }
   22 
   23     -- IPs are "127" . "zone" . "pool" . "srv"
   24     local pfx = 'fooz1'
   25     local fooz1 = {
   26         srv(pfx .. 'srv1', '127.1.1.1', 11212),
   27         srv(pfx .. 'srv2', '127.1.1.2', 11212),
   28         srv(pfx .. 'srv3', '127.1.1.3', 11212),
   29     }
   30     pfx = 'fooz2'
   31     local fooz2 = {
   32         srv(pfx .. 'srv1', '127.2.1.1', 11213),
   33         srv(pfx .. 'srv2', '127.2.1.2', 11213),
   34         srv(pfx .. 'srv3', '127.2.1.3', 11213),
   35     }
   36     pfx = 'fooz3'
   37     local fooz3 = {
   38         srv(pfx .. 'srv1', '127.3.1.1', 11214),
   39         srv(pfx .. 'srv2', '127.3.1.2', 11214),
   40         srv(pfx .. 'srv3', '127.3.1.3', 11214),
   41     }
   42 
   43     pfx = 'barz1'
   44     -- zone "/bar/"-s primary zone should fail; all down.
   45     local barz1 = {
   46         srv(pfx .. 'srv1', '127.1.2.1', 11210),
   47         srv(pfx .. 'srv2', '127.1.2.2', 11210),
   48         srv(pfx .. 'srv3', '127.1.2.3', 11210),
   49     }
   50     pfx = 'barz2'
   51     local barz2 = {
   52         srv(pfx .. 'srv1', '127.2.2.1', 11215),
   53         srv(pfx .. 'srv2', '127.2.2.2', 11215),
   54         srv(pfx .. 'srv3', '127.2.2.3', 11215),
   55     }
   56     pfx = 'barz3'
   57     local barz3 = {
   58         srv(pfx .. 'srv1', '127.3.2.1', 11216),
   59         srv(pfx .. 'srv2', '127.3.2.2', 11216),
   60         srv(pfx .. 'srv3', '127.3.2.3', 11216),
   61     }
   62 
   63     -- fallback cache for any zone
   64     -- NOT USED YET
   65     pfx = 'fallz1'
   66     local fallz1 = {
   67         srv(pfx .. 'srv1', '127.0.2.1', 11212),
   68     }
   69     pfx = 'fallz2'
   70     local fallz2 = {
   71         srv(pfx .. 'srv1', '127.0.2.2', 11212),
   72     }
   73     pfx = 'fallz3'
   74     local fallz3 = {
   75         srv(pfx .. 'srv1', '127.0.2.3', 11212),
   76     }
   77 
   78     local main_zones = {
   79         foo = { z1 = fooz1, z2 = fooz2, z3 = fooz3 },
   80         bar = { z1 = barz1, z2 = barz2, z3 = barz3 },
   81         -- fall = { z1 = fallz1, z2 = fallz2, z3 = fallz3 },
   82     }
   83 
   84     -- FIXME: should we copy the table to keep the pool tables around?
   85     -- does the hash selector hold a reference to the pool (but only available in main config?)
   86 
   87     -- convert the pools into hash selectors.
   88     -- TODO: is this a good place to add prefixing/hash editing?
   89     for _, subs in pairs(main_zones) do
   90         for k, v in pairs(subs) do
   91             -- next line uses a ring hash in "evcache compat" mode. note the
   92             -- hash= override to use MD5 key hashing from ketama.
   93             -- subs[k] = mcp.pool(v, { dist = mcp.dist_ring_hash, omode = "evcache", hash = mcp.dist_ring_hash.hash })
   94             -- override the number of buckets per server.
   95             -- subs[k] = mcp.pool(v, { dist = mcp.dist_ring_hash, omode = "evcache", hash = mcp.dist_ring_hash.hash, obuckets = 240 })
   96             -- this line uses the default (currently xxhash + jump hash)
   97             subs[k] = mcp.pool(v)
   98 
   99             -- use this next line instead for jump hash.
  100             -- the order of servers in the pool argument _must_ not change!
  101             -- adding the seed string will give a different key distribution
  102             -- for each zone.
  103             -- NOTE: 'k' may not be the right seed here:
  104             -- instead stitch main_zone's key + the sub key?
  105             -- subs[k] = mcp.pool(v, { dist = mcp.dist_jump_hash, seed = k })
  106             -- subs[k] = mcp.pool(v, { dist = mcp.dist_jump_hash, seed = k, filter = "stop", filter_conf = "|#|" })
  107             -- subs[k] = mcp.pool(v, { dist = mcp.dist_jump_hash, seed = k, filter = "tags", filter_conf = "{}" })
  108         end
  109     end
  110 
  111     return main_zones
  112 end
  113 
  114 -- WORKER CODE:
  115 
  116 -- need to redefine main_zones using fetched selectors?
  117 
  118 -- TODO: Fallback zone here?
  119 function failover_factory(zones, local_zone)
  120     local near_zone = zones[local_zone]
  121     local far_zones = {}
  122     -- NOTE: could shuffle/sort to re-order zone retry order
  123     -- or use 'next(far_zones, idx)' via a stored upvalue here
  124     for k, v in pairs(zones) do
  125         if k ~= local_zone then
  126             far_zones[k] = v
  127         end
  128     end
  129     return function(r)
  130         local res = near_zone(r)
  131         if res:hit() == false then
  132             -- example for mcp.log... Don't do this though :)
  133             mcp.log("failed to find " .. r:key() .. " in zone: " .. local_zone)
  134             --for _, zone in pairs(far_zones) do
  135             --    res = zone(r)
  136             local restable = mcp.await(r, far_zones, 1)
  137             for _, res in pairs(restable) do
  138                 if res:hit() then
  139                     --break
  140                     return res
  141                 end
  142             end
  143             return restable[1]
  144         end
  145         return res -- send result back to client
  146     end
  147 end
  148 
  149 -- SET's to main zone, issues deletes to far zones.
  150 function setinvalidate_factory(zones, local_zone)
  151     local near_zone = zones[local_zone]
  152     local far_zones = {}
  153     -- NOTE: could shuffle/sort to re-order zone retry order
  154     -- or use 'next(far_zones, idx)' via a stored upvalue here
  155     for k, v in pairs(zones) do
  156         if k ~= local_zone then
  157             far_zones[k] = v
  158         end
  159     end
  160     local new_req = mcp.request
  161     return function(r)
  162         local res = near_zone(r)
  163         if res:ok() == true then
  164             -- create a new delete request
  165             local dr = new_req("delete /testing/" .. r:key() .. "\r\n")
  166             for _, zone in pairs(far_zones) do
  167                 -- NOTE: can check/do things on the specific response here.
  168                 zone(dr)
  169             end
  170         end
  171         -- use original response for client, not DELETE's response.
  172         -- else client won't understand.
  173         return res -- send result back to client
  174     end
  175 end
  176 
  177 -- NOTE: this function is culling key prefixes. it is an error to use it
  178 -- without a left anchored (^) pattern.
  179 function prefixtrim_factory(pattern, list, default)
  180     local p = pattern
  181     local l = list
  182     local d = default
  183     local s = mcp.stat
  184     return function(r)
  185         local i, j, match = string.find(r:key(), p)
  186         local route
  187         if match ~= nil then
  188             -- remove the key prefix so we don't waste storage.
  189             r:ltrimkey(j)
  190             route = l[match]
  191             if route == nil then
  192                 -- example counter: tick when default route hit.
  193                 s(STAT_EXAMPLE, 1)
  194                 return d(r)
  195             end
  196         end
  197         return route(r)
  198     end
  199 end
  200 
  201 function prefix_factory(pattern, list, default)
  202     local p = pattern
  203     local l = list
  204     local d = default
  205     local s = mcp.stat
  206     return function(r)
  207         local route = l[string.match(r:key(), p)]
  208         if route == nil then
  209             -- example counter: tick when default route hit.
  210             s(STAT_EXAMPLE, 1)
  211             return d(r)
  212         end
  213         return route(r)
  214     end
  215 end
  216 
  217 -- TODO: Check tail call requirements?
  218 function command_factory(map, default)
  219     local m = map
  220     local d = default
  221     return function(r)
  222         local f = map[r:command()]
  223         if f == nil then
  224             -- print("default command")
  225             return d(r)
  226         end
  227         -- testing options replacement...
  228         -- if r:command() == mcp.CMD_SET then
  229         --    r:token(4, "100") -- set exptime.
  230         -- end
  231         -- print("override command")
  232         return f(r)
  233     end
  234 end
  235 
  236 -- TODO: is the return value the average? anything special?
  237 -- walks a list of selectors and repeats the request.
  238 function walkall_factory(pool)
  239     local p = {}
  240     -- TODO: a shuffle could be useful here.
  241     for _, v in pairs(pool) do
  242         table.insert(p, v)
  243     end
  244     local x = #p
  245     return function(r)
  246         local restable = mcp.await(r, p)
  247         -- walk results and return "best" result
  248         -- print("length of await result table", #restable)
  249         for _, res in pairs(restable) do
  250             if res:ok() then
  251                 return res
  252             end
  253         end
  254         -- else we return the first result.
  255         return restable[1]
  256     end
  257 end
  258 
  259 function mcp_config_routes(main_zones)
  260     -- generate the prefix routes from zones.
  261     local prefixes = {}
  262     for pfx, z in pairs(main_zones) do
  263         local failover = failover_factory(z, my_zone)
  264         local all = walkall_factory(main_zones[pfx])
  265         local setdel = setinvalidate_factory(z, my_zone)
  266         local map = {}
  267         map[mcp.CMD_SET] = all
  268         -- NOTE: in t/proxy.t all the backends point to the same place
  269         -- which makes replicating delete return NOT_FOUND
  270         map[mcp.CMD_DELETE] = all
  271         -- similar with ADD. will get an NOT_STORED back.
  272         -- need better routes designed for the test suite (edit the key
  273         -- prefix or something)
  274         map[mcp.CMD_ADD] = failover_factory(z, my_zone)
  275         prefixes[pfx] = command_factory(map, failover)
  276     end
  277 
  278     local routetop = prefix_factory("^/(%a+)/", prefixes, function(r) return "SERVER_ERROR no route\r\n" end)
  279 
  280     -- internally run parser at top of tree
  281     -- also wrap the request string with a convenience object until the C bits
  282     -- are attached to the internal parser.
  283     --mcp.attach(mcp.CMD_ANY, function (r) return routetop(r) end)
  284     mcp.attach(mcp.CMD_ANY_STORAGE, routetop)
  285 end