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

[QUESTION] try_lock fail #618

Open
hsh258 opened this issue Feb 15, 2025 · 6 comments
Open

[QUESTION] try_lock fail #618

hsh258 opened this issue Feb 15, 2025 · 6 comments

Comments

@hsh258
Copy link

hsh258 commented Feb 15, 2025

Environment:

  • OS: [e.g. ubuntu]
  • Compiler: [e.g. gcc 8.5, clang 3.9.1]
  • hiredis version: [e.g. v1.2.0, master]
  • redis-plus-plus version: [e.g. 1.3.14, master, commit b0a42e]

Additional context
two redis-plus-plus clients, try_lock fail
// client code:
std::unique_ptrredis::AsyncRedis redis_client;
std::shared_ptrredis::Redis syncredis_client;
std::unique_ptrredis::Redis watch_client;
std::shared_ptrredis::RedMutex mtx;
std::unique_lockredis::RedMutex redlock;
redis::ConnectionOptions opts;
opts.host = service; //redis service name,can find by kubectl get svc -n admin |grep redis
opts.port = endpoint_port_;
redis::ConnectionPoolOptions pool_opts;
pool_opts.size = 3;
// async redis client
redis_client.reset(new redis::AsyncRedis(opts, pool_opts));
// sync redis client
syncredis_client.reset(new redis::Redis(opts, pool_opts));
// watch sync redis client
watch_client.reset(new redis::Redis(opts, pool_opts));
mtx.reset(new redis::RedMutex(syncredis_client, "resource"));
redlock = std::unique_lockredis::RedMutex(*mtx, std::defer_lock);

// the code for try_lock
try {
while (true) {
if (self->redlock_.try_lock()) {
LOG(INFO) << "try_lock success ";
break;
}
LOG(INFO) << "wait for lock ";
std::this_thread::sleep_for(std::chrono::milliseconds(500));
}
auto val = *(self->redis_->get("redis_revision").get());
irev = static_cast(std::stol(val));
}

