Skip to content

Commit 87e88b3

Browse files
authored
fix: Handle bonus key + init error in squashing (#5303)
* fix: Handle bonus key + init error in squashing
1 parent 35a602c commit 87e88b3

File tree

3 files changed

+39
-7
lines changed

3 files changed

+39
-7
lines changed

src/server/multi_command_squasher.cc

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -153,10 +153,14 @@ bool MultiCommandSquasher::ExecuteStandalone(RedisReplyBuilder* rb, const Stored
153153
auto* tx = cntx_->transaction;
154154
if (cmd->Cid()->IsTransactional()) {
155155
tx->MultiSwitchCmd(cmd->Cid());
156-
tx->InitByArgs(cntx_->ns, cntx_->conn_state.db_index, args);
156+
auto status = tx->InitByArgs(cntx_->ns, cntx_->conn_state.db_index, args);
157+
if (status != OpStatus::OK) {
158+
rb->SendError(status);
159+
rb->ConsumeLastError();
160+
return !opts_.error_abort;
161+
}
157162
}
158163
service_->InvokeCmd(cmd->Cid(), args, CommandContext{tx, rb, cntx_});
159-
160164
return true;
161165
}
162166

@@ -195,10 +199,13 @@ OpStatus MultiCommandSquasher::SquashedHopCb(EngineShard* es, RespVersion resp_v
195199
crb.SetReplyMode(dispatched.cmd->ReplyMode());
196200

197201
local_tx->MultiSwitchCmd(dispatched.cmd->Cid());
198-
local_tx->InitByArgs(cntx_->ns, local_cntx.conn_state.db_index, args);
199-
service_->InvokeCmd(dispatched.cmd->Cid(), args,
200-
CommandContext{local_cntx.transaction, &crb, &local_cntx});
201-
202+
auto status = local_tx->InitByArgs(cntx_->ns, local_cntx.conn_state.db_index, args);
203+
if (status != OpStatus::OK) {
204+
crb.SendError(status);
205+
} else {
206+
service_->InvokeCmd(dispatched.cmd->Cid(), args,
207+
CommandContext{local_cntx.transaction, &crb, &local_cntx});
208+
}
202209
move_reply(crb.Take(), &dispatched.reply);
203210

204211
// Assert commands made no persistent state changes to stub context state

src/server/multi_test.cc

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,29 @@ TEST_F(MultiTest, MultiWithoutTx) {
330330
EXPECT_EQ(resp.GetVec()[4], "OK3");
331331
}
332332

333+
TEST_F(MultiTest, MultiCommandsWithBonusKeys) {
334+
absl::FlagSaver fs;
335+
absl::SetFlag(&FLAGS_multi_exec_squash, true);
336+
337+
EXPECT_EQ(Shard("za", shard_set->size()), Shard("zb", shard_set->size()));
338+
EXPECT_EQ(Shard("zb", shard_set->size()), Shard("ze", shard_set->size()));
339+
340+
// Check bonus keys are correctly processed with squashing
341+
Run({"multi"});
342+
Run({"zadd", "za", "1", "a", "2", "b"});
343+
Run({"zadd", "zb", "2", "b", "3", "c"});
344+
Run({"zinterstore", "ze", "2", "za", "zb"});
345+
auto resp = Run({"exec"});
346+
EXPECT_THAT(resp.GetVec()[2], IntArg(1));
347+
EXPECT_THAT(Run({"zcard", "ze"}), IntArg(1));
348+
349+
// Check squashing correctly pre-validates commands
350+
Run({"multi"});
351+
Run({"zinterstore", "ze", "2", "za", "zb", "z one extra"});
352+
resp = Run({"exec"});
353+
EXPECT_THAT(resp, ErrArg("syntax error"));
354+
}
355+
333356
TEST_F(MultiTest, MultiHop) {
334357
Run({"set", kKey1, "1"});
335358

src/server/transaction.cc

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -307,12 +307,14 @@ void Transaction::PrepareMultiFps(CmdArgList keys) {
307307
}
308308

309309
void Transaction::StoreKeysInArgs(const KeyIndex& key_index) {
310-
DCHECK(!key_index.bonus);
311310
DCHECK(kv_fp_.empty());
312311
DCHECK(args_slices_.empty());
313312

314313
// even for a single key we may have multiple arguments per key (MSET).
314+
if (key_index.bonus)
315+
args_slices_.emplace_back(*key_index.bonus, *key_index.bonus + 1);
315316
args_slices_.emplace_back(key_index.start, key_index.end);
317+
316318
for (string_view key : key_index.Range(full_args_))
317319
kv_fp_.push_back(LockTag(key).Fingerprint());
318320
}

0 commit comments

Comments
 (0)