Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

improve: use optimistic locking to avoid concurrency problem in admin… #2216

Merged
merged 3 commits into from
Sep 18, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions apisix/admin/global_rules.lua
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ function _M.patch(id, conf, sub_path)
core.json.delay_encode(res_old, true))

local node_value = res_old.body.node.value
local modified_index = res_old.body.node.modifiedIndex

if sub_path and sub_path ~= "" then
local code, err, node_val = core.table.patch(node_value, sub_path, conf)
Expand All @@ -153,8 +154,7 @@ function _M.patch(id, conf, sub_path)
return 400, err
end

-- TODO: this is not safe, we need to use compare-set
local res, err = core.etcd.set(key, node_value)
local res, err = core.etcd.atomic_set(key, node_value, nil, modified_index)
if not res then
core.log.error("failed to set new global rule[", key, "]: ", err)
return 500, {error_msg = err}
Expand Down
4 changes: 2 additions & 2 deletions apisix/admin/routes.lua
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,7 @@ function _M.patch(id, conf, sub_path, args)
core.json.delay_encode(res_old, true))

local node_value = res_old.body.node.value
local modified_index = res_old.body.node.modifiedIndex

if sub_path and sub_path ~= "" then
local code, err, node_val = core.table.patch(node_value, sub_path, conf)
Expand All @@ -259,8 +260,7 @@ function _M.patch(id, conf, sub_path, args)
return 400, err
end

-- TODO: this is not safe, we need to use compare-set
local res, err = core.etcd.set(key, node_value, args.ttl)
local res, err = core.etcd.atomic_set(key, node_value, args.ttl, modified_index)
if not res then
core.log.error("failed to set new route[", key, "] to etcd: ", err)
return 500, {error_msg = err}
Expand Down
4 changes: 2 additions & 2 deletions apisix/admin/services.lua
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,7 @@ function _M.patch(id, conf, sub_path)
core.json.delay_encode(res_old, true))

local node_value = res_old.body.node.value
local modified_index = res_old.body.node.modifiedIndex

if sub_path and sub_path ~= "" then
local code, err, node_val = core.table.patch(node_value, sub_path, conf)
Expand All @@ -237,8 +238,7 @@ function _M.patch(id, conf, sub_path)
return 400, err
end

-- TODO: this is not safe, we need to use compare-set
local res, err = core.etcd.set(key, node_value)
local res, err = core.etcd.atomic_set(key, node_value, nil, modified_index)
if not res then
core.log.error("failed to set new service[", key, "]: ", err)
return 500, {error_msg = err}
Expand Down
4 changes: 2 additions & 2 deletions apisix/admin/ssl.lua
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ function _M.patch(id, conf)


local node_value = res_old.body.node.value
local modified_index = res_old.body.node.modifiedIndex

node_value = core.table.merge(node_value, conf);

Expand All @@ -208,8 +209,7 @@ function _M.patch(id, conf)
return 400, err
end

-- TODO: this is not safe, we need to use compare-set
local res, err = core.etcd.set(key, node_value)
local res, err = core.etcd.atomic_set(key, node_value, nil, modified_index)
if not res then
core.log.error("failed to set new ssl[", key, "] to etcd: ", err)
return 500, {error_msg = err}
Expand Down
4 changes: 2 additions & 2 deletions apisix/admin/upstreams.lua
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,7 @@ function _M.patch(id, conf, sub_path)
core.json.delay_encode(res_old, true))

local new_value = res_old.body.node.value
local modified_index = res_old.body.node.modifiedIndex

if sub_path and sub_path ~= "" then
local code, err, node_val = core.table.patch(new_value, sub_path, conf)
Expand All @@ -271,8 +272,7 @@ function _M.patch(id, conf, sub_path)
return 400, err
end

-- TODO: this is not safe, we need to use compare-set
local res, err = core.etcd.set(key, new_value)
local res, err = core.etcd.atomic_set(key, new_value, nil, modified_index)
if not res then
core.log.error("failed to set new upstream[", key, "]: ", err)
return 500, {error_msg = err}
Expand Down
59 changes: 59 additions & 0 deletions apisix/core/etcd.lua
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,65 @@ end
_M.set = set


function _M.atomic_set(key, value, ttl, mod_revision)
local etcd_cli, prefix, err = new()
if not etcd_cli then
return nil, err
end

local lease_id
if ttl then
local data, grant_err = etcd_cli:grant(tonumber(ttl))
if not data then
return nil, grant_err
end

lease_id = data.body.ID
end

key = prefix .. key

local compare = {
{
key = key,
target = "MOD",
result = "EQUAL",
mod_revision = mod_revision,
}
}

local success = {
{
requestPut = {
key = key,
value = value,
lease = lease_id,
}
}
}

local res, err = etcd_cli:txn(compare, success)
if not res then
return nil, err
end

if not res.body.succeeded then
return nil, "value changed before overwritten"
end