// As redis server msg:
1739548293.958135 [0 192.168.2.138:45362] "EVAL" "\nif redis.call("GET",KEYS[1]) == ARGV[1] then\n return redis.call("pexpire",KEYS[1],ARGV[2])\nelse\n return 0\nend\n" "1" "resource" "xbk7o7JxZxz4onL0Am9f" "3000"
1739548293.958202 [0 lua] "GET" "resource"
1739548293.958242 [0 lua] "pexpire" "resource" "3000"
1739548294.130444 [0 192.168.1.198:34954] "SET" "resource" "FTnFC9cFuUwVcScABfzi" "PX" "3000" "NX"
1739548294.130926 [0 192.168.1.198:34954] "EVAL" "\nif redis.call("GET",KEYS[1]) == ARGV[1] then\n return redis.call("del",KEYS[1])\nelse\n return 0\nend\n" "1" "resource" "FTnFC9cFuUwVcScABfzi"
1739548294.130959 [0 lua] "GET" "resource"
1739548294.631596 [0 192.168.1.198:34954] "SET" "resource" "prcwfMsbSXZlMB1IjzwV" "PX" "3000" "NX"
1739548294.632120 [0 192.168.1.198:34954] "EVAL" "\nif redis.call("GET",KEYS[1]) == ARGV[1] then\n return redis.call("del",KEYS[1])\nelse\n return 0\nend\n" "1" "resource" "prcwfMsbSXZlMB1IjzwV"
1739548294.632154 [0 lua] "GET" "resource"
1739548295.132724 [0 192.168.1.198:34954] "SET" "resource" "8QuAhN2oA19YGqZ0BKG4" "PX" "3000" "NX"
1739548295.133187 [0 192.168.1.198:34954] "EVAL" "\nif redis.call("GET",KEYS[1]) == ARGV[1] then\n return redis.call("del",KEYS[1])\nelse\n return 0\nend\n" "1" "resource" "8QuAhN2oA19YGqZ0BKG4"
1739548295.133239 [0 lua] "GET" "resource"
1739548295.457990 [0 192.168.2.138:45362] "EVAL" "\nif redis.call("GET",KEYS[1]) == ARGV[1] then\n return redis.call("pexpire",KEYS[1],ARGV[2])\nelse\n return 0\nend\n" "1" "resource" "xbk7o7JxZxz4onL0Am9f" "3000"
1739548295.458035 [0 lua] "GET" "resource"
1739548295.458049 [0 lua] "pexpire" "resource" "3000"
1739548295.633821 [0 192.168.1.198:34954] "SET" "resource" "khQZYef6eL2QaLJsQOuc" "PX" "3000" "NX"
1739548295.634355 [0 192.168.1.198:34954] "EVAL" "\nif redis.call("GET",KEYS[1]) == ARGV[1] then\n return redis.call("del",KEYS[1])\nelse\n return 0\nend\n" "1" "resource" "khQZYef6eL2QaLJsQOuc"
1739548295.634391 [0 lua] "GET" "resource"
1739548296.134933 [0 192.168.1.198:34954] "SET" "resource" "94lZVGLx0ROFBXWkJfQU" "PX" "3000" "NX"
1739548296.135511 [0 192.168.1.198:34954] "EVAL" "\nif redis.call("GET",KEYS[1]) == ARGV[1] then\n return redis.call("del",KEYS[1])\nelse\n return 0\nend\n" "1" "resource" "94lZVGLx0ROFBXWkJfQU"
1739548296.135551 [0 lua] "GET" "resource"
1739548296.636383 [0 192.168.1.198:34954] "SET" "resource" "4ZfuiOYiCMEdHkUsFa9g" "PX" "3000" "NX"
1739548296.636900 [0 192.168.1.198:34954] "EVAL" "\nif redis.call("GET",KEYS[1]) == ARGV[1] then\n return redis.call("del",KEYS[1])\nelse\n return 0\nend\n" "1" "resource" "4ZfuiOYiCMEdHkUsFa9g"
1739548296.636939 [0 lua] "GET" "resource"
1739548296.957715 [0 192.168.2.138:45362] "EVAL" "\nif redis.call("GET",KEYS[1]) == ARGV[1] then\n return redis.call("pexpire",KEYS[1],ARGV[2])\nelse\n return 0\nend\n" "1" "resource" "xbk7o7JxZxz4onL0Am9f" "3000"
1739548296.957762 [0 lua] "GET" "resource"
1739548296.957776 [0 lua] "pexpire" "resource" "3000"
1739548297.137595 [0 192.168.1.198:34954] "SET" "resource" "eSQXdkQxFHQLVbUaZmt2" "PX" "3000" "NX"
1739548297.138100 [0 192.168.1.198:34954] "EVAL" "\nif redis.call("GET",KEYS[1]) == ARGV[1] then\n return redis.call("del",KEYS[1])\nelse\n return 0\nend\n" "1" "resource" "eSQXdkQxFHQLVbUaZmt2"
1739548297.138140 [0 lua] "GET" "resource"
1739548297.638716 [0 192.168.1.198:34954] "SET" "resource" "Xk0tdbylLBv0WBCSdwBc" "PX" "3000" "NX"
1739548297.639313 [0 192.168.1.198:34954] "EVAL" "\nif redis.call("GET",KEYS[1]) == ARGV[1] then\n return redis.call("del",KEYS[1])\nelse\n return 0\nend\n" "1" "resource" "Xk0tdbylLBv0WBCSdwBc"
1739548297.639357 [0 lua] "GET" "resource"
1739548298.139923 [0 192.168.1.198:34954] "SET" "resource" "8CKjOEqNnIJglgbjWbvp" "PX" "3000" "NX"
1739548298.140414 [0 192.168.1.198:34954] "EVAL" "\nif redis.call("GET",KEYS[1]) == ARGV[1] then\n return redis.call("del",KEYS[1])\nelse\n return 0\nend\n" "1" "resource" "8CKjOEqNnIJglgbjWbvp"
1739548298.140450 [0 lua] "GET" "resource"
1739548298.457439 [0 192.168.2.138:45362] "EVAL" "\nif redis.call("GET",KEYS[1]) == ARGV[1] then\n return redis.call("pexpire",KEYS[1],ARGV[2])\nelse\n return 0\nend\n" "1" "resource" "xbk7o7JxZxz4onL0Am9f" "3000"
1739548298.457484 [0 lua] "GET" "resource"
1739548298.457499 [0 lua] "pexpire" "resource" "3000"
1739548298.641143 [0 192.168.1.198:34954] "SET" "resource" "5twlw4Bf2TQIFrm7if5G" "PX" "3000" "NX"
1739548298.641639 [0 192.168.1.198:34954] "EVAL" "\nif redis.call("GET",KEYS[1]) == ARGV[1] then\n return redis.call("del",KEYS[1])\nelse\n return 0\nend\n" "1" "resource" "5twlw4Bf2TQIFrm7if5G"
1739548298.641675 [0 lua] "GET" "resource"
1739548299.142399 [0 192.168.1.198:34954] "SET" "resource" "Ctf3RLNMjbXQn3TU3T3B" "PX" "3000" "NX"
1739548299.142896 [0 192.168.1.198:34954] "EVAL" "\nif redis.call("GET",KEYS[1]) == ARGV[1] then\n return redis.call("del",KEYS[1])\nelse\n return 0\nend\n" "1" "resource" "Ctf3RLNMjbXQn3TU3T3B"
1739548299.142928 [0 lua] "GET" "resource"
1739548299.643625 [0 192.168.1.198:34954] "SET" "resource" "aCYUd66TtTzLe9vlxDWp" "PX" "3000" "NX"
1739548299.644259 [0 192.168.1.198:34954] "EVAL" "\nif redis.call("GET",KEYS[1]) == ARGV[1] then\n return redis.call("del",KEYS[1])\nelse\n return 0\nend\n" "1" "resource" "aCYUd66TtTzLe9vlxDWp"
1739548299.644289 [0 lua] "GET" "resource"
1739548299.957336 [0 192.168.2.138:45362] "EVAL" "\nif redis.call("GET",KEYS[1]) == ARGV[1] then\n return redis.call("pexpire",KEYS[1],ARGV[2])\nelse\n return 0\nend\n" "1" "resource" "xbk7o7JxZxz4onL0Am9f" "3000"
1739548299.957381 [0 lua] "GET" "resource"
1739548299.957395 [0 lua] "pexpire" "resource" "3000"
1739548300.144930 [0 192.168.1.198:34954] "SET" "resource" "sVslzZmnQ9wvKyyi3TUV" "PX" "3000" "NX"
1739548300.145542 [0 192.168.1.198:34954] "EVAL" "\nif redis.call("GET",KEYS[1]) == ARGV[1] then\n return redis.call("del",KEYS[1])\nelse\n return 0\nend\n" "1" "resource" "sVslzZmnQ9wvKyyi3TUV"
1739548300.145573 [0 lua] "GET" "resource"
1739548300.646421 [0 192.168.1.198:34954] "SET" "resource" "Out9rCtoS4A7XRPuoG8D" "PX" "3000" "NX"
1739548300.647023 [0 192.168.1.198:34954] "EVAL" "\nif redis.call("GET",KEYS[1]) == ARGV[1] then\n return redis.call("del",KEYS[1])\nelse\n return 0\nend\n" "1" "resource" "Out9rCtoS4A7XRPuoG8D"
1739548300.647072 [0 lua] "GET" "resource"
1739548301.147810 [0 192.168.1.198:34954] "SET" "resource" "tw0GsMfE5Y9KteS93QQm" "PX" "3000" "NX"
1739548301.148364 [0 192.168.1.198:34954] "EVAL" "\nif redis.call("GET",KEYS[1]) == ARGV[1] then\n return redis.call("del",KEYS[1])\nelse\n return 0\nend\n" "1" "resource" "tw0GsMfE5Y9KteS93QQm"
1739548301.148397 [0 lua] "GET" "resource"
1739548301.457003 [0 192.168.2.138:45362] "EVAL" "\nif redis.call("GET",KEYS[1]) == ARGV[1] then\n return redis.call("pexpire",KEYS[1],ARGV[2])\nelse\n return 0\nend\n" "1" "resource" "xbk7o7JxZxz4onL0Am9f" "3000"
1739548301.457057 [0 lua] "GET" "resource"
1739548301.457071 [0 lua] "pexpire" "resource" "3000"
1739548301.649015 [0 192.168.1.198:34954] "SET" "resource" "jOEO7kmfvwlZTbTD11LY" "PX" "3000" "NX"
1739548301.649586 [0 192.168.1.198:34954] "EVAL" "\nif redis.call("GET",KEYS[1]) == ARGV[1] then\n return redis.call("del",KEYS[1])\nelse\n return 0\nend\n" "1" "resource" "jOEO7kmfvwlZTbTD11LY"
1739548301.649618 [0 lua] "GET" "resource"
1739548302.150449 [0 192.168.1.198:34954] "SET" "resource" "g5AArbPhoeZwoG2i8ni0" "PX" "3000" "NX"
1739548302.150969 [0 192.168.1.198:34954] "EVAL" "\nif redis.call("GET",KEYS[1]) == ARGV[1] then\n return redis.call("del",KEYS[1])\nelse\n return 0\nend\n" "1" "resource" "g5AArbPhoeZwoG2i8ni0"
1739548302.151004 [0 lua] "GET" "resource"
1739548302.651684 [0 192.168.1.198:34954] "SET" "resource" "fsobQIGQFcDFahHjc0vI" "PX" "3000" "NX"
1739548302.652380 [0 192.168.1.198:34954] "EVAL" "\nif redis.call("GET",KEYS[1]) == ARGV[1] then\n return redis.call("del",KEYS[1])\nelse\n return 0\nend\n" "1" "resource" "fsobQIGQFcDFahHjc0vI"
1739548302.652415 [0 lua] "GET" "resource"
1739548302.956825 [0 192.168.2.138:45362] "EVAL" "\nif redis.call("GET",KEYS[1]) == ARGV[1] then\n return redis.call("pexpire",KEYS[1],ARGV[2])\nelse\n return 0\nend\n" "1" "resource" "xbk7o7JxZxz4onL0Am9f" "3000"
1739548302.956863 [0 lua] "GET" "resource"
1739548302.956876 [0 lua] "pexpire" "resource" "3000"
1739548303.153000 [0 192.168.1.198:34954] "SET" "resource" "rlX9h0V9dhqpNVJ3bHjx" "PX" "3000" "NX"
1739548303.153480 [0 192.168.1.198:34954] "EVAL" "\nif redis.call("GET",KEYS[1]) == ARGV[1] then\n return redis.call("del",KEYS[1])\nelse\n return 0\nend\n" "1" "resource" "rlX9h0V9dhqpNVJ3bHjx"
1739548303.153515 [0 lua] "GET" "resource"
1739548303.654154 [0 192.168.1.198:34954] "SET" "resource" "39dGPlWbLroWGdcxSHiM" "PX" "3000" "NX"
1739548303.654607 [0 192.168.1.198:34954] "EVAL" "\nif redis.call("GET",KEYS[1]) == ARGV[1] then\n return redis.call("del",KEYS[1])\nelse\n return 0\nend\n" "1" "resource" "39dGPlWbLroWGdcxSHiM"
1739548303.654635 [0 lua] "GET" "resource"
1739548304.155452 [0 192.168.1.198:34954] "SET" "resource" "HETPWYfAknXFmZpydptE" "PX" "3000" "NX"
1739548304.155968 [0 192.168.1.198:34954] "EVAL" "\nif redis.call("GET",KEYS[1]) == ARGV[1] then\n return redis.call("del",KEYS[1])\nelse\n return 0\nend\n" "1" "resource" "HETPWYfAknXFmZpydptE"
1739548304.156001 [0 lua] "GET" "resource"
1739548304.456639 [0 192.168.2.138:45362] "EVAL" "\nif redis.call("GET",KEYS[1]) == ARGV[1] then\n return redis.call("pexpire",KEYS[1],ARGV[2])\nelse\n return 0\nend\n" "1" "resource" "xbk7o7JxZxz4onL0Am9f" "3000"
1739548304.456683 [0 lua] "GET" "resource"
1739548304.456699 [0 lua] "pexpire" "resource" "3000"
1739548304.656648 [0 192.168.1.198:34954] "SET" "resource" "NWxWKX3IZHfXZOY6fipq" "PX" "3000" "NX"
1739548304.657140 [0 192.168.1.198:34954] "EVAL" "\nif redis.call("GET",KEYS[1]) == ARGV[1] then\n return redis.call("del",KEYS[1])\nelse\n return 0\nend\n" "1" "resource" "NWxWKX3IZHfXZOY6fipq"
1739548304.657172 [0 lua] "GET" "resource"
1739548305.157729 [0 192.168.1.198:34954] "SET" "resource" "ffs0fCQTb1G0HkZkP303" "PX" "3000" "NX"
1739548305.158215 [0 192.168.1.198:34954] "EVAL" "\nif redis.call("GET",KEYS[1]) == ARGV[1] then\n return redis.call("del",KEYS[1])\nelse\n return 0\nend\n" "1" "resource" "ffs0fCQTb1G0HkZkP303"

