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

feat(server): Implement SCRIPT FLUSH command #2493

Merged
merged 7 commits into from
Jan 31, 2024

Conversation

highpon
Copy link
Contributor

@highpon highpon commented Jan 28, 2024

Related Issue: #851

@romange romange requested a review from adiholden January 28, 2024 15:13
void ScriptMgr::FlushCmd(CmdArgList args, ConnectionContext* cntx) {
FlushAllScript();

auto rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
auto rb = static_cast<RedisReplyBuilder*>(cntx->reply_builder());
return cntx->SendOk();

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fix: 294208f



@pytest.mark.asyncio
async def test_script_flush(async_client):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We usually use pytest things we can not test in our unit tests.
I think this one is simple to add to our unit tests, check out dragonfly_test.cc for test example on script command tests

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fix: af62600

assert exists[0] == True

result = await async_client.script_flush()
exists = await async_client.script_exists(sha1)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the unit test I would also add a load script after flush and check that it was loaded

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fix: af62600


ServerState* ss = ServerState::tlocal();
auto interpreter = ss->BorrowInterpreter();
interpreter->ResetStack();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add
ss->ReturnInterpreter(interpreter);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fix: 9f7e184

EXPECT_THAT(1, resp.GetInt());

resp = Run({"script", "flush"});
resp = Run({"script", "exists", sha});
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I run you branch and it looks that it does not flushes the scripts.
If you run evalsha sha 0 the script will run and return 5.
Please add this check to unit test and I will try to help to explain what we should do in flush code below

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@adiholden
Thanks for your help!
I add test for evalsha.
494d923


ServerState* ss = ServerState::tlocal();
auto interpreter = ss->BorrowInterpreter();
interpreter->ResetStack();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So as I wrote above the ResetStack does not flushes the scripts data from interpreter.
From what I understand we should actually reset all interpreters in all shards.
To do so we need to do
shard_set->pool()->Await([&sha, &params](auto index, auto* pb) {
ServerState::tlocal()->ResetInterpreters();
});
This will make sure that ResetInterpreters will run on all dragonfly shards
ServerState::ResetInterpreters should access interpreter_mgr_ and reconstruct all the Interpreters in InterpreterManager::storage_. also you will need to make sure that no initerperter is borrowed i.e available_.size() == storage_.size() before you reset them as there might be other lua scripts running when you run flush

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@adiholden
Thanks for your help!
I fixed my code according to your advice.
ab2662b

Currently, my code occured segmentation fault when running EVALSHA command after running SCRIPT FLUSH command.
I was investigating this problem.

void InterpreterManager::Reset() {
waker_.await([this]() { return available_.size() == storage_.size(); });

for (auto& interpreter : storage_) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually I see that we need to reset the storage_ and the available_ as available holds pointers to interperters that are in storage_
check out the InterpreterManager::Get() logic
so you dont need to go over storage_ and call constructor again. reset will be enough

@adiholden
Copy link
Collaborator

Thanks for your contribution! @highpon

@adiholden adiholden merged commit 73fe5a4 into dragonflydb:main Jan 31, 2024
7 checks passed
@highpon highpon deleted the fix/851 branch January 31, 2024 13:44
@highpon
Copy link
Contributor Author

highpon commented Jan 31, 2024

@adiholden
Thanks for your great help!

@highpon highpon changed the title fix(server): Implement SCRIPT FLUSH command feat(server): Implement SCRIPT FLUSH command Jan 31, 2024
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

Successfully merging this pull request may close these issues.

2 participants