res.headers["X-Etcd-Index"] = res.body.header.revision
-- etcd v3 set would not return kv info
res.body.action = "compareAndSwap"
res.body.node = {
key = key,
value = value,
}
res.status = 201

return res, nil
end


function _M.push(key, value, ttl)
local etcd_cli, prefix, err = new()
if not etcd_cli then
Expand Down
4 changes: 2 additions & 2 deletions t/admin/global-rules.t
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ passed
},
"key": "/apisix/global_rules/1"
},
"action": "set"
"action": "compareAndSwap"
}]]
)

Expand Down Expand Up @@ -235,7 +235,7 @@ passed
},
"key": "/apisix/global_rules/1"
},
"action": "set"
"action": "compareAndSwap"
}]]
)

Expand Down
14 changes: 7 additions & 7 deletions t/admin/routes.t
Original file line number Diff line number Diff line change
Expand Up @@ -1009,7 +1009,7 @@ passed
},
"key": "/apisix/routes/1"
},
"action": "set"
"action": "compareAndSwap"
}]]
)

Expand Down Expand Up @@ -1060,7 +1060,7 @@ passed
},
"key": "/apisix/routes/1"
},
"action": "set"
"action": "compareAndSwap"
}]]
)

Expand Down Expand Up @@ -1094,7 +1094,7 @@ passed
},
"key": "/apisix/routes/1"
},
"action": "set"
"action": "compareAndSwap"
}]]
)

Expand Down Expand Up @@ -1128,7 +1128,7 @@ passed
},
"key": "/apisix/routes/1"
},
"action": "set"
"action": "compareAndSwap"
}]]
)

Expand Down Expand Up @@ -1162,7 +1162,7 @@ passed
},
"key": "/apisix/routes/1"
},
"action": "set"
"action": "compareAndSwap"
}]]
)

Expand Down Expand Up @@ -1194,7 +1194,7 @@ passed
},
"key": "/apisix/routes/1"
},
"action": "set"
"action": "compareAndSwap"
}]]
)

Expand Down Expand Up @@ -1246,7 +1246,7 @@ passed
},
"key": "/apisix/routes/1"
},
"action": "set"
"action": "compareAndSwap"
}]]
)

Expand Down
4 changes: 2 additions & 2 deletions t/admin/services-string-id.t
Original file line number Diff line number Diff line change
Expand Up @@ -657,7 +657,7 @@ GET /t
},
"key": "/apisix/services/5eeb3dc90f747328b2930b0b"
},
"action": "set"
"action": "compareAndSwap"
}]]
)

Expand Down Expand Up @@ -697,7 +697,7 @@ passed
},
"key": "/apisix/services/5eeb3dc90f747328b2930b0b"
},
"action": "set"
"action": "compareAndSwap"
}]]
)

Expand Down
8 changes: 4 additions & 4 deletions t/admin/services.t
Original file line number Diff line number Diff line change
Expand Up @@ -657,7 +657,7 @@ GET /t
},
"key": "/apisix/services/1"
},
"action": "set"
"action": "compareAndSwap"
}]]
)

Expand Down Expand Up @@ -697,7 +697,7 @@ passed
},
"key": "/apisix/services/1"
},
"action": "set"
"action": "compareAndSwap"
}]]
)

Expand Down Expand Up @@ -788,7 +788,7 @@ passed
},
"key": "/apisix/services/1"
},
"action": "set"
"action": "compareAndSwap"
}]]
)

Expand Down Expand Up @@ -826,7 +826,7 @@ passed
},
"key": "/apisix/services/1"
},
"action": "set"
"action": "compareAndSwap"
}]]
)

Expand Down
8 changes: 4 additions & 4 deletions t/admin/upstream.t
Original file line number Diff line number Diff line change
Expand Up @@ -672,7 +672,7 @@ GET /t
},
"key": "/apisix/upstreams/1"
},
"action": "set"
"action": "compareAndSwap"
}]]
)

Expand Down Expand Up @@ -710,7 +710,7 @@ passed
},
"key": "/apisix/upstreams/1"
},
"action": "set"
"action": "compareAndSwap"
}]]
)

Expand Down Expand Up @@ -833,7 +833,7 @@ passed
},
"key": "/apisix/upstreams/1"
},
"action": "set"
"action": "compareAndSwap"
}]]
)

Expand Down Expand Up @@ -869,7 +869,7 @@ passed
},
"key": "/apisix/upstreams/1"
},
"action": "set"
"action": "compareAndSwap"
}]]
)

Expand Down
4 changes: 2 additions & 2 deletions t/router/radixtree-sni.t
Original file line number Diff line number Diff line change
Expand Up @@ -589,7 +589,7 @@ location /t {
},
"key": "/apisix/ssl/1"
},
"action": "set"
"action": "compareAndSwap"
}]]
)

Expand Down Expand Up @@ -670,7 +670,7 @@ location /t {
},
"key": "/apisix/ssl/1"
},
"action": "set"
"action": "compareAndSwap"
}]]
)

Expand Down