@sewenew
Copy link
Owner

sewenew commented Feb 15, 2025

From the redis server logs, you've already gotten the lock.

"EVAL" "\nif redis.call("GET",KEYS[1]) == ARGV[1] then\n return redis.call("pexpire",KEYS[1],ARGV[2])\nelse\n return 0\nend\n" "1" "resource" "xbk7o7JxZxz4onL0Am9f" "3000"

This script is running only when redis-plus-plus gets the lock, and try to extend it in a background thread. You can check if your code forget to unlock redlock.

Since your code cannot be compiled, I wrote some test code. redis-plus-plus can get the lock successfully. You can try the following code.

void do_lock(int worker_id) {
    ConnectionOptions opts;
    opts.host = "127.0.0.1";
    opts.port = 6379;
    ConnectionPoolOptions pool_opts;
    pool_opts.size = 3;
    auto redis_cli = make_shared<Redis>(opts, pool_opts);
    RedMutex mtx(redis_cli, "some-unique-resource-name");
    auto redlock = std::unique_lock<RedMutex>(mtx, std::defer_lock);
    while (true) {
        if (redlock.try_lock()) {
            printf("worker: %d lock OK\n", worker_id);
            redlock.unlock();
            std::this_thread::sleep_for(std::chrono::seconds(1));
        } else {
            printf("worker: %d lock fail\n", worker_id);
            std::this_thread::sleep_for(std::chrono::seconds(1));
        }
    }
}

int main() {
    auto thread1 = std::thread([]() { do_lock(1); });
    auto thread2 = std::thread([]() { do_lock(2); });
    thread1.join();
    thread2.join();

    return 0;
}

Regards

@hsh258
Copy link
Author

hsh258 commented Feb 15, 2025

From the redis server logs, you've already gotten the lock.

"EVAL" "\nif redis.call("GET",KEYS[1]) == ARGV[1] then\n return redis.call("pexpire",KEYS[1],ARGV[2])\nelse\n return 0\nend\n" "1" "resource" "xbk7o7JxZxz4onL0Am9f" "3000"

This script is running only when redis-plus-plus gets the lock, and try to extend it in a background thread. You can check if your code forget to unlock redlock.

Since your code cannot be compiled, I wrote some test code. redis-plus-plus can get the lock successfully. You can try the following code.

void do_lock(int worker_id) {
    ConnectionOptions opts;
    opts.host = "127.0.0.1";
    opts.port = 6379;
    ConnectionPoolOptions pool_opts;
    pool_opts.size = 3;
    auto redis_cli = make_shared<Redis>(opts, pool_opts);
    RedMutex mtx(redis_cli, "some-unique-resource-name");
    auto redlock = std::unique_lock<RedMutex>(mtx, std::defer_lock);
    while (true) {
        if (redlock.try_lock()) {
            printf("worker: %d lock OK\n", worker_id);
            redlock.unlock();
            std::this_thread::sleep_for(std::chrono::seconds(1));
        } else {
            printf("worker: %d lock fail\n", worker_id);
            std::this_thread::sleep_for(std::chrono::seconds(1));
        }
    }
}

int main() {
    auto thread1 = std::thread([]() { do_lock(1); });
    auto thread2 = std::thread([]() { do_lock(2); });
    thread1.join();
    thread2.join();

    return 0;
}

Regards

Hi,
Thank you very much.
How do the redis-plus-plus find the issue of "This script is running only when redis-plus-plus gets the lock, and try to extend it in a background thread."?

@sewenew
Copy link
Owner

sewenew commented Feb 15, 2025

How do the redis-plus-plus find the issue of "This script is running only when redis-plus-plus gets the lock, and try to extend it in a background thread."?

Sorry, but I do not get your point. What do you by redis-plus-plus find the issue?

Regards

@hsh258
Copy link
Author

hsh258 commented Feb 16, 2025

How do the redis-plus-plus find the issue of "This script is running only when redis-plus-plus gets the lock, and try to extend it in a background thread."?

Sorry, but I do not get your point. What do you by redis-plus-plus find the issue?

Regards

Sorry,I want to express that:
Does the Redis-plus-plus client have a method to be aware that it has previously acquired the lock?
Thank you very much.

@hsh258
Copy link
Author

hsh258 commented Feb 16, 2025

How do the redis-plus-plus find the issue of "This script is running only when redis-plus-plus gets the lock, and try to extend it in a background thread."?

Sorry, but I do not get your point. What do you by redis-plus-plus find the issue?
Regards

Sorry,I want to express that: Does the Redis-plus-plus client have a method to be aware that it has previously acquired the lock? Thank you very much.
As you say, the lock was not release normal(try unlock,catch err, Why?).
However, after ttl expire,Why hasn't the server released the lock after the TTL has expired?
Thank you very much.

@sewenew
Copy link
Owner

sewenew commented Feb 18, 2025

Once std::unique_lock::try_lock returns true, or std::unique_lock::lock returns, redis-plus-plus acquires the lock. There's no other method to get this info.

Regards

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants